From: tbaudier Date: Wed, 30 Nov 2016 12:21:22 +0000 (+0100) Subject: cosmetic X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=df724140fd47a31aaa0feaba5938a1eecb263741;p=clitk.git cosmetic dos2unix --- diff --git a/itk/itkBinaryThinningImageFilter3D.h b/itk/itkBinaryThinningImageFilter3D.h index 12926e9..f75d883 100644 --- a/itk/itkBinaryThinningImageFilter3D.h +++ b/itk/itkBinaryThinningImageFilter3D.h @@ -15,160 +15,160 @@ - BSD See included LICENSE.txt file - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html ===========================================================================*/ -#ifndef __itkBinaryThinningImageFilter3D_h -#define __itkBinaryThinningImageFilter3D_h - -#include -#include -#include -#include - -namespace itk -{ -/** \class BinaryThinningImageFilter3D -* -* \brief This filter computes one-pixel-wide skeleton of a 3D input image. -* -* This class is parametrized over the type of the input image -* and the type of the output image. -* -* The input is assumed to be a binary image. All non-zero valued voxels -* are set to 1 internally to simplify the computation. The filter will -* produce a skeleton of the object. The output background values are 0, -* and the foreground values are 1. -* -* A 26-neighbourhood configuration is used for the foreground and a -* 6-neighbourhood configuration for the background. Thinning is performed -* symmetrically in order to guarantee that the skeleton lies medial within -* the object. -* -* This filter is a parallel thinning algorithm and is an implementation -* of the algorithm described in: -* -* T.C. Lee, R.L. Kashyap, and C.N. Chu. -* Building skeleton models via 3-D medial surface/axis thinning algorithms. -* Computer Vision, Graphics, and Image Processing, 56(6):462--478, 1994. -* -* To do: Make use of multi-threading. -* -* \author Hanno Homann, Oxford University, Wolfson Medical Vision Lab, UK. -* -* \sa MorphologyImageFilter -* \ingroup ImageEnhancement MathematicalMorphologyImageFilters -*/ - -template -class BinaryThinningImageFilter3D : - public ImageToImageFilter -{ -public: - /** Standard class typedefs. */ - typedef BinaryThinningImageFilter3D Self; - typedef ImageToImageFilter Superclass; - typedef SmartPointer Pointer; - typedef SmartPointer ConstPointer; - - /** Method for creation through the object factory */ - itkNewMacro(Self); - - /** Run-time type information (and related methods). */ - itkTypeMacro( BinaryThinningImageFilter3D, ImageToImageFilter ); - - /** Type for input image. */ - typedef TInputImage InputImageType; - - /** Type for output image: Skelenton of the object. */ - typedef TOutputImage OutputImageType; - - /** Type for the region of the input image. */ - typedef typename InputImageType::RegionType RegionType; - - /** Type for the index of the input image. */ - typedef typename RegionType::IndexType IndexType; - - /** Type for the pixel type of the input image. */ - typedef typename InputImageType::PixelType InputImagePixelType ; - - /** Type for the pixel type of the input image. */ - typedef typename OutputImageType::PixelType OutputImagePixelType ; - - /** Type for the size of the input image. */ - typedef typename RegionType::SizeType SizeType; - - /** Pointer Type for input image. */ - typedef typename InputImageType::ConstPointer InputImagePointer; - - /** Pointer Type for the output image. */ - typedef typename OutputImageType::Pointer OutputImagePointer; - - /** Boundary condition type for the neighborhood iterator */ - typedef ConstantBoundaryCondition< TInputImage > ConstBoundaryConditionType; - - /** Neighborhood iterator type */ - typedef NeighborhoodIterator NeighborhoodIteratorType; - - /** Neighborhood type */ - typedef typename NeighborhoodIteratorType::NeighborhoodType NeighborhoodType; - - /** Get Skelenton by thinning image. */ - OutputImageType * GetThinning(void); - - /** ImageDimension enumeration */ - itkStaticConstMacro(InputImageDimension, unsigned int, - TInputImage::ImageDimension ); - itkStaticConstMacro(OutputImageDimension, unsigned int, - TOutputImage::ImageDimension ); - -#ifdef ITK_USE_CONCEPT_CHECKING - /** Begin concept checking */ - itkConceptMacro(SameDimensionCheck, - (Concept::SameDimension)); - itkConceptMacro(SameTypeCheck, - (Concept::SameType)); - itkConceptMacro(InputAdditiveOperatorsCheck, - (Concept::AdditiveOperators)); - itkConceptMacro(InputConvertibleToIntCheck, - (Concept::Convertible)); - itkConceptMacro(IntConvertibleToInputCheck, - (Concept::Convertible)); - itkConceptMacro(InputIntComparableCheck, - (Concept::Comparable)); - /** End concept checking */ -#endif - -protected: - BinaryThinningImageFilter3D(); - virtual ~BinaryThinningImageFilter3D() {}; - void PrintSelf(std::ostream& os, Indent indent) const; - - /** Compute thinning Image. */ - void GenerateData(); - - /** Prepare data. */ - void PrepareData(); - - /** Compute thinning Image. */ - void ComputeThinImage(); - - /** isEulerInvariant [Lee94] */ - bool isEulerInvariant(NeighborhoodType neighbors, int *LUT); - void fillEulerLUT(int *LUT); - /** isSimplePoint [Lee94] */ - bool isSimplePoint(NeighborhoodType neighbors); - /** Octree_labeling [Lee94] */ - void Octree_labeling(int octant, int label, int *cube); - - -private: - BinaryThinningImageFilter3D(const Self&); //purposely not implemented - void operator=(const Self&); //purposely not implemented - -}; // end of BinaryThinningImageFilter3D class - -} //end namespace itk - -#ifndef ITK_MANUAL_INSTANTIATION -#include "itkBinaryThinningImageFilter3D.txx" -#endif - -#endif +#ifndef __itkBinaryThinningImageFilter3D_h +#define __itkBinaryThinningImageFilter3D_h + +#include +#include +#include +#include + +namespace itk +{ +/** \class BinaryThinningImageFilter3D +* +* \brief This filter computes one-pixel-wide skeleton of a 3D input image. +* +* This class is parametrized over the type of the input image +* and the type of the output image. +* +* The input is assumed to be a binary image. All non-zero valued voxels +* are set to 1 internally to simplify the computation. The filter will +* produce a skeleton of the object. The output background values are 0, +* and the foreground values are 1. +* +* A 26-neighbourhood configuration is used for the foreground and a +* 6-neighbourhood configuration for the background. Thinning is performed +* symmetrically in order to guarantee that the skeleton lies medial within +* the object. +* +* This filter is a parallel thinning algorithm and is an implementation +* of the algorithm described in: +* +* T.C. Lee, R.L. Kashyap, and C.N. Chu. +* Building skeleton models via 3-D medial surface/axis thinning algorithms. +* Computer Vision, Graphics, and Image Processing, 56(6):462--478, 1994. +* +* To do: Make use of multi-threading. +* +* \author Hanno Homann, Oxford University, Wolfson Medical Vision Lab, UK. +* +* \sa MorphologyImageFilter +* \ingroup ImageEnhancement MathematicalMorphologyImageFilters +*/ + +template +class BinaryThinningImageFilter3D : + public ImageToImageFilter +{ +public: + /** Standard class typedefs. */ + typedef BinaryThinningImageFilter3D Self; + typedef ImageToImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro( BinaryThinningImageFilter3D, ImageToImageFilter ); + + /** Type for input image. */ + typedef TInputImage InputImageType; + + /** Type for output image: Skelenton of the object. */ + typedef TOutputImage OutputImageType; + + /** Type for the region of the input image. */ + typedef typename InputImageType::RegionType RegionType; + + /** Type for the index of the input image. */ + typedef typename RegionType::IndexType IndexType; + + /** Type for the pixel type of the input image. */ + typedef typename InputImageType::PixelType InputImagePixelType ; + + /** Type for the pixel type of the input image. */ + typedef typename OutputImageType::PixelType OutputImagePixelType ; + + /** Type for the size of the input image. */ + typedef typename RegionType::SizeType SizeType; + + /** Pointer Type for input image. */ + typedef typename InputImageType::ConstPointer InputImagePointer; + + /** Pointer Type for the output image. */ + typedef typename OutputImageType::Pointer OutputImagePointer; + + /** Boundary condition type for the neighborhood iterator */ + typedef ConstantBoundaryCondition< TInputImage > ConstBoundaryConditionType; + + /** Neighborhood iterator type */ + typedef NeighborhoodIterator NeighborhoodIteratorType; + + /** Neighborhood type */ + typedef typename NeighborhoodIteratorType::NeighborhoodType NeighborhoodType; + + /** Get Skelenton by thinning image. */ + OutputImageType * GetThinning(void); + + /** ImageDimension enumeration */ + itkStaticConstMacro(InputImageDimension, unsigned int, + TInputImage::ImageDimension ); + itkStaticConstMacro(OutputImageDimension, unsigned int, + TOutputImage::ImageDimension ); + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(SameDimensionCheck, + (Concept::SameDimension)); + itkConceptMacro(SameTypeCheck, + (Concept::SameType)); + itkConceptMacro(InputAdditiveOperatorsCheck, + (Concept::AdditiveOperators)); + itkConceptMacro(InputConvertibleToIntCheck, + (Concept::Convertible)); + itkConceptMacro(IntConvertibleToInputCheck, + (Concept::Convertible)); + itkConceptMacro(InputIntComparableCheck, + (Concept::Comparable)); + /** End concept checking */ +#endif + +protected: + BinaryThinningImageFilter3D(); + virtual ~BinaryThinningImageFilter3D() {}; + void PrintSelf(std::ostream& os, Indent indent) const; + + /** Compute thinning Image. */ + void GenerateData(); + + /** Prepare data. */ + void PrepareData(); + + /** Compute thinning Image. */ + void ComputeThinImage(); + + /** isEulerInvariant [Lee94] */ + bool isEulerInvariant(NeighborhoodType neighbors, int *LUT); + void fillEulerLUT(int *LUT); + /** isSimplePoint [Lee94] */ + bool isSimplePoint(NeighborhoodType neighbors); + /** Octree_labeling [Lee94] */ + void Octree_labeling(int octant, int label, int *cube); + + +private: + BinaryThinningImageFilter3D(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; // end of BinaryThinningImageFilter3D class + +} //end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkBinaryThinningImageFilter3D.txx" +#endif + +#endif diff --git a/registration/clitkBSplineDeformableTransformInitializer.txx b/registration/clitkBSplineDeformableTransformInitializer.txx index 59af63c..5dce785 100644 --- a/registration/clitkBSplineDeformableTransformInitializer.txx +++ b/registration/clitkBSplineDeformableTransformInitializer.txx @@ -1,4 +1,4 @@ -/*========================================================================= +/*========================================================================= Program: vv http://www.creatis.insa-lyon.fr/rio/vv Authors belong to: diff --git a/utilities/CxImage/CxImageDLL/CxImageCrtDll.cpp b/utilities/CxImage/CxImageDLL/CxImageCrtDll.cpp index ad468ed..d4e022f 100644 --- a/utilities/CxImage/CxImageDLL/CxImageCrtDll.cpp +++ b/utilities/CxImage/CxImageDLL/CxImageCrtDll.cpp @@ -1,13 +1,13 @@ -// CxImageCrtDll.cpp : Defines the entry point for the CxImageCrtDll application. -// - -#include "stdcrt.h" - -BOOL APIENTRY DllMain( HANDLE /*hModule*/, - DWORD /*ul_reason_for_call*/, - LPVOID /*lpReserved*/ - ) -{ - return TRUE; -} - +// CxImageCrtDll.cpp : Defines the entry point for the CxImageCrtDll application. +// + +#include "stdcrt.h" + +BOOL APIENTRY DllMain( HANDLE /*hModule*/, + DWORD /*ul_reason_for_call*/, + LPVOID /*lpReserved*/ + ) +{ + return TRUE; +} + diff --git a/utilities/CxImage/CxImageDLL/CxImageCrtDll.dsp b/utilities/CxImage/CxImageDLL/CxImageCrtDll.dsp index 09d1c69..f92cfb9 100644 --- a/utilities/CxImage/CxImageDLL/CxImageCrtDll.dsp +++ b/utilities/CxImage/CxImageDLL/CxImageCrtDll.dsp @@ -1,415 +1,415 @@ -# Microsoft Developer Studio Project File - Name="CxImageCrtDll" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=CxImageCrtDll - Win32 Unicode Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "CxImageCrtDll.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "CxImageCrtDll.mak" CFG="CxImageCrtDll - Win32 Unicode Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "CxImageCrtDll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "CxImageCrtDll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "CxImageCrtDll - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "CxImageCrtDll - Win32 Unicode Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "CxImageCrtDll - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRCxImageCrtDll" /D "CxImageCrtDll_EXPORTS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /GZ /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept /CxImageCrtDll -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtd.dll" /pdbtype:sept -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRCxImageCrtDll" /D "CxImageCrtDll_EXPORTS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386 /CxImageCrtDll -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrt.dll" -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Unicode Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "CxImageCrtDll___Win32_Unicode_Debug" -# PROP BASE Intermediate_Dir "CxImageCrtDll___Win32_Unicode_Debug" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Unicode_Debug" -# PROP Intermediate_Dir "Unicode_Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /GZ /c -# SUBTRACT BASE CPP /YX /Yc /Yu -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /GZ /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtd.dll" /pdbtype:sept -# SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtdu.dll" /pdbtype:sept -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Unicode Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "CxImageCrtDll___Win32_Unicode_Release" -# PROP BASE Intermediate_Dir "CxImageCrtDll___Win32_Unicode_Release" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Unicode_Release" -# PROP Intermediate_Dir "Unicode_Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /c -# SUBTRACT BASE CPP /YX /Yc /Yu -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrt.dll" -# SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrtu.dll" -# SUBTRACT LINK32 /pdb:none - -!ENDIF - -# Begin Target - -# Name "CxImageCrtDll - Win32 Debug" -# Name "CxImageCrtDll - Win32 Release" -# Name "CxImageCrtDll - Win32 Unicode Debug" -# Name "CxImageCrtDll - Win32 Unicode Release" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\CxImageCrtDll.cpp -# End Source File -# Begin Source File - -SOURCE=.\CxImageCrtDll.rc -# End Source File -# Begin Source File - -SOURCE=..\tif_xfile.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximabmp.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximadsp.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximaenc.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximaexif.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximage.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximagif.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximahist.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaico.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximainfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaint.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximajas.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximajbg.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximajpg.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximalpha.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximalyr.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximamng.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximapal.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximapcx.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximapng.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximaraw.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximasel.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximaska.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximatga.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximath.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximatif.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximatran.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximawbmp.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximawmf.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\ximawnd.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\xmemfile.cpp -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\StdCrt.h -# End Source File -# Begin Source File - -SOURCE=..\xfile.h -# End Source File -# Begin Source File - -SOURCE=..\ximabmp.h -# End Source File -# Begin Source File - -SOURCE=..\ximadefs.h -# End Source File -# Begin Source File - -SOURCE=..\xImage.h -# End Source File -# Begin Source File - -SOURCE=..\ximagif.h -# End Source File -# Begin Source File - -SOURCE=..\ximaico.h -# End Source File -# Begin Source File - -SOURCE=..\ximaiter.h -# End Source File -# Begin Source File - -SOURCE=..\ximajas.h -# End Source File -# Begin Source File - -SOURCE=..\ximajbg.h -# End Source File -# Begin Source File - -SOURCE=..\ximajpg.h -# End Source File -# Begin Source File - -SOURCE=..\ximamng.h -# End Source File -# Begin Source File - -SOURCE=..\ximapcx.h -# End Source File -# Begin Source File - -SOURCE=..\ximapng.h -# End Source File -# Begin Source File - -SOURCE=..\ximaraw.h -# End Source File -# Begin Source File - -SOURCE=..\ximatga.h -# End Source File -# Begin Source File - -SOURCE=..\ximath.h -# End Source File -# Begin Source File - -SOURCE=..\ximatif.h -# End Source File -# Begin Source File - -SOURCE=..\ximawbmp.h -# End Source File -# Begin Source File - -SOURCE=..\ximawmf.h -# End Source File -# Begin Source File - -SOURCE=..\xiofile.h -# End Source File -# Begin Source File - -SOURCE=..\xmemfile.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="CxImageCrtDll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=CxImageCrtDll - Win32 Unicode Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "CxImageCrtDll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "CxImageCrtDll.mak" CFG="CxImageCrtDll - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CxImageCrtDll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "CxImageCrtDll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "CxImageCrtDll - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "CxImageCrtDll - Win32 Unicode Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "CxImageCrtDll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRCxImageCrtDll" /D "CxImageCrtDll_EXPORTS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept /CxImageCrtDll +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtd.dll" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRCxImageCrtDll" /D "CxImageCrtDll_EXPORTS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386 /CxImageCrtDll +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrt.dll" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "CxImageCrtDll___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "CxImageCrtDll___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Unicode_Debug" +# PROP Intermediate_Dir "Unicode_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtd.dll" /pdbtype:sept +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtdu.dll" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Unicode Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "CxImageCrtDll___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "CxImageCrtDll___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Unicode_Release" +# PROP Intermediate_Dir "Unicode_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrt.dll" +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrtu.dll" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "CxImageCrtDll - Win32 Debug" +# Name "CxImageCrtDll - Win32 Release" +# Name "CxImageCrtDll - Win32 Unicode Debug" +# Name "CxImageCrtDll - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\CxImageCrtDll.cpp +# End Source File +# Begin Source File + +SOURCE=.\CxImageCrtDll.rc +# End Source File +# Begin Source File + +SOURCE=..\tif_xfile.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximabmp.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximadsp.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximaenc.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximaexif.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximage.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximagif.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximahist.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaico.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximainfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaint.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximajas.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximajbg.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximajpg.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximalpha.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximalyr.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximamng.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximapal.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximapcx.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximapng.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximaraw.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximasel.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximaska.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximatga.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximath.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximatif.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximatran.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximawbmp.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximawmf.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\ximawnd.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\xmemfile.cpp +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\StdCrt.h +# End Source File +# Begin Source File + +SOURCE=..\xfile.h +# End Source File +# Begin Source File + +SOURCE=..\ximabmp.h +# End Source File +# Begin Source File + +SOURCE=..\ximadefs.h +# End Source File +# Begin Source File + +SOURCE=..\xImage.h +# End Source File +# Begin Source File + +SOURCE=..\ximagif.h +# End Source File +# Begin Source File + +SOURCE=..\ximaico.h +# End Source File +# Begin Source File + +SOURCE=..\ximaiter.h +# End Source File +# Begin Source File + +SOURCE=..\ximajas.h +# End Source File +# Begin Source File + +SOURCE=..\ximajbg.h +# End Source File +# Begin Source File + +SOURCE=..\ximajpg.h +# End Source File +# Begin Source File + +SOURCE=..\ximamng.h +# End Source File +# Begin Source File + +SOURCE=..\ximapcx.h +# End Source File +# Begin Source File + +SOURCE=..\ximapng.h +# End Source File +# Begin Source File + +SOURCE=..\ximaraw.h +# End Source File +# Begin Source File + +SOURCE=..\ximatga.h +# End Source File +# Begin Source File + +SOURCE=..\ximath.h +# End Source File +# Begin Source File + +SOURCE=..\ximatif.h +# End Source File +# Begin Source File + +SOURCE=..\ximawbmp.h +# End Source File +# Begin Source File + +SOURCE=..\ximawmf.h +# End Source File +# Begin Source File + +SOURCE=..\xiofile.h +# End Source File +# Begin Source File + +SOURCE=..\xmemfile.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/utilities/CxImage/CxImageDLL/CxImageCrtDll.rc b/utilities/CxImage/CxImageDLL/CxImageCrtDll.rc index 98adb20..4db01c1 100644 --- a/utilities/CxImage/CxImageDLL/CxImageCrtDll.rc +++ b/utilities/CxImage/CxImageDLL/CxImageCrtDll.rc @@ -1,123 +1,123 @@ -//Microsoft Developer Studio generated resource script. -// -#include "resrc1.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "resource.h" -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) -#ifdef _WIN32 -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -#pragma code_page(1252) -#endif //_WIN32 - -#ifndef _MAC -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,0,0,0 - PRODUCTVERSION 6,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000004b0" - BEGIN - VALUE "Comments", "CxImage 6.0.0.0 CRT DLL\0" - VALUE "CompanyName", "Pizzolato Davide - www.xdp.it\0" - VALUE "FileDescription", "cximage\0" - VALUE "FileVersion", "6, 0, 0, 0\0" - VALUE "InternalName", "cximage\0" - VALUE "LegalCopyright", "Copyright © 2001 - 2008\0" - VALUE "LegalTrademarks", "\0" - VALUE "OriginalFilename", "cximagecrt.dll\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", "cximage\0" - VALUE "ProductVersion", "6, 0, 0, 0\0" - VALUE "SpecialBuild", "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0, 1200 - END -END - -#endif // !_MAC - -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// Italian (Italy) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA) -#ifdef _WIN32 -LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE DISCARDABLE -BEGIN - "resrc1.h\0" -END - -2 TEXTINCLUDE DISCARDABLE -BEGIN - "#include ""resource.h""\r\n" - "#include ""winresrc.h""\r\n" - "\0" -END - -3 TEXTINCLUDE DISCARDABLE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Italian (Italy) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +//Microsoft Developer Studio generated resource script. +// +#include "resrc1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 6,0,0,0 + PRODUCTVERSION 6,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "CxImage 6.0.0.0 CRT DLL\0" + VALUE "CompanyName", "Pizzolato Davide - www.xdp.it\0" + VALUE "FileDescription", "cximage\0" + VALUE "FileVersion", "6, 0, 0, 0\0" + VALUE "InternalName", "cximage\0" + VALUE "LegalCopyright", "Copyright © 2001 - 2008\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "cximagecrt.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "cximage\0" + VALUE "ProductVersion", "6, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Italian (Italy) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA) +#ifdef _WIN32 +LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resrc1.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""resource.h""\r\n" + "#include ""winresrc.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Italian (Italy) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/utilities/CxImage/CxImageDLL/CxImageDll.dsw b/utilities/CxImage/CxImageDLL/CxImageDll.dsw index afdd4ba..45f97d5 100644 --- a/utilities/CxImage/CxImageDLL/CxImageDll.dsw +++ b/utilities/CxImage/CxImageDLL/CxImageDll.dsw @@ -1,152 +1,152 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "CxImageCrtDll"=.\CxImageCrtDll.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name j2000 - End Project Dependency - Begin Project Dependency - Project_Dep_Name jbig - End Project Dependency - Begin Project Dependency - Project_Dep_Name jpeg - End Project Dependency - Begin Project Dependency - Project_Dep_Name png - End Project Dependency - Begin Project Dependency - Project_Dep_Name tiff - End Project Dependency - Begin Project Dependency - Project_Dep_Name zlib - End Project Dependency - Begin Project Dependency - Project_Dep_Name j2k - End Project Dependency -}}} - -############################################################################### - -Project: "CxImageMfcDll"=.\cximagemfcdll.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name j2k - End Project Dependency - Begin Project Dependency - Project_Dep_Name jbig - End Project Dependency - Begin Project Dependency - Project_Dep_Name jpeg - End Project Dependency - Begin Project Dependency - Project_Dep_Name png - End Project Dependency - Begin Project Dependency - Project_Dep_Name tiff - End Project Dependency - Begin Project Dependency - Project_Dep_Name zlib - End Project Dependency -}}} - -############################################################################### - -Project: "j2k"=..\..\j2k\j2k.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "jbig"=..\..\jbig\jbig.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "jpeg"=..\..\jpeg\Jpeg.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "png"=..\..\png\png.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "tiff"=..\..\tiff\Tiff.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "zlib"=..\..\zlib\zlib.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "CxImageCrtDll"=.\CxImageCrtDll.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name j2000 + End Project Dependency + Begin Project Dependency + Project_Dep_Name jbig + End Project Dependency + Begin Project Dependency + Project_Dep_Name jpeg + End Project Dependency + Begin Project Dependency + Project_Dep_Name png + End Project Dependency + Begin Project Dependency + Project_Dep_Name tiff + End Project Dependency + Begin Project Dependency + Project_Dep_Name zlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name j2k + End Project Dependency +}}} + +############################################################################### + +Project: "CxImageMfcDll"=.\cximagemfcdll.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name j2k + End Project Dependency + Begin Project Dependency + Project_Dep_Name jbig + End Project Dependency + Begin Project Dependency + Project_Dep_Name jpeg + End Project Dependency + Begin Project Dependency + Project_Dep_Name png + End Project Dependency + Begin Project Dependency + Project_Dep_Name tiff + End Project Dependency + Begin Project Dependency + Project_Dep_Name zlib + End Project Dependency +}}} + +############################################################################### + +Project: "j2k"=..\..\j2k\j2k.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "jbig"=..\..\jbig\jbig.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "jpeg"=..\..\jpeg\Jpeg.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "png"=..\..\png\png.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "tiff"=..\..\tiff\Tiff.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "zlib"=..\..\zlib\zlib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/utilities/CxImage/CxImageDLL/CxImageMfcDll.clw b/utilities/CxImage/CxImageDLL/CxImageMfcDll.clw index 349133d..c14615c 100644 --- a/utilities/CxImage/CxImageDLL/CxImageMfcDll.clw +++ b/utilities/CxImage/CxImageDLL/CxImageMfcDll.clw @@ -1,16 +1,16 @@ -; CLW file contains information for the MFC ClassWizard - -[General Info] -Version=1 -ClassCount=1 -Class1=CcximagemfcdllApp -LastClass=CcximagemfcdllApp -NewFileInclude2=#include "cximagemfcdll.h" -ResourceCount=0 -NewFileInclude1=#include "stdafx.h" - -[CLS:CcximagemfcdllApp] -Type=0 -HeaderFile=cximagemfcdll.h -ImplementationFile=cximagemfcdll.cpp -Filter=N +; CLW file contains information for the MFC ClassWizard + +[General Info] +Version=1 +ClassCount=1 +Class1=CcximagemfcdllApp +LastClass=CcximagemfcdllApp +NewFileInclude2=#include "cximagemfcdll.h" +ResourceCount=0 +NewFileInclude1=#include "stdafx.h" + +[CLS:CcximagemfcdllApp] +Type=0 +HeaderFile=cximagemfcdll.h +ImplementationFile=cximagemfcdll.cpp +Filter=N diff --git a/utilities/CxImage/CxImageDLL/CxImageMfcDll.cpp b/utilities/CxImage/CxImageDLL/CxImageMfcDll.cpp index ff4e12e..092514b 100644 --- a/utilities/CxImage/CxImageDLL/CxImageMfcDll.cpp +++ b/utilities/CxImage/CxImageDLL/CxImageMfcDll.cpp @@ -1,62 +1,62 @@ -// cximagemfcdll.cpp : Defines the initialization routines for the DLL. -// - -#include "stdafx.h" -#include "cximagemfcdll.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -// -// Note! -// -// If this DLL is dynamically linked against the MFC -// DLLs, any functions exported from this DLL which -// call into MFC must have the AFX_MANAGE_STATE macro -// added at the very beginning of the function. -// -// For example: -// -// extern "C" BOOL PASCAL EXPORT ExportedFunction() -// { -// AFX_MANAGE_STATE(AfxGetStaticModuleState()); -// // normal function body here -// } -// -// It is very important that this macro appear in each -// function, prior to any calls into MFC. This means that -// it must appear as the first statement within the -// function, even before any object variable declarations -// as their constructors may generate calls into the MFC -// DLL. -// -// Please see MFC Technical Notes 33 and 58 for additional -// details. -// - -///////////////////////////////////////////////////////////////////////////// -// CcximagemfcdllApp - -BEGIN_MESSAGE_MAP(CcximagemfcdllApp, CWinApp) - //{{AFX_MSG_MAP(CcximagemfcdllApp) - // NOTE - the ClassWizard will add and remove mapping macros here. - // DO NOT EDIT what you see in these blocks of generated code! - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CcximagemfcdllApp construction - -CcximagemfcdllApp::CcximagemfcdllApp() -{ - // TODO: add construction code here, - // Place all significant initialization in InitInstance -} - -///////////////////////////////////////////////////////////////////////////// -// The one and only CcximagemfcdllApp object - -CcximagemfcdllApp theApp; +// cximagemfcdll.cpp : Defines the initialization routines for the DLL. +// + +#include "stdafx.h" +#include "cximagemfcdll.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +// +// Note! +// +// If this DLL is dynamically linked against the MFC +// DLLs, any functions exported from this DLL which +// call into MFC must have the AFX_MANAGE_STATE macro +// added at the very beginning of the function. +// +// For example: +// +// extern "C" BOOL PASCAL EXPORT ExportedFunction() +// { +// AFX_MANAGE_STATE(AfxGetStaticModuleState()); +// // normal function body here +// } +// +// It is very important that this macro appear in each +// function, prior to any calls into MFC. This means that +// it must appear as the first statement within the +// function, even before any object variable declarations +// as their constructors may generate calls into the MFC +// DLL. +// +// Please see MFC Technical Notes 33 and 58 for additional +// details. +// + +///////////////////////////////////////////////////////////////////////////// +// CcximagemfcdllApp + +BEGIN_MESSAGE_MAP(CcximagemfcdllApp, CWinApp) + //{{AFX_MSG_MAP(CcximagemfcdllApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CcximagemfcdllApp construction + +CcximagemfcdllApp::CcximagemfcdllApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CcximagemfcdllApp object + +CcximagemfcdllApp theApp; diff --git a/utilities/CxImage/CxImageDLL/CxImageMfcDll.h b/utilities/CxImage/CxImageDLL/CxImageMfcDll.h index 43d62cf..681d577 100644 --- a/utilities/CxImage/CxImageDLL/CxImageMfcDll.h +++ b/utilities/CxImage/CxImageDLL/CxImageMfcDll.h @@ -1,45 +1,45 @@ -// cximagemfcdll.h : main header file for the cximagemfcdll DLL -// - -#if !defined(AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) -#define AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#ifndef __AFXWIN_H__ - #error include 'stdafx.h' before including this file for PCH -#endif - -#include "resource.h" // main symbols - -///////////////////////////////////////////////////////////////////////////// -// CcximagemfcdllApp -// See cximagemfcdll.cpp for the implementation of this class -// - -class CcximagemfcdllApp : public CWinApp -{ -public: - CcximagemfcdllApp(); - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CcximagemfcdllApp) - //}}AFX_VIRTUAL - - //{{AFX_MSG(CcximagemfcdllApp) - // NOTE - the ClassWizard will add and remove member functions here. - // DO NOT EDIT what you see in these blocks of generated code ! - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) +// cximagemfcdll.h : main header file for the cximagemfcdll DLL +// + +#if !defined(AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) +#define AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __AFXWIN_H__ + #error include 'stdafx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CcximagemfcdllApp +// See cximagemfcdll.cpp for the implementation of this class +// + +class CcximagemfcdllApp : public CWinApp +{ +public: + CcximagemfcdllApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CcximagemfcdllApp) + //}}AFX_VIRTUAL + + //{{AFX_MSG(CcximagemfcdllApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) diff --git a/utilities/CxImage/CxImageDLL/CxImageMfcDll.rc b/utilities/CxImage/CxImageDLL/CxImageMfcDll.rc index 2210599..ad1b611 100644 --- a/utilities/CxImage/CxImageDLL/CxImageMfcDll.rc +++ b/utilities/CxImage/CxImageDLL/CxImageMfcDll.rc @@ -1,123 +1,123 @@ -//Microsoft Developer Studio generated resource script. -// -#include "resrc1.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "resource.h" -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) -#ifdef _WIN32 -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -#pragma code_page(1252) -#endif //_WIN32 - -#ifndef _MAC -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,0,0,0 - PRODUCTVERSION 6,0,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000004b0" - BEGIN - VALUE "Comments", "CxImage 6.0.0.0 MFC DLL\0" - VALUE "CompanyName", "Pizzolato Davide - www.xdp.it\0" - VALUE "FileDescription", "cximage\0" - VALUE "FileVersion", "6, 0, 0, 0\0" - VALUE "InternalName", "cximage\0" - VALUE "LegalCopyright", "Copyright © 2001 - 2008\0" - VALUE "LegalTrademarks", "\0" - VALUE "OriginalFilename", "cximage.dll\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", "cximage\0" - VALUE "ProductVersion", "6, 0, 0, 0\0" - VALUE "SpecialBuild", "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0, 1200 - END -END - -#endif // !_MAC - -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// Italian (Italy) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA) -#ifdef _WIN32 -LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE DISCARDABLE -BEGIN - "resrc1.h\0" -END - -2 TEXTINCLUDE DISCARDABLE -BEGIN - "#include ""resource.h""\r\n" - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE DISCARDABLE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Italian (Italy) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +//Microsoft Developer Studio generated resource script. +// +#include "resrc1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 6,0,0,0 + PRODUCTVERSION 6,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "CxImage 6.0.0.0 MFC DLL\0" + VALUE "CompanyName", "Pizzolato Davide - www.xdp.it\0" + VALUE "FileDescription", "cximage\0" + VALUE "FileVersion", "6, 0, 0, 0\0" + VALUE "InternalName", "cximage\0" + VALUE "LegalCopyright", "Copyright © 2001 - 2008\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "cximage.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "cximage\0" + VALUE "ProductVersion", "6, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Italian (Italy) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA) +#ifdef _WIN32 +LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resrc1.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""resource.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Italian (Italy) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/utilities/CxImage/CxImageDLL/StdAfx.cpp b/utilities/CxImage/CxImageDLL/StdAfx.cpp index a5e4a08..fb2fa8c 100644 --- a/utilities/CxImage/CxImageDLL/StdAfx.cpp +++ b/utilities/CxImage/CxImageDLL/StdAfx.cpp @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes -// cximagemfcdll.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - - - +// stdafx.cpp : source file that includes just the standard includes +// cximagemfcdll.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/utilities/CxImage/CxImageDLL/StdAfx.h b/utilities/CxImage/CxImageDLL/StdAfx.h index ad71840..261544b 100644 --- a/utilities/CxImage/CxImageDLL/StdAfx.h +++ b/utilities/CxImage/CxImageDLL/StdAfx.h @@ -1,46 +1,46 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) -#define AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#ifndef WINVER -#define WINVER 0x0400 -#endif - -#include // MFC core and standard components -#include // MFC extensions - -#ifndef _AFX_NO_OLE_SUPPORT -#include // MFC OLE classes -#include // MFC OLE dialog classes -#include // MFC Automation classes -#endif // _AFX_NO_OLE_SUPPORT - - -#ifndef _AFX_NO_DB_SUPPORT -#include // MFC ODBC database classes -#endif // _AFX_NO_DB_SUPPORT - -#ifndef _AFX_NO_DAO_SUPPORT -#include // MFC DAO database classes -#endif // _AFX_NO_DAO_SUPPORT - -#include // MFC support for Internet Explorer 4 Common Controls -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT - - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) +#define AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#ifndef WINVER +#define WINVER 0x0400 +#endif + +#include // MFC core and standard components +#include // MFC extensions + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC OLE classes +#include // MFC OLE dialog classes +#include // MFC Automation classes +#endif // _AFX_NO_OLE_SUPPORT + + +#ifndef _AFX_NO_DB_SUPPORT +#include // MFC ODBC database classes +#endif // _AFX_NO_DB_SUPPORT + +#ifndef _AFX_NO_DAO_SUPPORT +#include // MFC DAO database classes +#endif // _AFX_NO_DAO_SUPPORT + +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_) diff --git a/utilities/CxImage/CxImageDLL/StdCrt.h b/utilities/CxImage/CxImageDLL/StdCrt.h index 60e3632..b252a8f 100644 --- a/utilities/CxImage/CxImageDLL/StdCrt.h +++ b/utilities/CxImage/CxImageDLL/StdCrt.h @@ -1,24 +1,24 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_) -#define AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - - -// Insert your headers here -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_) +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_) +#define AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +// Insert your headers here +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_) diff --git a/utilities/CxImage/CxImageDLL/cximagemfcdll.dsp b/utilities/CxImage/CxImageDLL/cximagemfcdll.dsp index 26a150d..21321b6 100644 --- a/utilities/CxImage/CxImageDLL/cximagemfcdll.dsp +++ b/utilities/CxImage/CxImageDLL/cximagemfcdll.dsp @@ -1,396 +1,396 @@ -# Microsoft Developer Studio Project File - Name="CxImageMfcDll" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=CxImageMfcDll - Win32 Unicode Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "cximagemfcdll.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "cximagemfcdll.mak" CFG="CxImageMfcDll - Win32 Unicode Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "CxImageMfcDll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "CxImageMfcDll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "CxImageMfcDll - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "CxImageMfcDll - Win32 Unicode Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "CxImageMfcDll - Win32 Debug" - -# PROP BASE Use_MFC 6 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 6 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /GZ /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL" -# ADD RSC /l 0x809 /d "_DEBUG" /d "_AFXDLL" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximaged.dll" /pdbtype:sept - -!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Release" - -# PROP BASE Use_MFC 6 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 6 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL" -# ADD RSC /l 0x809 /d "NDEBUG" /d "_AFXDLL" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximage.dll" - -!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Unicode Debug" - -# PROP BASE Use_MFC 6 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "CxImageMfcDll___Win32_Unicode_Debug" -# PROP BASE Intermediate_Dir "CxImageMfcDll___Win32_Unicode_Debug" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 6 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Unicode_Debug" -# PROP Intermediate_Dir "Unicode_Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /GZ /c -# SUBTRACT BASE CPP /YX /Yc /Yu -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /GZ /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL" -# ADD RSC /l 0x809 /d "_DEBUG" /d "_AFXDLL" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximaged.dll" /pdbtype:sept -# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximagedu.dll" /pdbtype:sept - -!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Unicode Release" - -# PROP BASE Use_MFC 6 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "CxImageMfcDll___Win32_Unicode_Release" -# PROP BASE Intermediate_Dir "CxImageMfcDll___Win32_Unicode_Release" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 6 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Unicode_Release" -# PROP Intermediate_Dir "Unicode_Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /c -# SUBTRACT BASE CPP /YX /Yc /Yu -# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /c -# SUBTRACT CPP /YX /Yc /Yu -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL" -# ADD RSC /l 0x809 /d "NDEBUG" /d "_AFXDLL" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximage.dll" -# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximageu.dll" - -!ENDIF - -# Begin Target - -# Name "CxImageMfcDll - Win32 Debug" -# Name "CxImageMfcDll - Win32 Release" -# Name "CxImageMfcDll - Win32 Unicode Debug" -# Name "CxImageMfcDll - Win32 Unicode Release" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\cximagemfcdll.cpp -# End Source File -# Begin Source File - -SOURCE=.\cximagemfcdll.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"stdafx.h" -# End Source File -# Begin Source File - -SOURCE=..\tif_xfile.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximabmp.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximadsp.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaenc.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaexif.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximage.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximagif.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximahist.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaico.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximainfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaint.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximajas.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximajbg.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximajpg.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximalpha.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximalyr.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximamng.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximapal.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximapcx.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximapng.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaraw.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximasel.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximaska.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximatga.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximath.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximatif.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximatran.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximawbmp.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximawmf.cpp -# End Source File -# Begin Source File - -SOURCE=..\ximawnd.cpp -# End Source File -# Begin Source File - -SOURCE=..\xmemfile.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\cximagemfcdll.h -# End Source File -# Begin Source File - -SOURCE=.\Resource.h -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# Begin Source File - -SOURCE=..\xfile.h -# End Source File -# Begin Source File - -SOURCE=..\ximabmp.h -# End Source File -# Begin Source File - -SOURCE=..\ximadefs.h -# End Source File -# Begin Source File - -SOURCE=..\ximage.h -# End Source File -# Begin Source File - -SOURCE=..\ximagif.h -# End Source File -# Begin Source File - -SOURCE=..\ximaico.h -# End Source File -# Begin Source File - -SOURCE=..\ximaiter.h -# End Source File -# Begin Source File - -SOURCE=..\ximajas.h -# End Source File -# Begin Source File - -SOURCE=..\ximajpg.h -# End Source File -# Begin Source File - -SOURCE=..\ximamng.h -# End Source File -# Begin Source File - -SOURCE=..\ximapcx.h -# End Source File -# Begin Source File - -SOURCE=..\ximapng.h -# End Source File -# Begin Source File - -SOURCE=..\ximaska.h -# End Source File -# Begin Source File - -SOURCE=..\ximatga.h -# End Source File -# Begin Source File - -SOURCE=..\ximath.h -# End Source File -# Begin Source File - -SOURCE=..\ximatif.h -# End Source File -# Begin Source File - -SOURCE=..\ximawbmp.h -# End Source File -# Begin Source File - -SOURCE=..\ximawmf.h -# End Source File -# Begin Source File - -SOURCE=..\xiofile.h -# End Source File -# Begin Source File - -SOURCE=..\xmemfile.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="CxImageMfcDll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=CxImageMfcDll - Win32 Unicode Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cximagemfcdll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cximagemfcdll.mak" CFG="CxImageMfcDll - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CxImageMfcDll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "CxImageMfcDll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "CxImageMfcDll - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "CxImageMfcDll - Win32 Unicode Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "CxImageMfcDll - Win32 Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximaged.dll" /pdbtype:sept + +!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximage.dll" + +!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Unicode Debug" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "CxImageMfcDll___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "CxImageMfcDll___Win32_Unicode_Debug" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Unicode_Debug" +# PROP Intermediate_Dir "Unicode_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /GZ /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximaged.dll" /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximagedu.dll" /pdbtype:sept + +!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Unicode Release" + +# PROP BASE Use_MFC 6 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "CxImageMfcDll___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "CxImageMfcDll___Win32_Unicode_Release" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 6 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Unicode_Release" +# PROP Intermediate_Dir "Unicode_Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /FD /c +# SUBTRACT BASE CPP /YX /Yc /Yu +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../zlib" /I "../../jasper/include" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D _WIN32_IE=0x0400 /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximage.dll" +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximageu.dll" + +!ENDIF + +# Begin Target + +# Name "CxImageMfcDll - Win32 Debug" +# Name "CxImageMfcDll - Win32 Release" +# Name "CxImageMfcDll - Win32 Unicode Debug" +# Name "CxImageMfcDll - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\cximagemfcdll.cpp +# End Source File +# Begin Source File + +SOURCE=.\cximagemfcdll.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=..\tif_xfile.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximabmp.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximadsp.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaenc.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaexif.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximage.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximagif.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximahist.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaico.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximainfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaint.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximajas.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximajbg.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximajpg.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximalpha.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximalyr.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximamng.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximapal.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximapcx.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximapng.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaraw.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximasel.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximaska.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximatga.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximath.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximatif.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximatran.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximawbmp.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximawmf.cpp +# End Source File +# Begin Source File + +SOURCE=..\ximawnd.cpp +# End Source File +# Begin Source File + +SOURCE=..\xmemfile.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\cximagemfcdll.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=..\xfile.h +# End Source File +# Begin Source File + +SOURCE=..\ximabmp.h +# End Source File +# Begin Source File + +SOURCE=..\ximadefs.h +# End Source File +# Begin Source File + +SOURCE=..\ximage.h +# End Source File +# Begin Source File + +SOURCE=..\ximagif.h +# End Source File +# Begin Source File + +SOURCE=..\ximaico.h +# End Source File +# Begin Source File + +SOURCE=..\ximaiter.h +# End Source File +# Begin Source File + +SOURCE=..\ximajas.h +# End Source File +# Begin Source File + +SOURCE=..\ximajpg.h +# End Source File +# Begin Source File + +SOURCE=..\ximamng.h +# End Source File +# Begin Source File + +SOURCE=..\ximapcx.h +# End Source File +# Begin Source File + +SOURCE=..\ximapng.h +# End Source File +# Begin Source File + +SOURCE=..\ximaska.h +# End Source File +# Begin Source File + +SOURCE=..\ximatga.h +# End Source File +# Begin Source File + +SOURCE=..\ximath.h +# End Source File +# Begin Source File + +SOURCE=..\ximatif.h +# End Source File +# Begin Source File + +SOURCE=..\ximawbmp.h +# End Source File +# Begin Source File + +SOURCE=..\ximawmf.h +# End Source File +# Begin Source File + +SOURCE=..\xiofile.h +# End Source File +# Begin Source File + +SOURCE=..\xmemfile.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/utilities/CxImage/CxImageDLL/resource.h b/utilities/CxImage/CxImageDLL/resource.h index cc1626b..4a5384e 100644 --- a/utilities/CxImage/CxImageDLL/resource.h +++ b/utilities/CxImage/CxImageDLL/resource.h @@ -1,15 +1,15 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by CxImageMFCdll.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 6000 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 6000 -#define _APS_NEXT_SYMED_VALUE 6000 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by CxImageMFCdll.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 6000 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 6000 +#define _APS_NEXT_SYMED_VALUE 6000 +#endif +#endif diff --git a/utilities/CxImage/CxImageDLL/resrc1.h b/utilities/CxImage/CxImageDLL/resrc1.h index 39ff26e..0f1dd48 100644 --- a/utilities/CxImage/CxImageDLL/resrc1.h +++ b/utilities/CxImage/CxImageDLL/resrc1.h @@ -1,15 +1,15 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by CxImageCrtDll.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 6000 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 6000 -#define _APS_NEXT_SYMED_VALUE 6000 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by CxImageCrtDll.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 6000 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 6000 +#define _APS_NEXT_SYMED_VALUE 6000 +#endif +#endif diff --git a/utilities/CxImage/cximage.dsp b/utilities/CxImage/cximage.dsp index c93da4f..78b9b9d 100644 --- a/utilities/CxImage/cximage.dsp +++ b/utilities/CxImage/cximage.dsp @@ -1,364 +1,364 @@ -# Microsoft Developer Studio Project File - Name="CxImage" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - -CFG=CxImage - Win32 Unicode Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "cximage.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "cximage.mak" CFG="CxImage - Win32 Unicode Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "CxImage - Win32 Debug" (based on "Win32 (x86) Static Library") -!MESSAGE "CxImage - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "CxImage - Win32 Unicode Debug" (based on "Win32 (x86) Static Library") -!MESSAGE "CxImage - Win32 Unicode Release" (based on "Win32 (x86) Static Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "CxImage - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 2 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "_DEBUG" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /GZ /c -# SUBTRACT CPP /Fr /YX -# ADD BASE RSC /l 0x410 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ELSEIF "$(CFG)" == "CxImage - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 2 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "NDEBUG" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x410 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ELSEIF "$(CFG)" == "CxImage - Win32 Unicode Debug" - -# PROP BASE Use_MFC 2 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "CxImage___Win32_Unicode_Debug" -# PROP BASE Intermediate_Dir "CxImage___Win32_Unicode_Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 2 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Unicode_Debug" -# PROP Intermediate_Dir "Unicode_Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "_AFXDLL" /D "JAS_WIN_MSVC_BUILD" /FD /GZ /c -# SUBTRACT BASE CPP /Fr /YX -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /GZ /c -# SUBTRACT CPP /Fr /YX -# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ELSEIF "$(CFG)" == "CxImage - Win32 Unicode Release" - -# PROP BASE Use_MFC 2 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "CxImage___Win32_Unicode_Release" -# PROP BASE Intermediate_Dir "CxImage___Win32_Unicode_Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 2 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Unicode_Release" -# PROP Intermediate_Dir "Unicode_Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "_AFXDLL" /D "JAS_WIN_MSVC_BUILD" /FD /c -# SUBTRACT BASE CPP /YX -# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ENDIF - -# Begin Target - -# Name "CxImage - Win32 Debug" -# Name "CxImage - Win32 Release" -# Name "CxImage - Win32 Unicode Debug" -# Name "CxImage - Win32 Unicode Release" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\tif_xfile.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximabmp.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximadsp.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximaenc.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximaexif.cpp -# End Source File -# Begin Source File - -SOURCE=.\xImage.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximagif.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximahist.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximaico.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximainfo.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximaint.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximajas.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximajbg.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximajpg.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximalpha.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximalyr.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximamng.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximapal.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximapcx.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximapng.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximaraw.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximasel.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximaska.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximatga.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximath.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximatif.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximatran.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximawbmp.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximawmf.cpp -# End Source File -# Begin Source File - -SOURCE=.\ximawnd.cpp -# End Source File -# Begin Source File - -SOURCE=.\xmemfile.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\xfile.h -# End Source File -# Begin Source File - -SOURCE=.\ximabmp.h -# End Source File -# Begin Source File - -SOURCE=.\ximacfg.h -# End Source File -# Begin Source File - -SOURCE=.\ximadef.h -# End Source File -# Begin Source File - -SOURCE=.\ximage.h -# End Source File -# Begin Source File - -SOURCE=.\ximagif.h -# End Source File -# Begin Source File - -SOURCE=.\ximaico.h -# End Source File -# Begin Source File - -SOURCE=.\ximaiter.h -# End Source File -# Begin Source File - -SOURCE=.\ximajas.h -# End Source File -# Begin Source File - -SOURCE=.\ximajbg.h -# End Source File -# Begin Source File - -SOURCE=.\ximajpg.h -# End Source File -# Begin Source File - -SOURCE=.\ximamng.h -# End Source File -# Begin Source File - -SOURCE=.\ximapcx.h -# End Source File -# Begin Source File - -SOURCE=.\ximapng.h -# End Source File -# Begin Source File - -SOURCE=.\ximaraw.h -# End Source File -# Begin Source File - -SOURCE=.\ximaska.h -# End Source File -# Begin Source File - -SOURCE=.\ximatga.h -# End Source File -# Begin Source File - -SOURCE=.\ximath.h -# End Source File -# Begin Source File - -SOURCE=.\ximatif.h -# End Source File -# Begin Source File - -SOURCE=.\ximawbmp.h -# End Source File -# Begin Source File - -SOURCE=.\ximawmf.h -# End Source File -# Begin Source File - -SOURCE=.\xiofile.h -# End Source File -# Begin Source File - -SOURCE=.\xmemfile.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="CxImage" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=CxImage - Win32 Unicode Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cximage.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cximage.mak" CFG="CxImage - Win32 Unicode Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "CxImage - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "CxImage - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "CxImage - Win32 Unicode Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "CxImage - Win32 Unicode Release" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "CxImage - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "_DEBUG" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /GZ /c +# SUBTRACT CPP /Fr /YX +# ADD BASE RSC /l 0x410 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "CxImage - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "NDEBUG" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "_CRT_SECURE_NO_DEPRECATE" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x410 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "CxImage - Win32 Unicode Debug" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "CxImage___Win32_Unicode_Debug" +# PROP BASE Intermediate_Dir "CxImage___Win32_Unicode_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Unicode_Debug" +# PROP Intermediate_Dir "Unicode_Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "_AFXDLL" /D "JAS_WIN_MSVC_BUILD" /FD /GZ /c +# SUBTRACT BASE CPP /Fr /YX +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /GZ /c +# SUBTRACT CPP /Fr /YX +# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "CxImage - Win32 Unicode Release" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "CxImage___Win32_Unicode_Release" +# PROP BASE Intermediate_Dir "CxImage___Win32_Unicode_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Unicode_Release" +# PROP Intermediate_Dir "Unicode_Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "_AFXDLL" /D "JAS_WIN_MSVC_BUILD" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\jpeg" /I "..\png" /I "..\zlib" /I "..\mng" /I "..\tiff" /I "..\j2k" /I "..\jasper\include" /D "_LIB" /D "JAS_WIN_MSVC_BUILD" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NON_CONFORMING_SWPRINTFS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "CxImage - Win32 Debug" +# Name "CxImage - Win32 Release" +# Name "CxImage - Win32 Unicode Debug" +# Name "CxImage - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\tif_xfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximabmp.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximadsp.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximaenc.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximaexif.cpp +# End Source File +# Begin Source File + +SOURCE=.\xImage.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximagif.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximahist.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximaico.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximainfo.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximaint.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximajas.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximajbg.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximajpg.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximalpha.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximalyr.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximamng.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximapal.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximapcx.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximapng.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximaraw.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximasel.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximaska.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximatga.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximath.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximatif.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximatran.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximawbmp.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximawmf.cpp +# End Source File +# Begin Source File + +SOURCE=.\ximawnd.cpp +# End Source File +# Begin Source File + +SOURCE=.\xmemfile.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\xfile.h +# End Source File +# Begin Source File + +SOURCE=.\ximabmp.h +# End Source File +# Begin Source File + +SOURCE=.\ximacfg.h +# End Source File +# Begin Source File + +SOURCE=.\ximadef.h +# End Source File +# Begin Source File + +SOURCE=.\ximage.h +# End Source File +# Begin Source File + +SOURCE=.\ximagif.h +# End Source File +# Begin Source File + +SOURCE=.\ximaico.h +# End Source File +# Begin Source File + +SOURCE=.\ximaiter.h +# End Source File +# Begin Source File + +SOURCE=.\ximajas.h +# End Source File +# Begin Source File + +SOURCE=.\ximajbg.h +# End Source File +# Begin Source File + +SOURCE=.\ximajpg.h +# End Source File +# Begin Source File + +SOURCE=.\ximamng.h +# End Source File +# Begin Source File + +SOURCE=.\ximapcx.h +# End Source File +# Begin Source File + +SOURCE=.\ximapng.h +# End Source File +# Begin Source File + +SOURCE=.\ximaraw.h +# End Source File +# Begin Source File + +SOURCE=.\ximaska.h +# End Source File +# Begin Source File + +SOURCE=.\ximatga.h +# End Source File +# Begin Source File + +SOURCE=.\ximath.h +# End Source File +# Begin Source File + +SOURCE=.\ximatif.h +# End Source File +# Begin Source File + +SOURCE=.\ximawbmp.h +# End Source File +# Begin Source File + +SOURCE=.\ximawmf.h +# End Source File +# Begin Source File + +SOURCE=.\xiofile.h +# End Source File +# Begin Source File + +SOURCE=.\xmemfile.h +# End Source File +# End Group +# End Target +# End Project diff --git a/utilities/CxImage/cximage.dsw b/utilities/CxImage/cximage.dsw index d855b5f..cace8f0 100644 --- a/utilities/CxImage/cximage.dsw +++ b/utilities/CxImage/cximage.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "CxImage"=.\CxImage.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "CxImage"=.\CxImage.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/utilities/CxImage/license.txt b/utilities/CxImage/license.txt index 8cf0659..8cc0197 100644 --- a/utilities/CxImage/license.txt +++ b/utilities/CxImage/license.txt @@ -1,48 +1,48 @@ -This copy of the CxImage notices is provided for your convenience. In case of -any discrepancy between this copy and the notices in the file ximage.h that is -included in the CxImage distribution, the latter shall prevail. - -If you modify CxImage you may insert additional notices immediately following -this sentence. - --------------------------------------------------------------------------------- - -COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - -CxImage version 6.0.0 02/Feb/2008 - -CxImage : Copyright (C) 2001 - 2008, Davide Pizzolato - -Original CImage and CImageIterator implementation are: -Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx) - -Covered code is provided under this license on an "as is" basis, without warranty -of any kind, either expressed or implied, including, without limitation, warranties -that the covered code is free of defects, merchantable, fit for a particular purpose -or non-infringing. The entire risk as to the quality and performance of the covered -code is with you. Should any covered code prove defective in any respect, you (not -the initial developer or any other contributor) assume the cost of any necessary -servicing, repair or correction. This disclaimer of warranty constitutes an essential -part of this license. No use of any covered code is authorized hereunder except under -this disclaimer. - -Permission is hereby granted to use, copy, modify, and distribute this -source code, or portions hereof, for any purpose, including commercial applications, -freely and without fee, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. - -3. This notice may not be removed or altered from any source distribution. - --------------------------------------------------------------------------------- - -Other information: about CxImage, and the latest version, can be found at the -CxImage home page: http://www.xdp.it - --------------------------------------------------------------------------------- +This copy of the CxImage notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file ximage.h that is +included in the CxImage distribution, the latter shall prevail. + +If you modify CxImage you may insert additional notices immediately following +this sentence. + +-------------------------------------------------------------------------------- + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +CxImage version 6.0.0 02/Feb/2008 + +CxImage : Copyright (C) 2001 - 2008, Davide Pizzolato + +Original CImage and CImageIterator implementation are: +Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx) + +Covered code is provided under this license on an "as is" basis, without warranty +of any kind, either expressed or implied, including, without limitation, warranties +that the covered code is free of defects, merchantable, fit for a particular purpose +or non-infringing. The entire risk as to the quality and performance of the covered +code is with you. Should any covered code prove defective in any respect, you (not +the initial developer or any other contributor) assume the cost of any necessary +servicing, repair or correction. This disclaimer of warranty constitutes an essential +part of this license. No use of any covered code is authorized hereunder except under +this disclaimer. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, including commercial applications, +freely and without fee, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. + +-------------------------------------------------------------------------------- + +Other information: about CxImage, and the latest version, can be found at the +CxImage home page: http://www.xdp.it + +-------------------------------------------------------------------------------- diff --git a/utilities/CxImage/tif_xfile.cpp b/utilities/CxImage/tif_xfile.cpp index 98c83c1..ac92c95 100644 --- a/utilities/CxImage/tif_xfile.cpp +++ b/utilities/CxImage/tif_xfile.cpp @@ -1,218 +1,218 @@ -/* - * TIFF file IO, using CxFile. - */ - -#ifdef WIN32 - #include -#endif -#include - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_TIF - -#include "../tiff/tiffiop.h" - -#include "xfile.h" - -static tsize_t -_tiffReadProcEx(thandle_t fd, tdata_t buf, tsize_t size) -{ - return (tsize_t)((CxFile*)fd)->Read(buf, 1, size); -} - -static tsize_t -_tiffWriteProcEx(thandle_t fd, tdata_t buf, tsize_t size) -{ - return (tsize_t)((CxFile*)fd)->Write(buf, 1, size); -} - -static toff_t -_tiffSeekProcEx(thandle_t fd, toff_t off, int whence) -{ - if ( off == 0xFFFFFFFF ) - return 0xFFFFFFFF; - if (!((CxFile*)fd)->Seek(off, whence)) - return 0xFFFFFFFF; - if (whence == SEEK_SET) - return off; - - return (toff_t)((CxFile*)fd)->Tell(); -} - -// Return nonzero if error -static int -_tiffCloseProcEx(thandle_t /*fd*/) -{ -// return !((CxFile*)fd)->Close(); // "//" needed for memory files - return 0; -} - -#include - -static toff_t -_tiffSizeProcEx(thandle_t fd) -{ - return ((CxFile*)fd)->Size(); -} - -static int -_tiffMapProcEx(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/) -{ - return (0); -} - -static void -_tiffUnmapProcEx(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/) -{ -} - -// Open a TIFF file descriptor for read/writing. -/* -TIFF* -TIFFOpen(const char* name, const char* mode) -{ - static const char module[] = "TIFFOpen"; - FILE* stream = fopen(name, mode); - if (stream == NULL) - { - TIFFError(module, "%s: Cannot open", name); - return NULL; - } - return (TIFFFdOpen((int)stream, name, mode)); -} -*/ - -TIFF* -_TIFFFdOpen(void* fd, const char* name, const char* mode) -{ - TIFF* tif; - - tif = TIFFClientOpen(name, mode, - (thandle_t) fd, - _tiffReadProcEx, _tiffWriteProcEx, _tiffSeekProcEx, _tiffCloseProcEx, - _tiffSizeProcEx, _tiffMapProcEx, _tiffUnmapProcEx); - if (tif) - tif->tif_fd = fd; - return (tif); -} - -extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode) -{ - return (_TIFFFdOpen(stream, "TIFF IMAGE", mode)); -} - -#ifdef __GNUC__ -extern char* malloc(); -extern char* realloc(); -#else -#include -#endif - -tdata_t -_TIFFmalloc(tsize_t s) -{ - return (malloc((size_t) s)); -} - -void -_TIFFfree(tdata_t p) -{ - free(p); -} - -tdata_t -_TIFFrealloc(tdata_t p, tsize_t s) -{ - return (realloc(p, (size_t) s)); -} - -void -_TIFFmemset(tdata_t p, int v, tsize_t c) -{ - memset(p, v, (size_t) c); -} - -void -_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) -{ - memcpy(d, s, (size_t) c); -} - -int -_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) -{ - return (memcmp(p1, p2, (size_t) c)); -} - -#ifndef UNICODE -#define DbgPrint wvsprintf -#define DbgPrint2 wsprintf -#define DbgMsgBox MessageBox -#else -#define DbgPrint wvsprintfA -#define DbgPrint2 wsprintfA -#define DbgMsgBox MessageBoxA -#endif - -static void -Win32WarningHandler(const char* module, const char* fmt, va_list ap) -{ -#ifdef _DEBUG -#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32)) - LPSTR szTitle; - LPSTR szTmp; - LPCSTR szTitleText = "%s Warning"; - LPCSTR szDefaultModule = "TIFFLIB"; - szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module; - if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) + - strlen(szTitleText) + strlen(fmt) + 128))) == NULL) - return; - DbgPrint2(szTitle, szTitleText, szTmp); - szTmp = szTitle + (strlen(szTitle)+2); - DbgPrint(szTmp, fmt, ap); - DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION); - LocalFree(szTitle); - return; -#else - if (module != NULL) - fprintf(stderr, "%s: ", module); - fprintf(stderr, "Warning, "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, ".\n"); -#endif -#endif -} -TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler; - -static void -Win32ErrorHandler(const char* module, const char* fmt, va_list ap) -{ -#ifdef _DEBUG -#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32)) - LPSTR szTitle; - LPSTR szTmp; - LPCSTR szTitleText = "%s Error"; - LPCSTR szDefaultModule = "TIFFLIB"; - szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module; - if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) + - strlen(szTitleText) + strlen(fmt) + 128))) == NULL) - return; - DbgPrint2(szTitle, szTitleText, szTmp); - szTmp = szTitle + (strlen(szTitle)+2); - DbgPrint(szTmp, fmt, ap); - DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION); - LocalFree(szTitle); - return; -#else - if (module != NULL) - fprintf(stderr, "%s: ", module); - vfprintf(stderr, fmt, ap); - fprintf(stderr, ".\n"); -#endif -#endif -} -TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler; - -#endif - +/* + * TIFF file IO, using CxFile. + */ + +#ifdef WIN32 + #include +#endif +#include + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_TIF + +#include "../tiff/tiffiop.h" + +#include "xfile.h" + +static tsize_t +_tiffReadProcEx(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (tsize_t)((CxFile*)fd)->Read(buf, 1, size); +} + +static tsize_t +_tiffWriteProcEx(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (tsize_t)((CxFile*)fd)->Write(buf, 1, size); +} + +static toff_t +_tiffSeekProcEx(thandle_t fd, toff_t off, int whence) +{ + if ( off == 0xFFFFFFFF ) + return 0xFFFFFFFF; + if (!((CxFile*)fd)->Seek(off, whence)) + return 0xFFFFFFFF; + if (whence == SEEK_SET) + return off; + + return (toff_t)((CxFile*)fd)->Tell(); +} + +// Return nonzero if error +static int +_tiffCloseProcEx(thandle_t /*fd*/) +{ +// return !((CxFile*)fd)->Close(); // "//" needed for memory files + return 0; +} + +#include + +static toff_t +_tiffSizeProcEx(thandle_t fd) +{ + return ((CxFile*)fd)->Size(); +} + +static int +_tiffMapProcEx(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/) +{ + return (0); +} + +static void +_tiffUnmapProcEx(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/) +{ +} + +// Open a TIFF file descriptor for read/writing. +/* +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + FILE* stream = fopen(name, mode); + if (stream == NULL) + { + TIFFError(module, "%s: Cannot open", name); + return NULL; + } + return (TIFFFdOpen((int)stream, name, mode)); +} +*/ + +TIFF* +_TIFFFdOpen(void* fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (thandle_t) fd, + _tiffReadProcEx, _tiffWriteProcEx, _tiffSeekProcEx, _tiffCloseProcEx, + _tiffSizeProcEx, _tiffMapProcEx, _tiffUnmapProcEx); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode) +{ + return (_TIFFFdOpen(stream, "TIFF IMAGE", mode)); +} + +#ifdef __GNUC__ +extern char* malloc(); +extern char* realloc(); +#else +#include +#endif + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return (malloc((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + free(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +#ifndef UNICODE +#define DbgPrint wvsprintf +#define DbgPrint2 wsprintf +#define DbgMsgBox MessageBox +#else +#define DbgPrint wvsprintfA +#define DbgPrint2 wsprintfA +#define DbgMsgBox MessageBoxA +#endif + +static void +Win32WarningHandler(const char* module, const char* fmt, va_list ap) +{ +#ifdef _DEBUG +#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32)) + LPSTR szTitle; + LPSTR szTmp; + LPCSTR szTitleText = "%s Warning"; + LPCSTR szDefaultModule = "TIFFLIB"; + szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module; + if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) + + strlen(szTitleText) + strlen(fmt) + 128))) == NULL) + return; + DbgPrint2(szTitle, szTitleText, szTmp); + szTmp = szTitle + (strlen(szTitle)+2); + DbgPrint(szTmp, fmt, ap); + DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION); + LocalFree(szTitle); + return; +#else + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +#endif +#endif +} +TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler; + +static void +Win32ErrorHandler(const char* module, const char* fmt, va_list ap) +{ +#ifdef _DEBUG +#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32)) + LPSTR szTitle; + LPSTR szTmp; + LPCSTR szTitleText = "%s Error"; + LPCSTR szDefaultModule = "TIFFLIB"; + szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module; + if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) + + strlen(szTitleText) + strlen(fmt) + 128))) == NULL) + return; + DbgPrint2(szTitle, szTitleText, szTmp); + szTmp = szTitle + (strlen(szTitle)+2); + DbgPrint(szTmp, fmt, ap); + DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION); + LocalFree(szTitle); + return; +#else + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +#endif +#endif +} +TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler; + +#endif + diff --git a/utilities/CxImage/xfile.h b/utilities/CxImage/xfile.h index c0e4e22..b64594e 100644 --- a/utilities/CxImage/xfile.h +++ b/utilities/CxImage/xfile.h @@ -1,79 +1,79 @@ -/* - * File: xfile.h - * Purpose: General Purpose File Class - */ -/* - -------------------------------------------------------------------------------- - - COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - - CxFile (c) 11/May/2002 Davide Pizzolato - www.xdp.it - CxFile version 2.00 23/Aug/2002 - CxFile version 2.10 16/Dec/2007 - - Special thanks to Chris Shearer Cooper for new features, enhancements and bugfixes - - Covered code is provided under this license on an "as is" basis, without warranty - of any kind, either expressed or implied, including, without limitation, warranties - that the covered code is free of defects, merchantable, fit for a particular purpose - or non-infringing. The entire risk as to the quality and performance of the covered - code is with you. Should any covered code prove defective in any respect, you (not - the initial developer or any other contributor) assume the cost of any necessary - servicing, repair or correction. This disclaimer of warranty constitutes an essential - part of this license. No use of any covered code is authorized hereunder except under - this disclaimer. - - Permission is hereby granted to use, copy, modify, and distribute this - source code, or portions hereof, for any purpose, including commercial applications, - freely and without fee, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source distribution. - -------------------------------------------------------------------------------- - */ -#if !defined(__xfile_h) -#define __xfile_h - -#if defined (WIN32) || defined (_WIN32_WCE) - #include -#endif - -#include -#include - -#include "ximadef.h" - -class DLL_EXP CxFile -{ -public: - CxFile(void) { }; - virtual ~CxFile() { }; - - virtual bool Close() = 0; - virtual size_t Read(void *buffer, size_t size, size_t count) = 0; - virtual size_t Write(const void *buffer, size_t size, size_t count) = 0; - virtual bool Seek(long offset, int origin) = 0; - virtual long Tell() = 0; - virtual long Size() = 0; - virtual bool Flush() = 0; - virtual bool Eof() = 0; - virtual long Error() = 0; - virtual bool PutC(unsigned char c) - { - // Default implementation - size_t nWrote = Write(&c, 1, 1); - return (bool)(nWrote == 1); - } - virtual long GetC() = 0; - virtual char * GetS(char *string, int n) = 0; - virtual long Scanf(const char *format, void* output) = 0; -}; - -#endif //__xfile_h +/* + * File: xfile.h + * Purpose: General Purpose File Class + */ +/* + -------------------------------------------------------------------------------- + + COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + + CxFile (c) 11/May/2002 Davide Pizzolato - www.xdp.it + CxFile version 2.00 23/Aug/2002 + CxFile version 2.10 16/Dec/2007 + + Special thanks to Chris Shearer Cooper for new features, enhancements and bugfixes + + Covered code is provided under this license on an "as is" basis, without warranty + of any kind, either expressed or implied, including, without limitation, warranties + that the covered code is free of defects, merchantable, fit for a particular purpose + or non-infringing. The entire risk as to the quality and performance of the covered + code is with you. Should any covered code prove defective in any respect, you (not + the initial developer or any other contributor) assume the cost of any necessary + servicing, repair or correction. This disclaimer of warranty constitutes an essential + part of this license. No use of any covered code is authorized hereunder except under + this disclaimer. + + Permission is hereby granted to use, copy, modify, and distribute this + source code, or portions hereof, for any purpose, including commercial applications, + freely and without fee, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + -------------------------------------------------------------------------------- + */ +#if !defined(__xfile_h) +#define __xfile_h + +#if defined (WIN32) || defined (_WIN32_WCE) + #include +#endif + +#include +#include + +#include "ximadef.h" + +class DLL_EXP CxFile +{ +public: + CxFile(void) { }; + virtual ~CxFile() { }; + + virtual bool Close() = 0; + virtual size_t Read(void *buffer, size_t size, size_t count) = 0; + virtual size_t Write(const void *buffer, size_t size, size_t count) = 0; + virtual bool Seek(long offset, int origin) = 0; + virtual long Tell() = 0; + virtual long Size() = 0; + virtual bool Flush() = 0; + virtual bool Eof() = 0; + virtual long Error() = 0; + virtual bool PutC(unsigned char c) + { + // Default implementation + size_t nWrote = Write(&c, 1, 1); + return (bool)(nWrote == 1); + } + virtual long GetC() = 0; + virtual char * GetS(char *string, int n) = 0; + virtual long Scanf(const char *format, void* output) = 0; +}; + +#endif //__xfile_h diff --git a/utilities/CxImage/ximabmp.cpp b/utilities/CxImage/ximabmp.cpp index 4793707..a621ba5 100644 --- a/utilities/CxImage/ximabmp.cpp +++ b/utilities/CxImage/ximabmp.cpp @@ -1,444 +1,444 @@ -/* - * File: ximabmp.cpp - * Purpose: Platform Independent BMP Image Class Loader and Writer - * 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximabmp.h" - -#if CXIMAGE_SUPPORT_BMP - -#include "ximaiter.h" - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageBMP::Encode(CxFile * hFile) -{ - - if (EncodeSafeCheck(hFile)) return false; - - BITMAPFILEHEADER hdr; - - hdr.bfType = 0x4d42; // 'BM' WINDOWS_BITMAP_SIGNATURE - hdr.bfSize = GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/; - hdr.bfReserved1 = hdr.bfReserved2 = 0; - hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + head.biSize + GetPaletteSize(); - - hdr.bfType = ntohs(hdr.bfType); - hdr.bfSize = ntohl(hdr.bfSize); - hdr.bfOffBits = ntohl(hdr.bfOffBits); - -#if CXIMAGE_SUPPORT_ALPHA - if (GetNumColors()==0 && AlphaIsValid()){ - - BITMAPINFOHEADER infohdr; - memcpy(&infohdr,&head,sizeof(BITMAPINFOHEADER)); - infohdr.biCompression = BI_RGB; - infohdr.biBitCount = 32; - DWORD dwEffWidth = ((((infohdr.biBitCount * infohdr.biWidth) + 31) / 32) * 4); - infohdr.biSizeImage = dwEffWidth * infohdr.biHeight; - - hdr.bfSize = infohdr.biSize + infohdr.biSizeImage + 14 /*sizeof(BITMAPFILEHEADER)*/; - - hdr.bfSize = ntohl(hdr.bfSize); - bihtoh(&infohdr); - - // Write the file header - hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1); - hFile->Write(&infohdr,sizeof(BITMAPINFOHEADER),1); - //and DIB+ALPHA interlaced - BYTE *srcalpha = AlphaGetPointer(); - for(long y = 0; y < infohdr.biHeight; ++y){ - BYTE *srcdib = GetBits(y); - for(long x = 0; x < infohdr.biWidth; ++x){ - hFile->Write(srcdib,3,1); - hFile->Write(srcalpha,1,1); - srcdib += 3; - ++srcalpha; - } - } - - } else -#endif //CXIMAGE_SUPPORT_ALPHA - { - // Write the file header - hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1); - //copy attributes - memcpy(pDib,&head,sizeof(BITMAPINFOHEADER)); - bihtoh((BITMAPINFOHEADER*)pDib); - // Write the DIB header and the pixels - hFile->Write(pDib,GetSize(),1); - bihtoh((BITMAPINFOHEADER*)pDib); - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageBMP::Decode(CxFile * hFile) -{ - if (hFile == NULL) return false; - - BITMAPFILEHEADER bf; - DWORD off = hFile->Tell(); // - cx_try { - if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) cx_throw("Not a BMP"); - - bf.bfSize = ntohl(bf.bfSize); - bf.bfOffBits = ntohl(bf.bfOffBits); - - if (bf.bfType != BFT_BITMAP) { //do we have a RC HEADER? - bf.bfOffBits = 0L; - hFile->Seek(off,SEEK_SET); - } - - BITMAPINFOHEADER bmpHeader; - if (!DibReadBitmapInfo(hFile,&bmpHeader)) cx_throw("Error reading BMP info"); - DWORD dwCompression=bmpHeader.biCompression; - DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression - bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER); - - bool bTopDownDib = bmpHeader.biHeight<0; // check if it's a top-down bitmap - if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight; - - if (info.nEscape == -1) { - // Return output dimensions only - head.biWidth = bmpHeader.biWidth; - head.biHeight = bmpHeader.biHeight; - info.dwType = CXIMAGE_FORMAT_BMP; - cx_throw("output dimensions returned"); - } - - if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP)) - cx_throw(""); - - SetXDPI((long) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5)); - SetYDPI((long) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5)); - - if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding - - RGBQUAD *pRgb = GetPalette(); - if (pRgb){ - if (bIsOldBmp){ - // convert a old color table (3 byte entries) to a new - // color table (4 byte entries) - hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1); - for (int i=DibNumColors(&head)-1; i>=0; i--){ - pRgb[i].rgbRed = ((RGBTRIPLE *)pRgb)[i].rgbtRed; - pRgb[i].rgbBlue = ((RGBTRIPLE *)pRgb)[i].rgbtBlue; - pRgb[i].rgbGreen = ((RGBTRIPLE *)pRgb)[i].rgbtGreen; - pRgb[i].rgbReserved = (BYTE)0; - } - } else { - hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1); - //force rgbReserved=0, to avoid problems with some WinXp bitmaps - for (unsigned int i=0; i - cancel decoding - - switch (dwBitCount) { - case 32 : - DWORD bfmask[3]; - if (dwCompression == BI_BITFIELDS) - { - hFile->Read(bfmask, 12, 1); - } else { - bfmask[0]=0x00FF0000; - bfmask[1]=0x0000FF00; - bfmask[2]=0x000000FF; - } - if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET); - if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){ - long imagesize=4*head.biHeight*head.biWidth; - BYTE* buff32=(BYTE*)malloc(imagesize); - if (buff32){ - hFile->Read(buff32, imagesize,1); // read in the pixels - -#if CXIMAGE_SUPPORT_ALPHA - if (dwCompression == BI_RGB){ - AlphaCreate(); - if (AlphaIsValid()){ - bool bAlphaOk = false; - BYTE* p; - for (long y=0; ySeek(off + bf.bfOffBits,SEEK_SET); - if (dwCompression == BI_RGB){ - hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels - } else cx_throw("unknown compression"); - break; - case 16 : - { - DWORD bfmask[3]; - if (dwCompression == BI_BITFIELDS) - { - hFile->Read(bfmask, 12, 1); - } else { - bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555 - } - // bf.bfOffBits required after the bitfield mask - if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET); - // read in the pixels - hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1); - // transform into RGB - Bitfield2RGB(info.pImage,bfmask[0],bfmask[1],bfmask[2],16); - break; - } - case 8 : - case 4 : - case 1 : - if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET); - switch (dwCompression) { - case BI_RGB : - hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels - break; - case BI_RLE4 : - { - BYTE status_byte = 0; - BYTE second_byte = 0; - int scanline = 0; - int bits = 0; - BOOL low_nibble = FALSE; - CImageIterator iter(this); - - for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) { - - switch (status_byte) { - case RLE_COMMAND : - hFile->Read(&status_byte, sizeof(BYTE), 1); - switch (status_byte) { - case RLE_ENDOFLINE : - bits = 0; - scanline++; - low_nibble = FALSE; - break; - case RLE_ENDOFBITMAP : - bContinue=FALSE; - break; - case RLE_DELTA : - { - // read the delta values - BYTE delta_x; - BYTE delta_y; - hFile->Read(&delta_x, sizeof(BYTE), 1); - hFile->Read(&delta_y, sizeof(BYTE), 1); - // apply them - bits += delta_x / 2; - scanline += delta_y; - break; - } - default : - hFile->Read(&second_byte, sizeof(BYTE), 1); - BYTE *sline = iter.GetRow(scanline); - for (int i = 0; i < status_byte; i++) { - if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ - if (low_nibble) { - if (i&1) - *(sline + bits) |= (second_byte & 0x0f); - else - *(sline + bits) |= (second_byte & 0xf0)>>4; - bits++; - } else { - if (i&1) - *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; - else - *(sline + bits) = (BYTE)(second_byte & 0xf0); - } - } - - if ((i & 1) && (i != (status_byte - 1))) - hFile->Read(&second_byte, sizeof(BYTE), 1); - - low_nibble = !low_nibble; - } - if ((((status_byte+1) >> 1) & 1 ) == 1) - hFile->Read(&second_byte, sizeof(BYTE), 1); - break; - }; - break; - default : - { - BYTE *sline = iter.GetRow(scanline); - hFile->Read(&second_byte, sizeof(BYTE), 1); - for (unsigned i = 0; i < status_byte; i++) { - if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ - if (low_nibble) { - if (i&1) - *(sline + bits) |= (second_byte & 0x0f); - else - *(sline + bits) |= (second_byte & 0xf0)>>4; - bits++; - } else { - if (i&1) - *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; - else - *(sline + bits) = (BYTE)(second_byte & 0xf0); - } - } - low_nibble = !low_nibble; - } - } - break; - }; - } - break; - } - case BI_RLE8 : - { - BYTE status_byte = 0; - BYTE second_byte = 0; - int scanline = 0; - int bits = 0; - CImageIterator iter(this); - - for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) { - switch (status_byte) { - case RLE_COMMAND : - hFile->Read(&status_byte, sizeof(BYTE), 1); - switch (status_byte) { - case RLE_ENDOFLINE : - bits = 0; - scanline++; - break; - case RLE_ENDOFBITMAP : - bContinue=FALSE; - break; - case RLE_DELTA : - { - // read the delta values - BYTE delta_x; - BYTE delta_y; - hFile->Read(&delta_x, sizeof(BYTE), 1); - hFile->Read(&delta_y, sizeof(BYTE), 1); - // apply them - bits += delta_x; - scanline += delta_y; - break; - } - default : - hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(BYTE) * status_byte, 1); - // align run length to even number of bytes - if ((status_byte & 1) == 1) - hFile->Read(&second_byte, sizeof(BYTE), 1); - bits += status_byte; - break; - }; - break; - default : - BYTE *sline = iter.GetRow(scanline); - hFile->Read(&second_byte, sizeof(BYTE), 1); - for (unsigned i = 0; i < status_byte; i++) { - if ((DWORD)bits - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_BMP) return true; - return false; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/* ReadDibBitmapInfo() - * - * Will read a file in DIB format and return a global HANDLE to its - * BITMAPINFO. This function will work with both "old" and "new" - * bitmap formats, but will always return a "new" BITMAPINFO. - */ -bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib) -{ - if ((fh==NULL)||(pdib==NULL)) return false; - - if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false; - - bihtoh(pdib); - - switch (pdib->biSize) // what type of bitmap info is this? - { - case sizeof(BITMAPINFOHEADER): - break; - - case 64: //sizeof(OS2_BMP_HEADER): - fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR); - break; - - case sizeof(BITMAPCOREHEADER): - { - BITMAPCOREHEADER bc = *(BITMAPCOREHEADER*)pdib; - pdib->biSize = bc.bcSize; - pdib->biWidth = (DWORD)bc.bcWidth; - pdib->biHeight = (DWORD)bc.bcHeight; - pdib->biPlanes = bc.bcPlanes; - pdib->biBitCount = bc.bcBitCount; - pdib->biCompression = BI_RGB; - pdib->biSizeImage = 0; - pdib->biXPelsPerMeter = 0; - pdib->biYPelsPerMeter = 0; - pdib->biClrUsed = 0; - pdib->biClrImportant = 0; - - fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR); - } - break; - default: - //give a last chance - if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&& - (pdib->biSizeImage>=(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&& - (pdib->biPlanes==1)&&(pdib->biClrUsed==0)) - { - if (pdib->biCompression==BI_RGB) - fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR); - break; - } - return false; - } - - FixBitmapInfo(pdib); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_BMP -//////////////////////////////////////////////////////////////////////////////// +/* + * File: ximabmp.cpp + * Purpose: Platform Independent BMP Image Class Loader and Writer + * 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximabmp.h" + +#if CXIMAGE_SUPPORT_BMP + +#include "ximaiter.h" + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageBMP::Encode(CxFile * hFile) +{ + + if (EncodeSafeCheck(hFile)) return false; + + BITMAPFILEHEADER hdr; + + hdr.bfType = 0x4d42; // 'BM' WINDOWS_BITMAP_SIGNATURE + hdr.bfSize = GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/; + hdr.bfReserved1 = hdr.bfReserved2 = 0; + hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + head.biSize + GetPaletteSize(); + + hdr.bfType = ntohs(hdr.bfType); + hdr.bfSize = ntohl(hdr.bfSize); + hdr.bfOffBits = ntohl(hdr.bfOffBits); + +#if CXIMAGE_SUPPORT_ALPHA + if (GetNumColors()==0 && AlphaIsValid()){ + + BITMAPINFOHEADER infohdr; + memcpy(&infohdr,&head,sizeof(BITMAPINFOHEADER)); + infohdr.biCompression = BI_RGB; + infohdr.biBitCount = 32; + DWORD dwEffWidth = ((((infohdr.biBitCount * infohdr.biWidth) + 31) / 32) * 4); + infohdr.biSizeImage = dwEffWidth * infohdr.biHeight; + + hdr.bfSize = infohdr.biSize + infohdr.biSizeImage + 14 /*sizeof(BITMAPFILEHEADER)*/; + + hdr.bfSize = ntohl(hdr.bfSize); + bihtoh(&infohdr); + + // Write the file header + hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1); + hFile->Write(&infohdr,sizeof(BITMAPINFOHEADER),1); + //and DIB+ALPHA interlaced + BYTE *srcalpha = AlphaGetPointer(); + for(long y = 0; y < infohdr.biHeight; ++y){ + BYTE *srcdib = GetBits(y); + for(long x = 0; x < infohdr.biWidth; ++x){ + hFile->Write(srcdib,3,1); + hFile->Write(srcalpha,1,1); + srcdib += 3; + ++srcalpha; + } + } + + } else +#endif //CXIMAGE_SUPPORT_ALPHA + { + // Write the file header + hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1); + //copy attributes + memcpy(pDib,&head,sizeof(BITMAPINFOHEADER)); + bihtoh((BITMAPINFOHEADER*)pDib); + // Write the DIB header and the pixels + hFile->Write(pDib,GetSize(),1); + bihtoh((BITMAPINFOHEADER*)pDib); + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageBMP::Decode(CxFile * hFile) +{ + if (hFile == NULL) return false; + + BITMAPFILEHEADER bf; + DWORD off = hFile->Tell(); // + cx_try { + if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) cx_throw("Not a BMP"); + + bf.bfSize = ntohl(bf.bfSize); + bf.bfOffBits = ntohl(bf.bfOffBits); + + if (bf.bfType != BFT_BITMAP) { //do we have a RC HEADER? + bf.bfOffBits = 0L; + hFile->Seek(off,SEEK_SET); + } + + BITMAPINFOHEADER bmpHeader; + if (!DibReadBitmapInfo(hFile,&bmpHeader)) cx_throw("Error reading BMP info"); + DWORD dwCompression=bmpHeader.biCompression; + DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression + bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER); + + bool bTopDownDib = bmpHeader.biHeight<0; // check if it's a top-down bitmap + if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight; + + if (info.nEscape == -1) { + // Return output dimensions only + head.biWidth = bmpHeader.biWidth; + head.biHeight = bmpHeader.biHeight; + info.dwType = CXIMAGE_FORMAT_BMP; + cx_throw("output dimensions returned"); + } + + if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP)) + cx_throw(""); + + SetXDPI((long) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5)); + SetYDPI((long) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5)); + + if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding + + RGBQUAD *pRgb = GetPalette(); + if (pRgb){ + if (bIsOldBmp){ + // convert a old color table (3 byte entries) to a new + // color table (4 byte entries) + hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1); + for (int i=DibNumColors(&head)-1; i>=0; i--){ + pRgb[i].rgbRed = ((RGBTRIPLE *)pRgb)[i].rgbtRed; + pRgb[i].rgbBlue = ((RGBTRIPLE *)pRgb)[i].rgbtBlue; + pRgb[i].rgbGreen = ((RGBTRIPLE *)pRgb)[i].rgbtGreen; + pRgb[i].rgbReserved = (BYTE)0; + } + } else { + hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1); + //force rgbReserved=0, to avoid problems with some WinXp bitmaps + for (unsigned int i=0; i - cancel decoding + + switch (dwBitCount) { + case 32 : + DWORD bfmask[3]; + if (dwCompression == BI_BITFIELDS) + { + hFile->Read(bfmask, 12, 1); + } else { + bfmask[0]=0x00FF0000; + bfmask[1]=0x0000FF00; + bfmask[2]=0x000000FF; + } + if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET); + if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){ + long imagesize=4*head.biHeight*head.biWidth; + BYTE* buff32=(BYTE*)malloc(imagesize); + if (buff32){ + hFile->Read(buff32, imagesize,1); // read in the pixels + +#if CXIMAGE_SUPPORT_ALPHA + if (dwCompression == BI_RGB){ + AlphaCreate(); + if (AlphaIsValid()){ + bool bAlphaOk = false; + BYTE* p; + for (long y=0; ySeek(off + bf.bfOffBits,SEEK_SET); + if (dwCompression == BI_RGB){ + hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels + } else cx_throw("unknown compression"); + break; + case 16 : + { + DWORD bfmask[3]; + if (dwCompression == BI_BITFIELDS) + { + hFile->Read(bfmask, 12, 1); + } else { + bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555 + } + // bf.bfOffBits required after the bitfield mask + if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET); + // read in the pixels + hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1); + // transform into RGB + Bitfield2RGB(info.pImage,bfmask[0],bfmask[1],bfmask[2],16); + break; + } + case 8 : + case 4 : + case 1 : + if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET); + switch (dwCompression) { + case BI_RGB : + hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels + break; + case BI_RLE4 : + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + BOOL low_nibble = FALSE; + CImageIterator iter(this); + + for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) { + + switch (status_byte) { + case RLE_COMMAND : + hFile->Read(&status_byte, sizeof(BYTE), 1); + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + low_nibble = FALSE; + break; + case RLE_ENDOFBITMAP : + bContinue=FALSE; + break; + case RLE_DELTA : + { + // read the delta values + BYTE delta_x; + BYTE delta_y; + hFile->Read(&delta_x, sizeof(BYTE), 1); + hFile->Read(&delta_y, sizeof(BYTE), 1); + // apply them + bits += delta_x / 2; + scanline += delta_y; + break; + } + default : + hFile->Read(&second_byte, sizeof(BYTE), 1); + BYTE *sline = iter.GetRow(scanline); + for (int i = 0; i < status_byte; i++) { + if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ + if (low_nibble) { + if (i&1) + *(sline + bits) |= (second_byte & 0x0f); + else + *(sline + bits) |= (second_byte & 0xf0)>>4; + bits++; + } else { + if (i&1) + *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; + else + *(sline + bits) = (BYTE)(second_byte & 0xf0); + } + } + + if ((i & 1) && (i != (status_byte - 1))) + hFile->Read(&second_byte, sizeof(BYTE), 1); + + low_nibble = !low_nibble; + } + if ((((status_byte+1) >> 1) & 1 ) == 1) + hFile->Read(&second_byte, sizeof(BYTE), 1); + break; + }; + break; + default : + { + BYTE *sline = iter.GetRow(scanline); + hFile->Read(&second_byte, sizeof(BYTE), 1); + for (unsigned i = 0; i < status_byte; i++) { + if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ + if (low_nibble) { + if (i&1) + *(sline + bits) |= (second_byte & 0x0f); + else + *(sline + bits) |= (second_byte & 0xf0)>>4; + bits++; + } else { + if (i&1) + *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; + else + *(sline + bits) = (BYTE)(second_byte & 0xf0); + } + } + low_nibble = !low_nibble; + } + } + break; + }; + } + break; + } + case BI_RLE8 : + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + CImageIterator iter(this); + + for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) { + switch (status_byte) { + case RLE_COMMAND : + hFile->Read(&status_byte, sizeof(BYTE), 1); + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + break; + case RLE_ENDOFBITMAP : + bContinue=FALSE; + break; + case RLE_DELTA : + { + // read the delta values + BYTE delta_x; + BYTE delta_y; + hFile->Read(&delta_x, sizeof(BYTE), 1); + hFile->Read(&delta_y, sizeof(BYTE), 1); + // apply them + bits += delta_x; + scanline += delta_y; + break; + } + default : + hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(BYTE) * status_byte, 1); + // align run length to even number of bytes + if ((status_byte & 1) == 1) + hFile->Read(&second_byte, sizeof(BYTE), 1); + bits += status_byte; + break; + }; + break; + default : + BYTE *sline = iter.GetRow(scanline); + hFile->Read(&second_byte, sizeof(BYTE), 1); + for (unsigned i = 0; i < status_byte; i++) { + if ((DWORD)bits + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_BMP) return true; + return false; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/* ReadDibBitmapInfo() + * + * Will read a file in DIB format and return a global HANDLE to its + * BITMAPINFO. This function will work with both "old" and "new" + * bitmap formats, but will always return a "new" BITMAPINFO. + */ +bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib) +{ + if ((fh==NULL)||(pdib==NULL)) return false; + + if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false; + + bihtoh(pdib); + + switch (pdib->biSize) // what type of bitmap info is this? + { + case sizeof(BITMAPINFOHEADER): + break; + + case 64: //sizeof(OS2_BMP_HEADER): + fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR); + break; + + case sizeof(BITMAPCOREHEADER): + { + BITMAPCOREHEADER bc = *(BITMAPCOREHEADER*)pdib; + pdib->biSize = bc.bcSize; + pdib->biWidth = (DWORD)bc.bcWidth; + pdib->biHeight = (DWORD)bc.bcHeight; + pdib->biPlanes = bc.bcPlanes; + pdib->biBitCount = bc.bcBitCount; + pdib->biCompression = BI_RGB; + pdib->biSizeImage = 0; + pdib->biXPelsPerMeter = 0; + pdib->biYPelsPerMeter = 0; + pdib->biClrUsed = 0; + pdib->biClrImportant = 0; + + fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR); + } + break; + default: + //give a last chance + if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&& + (pdib->biSizeImage>=(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&& + (pdib->biPlanes==1)&&(pdib->biClrUsed==0)) + { + if (pdib->biCompression==BI_RGB) + fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR); + break; + } + return false; + } + + FixBitmapInfo(pdib); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_BMP +//////////////////////////////////////////////////////////////////////////////// diff --git a/utilities/CxImage/ximabmp.h b/utilities/CxImage/ximabmp.h index 3b794d9..2bda4fe 100644 --- a/utilities/CxImage/ximabmp.h +++ b/utilities/CxImage/ximabmp.h @@ -1,79 +1,79 @@ -/* - * File: ximabmp.h - * Purpose: BMP Image Class Loader and Writer - */ -/* ========================================================== - * CxImageBMP (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes - * - * original CImageBMP and CImageIterator implementation are: - * Copyright: (c) 1995, Alejandro Aguilar Sierra - * - * ========================================================== - */ - -#if !defined(__ximaBMP_h) -#define __ximaBMP_h - -#include "ximage.h" - -const int RLE_COMMAND = 0; -const int RLE_ENDOFLINE = 0; -const int RLE_ENDOFBITMAP = 1; -const int RLE_DELTA = 2; - -#if !defined(BI_RLE8) - #define BI_RLE8 1L -#endif -#if !defined(BI_RLE4) - #define BI_RLE4 2L -#endif - -#if CXIMAGE_SUPPORT_BMP - -class CxImageBMP: public CxImage -{ -public: - CxImageBMP(): CxImage(CXIMAGE_FORMAT_BMP) {}; - - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE - -protected: - bool DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib); -}; - -#define BFT_ICON 0x4349 /* 'IC' */ -#define BFT_BITMAP 0x4d42 /* 'BM' */ -#define BFT_CURSOR 0x5450 /* 'PT' */ - -#ifndef WIDTHBYTES -#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */ -#endif - -#endif - -#define DibWidthBytesN(lpbi, n) (UINT)WIDTHBYTES((UINT)(lpbi)->biWidth * (UINT)(n)) -#define DibWidthBytes(lpbi) DibWidthBytesN(lpbi, (lpbi)->biBitCount) - -#define DibSizeImage(lpbi) ((lpbi)->biSizeImage == 0 \ - ? ((DWORD)(UINT)DibWidthBytes(lpbi) * (DWORD)(UINT)(lpbi)->biHeight) \ - : (lpbi)->biSizeImage) - -#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \ - ? (int)(1 << (int)(lpbi)->biBitCount) \ - : (int)(lpbi)->biClrUsed) - -#define FixBitmapInfo(lpbi) if ((lpbi)->biSizeImage == 0) \ - (lpbi)->biSizeImage = DibSizeImage(lpbi); \ - if ((lpbi)->biClrUsed == 0) \ - (lpbi)->biClrUsed = DibNumColors(lpbi); \ - -#endif +/* + * File: ximabmp.h + * Purpose: BMP Image Class Loader and Writer + */ +/* ========================================================== + * CxImageBMP (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes + * + * original CImageBMP and CImageIterator implementation are: + * Copyright: (c) 1995, Alejandro Aguilar Sierra + * + * ========================================================== + */ + +#if !defined(__ximaBMP_h) +#define __ximaBMP_h + +#include "ximage.h" + +const int RLE_COMMAND = 0; +const int RLE_ENDOFLINE = 0; +const int RLE_ENDOFBITMAP = 1; +const int RLE_DELTA = 2; + +#if !defined(BI_RLE8) + #define BI_RLE8 1L +#endif +#if !defined(BI_RLE4) + #define BI_RLE4 2L +#endif + +#if CXIMAGE_SUPPORT_BMP + +class CxImageBMP: public CxImage +{ +public: + CxImageBMP(): CxImage(CXIMAGE_FORMAT_BMP) {}; + + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE + +protected: + bool DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib); +}; + +#define BFT_ICON 0x4349 /* 'IC' */ +#define BFT_BITMAP 0x4d42 /* 'BM' */ +#define BFT_CURSOR 0x5450 /* 'PT' */ + +#ifndef WIDTHBYTES +#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */ +#endif + +#endif + +#define DibWidthBytesN(lpbi, n) (UINT)WIDTHBYTES((UINT)(lpbi)->biWidth * (UINT)(n)) +#define DibWidthBytes(lpbi) DibWidthBytesN(lpbi, (lpbi)->biBitCount) + +#define DibSizeImage(lpbi) ((lpbi)->biSizeImage == 0 \ + ? ((DWORD)(UINT)DibWidthBytes(lpbi) * (DWORD)(UINT)(lpbi)->biHeight) \ + : (lpbi)->biSizeImage) + +#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \ + ? (int)(1 << (int)(lpbi)->biBitCount) \ + : (int)(lpbi)->biClrUsed) + +#define FixBitmapInfo(lpbi) if ((lpbi)->biSizeImage == 0) \ + (lpbi)->biSizeImage = DibSizeImage(lpbi); \ + if ((lpbi)->biClrUsed == 0) \ + (lpbi)->biClrUsed = DibNumColors(lpbi); \ + +#endif diff --git a/utilities/CxImage/ximacfg.h b/utilities/CxImage/ximacfg.h index ef89b22..92a6cb6 100644 --- a/utilities/CxImage/ximacfg.h +++ b/utilities/CxImage/ximacfg.h @@ -1,78 +1,78 @@ -#if !defined(__ximaCFG_h) -#define __ximaCFG_h - -///////////////////////////////////////////////////////////////////////////// -// Protability issues -#ifdef ntohs -# undef ntohs -#endif -#ifdef ntohl -# undef ntohl -#endif -#ifndef _tfopen -# define _tfopen fopen -#endif -#ifndef LPCTSTR -# define LPCTSTR char* -#endif -#ifndef HDC -# define HDC void* -#endif -#ifndef _tcsnicmp -# define _tcsnicmp strncasecmp -#endif - -///////////////////////////////////////////////////////////////////////////// -// CxImage supported features -#define CXIMAGE_SUPPORT_ALPHA 1 -#define CXIMAGE_SUPPORT_SELECTION 1 -#define CXIMAGE_SUPPORT_TRANSFORMATION 1 -#define CXIMAGE_SUPPORT_DSP 0 -#define CXIMAGE_SUPPORT_LAYERS 1 -#define CXIMAGE_SUPPORT_INTERPOLATION 0 - -#define CXIMAGE_SUPPORT_DECODE 1 -#define CXIMAGE_SUPPORT_ENCODE 1 // -#define CXIMAGE_SUPPORT_WINDOWS 0 - -///////////////////////////////////////////////////////////////////////////// -// CxImage supported formats -#define CXIMAGE_SUPPORT_BMP 0 -#define CXIMAGE_SUPPORT_GIF 1 -#define CXIMAGE_SUPPORT_JPG 0 -#define CXIMAGE_SUPPORT_PNG 0 -#define CXIMAGE_SUPPORT_ICO 0 -#define CXIMAGE_SUPPORT_TIF 0 -#define CXIMAGE_SUPPORT_TGA 0 -#define CXIMAGE_SUPPORT_PCX 0 -#define CXIMAGE_SUPPORT_WBMP 0 -#define CXIMAGE_SUPPORT_WMF 0 - -#define CXIMAGE_SUPPORT_JP2 0 -#define CXIMAGE_SUPPORT_JPC 0 -#define CXIMAGE_SUPPORT_PGX 0 -#define CXIMAGE_SUPPORT_PNM 0 -#define CXIMAGE_SUPPORT_RAS 0 - -#define CXIMAGE_SUPPORT_JBG 0 // GPL'd see ../jbig/copying.txt & ../jbig/patents.htm - -#define CXIMAGE_SUPPORT_MNG 0 -#define CXIMAGE_SUPPORT_SKA 0 -#define CXIMAGE_SUPPORT_RAW 0 - -///////////////////////////////////////////////////////////////////////////// -#define CXIMAGE_MAX_MEMORY 268435456 - -#define CXIMAGE_DEFAULT_DPI 96 - -#define CXIMAGE_ERR_NOFILE "null file handler" -#define CXIMAGE_ERR_NOIMAGE "null image!!!" - -#define CXIMAGE_SUPPORT_EXCEPTION_HANDLING 1 - -///////////////////////////////////////////////////////////////////////////// -//color to grey mapping -//#define RGB2GRAY(r,g,b) (((b)*114 + (g)*587 + (r)*299)/1000) -#define RGB2GRAY(r,g,b) (((b)*117 + (g)*601 + (r)*306) >> 10) - -#endif +#if !defined(__ximaCFG_h) +#define __ximaCFG_h + +///////////////////////////////////////////////////////////////////////////// +// Protability issues +#ifdef ntohs +# undef ntohs +#endif +#ifdef ntohl +# undef ntohl +#endif +#ifndef _tfopen +# define _tfopen fopen +#endif +#ifndef LPCTSTR +# define LPCTSTR char* +#endif +#ifndef HDC +# define HDC void* +#endif +#ifndef _tcsnicmp +# define _tcsnicmp strncasecmp +#endif + +///////////////////////////////////////////////////////////////////////////// +// CxImage supported features +#define CXIMAGE_SUPPORT_ALPHA 1 +#define CXIMAGE_SUPPORT_SELECTION 1 +#define CXIMAGE_SUPPORT_TRANSFORMATION 1 +#define CXIMAGE_SUPPORT_DSP 0 +#define CXIMAGE_SUPPORT_LAYERS 1 +#define CXIMAGE_SUPPORT_INTERPOLATION 0 + +#define CXIMAGE_SUPPORT_DECODE 1 +#define CXIMAGE_SUPPORT_ENCODE 1 // +#define CXIMAGE_SUPPORT_WINDOWS 0 + +///////////////////////////////////////////////////////////////////////////// +// CxImage supported formats +#define CXIMAGE_SUPPORT_BMP 0 +#define CXIMAGE_SUPPORT_GIF 1 +#define CXIMAGE_SUPPORT_JPG 0 +#define CXIMAGE_SUPPORT_PNG 0 +#define CXIMAGE_SUPPORT_ICO 0 +#define CXIMAGE_SUPPORT_TIF 0 +#define CXIMAGE_SUPPORT_TGA 0 +#define CXIMAGE_SUPPORT_PCX 0 +#define CXIMAGE_SUPPORT_WBMP 0 +#define CXIMAGE_SUPPORT_WMF 0 + +#define CXIMAGE_SUPPORT_JP2 0 +#define CXIMAGE_SUPPORT_JPC 0 +#define CXIMAGE_SUPPORT_PGX 0 +#define CXIMAGE_SUPPORT_PNM 0 +#define CXIMAGE_SUPPORT_RAS 0 + +#define CXIMAGE_SUPPORT_JBG 0 // GPL'd see ../jbig/copying.txt & ../jbig/patents.htm + +#define CXIMAGE_SUPPORT_MNG 0 +#define CXIMAGE_SUPPORT_SKA 0 +#define CXIMAGE_SUPPORT_RAW 0 + +///////////////////////////////////////////////////////////////////////////// +#define CXIMAGE_MAX_MEMORY 268435456 + +#define CXIMAGE_DEFAULT_DPI 96 + +#define CXIMAGE_ERR_NOFILE "null file handler" +#define CXIMAGE_ERR_NOIMAGE "null image!!!" + +#define CXIMAGE_SUPPORT_EXCEPTION_HANDLING 1 + +///////////////////////////////////////////////////////////////////////////// +//color to grey mapping +//#define RGB2GRAY(r,g,b) (((b)*114 + (g)*587 + (r)*299)/1000) +#define RGB2GRAY(r,g,b) (((b)*117 + (g)*601 + (r)*306) >> 10) + +#endif diff --git a/utilities/CxImage/ximadef.h b/utilities/CxImage/ximadef.h index f73bcd2..b388b2b 100644 --- a/utilities/CxImage/ximadef.h +++ b/utilities/CxImage/ximadef.h @@ -1,206 +1,206 @@ -#if !defined(__ximadefs_h) -#define __ximadefs_h - -#include "ximacfg.h" - -#if defined(_AFXDLL)||defined(_USRDLL) - #define DLL_EXP __declspec(dllexport) -#elif defined(_MSC_VER)&&(_MSC_VER<1200) - #define DLL_EXP __declspec(dllimport) -#else - #define DLL_EXP -#endif - - -#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - #define cx_try try - #define cx_throw(message) throw(message) - #define cx_catch catch (const char *message) -#else - #define cx_try bool cx_error=false; - #define cx_throw(message) {cx_error=true; if(strcmp(message,"")) strncpy(info.szLastError,message,255); goto cx_error_catch;} - #define cx_catch cx_error_catch: char message[]=""; if(cx_error) -#endif - - -#if CXIMAGE_SUPPORT_JP2 || CXIMAGE_SUPPORT_JPC || CXIMAGE_SUPPORT_PGX || CXIMAGE_SUPPORT_PNM || CXIMAGE_SUPPORT_RAS - #define CXIMAGE_SUPPORT_JASPER 1 -#else - #define CXIMAGE_SUPPORT_JASPER 0 -#endif - -#if CXIMAGE_SUPPORT_DSP -#undef CXIMAGE_SUPPORT_TRANSFORMATION - #define CXIMAGE_SUPPORT_TRANSFORMATION 1 -#endif - -#if CXIMAGE_SUPPORT_TRANSFORMATION || CXIMAGE_SUPPORT_TIF || CXIMAGE_SUPPORT_TGA || CXIMAGE_SUPPORT_BMP || CXIMAGE_SUPPORT_WINDOWS - #define CXIMAGE_SUPPORT_BASICTRANSFORMATIONS 1 -#endif - -#if CXIMAGE_SUPPORT_DSP || CXIMAGE_SUPPORT_TRANSFORMATION -#undef CXIMAGE_SUPPORT_INTERPOLATION - #define CXIMAGE_SUPPORT_INTERPOLATION 1 -#endif - -#if defined (_WIN32_WCE) - #undef CXIMAGE_SUPPORT_WMF - #define CXIMAGE_SUPPORT_WMF 0 -#endif - -#if !defined(WIN32) && !defined(_WIN32_WCE) - #undef CXIMAGE_SUPPORT_WINDOWS - #define CXIMAGE_SUPPORT_WINDOWS 0 -#endif - -#ifndef min -#define min(a,b) (((a)<(b))?(a):(b)) -#endif -#ifndef max -#define max(a,b) (((a)>(b))?(a):(b)) -#endif - -#ifndef PI - #define PI 3.141592653589793f -#endif - - -#if defined(WIN32) || defined(_WIN32_WCE) -#include -#include -#endif - -#include -#include - -#ifdef __BORLANDC__ - -#ifndef _COMPLEX_DEFINED - -typedef struct tagcomplex { - double x,y; -} _complex; - -#endif - -#define _cabs(c) sqrt(c.x*c.x+c.y*c.y) - -#endif - - -#if !defined(WIN32) && !defined(_WIN32_WCE) - -#include -#include -#include - -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned long DWORD; -typedef unsigned int UINT; - -typedef DWORD COLORREF; -typedef unsigned int HANDLE; -typedef void* HRGN; - -#ifndef BOOL -#define BOOL bool -#endif - -#ifndef TRUE -#define TRUE true -#endif - -#ifndef FALSE -#define FALSE false -#endif - -#ifndef TCHAR -#define TCHAR char -#define _T -#endif - -typedef struct tagRECT -{ - long left; - long top; - long right; - long bottom; -} RECT; - -typedef struct tagPOINT -{ - long x; - long y; -} POINT; - -typedef struct tagRGBQUAD { - BYTE rgbBlue; - BYTE rgbGreen; - BYTE rgbRed; - BYTE rgbReserved; -} RGBQUAD; - -#pragma pack(1) - -typedef struct tagBITMAPINFOHEADER{ - DWORD biSize; - long biWidth; - long biHeight; - WORD biPlanes; - WORD biBitCount; - DWORD biCompression; - DWORD biSizeImage; - long biXPelsPerMeter; - long biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; -} BITMAPINFOHEADER; - -typedef struct tagBITMAPFILEHEADER { - WORD bfType; - DWORD bfSize; - WORD bfReserved1; - WORD bfReserved2; - DWORD bfOffBits; -} BITMAPFILEHEADER; - -typedef struct tagBITMAPCOREHEADER { - DWORD bcSize; - WORD bcWidth; - WORD bcHeight; - WORD bcPlanes; - WORD bcBitCount; -} BITMAPCOREHEADER; - -typedef struct tagRGBTRIPLE { - BYTE rgbtBlue; - BYTE rgbtGreen; - BYTE rgbtRed; -} RGBTRIPLE; - -#pragma pack() - -#define BI_RGB 0L -#define BI_RLE8 1L -#define BI_RLE4 2L -#define BI_BITFIELDS 3L - -#define GetRValue(rgb) ((BYTE)(rgb)) -#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8)) -#define GetBValue(rgb) ((BYTE)((rgb)>>16)) -#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) - -#ifndef _COMPLEX_DEFINED - -typedef struct tagcomplex { - double x,y; -} _complex; - -#endif - -#define _cabs(c) sqrt(c.x*c.x+c.y*c.y) - -#endif - -#endif //__ximadefs +#if !defined(__ximadefs_h) +#define __ximadefs_h + +#include "ximacfg.h" + +#if defined(_AFXDLL)||defined(_USRDLL) + #define DLL_EXP __declspec(dllexport) +#elif defined(_MSC_VER)&&(_MSC_VER<1200) + #define DLL_EXP __declspec(dllimport) +#else + #define DLL_EXP +#endif + + +#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + #define cx_try try + #define cx_throw(message) throw(message) + #define cx_catch catch (const char *message) +#else + #define cx_try bool cx_error=false; + #define cx_throw(message) {cx_error=true; if(strcmp(message,"")) strncpy(info.szLastError,message,255); goto cx_error_catch;} + #define cx_catch cx_error_catch: char message[]=""; if(cx_error) +#endif + + +#if CXIMAGE_SUPPORT_JP2 || CXIMAGE_SUPPORT_JPC || CXIMAGE_SUPPORT_PGX || CXIMAGE_SUPPORT_PNM || CXIMAGE_SUPPORT_RAS + #define CXIMAGE_SUPPORT_JASPER 1 +#else + #define CXIMAGE_SUPPORT_JASPER 0 +#endif + +#if CXIMAGE_SUPPORT_DSP +#undef CXIMAGE_SUPPORT_TRANSFORMATION + #define CXIMAGE_SUPPORT_TRANSFORMATION 1 +#endif + +#if CXIMAGE_SUPPORT_TRANSFORMATION || CXIMAGE_SUPPORT_TIF || CXIMAGE_SUPPORT_TGA || CXIMAGE_SUPPORT_BMP || CXIMAGE_SUPPORT_WINDOWS + #define CXIMAGE_SUPPORT_BASICTRANSFORMATIONS 1 +#endif + +#if CXIMAGE_SUPPORT_DSP || CXIMAGE_SUPPORT_TRANSFORMATION +#undef CXIMAGE_SUPPORT_INTERPOLATION + #define CXIMAGE_SUPPORT_INTERPOLATION 1 +#endif + +#if defined (_WIN32_WCE) + #undef CXIMAGE_SUPPORT_WMF + #define CXIMAGE_SUPPORT_WMF 0 +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) + #undef CXIMAGE_SUPPORT_WINDOWS + #define CXIMAGE_SUPPORT_WINDOWS 0 +#endif + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +#ifndef PI + #define PI 3.141592653589793f +#endif + + +#if defined(WIN32) || defined(_WIN32_WCE) +#include +#include +#endif + +#include +#include + +#ifdef __BORLANDC__ + +#ifndef _COMPLEX_DEFINED + +typedef struct tagcomplex { + double x,y; +} _complex; + +#endif + +#define _cabs(c) sqrt(c.x*c.x+c.y*c.y) + +#endif + + +#if !defined(WIN32) && !defined(_WIN32_WCE) + +#include +#include +#include + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef unsigned int UINT; + +typedef DWORD COLORREF; +typedef unsigned int HANDLE; +typedef void* HRGN; + +#ifndef BOOL +#define BOOL bool +#endif + +#ifndef TRUE +#define TRUE true +#endif + +#ifndef FALSE +#define FALSE false +#endif + +#ifndef TCHAR +#define TCHAR char +#define _T +#endif + +typedef struct tagRECT +{ + long left; + long top; + long right; + long bottom; +} RECT; + +typedef struct tagPOINT +{ + long x; + long y; +} POINT; + +typedef struct tagRGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; +} RGBQUAD; + +#pragma pack(1) + +typedef struct tagBITMAPINFOHEADER{ + DWORD biSize; + long biWidth; + long biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + long biXPelsPerMeter; + long biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER; + +typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +} BITMAPFILEHEADER; + +typedef struct tagBITMAPCOREHEADER { + DWORD bcSize; + WORD bcWidth; + WORD bcHeight; + WORD bcPlanes; + WORD bcBitCount; +} BITMAPCOREHEADER; + +typedef struct tagRGBTRIPLE { + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; +} RGBTRIPLE; + +#pragma pack() + +#define BI_RGB 0L +#define BI_RLE8 1L +#define BI_RLE4 2L +#define BI_BITFIELDS 3L + +#define GetRValue(rgb) ((BYTE)(rgb)) +#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8)) +#define GetBValue(rgb) ((BYTE)((rgb)>>16)) +#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) + +#ifndef _COMPLEX_DEFINED + +typedef struct tagcomplex { + double x,y; +} _complex; + +#endif + +#define _cabs(c) sqrt(c.x*c.x+c.y*c.y) + +#endif + +#endif //__ximadefs diff --git a/utilities/CxImage/ximadsp.cpp b/utilities/CxImage/ximadsp.cpp index 68695db..1623d5a 100644 --- a/utilities/CxImage/ximadsp.cpp +++ b/utilities/CxImage/ximadsp.cpp @@ -1,3642 +1,3642 @@ -// xImaDsp.cpp : DSP functions -/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" - -#include "ximaiter.h" - -#if CXIMAGE_SUPPORT_DSP - -//////////////////////////////////////////////////////////////////////////////// -/** - * Converts the image to B&W. - * The OptimalThreshold() function can be used for calculating the optimal threshold. - * \param level: the lightness threshold. - * \return true if everything is ok - */ -bool CxImage::Threshold(BYTE level) -{ - if (!pDib) return false; - if (head.biBitCount == 1) return true; - - GrayScale(); - - CxImage tmp(head.biWidth,head.biHeight,1); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - for (long y=0;ylevel) - tmp.BlindSetPixelIndex(x,y,1); - else - tmp.BlindSetPixelIndex(x,y,0); - } - } - tmp.SetPaletteColor(0,0,0,0); - tmp.SetPaletteColor(1,255,255,255); - Transfer(tmp); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Converts the image to B&W, using a threshold mask - * \param pThresholdMask: the lightness threshold mask. - * the pThresholdMask image must be grayscale with same with and height of the current image - * \return true if everything is ok - */ -bool CxImage::Threshold(CxImage* pThresholdMask) -{ - if (!pDib) return false; - if (head.biBitCount == 1) return true; - - if (!pThresholdMask) return false; - - if (!pThresholdMask->IsValid() || - !pThresholdMask->IsGrayScale() || - pThresholdMask->GetWidth() != GetWidth() || - pThresholdMask->GetHeight() != GetHeight()){ - strcpy(info.szLastError,"invalid ThresholdMask"); - return false; - } - - GrayScale(); - - CxImage tmp(head.biWidth,head.biHeight,1); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - for (long y=0;ypThresholdMask->BlindGetPixelIndex(x,y)) - tmp.BlindSetPixelIndex(x,y,1); - else - tmp.BlindSetPixelIndex(x,y,0); - } - } - tmp.SetPaletteColor(0,0,0,0); - tmp.SetPaletteColor(1,255,255,255); - Transfer(tmp); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Filters only the pixels with a lightness less (or more) than the threshold level, - * and preserves the colors for the unfiltered pixels. - * \param level = the lightness threshold. - * \param bDirection = false: filter dark pixels, true: filter light pixels - * \param nBkgndColor = filtered pixels are set to nBkgndColor color - * \param bSetAlpha = if true, sets also the alpha component for the filtered pixels, with nBkgndColor.rgbReserved - * \return true if everything is ok - * \author [DP], [wangsongtao] - */ -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::Threshold2(BYTE level, bool bDirection, RGBQUAD nBkgndColor, bool bSetAlpha) -{ - if (!pDib) return false; - if (head.biBitCount == 1) return true; - - CxImage tmp(*this, true, false, false); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - tmp.GrayScale(); - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; y=level) BlindSetPixelColor(x,y,nBkgndColor,bSetAlpha); - } - } - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Extract RGB channels from the image. Each channel is an 8 bit grayscale image. - * \param r,g,b: pointers to CxImage objects, to store the splited channels - * \return true if everything is ok - */ -bool CxImage::SplitRGB(CxImage* r,CxImage* g,CxImage* b) -{ - if (!pDib) return false; - if (r==NULL && g==NULL && b==NULL) return false; - - CxImage tmpr(head.biWidth,head.biHeight,8); - CxImage tmpg(head.biWidth,head.biHeight,8); - CxImage tmpb(head.biWidth,head.biHeight,8); - - RGBQUAD color; - for(long y=0; yTransfer(tmpr); - if (g) g->Transfer(tmpg); - if (b) b->Transfer(tmpb); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Extract CMYK channels from the image. Each channel is an 8 bit grayscale image. - * \param c,m,y,k: pointers to CxImage objects, to store the splited channels - * \return true if everything is ok - */ -bool CxImage::SplitCMYK(CxImage* c,CxImage* m,CxImage* y,CxImage* k) -{ - if (!pDib) return false; - if (c==NULL && m==NULL && y==NULL && k==NULL) return false; - - CxImage tmpc(head.biWidth,head.biHeight,8); - CxImage tmpm(head.biWidth,head.biHeight,8); - CxImage tmpy(head.biWidth,head.biHeight,8); - CxImage tmpk(head.biWidth,head.biHeight,8); - - RGBQUAD color; - for(long yy=0; yyTransfer(tmpc); - if (m) m->Transfer(tmpm); - if (y) y->Transfer(tmpy); - if (k) k->Transfer(tmpk); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Extract YUV channels from the image. Each channel is an 8 bit grayscale image. - * \param y,u,v: pointers to CxImage objects, to store the splited channels - * \return true if everything is ok - */ -bool CxImage::SplitYUV(CxImage* y,CxImage* u,CxImage* v) -{ - if (!pDib) return false; - if (y==NULL && u==NULL && v==NULL) return false; - - CxImage tmpy(head.biWidth,head.biHeight,8); - CxImage tmpu(head.biWidth,head.biHeight,8); - CxImage tmpv(head.biWidth,head.biHeight,8); - - RGBQUAD color; - for(long yy=0; yyTransfer(tmpy); - if (u) u->Transfer(tmpu); - if (v) v->Transfer(tmpv); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Extract YIQ channels from the image. Each channel is an 8 bit grayscale image. - * \param y,i,q: pointers to CxImage objects, to store the splited channels - * \return true if everything is ok - */ -bool CxImage::SplitYIQ(CxImage* y,CxImage* i,CxImage* q) -{ - if (!pDib) return false; - if (y==NULL && i==NULL && q==NULL) return false; - - CxImage tmpy(head.biWidth,head.biHeight,8); - CxImage tmpi(head.biWidth,head.biHeight,8); - CxImage tmpq(head.biWidth,head.biHeight,8); - - RGBQUAD color; - for(long yy=0; yyTransfer(tmpy); - if (i) i->Transfer(tmpi); - if (q) q->Transfer(tmpq); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Extract XYZ channels from the image. Each channel is an 8 bit grayscale image. - * \param x,y,z: pointers to CxImage objects, to store the splited channels - * \return true if everything is ok - */ -bool CxImage::SplitXYZ(CxImage* x,CxImage* y,CxImage* z) -{ - if (!pDib) return false; - if (x==NULL && y==NULL && z==NULL) return false; - - CxImage tmpx(head.biWidth,head.biHeight,8); - CxImage tmpy(head.biWidth,head.biHeight,8); - CxImage tmpz(head.biWidth,head.biHeight,8); - - RGBQUAD color; - for(long yy=0; yyTransfer(tmpx); - if (y) y->Transfer(tmpy); - if (z) z->Transfer(tmpz); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Extract HSL channels from the image. Each channel is an 8 bit grayscale image. - * \param h,s,l: pointers to CxImage objects, to store the splited channels - * \return true if everything is ok - */ -bool CxImage::SplitHSL(CxImage* h,CxImage* s,CxImage* l) -{ - if (!pDib) return false; - if (h==NULL && s==NULL && l==NULL) return false; - - CxImage tmph(head.biWidth,head.biHeight,8); - CxImage tmps(head.biWidth,head.biHeight,8); - CxImage tmpl(head.biWidth,head.biHeight,8); - - RGBQUAD color; - for(long y=0; yTransfer(tmph); - if (s) s->Transfer(tmps); - if (l) l->Transfer(tmpl); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#define HSLMAX 255 /* H,L, and S vary over 0-HSLMAX */ -#define RGBMAX 255 /* R,G, and B vary over 0-RGBMAX */ - /* HSLMAX BEST IF DIVISIBLE BY 6 */ - /* RGBMAX, HSLMAX must each fit in a BYTE. */ -/* Hue is undefined if Saturation is 0 (grey-scale) */ -/* This value determines where the Hue scrollbar is */ -/* initially set for achromatic colors */ -#define HSLUNDEFINED (HSLMAX*2/3) -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::RGBtoHSL(RGBQUAD lRGBColor) -{ - BYTE R,G,B; /* input RGB values */ - BYTE H,L,S; /* output HSL values */ - BYTE cMax,cMin; /* max and min RGB values */ - WORD Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max*/ - - R = lRGBColor.rgbRed; /* get R, G, and B out of DWORD */ - G = lRGBColor.rgbGreen; - B = lRGBColor.rgbBlue; - - cMax = max( max(R,G), B); /* calculate lightness */ - cMin = min( min(R,G), B); - L = (BYTE)((((cMax+cMin)*HSLMAX)+RGBMAX)/(2*RGBMAX)); - - if (cMax==cMin){ /* r=g=b --> achromatic case */ - S = 0; /* saturation */ - H = HSLUNDEFINED; /* hue */ - } else { /* chromatic case */ - if (L <= (HSLMAX/2)) /* saturation */ - S = (BYTE)((((cMax-cMin)*HSLMAX)+((cMax+cMin)/2))/(cMax+cMin)); - else - S = (BYTE)((((cMax-cMin)*HSLMAX)+((2*RGBMAX-cMax-cMin)/2))/(2*RGBMAX-cMax-cMin)); - /* hue */ - Rdelta = (WORD)((((cMax-R)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); - Gdelta = (WORD)((((cMax-G)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); - Bdelta = (WORD)((((cMax-B)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); - - if (R == cMax) - H = (BYTE)(Bdelta - Gdelta); - else if (G == cMax) - H = (BYTE)((HSLMAX/3) + Rdelta - Bdelta); - else /* B == cMax */ - H = (BYTE)(((2*HSLMAX)/3) + Gdelta - Rdelta); - -// if (H < 0) H += HSLMAX; //always false - if (H > HSLMAX) H -= HSLMAX; - } - RGBQUAD hsl={L,S,H,0}; - return hsl; -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::HueToRGB(float n1,float n2, float hue) -{ - // fixed implementation for HSL2RGB routine - float rValue; - - if (hue > 360) - hue = hue - 360; - else if (hue < 0) - hue = hue + 360; - - if (hue < 60) - rValue = n1 + (n2-n1)*hue/60.0f; - else if (hue < 180) - rValue = n2; - else if (hue < 240) - rValue = n1+(n2-n1)*(240-hue)/60; - else - rValue = n1; - - return rValue; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::HSLtoRGB(COLORREF cHSLColor) -{ - return HSLtoRGB(RGBtoRGBQUAD(cHSLColor)); -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::HSLtoRGB(RGBQUAD lHSLColor) -{ - // fixed implementation for HSL2RGB routine - float h,s,l; - float m1,m2; - BYTE r,g,b; - - h = (float)lHSLColor.rgbRed * 360.0f/255.0f; - s = (float)lHSLColor.rgbGreen/255.0f; - l = (float)lHSLColor.rgbBlue/255.0f; - - if (l <= 0.5) m2 = l * (1+s); - else m2 = l + s - l*s; - - m1 = 2 * l - m2; - - if (s == 0) { - r=g=b=(BYTE)(l*255.0f); - } else { - r = (BYTE)(HueToRGB(m1,m2,h+120) * 255.0f); - g = (BYTE)(HueToRGB(m1,m2,h) * 255.0f); - b = (BYTE)(HueToRGB(m1,m2,h-120) * 255.0f); - } - - RGBQUAD rgb = {b,g,r,0}; - return rgb; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::YUVtoRGB(RGBQUAD lYUVColor) -{ - int U,V,R,G,B; - float Y = lYUVColor.rgbRed; - U = lYUVColor.rgbGreen - 128; - V = lYUVColor.rgbBlue - 128; - -// R = (int)(1.164 * Y + 2.018 * U); -// G = (int)(1.164 * Y - 0.813 * V - 0.391 * U); -// B = (int)(1.164 * Y + 1.596 * V); - R = (int)( Y + 1.403f * V); - G = (int)( Y - 0.344f * U - 0.714f * V); - B = (int)( Y + 1.770f * U); - - R= min(255,max(0,R)); - G= min(255,max(0,G)); - B= min(255,max(0,B)); - RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; - return rgb; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::RGBtoYUV(RGBQUAD lRGBColor) -{ - int Y,U,V,R,G,B; - R = lRGBColor.rgbRed; - G = lRGBColor.rgbGreen; - B = lRGBColor.rgbBlue; - -// Y = (int)( 0.257 * R + 0.504 * G + 0.098 * B); -// U = (int)( 0.439 * R - 0.368 * G - 0.071 * B + 128); -// V = (int)(-0.148 * R - 0.291 * G + 0.439 * B + 128); - Y = (int)(0.299f * R + 0.587f * G + 0.114f * B); - U = (int)((B-Y) * 0.565f + 128); - V = (int)((R-Y) * 0.713f + 128); - - Y= min(255,max(0,Y)); - U= min(255,max(0,U)); - V= min(255,max(0,V)); - RGBQUAD yuv={(BYTE)V,(BYTE)U,(BYTE)Y,0}; - return yuv; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::YIQtoRGB(RGBQUAD lYIQColor) -{ - int I,Q,R,G,B; - float Y = lYIQColor.rgbRed; - I = lYIQColor.rgbGreen - 128; - Q = lYIQColor.rgbBlue - 128; - - R = (int)( Y + 0.956f * I + 0.621f * Q); - G = (int)( Y - 0.273f * I - 0.647f * Q); - B = (int)( Y - 1.104f * I + 1.701f * Q); - - R= min(255,max(0,R)); - G= min(255,max(0,G)); - B= min(255,max(0,B)); - RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; - return rgb; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::RGBtoYIQ(RGBQUAD lRGBColor) -{ - int Y,I,Q,R,G,B; - R = lRGBColor.rgbRed; - G = lRGBColor.rgbGreen; - B = lRGBColor.rgbBlue; - - Y = (int)( 0.2992f * R + 0.5868f * G + 0.1140f * B); - I = (int)( 0.5960f * R - 0.2742f * G - 0.3219f * B + 128); - Q = (int)( 0.2109f * R - 0.5229f * G + 0.3120f * B + 128); - - Y= min(255,max(0,Y)); - I= min(255,max(0,I)); - Q= min(255,max(0,Q)); - RGBQUAD yiq={(BYTE)Q,(BYTE)I,(BYTE)Y,0}; - return yiq; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::XYZtoRGB(RGBQUAD lXYZColor) -{ - int X,Y,Z,R,G,B; - X = lXYZColor.rgbRed; - Y = lXYZColor.rgbGreen; - Z = lXYZColor.rgbBlue; - double k=1.088751; - - R = (int)( 3.240479f * X - 1.537150f * Y - 0.498535f * Z * k); - G = (int)( -0.969256f * X + 1.875992f * Y + 0.041556f * Z * k); - B = (int)( 0.055648f * X - 0.204043f * Y + 1.057311f * Z * k); - - R= min(255,max(0,R)); - G= min(255,max(0,G)); - B= min(255,max(0,B)); - RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; - return rgb; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::RGBtoXYZ(RGBQUAD lRGBColor) -{ - int X,Y,Z,R,G,B; - R = lRGBColor.rgbRed; - G = lRGBColor.rgbGreen; - B = lRGBColor.rgbBlue; - - X = (int)( 0.412453f * R + 0.357580f * G + 0.180423f * B); - Y = (int)( 0.212671f * R + 0.715160f * G + 0.072169f * B); - Z = (int)((0.019334f * R + 0.119193f * G + 0.950227f * B)*0.918483657f); - - //X= min(255,max(0,X)); - //Y= min(255,max(0,Y)); - //Z= min(255,max(0,Z)); - RGBQUAD xyz={(BYTE)Z,(BYTE)Y,(BYTE)X,0}; - return xyz; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Generates a "rainbow" palette with saturated colors - * \param correction: 1 generates a single hue spectrum. 0.75 is nice for scientific applications. - */ -void CxImage::HuePalette(float correction) -{ - if (head.biClrUsed==0) return; - - for(DWORD j=0; j 1.0f) blend = 1.0f; - int a0 = (int)(256*blend); - int a1 = 256 - a0; - - bool bFullBlend = false; - if (blend > 0.999f) bFullBlend = true; - - RGBQUAD color,hsl; - if (head.biClrUsed==0){ - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; y>8); - color.rgbBlue = (BYTE)((hsl.rgbBlue * a0 + color.rgbBlue * a1)>>8); - color.rgbGreen = (BYTE)((hsl.rgbGreen * a0 + color.rgbGreen * a1)>>8); - BlindSetPixelColor(x,y,color); - } - } - } - } - } else { - for(DWORD j=0; j - for (int i=0;i<256;i++) { - cTable[i] = (BYTE)max(0,min(255,(int)((i-128)*c + brightness + 0.5f))); - } - - return Lut(cTable); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return mean lightness of the image. Useful with Threshold() and Light() - */ -float CxImage::Mean() -{ - if (!pDib) return 0; - - CxImage tmp(*this,true); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - tmp.GrayScale(); - float sum=0; - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - if (xmin==xmax || ymin==ymax) return (float)0.0; - - BYTE *iSrc=tmp.info.pImage; - iSrc += tmp.info.dwEffWidth*ymin; // necessary for selections - - for(long y=ymin; y - for(long x=xmin; x(y+j) || (y+j)>=head.biHeight) continue; - iY = iY2+x; - for(long k=-k2;k(x+k) || (x+k)>=head.biWidth) continue; - i=kernel[iCount]; - b += cPtr[iY+k] * i; - ksumcur += i; - } - } - if (Kfactor==0 || ksumcur==0){ - cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b + Koffset))); - } else if (ksumtot == ksumcur) { - cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b/Kfactor + Koffset))); - } else { - cPtr2[iY1] = (BYTE)min(255, max(0,(int)((b*ksumtot)/(ksumcur*Kfactor) + Koffset))); - } - } - } - } - } - else - { - for(long y=ymin; y r) r=c.rgbRed; - if (c.rgbGreen > g) g=c.rgbGreen; - if (c.rgbBlue > b) b=c.rgbBlue; - } - } - c.rgbRed = r; - c.rgbGreen = g; - c.rgbBlue = b; - tmp.BlindSetPixelColor(x,y,c); - } - } - } - Transfer(tmp); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Enhance the variations between adjacent pixels. - * Similar results can be achieved using Filter(), - * but the algorithms are different both in Edge() and in Contour(). - * \param Ksize: size of the kernel. - * \return true if everything is ok - */ -bool CxImage::Edge(long Ksize) -{ - if (!pDib) return false; - - long k2 = Ksize/2; - long kmax= Ksize-k2; - BYTE r,g,b,rr,gg,bb; - RGBQUAD c; - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; y r) r=c.rgbRed; - if (c.rgbGreen > g) g=c.rgbGreen; - if (c.rgbBlue > b) b=c.rgbBlue; - - if (c.rgbRed < rr) rr=c.rgbRed; - if (c.rgbGreen < gg) gg=c.rgbGreen; - if (c.rgbBlue < bb) bb=c.rgbBlue; - } - } - c.rgbRed = (BYTE)(255-abs(r-rr)); - c.rgbGreen = (BYTE)(255-abs(g-gg)); - c.rgbBlue = (BYTE)(255-abs(b-bb)); - tmp.BlindSetPixelColor(x,y,c); - } - } - } - Transfer(tmp); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Blends two images - * \param imgsrc2: image to be mixed with this - * \param op: blending method; see ImageOpType - * \param lXOffset, lYOffset: image displacement - * \param bMixAlpha: if true and imgsrc2 has a valid alpha layer, it will be mixed in the destination image. - * \return true if everything is ok - * - * thanks to Mwolski - */ -// -void CxImage::Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset, long lYOffset, bool bMixAlpha) -{ - long lWide = min(GetWidth(),imgsrc2.GetWidth()-lXOffset); - long lHeight = min(GetHeight(),imgsrc2.GetHeight()-lYOffset); - - bool bEditAlpha = imgsrc2.AlphaIsValid() & bMixAlpha; - - if (bEditAlpha && AlphaIsValid()==false){ - AlphaCreate(); - } - - RGBQUAD rgbBackgrnd1 = GetTransColor(); - RGBQUAD rgb1, rgb2, rgbDest; - - for(long lY=0;lY - for(x = 0; x < width; x++) { - for(y = 0; y < height; y++) { - SetPixelColor(x + lXOffset, y + lYOffset, imagesrc2.BlindGetPixelColor(x, y)); - } - } - } -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Adjusts separately the red, green, and blue values in the image. - * \param r, g, b: can be from -255 to +255. - * \return true if everything is ok - */ -bool CxImage::ShiftRGB(long r, long g, long b) -{ - if (!pDib) return false; - RGBQUAD color; - if (head.biClrUsed==0){ - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; y - for (int i=0;i<256;i++) { - cTable[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); - } - - return Lut(cTable); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Adjusts the color balance indipendent for each color channel - * \param gammaR, gammaG, gammaB can be from 0.1 to 5. - * \return true if everything is ok - * \sa Gamma - */ -bool CxImage::GammaRGB(float gammaR, float gammaG, float gammaB) -{ - if (!pDib) return false; - - if (gammaR <= 0.0f) return false; - if (gammaG <= 0.0f) return false; - if (gammaB <= 0.0f) return false; - - double dinvgamma, dMax; - int i; - - dinvgamma = 1/gammaR; - dMax = pow(255.0, dinvgamma) / 255.0; - BYTE cTableR[256]; - for (i=0;i<256;i++) { - cTableR[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); - } - - dinvgamma = 1/gammaG; - dMax = pow(255.0, dinvgamma) / 255.0; - BYTE cTableG[256]; - for (i=0;i<256;i++) { - cTableG[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); - } - - dinvgamma = 1/gammaB; - dMax = pow(255.0, dinvgamma) / 255.0; - BYTE cTableB[256]; - for (i=0;i<256;i++) { - cTableB[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); - } - - return Lut(cTableR, cTableG, cTableB); -} -//////////////////////////////////////////////////////////////////////////////// - -//#if !defined (_WIN32_WCE) -/** - * Adjusts the intensity of each pixel to the median intensity of its surrounding pixels. - * \param Ksize: size of the kernel. - * \return true if everything is ok - */ -bool CxImage::Median(long Ksize) -{ - if (!pDib) return false; - - long k2 = Ksize/2; - long kmax= Ksize-k2; - long i,j,k; - - RGBQUAD* kernel = (RGBQUAD*)malloc(Ksize*Ksize*sizeof(RGBQUAD)); - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; y - for(long x=xmin; xGetWidth(); - h=srcReal->GetHeight(); - } else { - w=srcImag->GetWidth(); - h=srcImag->GetHeight(); - } - - bool bXpow2 = IsPowerof2(w); - bool bYpow2 = IsPowerof2(h); - //if bForceFFT, width AND height must be powers of 2 - if (bForceFFT && !(bXpow2 && bYpow2)) { - long i; - - i=0; - while((1< copy the image - if (srcReal && dstReal) tmpReal->Copy(*srcReal,true,false,false); - if (srcImag && dstImag) tmpImag->Copy(*srcImag,true,false,false); - - // dst&&src are empty -> create new one, else turn to GrayScale - if (srcReal==0 && dstReal==0){ - tmpReal = new CxImage(w,h,8); - tmpReal->Clear(0); - tmpReal->SetGrayPalette(); - } else { - if (!tmpReal->IsGrayScale()) tmpReal->GrayScale(); - } - if (srcImag==0 && dstImag==0){ - tmpImag = new CxImage(w,h,8); - tmpImag->Clear(0); - tmpImag->SetGrayPalette(); - } else { - if (!tmpImag->IsGrayScale()) tmpImag->GrayScale(); - } - - if (!(tmpReal->IsValid() && tmpImag->IsValid())){ - if (srcReal==0 && dstReal==0) delete tmpReal; - if (srcImag==0 && dstImag==0) delete tmpImag; - return false; - } - - //resample for FFT, if necessary - tmpReal->Resample(w,h,0); - tmpImag->Resample(w,h,0); - - //ok, here we have 2 (w x h), grayscale images ready for a FFT - - double* real; - double* imag; - long j,k,m; - - _complex **grid; - //double mean = tmpReal->Mean(); - /* Allocate memory for the grid */ - grid = (_complex **)malloc(w * sizeof(_complex)); - for (k=0;kGetPixelIndex(k,j)-128; - grid[k][j].y = tmpImag->GetPixelIndex(k,j)-128; - } - } - - //DFT buffers - double *real2,*imag2; - real2 = (double*)malloc(max(w,h) * sizeof(double)); - imag2 = (double*)malloc(max(w,h) * sizeof(double)); - - /* Transform the rows */ - real = (double *)malloc(w * sizeof(double)); - imag = (double *)malloc(w * sizeof(double)); - - m=0; - while((1<SetPixelIndex(k,j,(BYTE)max(0,min(255,(nn*(3+log(_cabs(grid[k][j]))))))); - if (grid[k][j].x==0){ - tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/0.0000000001)*nn))))); - } else { - tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/grid[k][j].x)*nn))))); - } - } else { - tmpReal->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].x*nn)))); - tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].y*nn)))); - } - } - } - - for (k=0;k> 1; - j = 0; - for (i=0;i>= 1; - } - j += k; - } - - /* Compute the FFT */ - c1 = -1.0; - c2 = 0.0; - l2 = 1; - for (l=0;lGetWidth(); - long h = r->GetHeight(); - - Create(w,h,24); - - g->Resample(w,h); - b->Resample(w,h); - - if (a) { - a->Resample(w,h); -#if CXIMAGE_SUPPORT_ALPHA - AlphaCreate(); -#endif //CXIMAGE_SUPPORT_ALPHA - } - - RGBQUAD c; - for (long y=0;y - for (long x=0;xGetPixelIndex(x,y); - c.rgbGreen=g->GetPixelIndex(x,y); - c.rgbBlue=b->GetPixelIndex(x,y); - switch (colorspace){ - case 1: - BlindSetPixelColor(x,y,HSLtoRGB(c)); - break; - case 2: - BlindSetPixelColor(x,y,YUVtoRGB(c)); - break; - case 3: - BlindSetPixelColor(x,y,YIQtoRGB(c)); - break; - case 4: - BlindSetPixelColor(x,y,XYZtoRGB(c)); - break; - default: - BlindSetPixelColor(x,y,c); - } -#if CXIMAGE_SUPPORT_ALPHA - if (a) AlphaSet(x,y,a->GetPixelIndex(x,y)); -#endif //CXIMAGE_SUPPORT_ALPHA - } - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Smart blurring to remove small defects, dithering or artifacts. - * \param radius: normally between 0.01 and 0.5 - * \param niterations: should be trimmed with radius, to avoid blurring should be (radius*niterations)<1 - * \param colorspace: 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ - * \return true if everything is ok - */ -bool CxImage::Repair(float radius, long niterations, long colorspace) -{ - if (!IsValid()) return false; - - long w = GetWidth(); - long h = GetHeight(); - - CxImage r,g,b; - - r.Create(w,h,8); - g.Create(w,h,8); - b.Create(w,h,8); - - switch (colorspace){ - case 1: - SplitHSL(&r,&g,&b); - break; - case 2: - SplitYUV(&r,&g,&b); - break; - case 3: - SplitYIQ(&r,&g,&b); - break; - case 4: - SplitXYZ(&r,&g,&b); - break; - default: - SplitRGB(&r,&g,&b); - } - - for (int i=0; iGetWidth()-1; - long h = ch->GetHeight()-1; - - double correction,ix,iy,ixx,ixy,iyy; - int x,y,xy0,xp1,xm1,yp1,ym1; - - for(x=1; xBlindGetPixelIndex(x,y); - xm1 = ch->BlindGetPixelIndex(x-1,y); - xp1 = ch->BlindGetPixelIndex(x+1,y); - ym1 = ch->BlindGetPixelIndex(x,y-1); - yp1 = ch->BlindGetPixelIndex(x,y+1); - - ix= (xp1-xm1)/2.0; - iy= (yp1-ym1)/2.0; - ixx= xp1 - 2.0 * xy0 + xm1; - iyy= yp1 - 2.0 * xy0 + ym1; - ixy=(ch->BlindGetPixelIndex(x+1,y+1) + ch->BlindGetPixelIndex(x-1,y-1) - - ch->BlindGetPixelIndex(x-1,y+1) - ch->BlindGetPixelIndex(x+1,y-1))/4.0; - - correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy); - - tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5)))); - } - } - - for (x=0;x<=w;x++){ - for(y=0; y<=h; y+=h){ - xy0 = ch->BlindGetPixelIndex(x,y); - xm1 = ch->GetPixelIndex(x-1,y); - xp1 = ch->GetPixelIndex(x+1,y); - ym1 = ch->GetPixelIndex(x,y-1); - yp1 = ch->GetPixelIndex(x,y+1); - - ix= (xp1-xm1)/2.0; - iy= (yp1-ym1)/2.0; - ixx= xp1 - 2.0 * xy0 + xm1; - iyy= yp1 - 2.0 * xy0 + ym1; - ixy=(ch->GetPixelIndex(x+1,y+1) + ch->GetPixelIndex(x-1,y-1) - - ch->GetPixelIndex(x-1,y+1) - ch->GetPixelIndex(x+1,y-1))/4.0; - - correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy); - - tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5)))); - } - } - for (x=0;x<=w;x+=w){ - for (y=0;y<=h;y++){ - xy0 = ch->BlindGetPixelIndex(x,y); - xm1 = ch->GetPixelIndex(x-1,y); - xp1 = ch->GetPixelIndex(x+1,y); - ym1 = ch->GetPixelIndex(x,y-1); - yp1 = ch->GetPixelIndex(x,y+1); - - ix= (xp1-xm1)/2.0; - iy= (yp1-ym1)/2.0; - ixx= xp1 - 2.0 * xy0 + xm1; - iyy= yp1 - 2.0 * xy0 + ym1; - ixy=(ch->GetPixelIndex(x+1,y+1) + ch->GetPixelIndex(x-1,y-1) - - ch->GetPixelIndex(x-1,y+1) - ch->GetPixelIndex(x+1,y-1))/4.0; - - correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy); - - tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5)))); - } - } - - ch->Transfer(tmp); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Enhance the variations between adjacent pixels. - * Similar results can be achieved using Filter(), - * but the algorithms are different both in Edge() and in Contour(). - * \return true if everything is ok - */ -bool CxImage::Contour() -{ - if (!pDib) return false; - - long Ksize = 3; - long k2 = Ksize/2; - long kmax= Ksize-k2; - long i,j,k; - BYTE maxr,maxg,maxb; - RGBQUAD pix1,pix2; - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; ymaxb) maxb = pix2.rgbBlue; - if ((pix2.rgbGreen-pix1.rgbGreen)>maxg) maxg = pix2.rgbGreen; - if ((pix2.rgbRed-pix1.rgbRed)>maxr) maxr = pix2.rgbRed; - } - } - pix1.rgbBlue=(BYTE)(255-maxb); - pix1.rgbGreen=(BYTE)(255-maxg); - pix1.rgbRed=(BYTE)(255-maxr); - tmp.BlindSetPixelColor(x,y,pix1); - } - } - } - Transfer(tmp); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Adds a random offset to each pixel in the image - * \param radius: maximum pixel displacement - * \return true if everything is ok - */ -bool CxImage::Jitter(long radius) -{ - if (!pDib) return false; - - long nx,ny; - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; y modified scaling, so that matrix_lenght = 1+2*radius parameter - */ - radius = (float)fabs(0.5*radius) + 0.25f; - - std_dev = radius; - radius = std_dev * 2; - - /* go out 'radius' in each direction */ - matrix_length = int (2 * ceil(radius-0.5) + 1); - if (matrix_length <= 0) matrix_length = 1; - matrix_midpoint = matrix_length/2 + 1; - *cmatrix_p = new float[matrix_length]; - cmatrix = *cmatrix_p; - - /* Now we fill the matrix by doing a numeric integration approximation - * from -2*std_dev to 2*std_dev, sampling 50 points per pixel. - * We do the bottom half, mirror it to the top half, then compute the - * center point. Otherwise asymmetric quantization errors will occur. - * The formula to integrate is e^-(x^2/2s^2). - */ - - /* first we do the top (right) half of matrix */ - for (i = matrix_length/2 + 1; i < matrix_length; i++) - { - float base_x = i - (float)floor((float)(matrix_length/2)) - 0.5f; - sum = 0; - for (j = 1; j <= 50; j++) - { - if ( base_x+0.02*j <= radius ) - sum += (float)exp (-(base_x+0.02*j)*(base_x+0.02*j) / - (2*std_dev*std_dev)); - } - cmatrix[i] = sum/50; - } - - /* mirror the thing to the bottom half */ - for (i=0; i<=matrix_length/2; i++) { - cmatrix[i] = cmatrix[matrix_length-1-i]; - } - - /* find center val -- calculate an odd number of quanta to make it symmetric, - * even if the center point is weighted slightly higher than others. */ - sum = 0; - for (j=0; j<=50; j++) - { - sum += (float)exp (-(0.5+0.02*j)*(0.5+0.02*j) / - (2*std_dev*std_dev)); - } - cmatrix[matrix_length/2] = sum/51; - - /* normalize the distribution by scaling the total sum to one */ - sum=0; - for (i=0; i y) - { - for (row = 0; row < y ; row++) - { - scale=0; - /* find the scale factor */ - for (j = 0; j < y ; j++) - { - /* if the index is in bounds, add it to the scale counter */ - if ((j + cmatrix_middle - row >= 0) && - (j + cmatrix_middle - row < cmatrix_length)) - scale += cmatrix[j + cmatrix_middle - row]; - } - for (i = 0; i= row - cmatrix_middle) && - (j <= row + cmatrix_middle)) - sum += cur_col[j*bytes + i] * cmatrix[j]; - } - dest_col[row*bytes + i] = (BYTE)(0.5f + sum / scale); - } - } - } - else - { - /* for the edge condition, we only use available info and scale to one */ - for (row = 0; row < cmatrix_middle; row++) - { - /* find scale factor */ - scale=0; - for (j = cmatrix_middle - row; j0; j--) - { - sum += *(ctable_p + *cur_col_p1); - cur_col_p1 += bytes; - ctable_p += 256; - } - cur_col_p++; - *(dest_col_p++) = (BYTE)(0.5f + sum); - } - } - - /* for the edge condition , we only use available info, and scale to one */ - for (; row < y; row++) - { - /* find scale factor */ - scale=0; - for (j = 0; j< y-row + cmatrix_middle; j++) - scale += cmatrix[j]; - for (i = 0; ihead.biWidth; - ymax = iSrc->head.biHeight; - - if (xmin==xmax || ymin==ymax) return; - - nmin = xmin * bytes; - nmax = xmax * bytes; - - CImageIterator itSrc(iSrc); - CImageIterator itTmp(iDst); - - double dbScaler = 100.0f/(ymax-ymin)/bytes; - - for (n=0; n=pivot){ - while (z1) ? ((m/bytes)/decay+1) : m/bytes; - if (m>max_depth) m = max_depth; - step = (BYTE)((pSrc[x+bytes]-pSrc[x])/(m+1)); - while (m-->1){ - pDst[x+m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); - } - } - //find lower corner - z=x+bytes; - if (pSrc[x]=pivot){ - while (z1) ? ((m/bytes)/decay+1) : m/bytes; - if (m>max_depth) m = max_depth; - step = (BYTE)((pSrc[x+bytes]-pSrc[x])/(m+1)); - while (m-->1){ - pDst[x+m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); - } - } - } - //scan right to left - for (x=nmax-1-n /*,i=(xmax-1)*/; x>0; x-=bytes /*,i--*/) - { - z=x-bytes; - pivot = pSrc[z]-threshold; - //find upper corner - if (pSrc[x]=pivot){ - while (z>n && pSrc2[z]1) ? ((m/bytes)/decay+1) : m/bytes; - if (m>max_depth) m = max_depth; - step = (BYTE)((pSrc[x-bytes]-pSrc[x])/(m+1)); - while (m-->1){ - pDst[x-m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); - } - } - //find lower corner - z=x-bytes; - if (pSrc[x]=pivot){ - while (z>n && pSrc3[z]1) ? ((m/bytes)/decay+1) : m/bytes; - if (m>max_depth) m = max_depth; - step = (BYTE)((pSrc[x-bytes]-pSrc[x])/(m+1)); - while (m-->1){ - pDst[x-m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); - } - } - } - } - } -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \author [DP] - */ -bool CxImage::TextBlur(BYTE threshold, BYTE decay, BYTE max_depth, bool bBlurHorizontal, bool bBlurVertical, CxImage* iDst) -{ - if (!pDib) return false; - - RGBQUAD* pPalette=NULL; - WORD bpp = GetBpp(); - - //the routine is optimized for RGB or GrayScale images - if (!(head.biBitCount == 24 || IsGrayScale())){ - pPalette = new RGBQUAD[head.biClrUsed]; - memcpy(pPalette, GetPalette(),GetPaletteSize()); - if (!IncreaseBpp(24)) - return false; - } - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - if (bBlurHorizontal) - blur_text(threshold, decay, max_depth, this, &tmp, head.biBitCount>>3); - - if (bBlurVertical){ - CxImage src2(*this); - src2.RotateLeft(); - tmp.RotateLeft(); - blur_text(threshold, decay, max_depth, &src2, &tmp, head.biBitCount>>3); - tmp.RotateRight(); - } - -#if CXIMAGE_SUPPORT_SELECTION - //restore the non selected region - if (pSelection){ - for(long y=0; yTransfer(tmp); - else Transfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \author [nipper]; changes [DP] - */ -bool CxImage::GaussianBlur(float radius /*= 1.0f*/, CxImage* iDst /*= 0*/) -{ - if (!pDib) return false; - - RGBQUAD* pPalette=NULL; - WORD bpp = GetBpp(); - - //the routine is optimized for RGB or GrayScale images - if (!(head.biBitCount == 24 || IsGrayScale())){ - pPalette = new RGBQUAD[head.biClrUsed]; - memcpy(pPalette, GetPalette(),GetPaletteSize()); - if (!IncreaseBpp(24)) - return false; - } - - CxImage tmp_x(*this, false, true, true); - if (!tmp_x.IsValid()){ - strcpy(info.szLastError,tmp_x.GetLastError()); - return false; - } - - // generate convolution matrix and make sure it's smaller than each dimension - float *cmatrix = NULL; - int cmatrix_length = gen_convolve_matrix(radius, &cmatrix); - // generate lookup table - float *ctable = gen_lookup_table(cmatrix, cmatrix_length); - - long x,y; - int bypp = head.biBitCount>>3; - - CImageIterator itSrc(this); - CImageIterator itTmp(&tmp_x); - - double dbScaler = 50.0f/head.biHeight; - - // blur the rows - for (y=0;yTransfer(tmp_y); - else Transfer(tmp_y); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \author [DP],[nipper] - */ -bool CxImage::SelectiveBlur(float radius, BYTE threshold, CxImage* iDst) -{ - if (!pDib) return false; - - RGBQUAD* pPalette=NULL; - WORD bpp = GetBpp(); - - CxImage Tmp(*this, true, true, true); - if (!Tmp.IsValid()){ - strcpy(info.szLastError,Tmp.GetLastError()); - return false; - } - - //the routine is optimized for RGB or GrayScale images - if (!(head.biBitCount == 24 || IsGrayScale())){ - pPalette = new RGBQUAD[head.biClrUsed]; - memcpy(pPalette, GetPalette(),GetPaletteSize()); - if (!Tmp.IncreaseBpp(24)) - return false; - } - - CxImage Dst(Tmp, true, true, true); - if (!Dst.IsValid()){ - strcpy(info.szLastError,Dst.GetLastError()); - return false; - } - - //build the difference mask - BYTE thresh_dw = (BYTE)max( 0 ,(int)(128 - threshold)); - BYTE thresh_up = (BYTE)min(255,(int)(128 + threshold)); - long kernel[]={-100,-100,-100,-100,801,-100,-100,-100,-100}; - if (!Tmp.Filter(kernel,3,800,128)){ - strcpy(info.szLastError,Tmp.GetLastError()); - return false; - } - - //if the image has no selection, build a selection for the whole image - if (!Tmp.SelectionIsValid()){ - Tmp.SelectionCreate(); - Tmp.SelectionClear(255); - } - - long xmin,xmax,ymin,ymax; - xmin = Tmp.info.rSelectionBox.left; - xmax = Tmp.info.rSelectionBox.right; - ymin = Tmp.info.rSelectionBox.bottom; - ymax = Tmp.info.rSelectionBox.top; - - //modify the selection where the difference mask is over the threshold - for(long y=ymin; y thresh_up) || - (c.rgbGreen < thresh_dw || c.rgbGreen > thresh_up) || - (c.rgbBlue < thresh_dw || c.rgbBlue > thresh_up)) - { - Tmp.SelectionSet(x,y,0); - } - } - } - } - - //blur the image (only in the selected pixels) - Dst.SelectionCopy(Tmp); - if (!Dst.GaussianBlur(radius)){ - strcpy(info.szLastError,Dst.GetLastError()); - return false; - } - - //restore the original selection - Dst.SelectionCopy(*this); - - //if necessary, restore the original BPP and palette - if (pPalette){ - Dst.DecreaseBpp(bpp, false, pPalette); - delete [] pPalette; - } - - if (iDst) iDst->Transfer(Dst); - else Transfer(Dst); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * sharpen the image by subtracting a blurred copy from the original image. - * \param radius: width in pixels of the blurring effect. Range: >0; default = 5. - * \param amount: strength of the filter. Range: 0.0 (none) to 1.0 (max); default = 0.5 - * \param threshold: difference, between blurred and original pixel, to trigger the filter - * Range: 0 (always triggered) to 255 (never triggered); default = 0. - * \return true if everything is ok - * \author [nipper]; changes [DP] - */ -bool CxImage::UnsharpMask(float radius /*= 5.0*/, float amount /*= 0.5*/, int threshold /*= 0*/) -{ - if (!pDib) return false; - - RGBQUAD* pPalette=NULL; - WORD bpp = GetBpp(); - - //the routine is optimized for RGB or GrayScale images - if (!(head.biBitCount == 24 || IsGrayScale())){ - pPalette = new RGBQUAD[head.biClrUsed]; - memcpy(pPalette, GetPalette(),GetPaletteSize()); - if (!IncreaseBpp(24)) - return false; - } - - CxImage iDst; - if (!GaussianBlur(radius,&iDst)) - return false; - - CImageIterator itSrc(this); - CImageIterator itDst(&iDst); - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - if (xmin==xmax || ymin==ymax) - return false; - - double dbScaler = 100.0/(ymax-ymin); - int bypp = head.biBitCount>>3; - - // merge the source and destination (which currently contains - // the blurred version) images - for (long y=ymin; y - for(long x=xmin; x1.0f) strength = 1.0f; - - for(long y=ymin; ylevel){ - BlindSetPixelIndex(x,y,255-index); - } - } - } - } - } else { //PALETTE, full image - RGBQUAD* ppal=GetPalette(); - for(DWORD i=0;ilevel){ - ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue); - ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen); - ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed); - } - } else { - if (color.rgbBlue>level) ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue); - if (color.rgbGreen>level) ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen); - if (color.rgbRed>level) ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed); - } - } - } - } else { //RGB, selection - for(long y=ymin; ylevel){ - color.rgbRed = (BYTE)(255-color.rgbRed); - color.rgbGreen = (BYTE)(255-color.rgbGreen); - color.rgbBlue = (BYTE)(255-color.rgbBlue); - } - } else { - if (color.rgbBlue>level) color.rgbBlue =(BYTE)(255-color.rgbBlue); - if (color.rgbGreen>level) color.rgbGreen =(BYTE)(255-color.rgbGreen); - if (color.rgbRed>level) color.rgbRed =(BYTE)(255-color.rgbRed); - } - BlindSetPixelColor(x,y,color); - } - } - } - } - - //invert transparent color only in case of full image processing - if (pSelection==0 || (!IsGrayScale() && IsIndexed())){ - if (bLinkedChannels){ - if ((BYTE)RGB2GRAY(info.nBkgndColor.rgbRed,info.nBkgndColor.rgbGreen,info.nBkgndColor.rgbBlue)>level){ - info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); - info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); - info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); - } - } else { - if (info.nBkgndColor.rgbBlue>level) info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); - if (info.nBkgndColor.rgbGreen>level) info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); - if (info.nBkgndColor.rgbRed>level) info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); - } - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Converts the RGB triplets to and from different colorspace - * \param dstColorSpace: destination colorspace; 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ - * \param srcColorSpace: source colorspace; 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ - * \return true if everything is ok - */ -bool CxImage::ConvertColorSpace(const long dstColorSpace, const long srcColorSpace) -{ - if (!pDib) - return false; - - if (dstColorSpace == srcColorSpace) - return true; - - long w = GetWidth(); - long h = GetHeight(); - - for (long y=0;yIsValid() || - !pContrastMask->IsGrayScale() || - pContrastMask->GetWidth() != GetWidth() || - pContrastMask->GetHeight() != GetHeight()){ - strcpy(info.szLastError,"OptimalThreshold invalid ContrastMask"); - return -1; - } - } - - long xmin,xmax,ymin,ymax; - if (pBox){ - xmin = max(pBox->left,0); - xmax = min(pBox->right,head.biWidth); - ymin = max(pBox->bottom,0); - ymax = min(pBox->top,head.biHeight); - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - if (xmin>=xmax || ymin>=ymax) - return -1; - - double p[256]; - memset(p, 0, 256*sizeof(double)); - //build histogram - for (long y = ymin; yGetBits(y) + xmin; - for (long x = xmin; x0 && p[gray_max]==0) gray_max--; - if (gray_min > gray_max) - return -1; - if (gray_min == gray_max){ - if (gray_min == 0) - return 0; - else - return gray_max-1; - } - - //compute total moments 0th,1st,2nd order - int i,k; - double w_tot = 0; - double m_tot = 0; - double q_tot = 0; - for (i = gray_min; i <= gray_max; i++){ - w_tot += p[i]; - m_tot += i*p[i]; - q_tot += i*i*p[i]; - } - - double L, L1max, L2max, L3max, L4max; //objective functions - int th1,th2,th3,th4; //optimal thresholds - L1max = L2max = L3max = L4max = 0; - th1 = th2 = th3 = th4 = -1; - - double w1, w2, m1, m2, q1, q2, s1, s2; - w1 = m1 = q1 = 0; - for (i = gray_min; i < gray_max; i++){ - w1 += p[i]; - w2 = w_tot - w1; - m1 += i*p[i]; - m2 = m_tot - m1; - q1 += i*i*p[i]; - q2 = q_tot - q1; - s1 = q1/w1-m1*m1/w1/w1; //s1 = q1/w1-pow(m1/w1,2); - s2 = q2/w2-m2*m2/w2/w2; //s2 = q2/w2-pow(m2/w2,2); - - //Otsu - L = -(s1*w1 + s2*w2); //implemented as definition - //L = w1 * w2 * (m2/w2 - m1/w1)*(m2/w2 - m1/w1); //implementation that doesn't need s1 & s2 - if (L1max < L || th1<0){ - L1max = L; - th1 = i; - } - - //Kittler and Illingworth - if (s1>0 && s2>0){ - L = w1*log(w1/sqrt(s1))+w2*log(w2/sqrt(s2)); - //L = w1*log(w1*w1/s1)+w2*log(w2*w2/s2); - if (L2max < L || th2<0){ - L2max = L; - th2 = i; - } - } - - //max entropy - L = 0; - for (k=gray_min;k<=i;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w1)/w1; - for (k;k<=gray_max;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w2)/w2; - if (L3max < L || th3<0){ - L3max = L; - th3 = i; - } - - //potential difference (based on Electrostatic Binarization method by J. Acharya & G. Sreechakra) - // L=-fabs(vdiff/vsum); è molto selettivo, sembra che L=-fabs(vdiff) o L=-(vsum) - // abbiano lo stesso valore di soglia... il che semplificherebbe molto la routine - double vdiff = 0; - for (k=gray_min;k<=i;k++) - vdiff += p[k]*(i-k)*(i-k); - double vsum = vdiff; - for (k;k<=gray_max;k++){ - double dv = p[k]*(k-i)*(k-i); - vdiff -= dv; - vsum += dv; - } - if (vsum>0) L = -fabs(vdiff/vsum); else L = 0; - if (L4max < L || th4<0){ - L4max = L; - th4 = i; - } - } - - int threshold; - switch (method){ - case 1: //Otsu - threshold = th1; - break; - case 2: //Kittler and Illingworth - threshold = th2; - break; - case 3: //max entropy - threshold = th3; - break; - case 4: //potential difference - threshold = th4; - break; - default: //auto - { - int nt = 0; - threshold = 0; - if (th1>=0) { threshold += th1; nt++;} - if (th2>=0) { threshold += th2; nt++;} - if (th3>=0) { threshold += th3; nt++;} - if (th4>=0) { threshold += th4; nt++;} - if (nt) - threshold /= nt; - else - threshold = (gray_min+gray_max)/2; - - /*better(?) but really expensive alternative: - n = 0:255; - pth1 = c1(th1)/sqrt(2*pi*s1(th1))*exp(-((n - m1(th1)).^2)/2/s1(th1)) + c2(th1)/sqrt(2*pi*s2(th1))*exp(-((n - m2(th1)).^2)/2/s2(th1)); - pth2 = c1(th2)/sqrt(2*pi*s1(th2))*exp(-((n - m1(th2)).^2)/2/s1(th2)) + c2(th2)/sqrt(2*pi*s2(th2))*exp(-((n - m2(th2)).^2)/2/s2(th2)); - ... - mse_th1 = sum((p-pth1).^2); - mse_th2 = sum((p-pth2).^2); - ... - select th# that gives minimum mse_th# - */ - - } - } - - if (threshold <= gray_min || threshold >= gray_max) - threshold = (gray_min+gray_max)/2; - - return threshold; -} -/////////////////////////////////////////////////////////////////////////////// -/** - * Converts the image to B&W, using an optimal threshold mask - * \param method: 0 = average all methods (default); 1 = Otsu; 2 = Kittler & Illingworth; 3 = max entropy; 4 = potential difference; - * \param nBoxSize: the image is divided into "nBoxSize x nBoxSize" blocks, from where the threshold is computed; min = 8; default = 64. - * \param pContrastMask: limit the computation only in regions with contrasted (!=0) pixels; default = 0. - * \param nBias: global offset added to the threshold mask; default = 0. - * \param fGlobalLocalBalance: balance between local and global threshold. default = 0.5 - * fGlobalLocalBalance can be from 0.0 (use only local threshold) to 1.0 (use only global threshold) - * the pContrastMask image must be grayscale with same with and height of the current image, - * \return true if everything is ok. - * \sa OptimalThreshold - */ -bool CxImage::AdaptiveThreshold(long method, long nBoxSize, CxImage* pContrastMask, long nBias, float fGlobalLocalBalance) -{ - if (!pDib) - return false; - - if (pContrastMask){ - if (!pContrastMask->IsValid() || - !pContrastMask->IsGrayScale() || - pContrastMask->GetWidth() != GetWidth() || - pContrastMask->GetHeight() != GetHeight()){ - strcpy(info.szLastError,"AdaptiveThreshold invalid ContrastMask"); - return false; - } - } - - if (nBoxSize<8) nBoxSize = 8; - if (fGlobalLocalBalance<0.0f) fGlobalLocalBalance = 0.0f; - if (fGlobalLocalBalance>1.0f) fGlobalLocalBalance = 1.0f; - - long mw = (head.biWidth + nBoxSize - 1)/nBoxSize; - long mh = (head.biHeight + nBoxSize - 1)/nBoxSize; - - CxImage mask(mw,mh,8); - if(!mask.GrayScale()) - return false; - - if(!GrayScale()) - return false; - - int globalthreshold = OptimalThreshold(method, 0, pContrastMask); - if (globalthreshold <0) - return false; - - for (long y=0; y -//////////////////////////////////////////////////////////////////////////////// -/** - * Flood Fill - * \param xStart, yStart: starting point - * \param cFillColor: filling color - * \param nTolerance: deviation from the starting point color - * \param nOpacity: can be from 0 (transparent) to 255 (opaque, default) - * \param bSelectFilledArea: if true, the pixels in the region are also set in the selection layer; default = false - * \param nSelectionLevel: if bSelectFilledArea is true, the selected pixels are set to nSelectionLevel; default = 255 - * Note: nOpacity=0 && bSelectFilledArea=true act as a "magic wand" - * \return true if everything is ok - */ -bool CxImage::FloodFill(const long xStart, const long yStart, const RGBQUAD cFillColor, const BYTE nTolerance, - BYTE nOpacity, const bool bSelectFilledArea, const BYTE nSelectionLevel) -{ - if (!pDib) - return false; - - if (!IsInside(xStart,yStart)) - return true; - -#if CXIMAGE_SUPPORT_SELECTION - if (!SelectionIsInside(xStart,yStart)) - return true; -#endif //CXIMAGE_SUPPORT_SELECTION - - RGBQUAD* pPalette=NULL; - WORD bpp = GetBpp(); - //nTolerance or nOpacity implemented only for grayscale or 24bpp images - if ((nTolerance || nOpacity != 255) && !(head.biBitCount == 24 || IsGrayScale())){ - pPalette = new RGBQUAD[head.biClrUsed]; - memcpy(pPalette, GetPalette(),GetPaletteSize()); - if (!IncreaseBpp(24)) - return false; - } - - BYTE* pFillMask = (BYTE*)calloc(head.biWidth * head.biHeight,1); - if (!pFillMask) - return false; - -//------------------------------------- Begin of Flood Fill - POINT offset[4] = {{-1,0},{0,-1},{1,0},{0,1}}; - std::queue q; - POINT point = {xStart,yStart}; - q.push(point); - - if (IsIndexed()){ //--- Generic indexed image, no tolerance OR Grayscale image with tolerance - BYTE idxRef = GetPixelIndex(xStart,yStart); - BYTE idxFill = GetNearestIndex(cFillColor); - BYTE idxMin = (BYTE)min(255, max(0,(int)(idxRef - nTolerance))); - BYTE idxMax = (BYTE)min(255, max(0,(int)(idxRef + nTolerance))); - - while(!q.empty()) - { - point = q.front(); - q.pop(); - - for (int z=0; z<4; z++){ - int x = point.x + offset[z].x; - int y = point.y + offset[z].y; - if(IsInside(x,y)){ -#if CXIMAGE_SUPPORT_SELECTION - if (BlindSelectionIsInside(x,y)) -#endif //CXIMAGE_SUPPORT_SELECTION - { - BYTE idx = BlindGetPixelIndex(x, y); - BYTE* pFill = pFillMask + x + y * head.biWidth; - if (*pFill==0 && idxMin <= idx && idx <= idxMax ) - { - if (nOpacity>0){ - if (nOpacity == 255) - BlindSetPixelIndex(x, y, idxFill); - else - BlindSetPixelIndex(x, y, (BYTE)((idxFill * nOpacity + idx * (255-nOpacity))>>8)); - } - POINT pt = {x,y}; - q.push(pt); - *pFill = 1; - } - } - } - } - } - } else { //--- RGB image - RGBQUAD cRef = GetPixelColor(xStart,yStart); - RGBQUAD cRefMin, cRefMax; - cRefMin.rgbRed = (BYTE)min(255, max(0,(int)(cRef.rgbRed - nTolerance))); - cRefMin.rgbGreen = (BYTE)min(255, max(0,(int)(cRef.rgbGreen - nTolerance))); - cRefMin.rgbBlue = (BYTE)min(255, max(0,(int)(cRef.rgbBlue - nTolerance))); - cRefMax.rgbRed = (BYTE)min(255, max(0,(int)(cRef.rgbRed + nTolerance))); - cRefMax.rgbGreen = (BYTE)min(255, max(0,(int)(cRef.rgbGreen + nTolerance))); - cRefMax.rgbBlue = (BYTE)min(255, max(0,(int)(cRef.rgbBlue + nTolerance))); - - while(!q.empty()) - { - point = q.front(); - q.pop(); - - for (int z=0; z<4; z++){ - int x = point.x + offset[z].x; - int y = point.y + offset[z].y; - if(IsInside(x,y)){ -#if CXIMAGE_SUPPORT_SELECTION - if (BlindSelectionIsInside(x,y)) -#endif //CXIMAGE_SUPPORT_SELECTION - { - RGBQUAD cc = BlindGetPixelColor(x, y); - BYTE* pFill = pFillMask + x + y * head.biWidth; - if (*pFill==0 && - cRefMin.rgbRed <= cc.rgbRed && cc.rgbRed <= cRefMax.rgbRed && - cRefMin.rgbGreen <= cc.rgbGreen && cc.rgbGreen <= cRefMax.rgbGreen && - cRefMin.rgbBlue <= cc.rgbBlue && cc.rgbBlue <= cRefMax.rgbBlue ) - { - if (nOpacity>0){ - if (nOpacity == 255) - BlindSetPixelColor(x, y, cFillColor); - else - { - cc.rgbRed = (BYTE)((cFillColor.rgbRed * nOpacity + cc.rgbRed * (255-nOpacity))>>8); - cc.rgbGreen = (BYTE)((cFillColor.rgbGreen * nOpacity + cc.rgbGreen * (255-nOpacity))>>8); - cc.rgbBlue = (BYTE)((cFillColor.rgbBlue * nOpacity + cc.rgbBlue * (255-nOpacity))>>8); - BlindSetPixelColor(x, y, cc); - } - } - POINT pt = {x,y}; - q.push(pt); - *pFill = 1; - } - } - } - } - } - } - if (pFillMask[xStart+yStart*head.biWidth] == 0 && nOpacity>0){ - if (nOpacity == 255) - BlindSetPixelColor(xStart, yStart, cFillColor); - else - { - RGBQUAD cc = BlindGetPixelColor(xStart, yStart); - cc.rgbRed = (BYTE)((cFillColor.rgbRed * nOpacity + cc.rgbRed * (255-nOpacity))>>8); - cc.rgbGreen = (BYTE)((cFillColor.rgbGreen * nOpacity + cc.rgbGreen * (255-nOpacity))>>8); - cc.rgbBlue = (BYTE)((cFillColor.rgbBlue * nOpacity + cc.rgbBlue * (255-nOpacity))>>8); - BlindSetPixelColor(xStart, yStart, cc); - } - } - pFillMask[xStart+yStart*head.biWidth] = 1; -//------------------------------------- End of Flood Fill - - //if necessary, restore the original BPP and palette - if (pPalette){ - DecreaseBpp(bpp, false, pPalette); - delete [] pPalette; - } - -#if CXIMAGE_SUPPORT_SELECTION - if (bSelectFilledArea){ - if (!SelectionIsValid()){ - if (!SelectionCreate()){ - return false; - } - SelectionClear(); - info.rSelectionBox.right = head.biWidth; - info.rSelectionBox.top = head.biHeight; - info.rSelectionBox.left = info.rSelectionBox.bottom = 0; - } - RECT r; - SelectionGetBox(r); - for (long y = r.bottom; y < r.top; y++){ - BYTE* pFill = pFillMask + r.left + y * head.biWidth; - for (long x = r.left; xlevel) + tmp.BlindSetPixelIndex(x,y,1); + else + tmp.BlindSetPixelIndex(x,y,0); + } + } + tmp.SetPaletteColor(0,0,0,0); + tmp.SetPaletteColor(1,255,255,255); + Transfer(tmp); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Converts the image to B&W, using a threshold mask + * \param pThresholdMask: the lightness threshold mask. + * the pThresholdMask image must be grayscale with same with and height of the current image + * \return true if everything is ok + */ +bool CxImage::Threshold(CxImage* pThresholdMask) +{ + if (!pDib) return false; + if (head.biBitCount == 1) return true; + + if (!pThresholdMask) return false; + + if (!pThresholdMask->IsValid() || + !pThresholdMask->IsGrayScale() || + pThresholdMask->GetWidth() != GetWidth() || + pThresholdMask->GetHeight() != GetHeight()){ + strcpy(info.szLastError,"invalid ThresholdMask"); + return false; + } + + GrayScale(); + + CxImage tmp(head.biWidth,head.biHeight,1); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + for (long y=0;ypThresholdMask->BlindGetPixelIndex(x,y)) + tmp.BlindSetPixelIndex(x,y,1); + else + tmp.BlindSetPixelIndex(x,y,0); + } + } + tmp.SetPaletteColor(0,0,0,0); + tmp.SetPaletteColor(1,255,255,255); + Transfer(tmp); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Filters only the pixels with a lightness less (or more) than the threshold level, + * and preserves the colors for the unfiltered pixels. + * \param level = the lightness threshold. + * \param bDirection = false: filter dark pixels, true: filter light pixels + * \param nBkgndColor = filtered pixels are set to nBkgndColor color + * \param bSetAlpha = if true, sets also the alpha component for the filtered pixels, with nBkgndColor.rgbReserved + * \return true if everything is ok + * \author [DP], [wangsongtao] + */ +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::Threshold2(BYTE level, bool bDirection, RGBQUAD nBkgndColor, bool bSetAlpha) +{ + if (!pDib) return false; + if (head.biBitCount == 1) return true; + + CxImage tmp(*this, true, false, false); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + tmp.GrayScale(); + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; y=level) BlindSetPixelColor(x,y,nBkgndColor,bSetAlpha); + } + } + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Extract RGB channels from the image. Each channel is an 8 bit grayscale image. + * \param r,g,b: pointers to CxImage objects, to store the splited channels + * \return true if everything is ok + */ +bool CxImage::SplitRGB(CxImage* r,CxImage* g,CxImage* b) +{ + if (!pDib) return false; + if (r==NULL && g==NULL && b==NULL) return false; + + CxImage tmpr(head.biWidth,head.biHeight,8); + CxImage tmpg(head.biWidth,head.biHeight,8); + CxImage tmpb(head.biWidth,head.biHeight,8); + + RGBQUAD color; + for(long y=0; yTransfer(tmpr); + if (g) g->Transfer(tmpg); + if (b) b->Transfer(tmpb); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Extract CMYK channels from the image. Each channel is an 8 bit grayscale image. + * \param c,m,y,k: pointers to CxImage objects, to store the splited channels + * \return true if everything is ok + */ +bool CxImage::SplitCMYK(CxImage* c,CxImage* m,CxImage* y,CxImage* k) +{ + if (!pDib) return false; + if (c==NULL && m==NULL && y==NULL && k==NULL) return false; + + CxImage tmpc(head.biWidth,head.biHeight,8); + CxImage tmpm(head.biWidth,head.biHeight,8); + CxImage tmpy(head.biWidth,head.biHeight,8); + CxImage tmpk(head.biWidth,head.biHeight,8); + + RGBQUAD color; + for(long yy=0; yyTransfer(tmpc); + if (m) m->Transfer(tmpm); + if (y) y->Transfer(tmpy); + if (k) k->Transfer(tmpk); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Extract YUV channels from the image. Each channel is an 8 bit grayscale image. + * \param y,u,v: pointers to CxImage objects, to store the splited channels + * \return true if everything is ok + */ +bool CxImage::SplitYUV(CxImage* y,CxImage* u,CxImage* v) +{ + if (!pDib) return false; + if (y==NULL && u==NULL && v==NULL) return false; + + CxImage tmpy(head.biWidth,head.biHeight,8); + CxImage tmpu(head.biWidth,head.biHeight,8); + CxImage tmpv(head.biWidth,head.biHeight,8); + + RGBQUAD color; + for(long yy=0; yyTransfer(tmpy); + if (u) u->Transfer(tmpu); + if (v) v->Transfer(tmpv); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Extract YIQ channels from the image. Each channel is an 8 bit grayscale image. + * \param y,i,q: pointers to CxImage objects, to store the splited channels + * \return true if everything is ok + */ +bool CxImage::SplitYIQ(CxImage* y,CxImage* i,CxImage* q) +{ + if (!pDib) return false; + if (y==NULL && i==NULL && q==NULL) return false; + + CxImage tmpy(head.biWidth,head.biHeight,8); + CxImage tmpi(head.biWidth,head.biHeight,8); + CxImage tmpq(head.biWidth,head.biHeight,8); + + RGBQUAD color; + for(long yy=0; yyTransfer(tmpy); + if (i) i->Transfer(tmpi); + if (q) q->Transfer(tmpq); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Extract XYZ channels from the image. Each channel is an 8 bit grayscale image. + * \param x,y,z: pointers to CxImage objects, to store the splited channels + * \return true if everything is ok + */ +bool CxImage::SplitXYZ(CxImage* x,CxImage* y,CxImage* z) +{ + if (!pDib) return false; + if (x==NULL && y==NULL && z==NULL) return false; + + CxImage tmpx(head.biWidth,head.biHeight,8); + CxImage tmpy(head.biWidth,head.biHeight,8); + CxImage tmpz(head.biWidth,head.biHeight,8); + + RGBQUAD color; + for(long yy=0; yyTransfer(tmpx); + if (y) y->Transfer(tmpy); + if (z) z->Transfer(tmpz); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Extract HSL channels from the image. Each channel is an 8 bit grayscale image. + * \param h,s,l: pointers to CxImage objects, to store the splited channels + * \return true if everything is ok + */ +bool CxImage::SplitHSL(CxImage* h,CxImage* s,CxImage* l) +{ + if (!pDib) return false; + if (h==NULL && s==NULL && l==NULL) return false; + + CxImage tmph(head.biWidth,head.biHeight,8); + CxImage tmps(head.biWidth,head.biHeight,8); + CxImage tmpl(head.biWidth,head.biHeight,8); + + RGBQUAD color; + for(long y=0; yTransfer(tmph); + if (s) s->Transfer(tmps); + if (l) l->Transfer(tmpl); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#define HSLMAX 255 /* H,L, and S vary over 0-HSLMAX */ +#define RGBMAX 255 /* R,G, and B vary over 0-RGBMAX */ + /* HSLMAX BEST IF DIVISIBLE BY 6 */ + /* RGBMAX, HSLMAX must each fit in a BYTE. */ +/* Hue is undefined if Saturation is 0 (grey-scale) */ +/* This value determines where the Hue scrollbar is */ +/* initially set for achromatic colors */ +#define HSLUNDEFINED (HSLMAX*2/3) +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::RGBtoHSL(RGBQUAD lRGBColor) +{ + BYTE R,G,B; /* input RGB values */ + BYTE H,L,S; /* output HSL values */ + BYTE cMax,cMin; /* max and min RGB values */ + WORD Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max*/ + + R = lRGBColor.rgbRed; /* get R, G, and B out of DWORD */ + G = lRGBColor.rgbGreen; + B = lRGBColor.rgbBlue; + + cMax = max( max(R,G), B); /* calculate lightness */ + cMin = min( min(R,G), B); + L = (BYTE)((((cMax+cMin)*HSLMAX)+RGBMAX)/(2*RGBMAX)); + + if (cMax==cMin){ /* r=g=b --> achromatic case */ + S = 0; /* saturation */ + H = HSLUNDEFINED; /* hue */ + } else { /* chromatic case */ + if (L <= (HSLMAX/2)) /* saturation */ + S = (BYTE)((((cMax-cMin)*HSLMAX)+((cMax+cMin)/2))/(cMax+cMin)); + else + S = (BYTE)((((cMax-cMin)*HSLMAX)+((2*RGBMAX-cMax-cMin)/2))/(2*RGBMAX-cMax-cMin)); + /* hue */ + Rdelta = (WORD)((((cMax-R)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); + Gdelta = (WORD)((((cMax-G)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); + Bdelta = (WORD)((((cMax-B)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin)); + + if (R == cMax) + H = (BYTE)(Bdelta - Gdelta); + else if (G == cMax) + H = (BYTE)((HSLMAX/3) + Rdelta - Bdelta); + else /* B == cMax */ + H = (BYTE)(((2*HSLMAX)/3) + Gdelta - Rdelta); + +// if (H < 0) H += HSLMAX; //always false + if (H > HSLMAX) H -= HSLMAX; + } + RGBQUAD hsl={L,S,H,0}; + return hsl; +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::HueToRGB(float n1,float n2, float hue) +{ + // fixed implementation for HSL2RGB routine + float rValue; + + if (hue > 360) + hue = hue - 360; + else if (hue < 0) + hue = hue + 360; + + if (hue < 60) + rValue = n1 + (n2-n1)*hue/60.0f; + else if (hue < 180) + rValue = n2; + else if (hue < 240) + rValue = n1+(n2-n1)*(240-hue)/60; + else + rValue = n1; + + return rValue; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::HSLtoRGB(COLORREF cHSLColor) +{ + return HSLtoRGB(RGBtoRGBQUAD(cHSLColor)); +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::HSLtoRGB(RGBQUAD lHSLColor) +{ + // fixed implementation for HSL2RGB routine + float h,s,l; + float m1,m2; + BYTE r,g,b; + + h = (float)lHSLColor.rgbRed * 360.0f/255.0f; + s = (float)lHSLColor.rgbGreen/255.0f; + l = (float)lHSLColor.rgbBlue/255.0f; + + if (l <= 0.5) m2 = l * (1+s); + else m2 = l + s - l*s; + + m1 = 2 * l - m2; + + if (s == 0) { + r=g=b=(BYTE)(l*255.0f); + } else { + r = (BYTE)(HueToRGB(m1,m2,h+120) * 255.0f); + g = (BYTE)(HueToRGB(m1,m2,h) * 255.0f); + b = (BYTE)(HueToRGB(m1,m2,h-120) * 255.0f); + } + + RGBQUAD rgb = {b,g,r,0}; + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::YUVtoRGB(RGBQUAD lYUVColor) +{ + int U,V,R,G,B; + float Y = lYUVColor.rgbRed; + U = lYUVColor.rgbGreen - 128; + V = lYUVColor.rgbBlue - 128; + +// R = (int)(1.164 * Y + 2.018 * U); +// G = (int)(1.164 * Y - 0.813 * V - 0.391 * U); +// B = (int)(1.164 * Y + 1.596 * V); + R = (int)( Y + 1.403f * V); + G = (int)( Y - 0.344f * U - 0.714f * V); + B = (int)( Y + 1.770f * U); + + R= min(255,max(0,R)); + G= min(255,max(0,G)); + B= min(255,max(0,B)); + RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::RGBtoYUV(RGBQUAD lRGBColor) +{ + int Y,U,V,R,G,B; + R = lRGBColor.rgbRed; + G = lRGBColor.rgbGreen; + B = lRGBColor.rgbBlue; + +// Y = (int)( 0.257 * R + 0.504 * G + 0.098 * B); +// U = (int)( 0.439 * R - 0.368 * G - 0.071 * B + 128); +// V = (int)(-0.148 * R - 0.291 * G + 0.439 * B + 128); + Y = (int)(0.299f * R + 0.587f * G + 0.114f * B); + U = (int)((B-Y) * 0.565f + 128); + V = (int)((R-Y) * 0.713f + 128); + + Y= min(255,max(0,Y)); + U= min(255,max(0,U)); + V= min(255,max(0,V)); + RGBQUAD yuv={(BYTE)V,(BYTE)U,(BYTE)Y,0}; + return yuv; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::YIQtoRGB(RGBQUAD lYIQColor) +{ + int I,Q,R,G,B; + float Y = lYIQColor.rgbRed; + I = lYIQColor.rgbGreen - 128; + Q = lYIQColor.rgbBlue - 128; + + R = (int)( Y + 0.956f * I + 0.621f * Q); + G = (int)( Y - 0.273f * I - 0.647f * Q); + B = (int)( Y - 1.104f * I + 1.701f * Q); + + R= min(255,max(0,R)); + G= min(255,max(0,G)); + B= min(255,max(0,B)); + RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::RGBtoYIQ(RGBQUAD lRGBColor) +{ + int Y,I,Q,R,G,B; + R = lRGBColor.rgbRed; + G = lRGBColor.rgbGreen; + B = lRGBColor.rgbBlue; + + Y = (int)( 0.2992f * R + 0.5868f * G + 0.1140f * B); + I = (int)( 0.5960f * R - 0.2742f * G - 0.3219f * B + 128); + Q = (int)( 0.2109f * R - 0.5229f * G + 0.3120f * B + 128); + + Y= min(255,max(0,Y)); + I= min(255,max(0,I)); + Q= min(255,max(0,Q)); + RGBQUAD yiq={(BYTE)Q,(BYTE)I,(BYTE)Y,0}; + return yiq; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::XYZtoRGB(RGBQUAD lXYZColor) +{ + int X,Y,Z,R,G,B; + X = lXYZColor.rgbRed; + Y = lXYZColor.rgbGreen; + Z = lXYZColor.rgbBlue; + double k=1.088751; + + R = (int)( 3.240479f * X - 1.537150f * Y - 0.498535f * Z * k); + G = (int)( -0.969256f * X + 1.875992f * Y + 0.041556f * Z * k); + B = (int)( 0.055648f * X - 0.204043f * Y + 1.057311f * Z * k); + + R= min(255,max(0,R)); + G= min(255,max(0,G)); + B= min(255,max(0,B)); + RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0}; + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::RGBtoXYZ(RGBQUAD lRGBColor) +{ + int X,Y,Z,R,G,B; + R = lRGBColor.rgbRed; + G = lRGBColor.rgbGreen; + B = lRGBColor.rgbBlue; + + X = (int)( 0.412453f * R + 0.357580f * G + 0.180423f * B); + Y = (int)( 0.212671f * R + 0.715160f * G + 0.072169f * B); + Z = (int)((0.019334f * R + 0.119193f * G + 0.950227f * B)*0.918483657f); + + //X= min(255,max(0,X)); + //Y= min(255,max(0,Y)); + //Z= min(255,max(0,Z)); + RGBQUAD xyz={(BYTE)Z,(BYTE)Y,(BYTE)X,0}; + return xyz; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Generates a "rainbow" palette with saturated colors + * \param correction: 1 generates a single hue spectrum. 0.75 is nice for scientific applications. + */ +void CxImage::HuePalette(float correction) +{ + if (head.biClrUsed==0) return; + + for(DWORD j=0; j 1.0f) blend = 1.0f; + int a0 = (int)(256*blend); + int a1 = 256 - a0; + + bool bFullBlend = false; + if (blend > 0.999f) bFullBlend = true; + + RGBQUAD color,hsl; + if (head.biClrUsed==0){ + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; y>8); + color.rgbBlue = (BYTE)((hsl.rgbBlue * a0 + color.rgbBlue * a1)>>8); + color.rgbGreen = (BYTE)((hsl.rgbGreen * a0 + color.rgbGreen * a1)>>8); + BlindSetPixelColor(x,y,color); + } + } + } + } + } else { + for(DWORD j=0; j + for (int i=0;i<256;i++) { + cTable[i] = (BYTE)max(0,min(255,(int)((i-128)*c + brightness + 0.5f))); + } + + return Lut(cTable); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return mean lightness of the image. Useful with Threshold() and Light() + */ +float CxImage::Mean() +{ + if (!pDib) return 0; + + CxImage tmp(*this,true); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + tmp.GrayScale(); + float sum=0; + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + if (xmin==xmax || ymin==ymax) return (float)0.0; + + BYTE *iSrc=tmp.info.pImage; + iSrc += tmp.info.dwEffWidth*ymin; // necessary for selections + + for(long y=ymin; y + for(long x=xmin; x(y+j) || (y+j)>=head.biHeight) continue; + iY = iY2+x; + for(long k=-k2;k(x+k) || (x+k)>=head.biWidth) continue; + i=kernel[iCount]; + b += cPtr[iY+k] * i; + ksumcur += i; + } + } + if (Kfactor==0 || ksumcur==0){ + cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b + Koffset))); + } else if (ksumtot == ksumcur) { + cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b/Kfactor + Koffset))); + } else { + cPtr2[iY1] = (BYTE)min(255, max(0,(int)((b*ksumtot)/(ksumcur*Kfactor) + Koffset))); + } + } + } + } + } + else + { + for(long y=ymin; y r) r=c.rgbRed; + if (c.rgbGreen > g) g=c.rgbGreen; + if (c.rgbBlue > b) b=c.rgbBlue; + } + } + c.rgbRed = r; + c.rgbGreen = g; + c.rgbBlue = b; + tmp.BlindSetPixelColor(x,y,c); + } + } + } + Transfer(tmp); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Enhance the variations between adjacent pixels. + * Similar results can be achieved using Filter(), + * but the algorithms are different both in Edge() and in Contour(). + * \param Ksize: size of the kernel. + * \return true if everything is ok + */ +bool CxImage::Edge(long Ksize) +{ + if (!pDib) return false; + + long k2 = Ksize/2; + long kmax= Ksize-k2; + BYTE r,g,b,rr,gg,bb; + RGBQUAD c; + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; y r) r=c.rgbRed; + if (c.rgbGreen > g) g=c.rgbGreen; + if (c.rgbBlue > b) b=c.rgbBlue; + + if (c.rgbRed < rr) rr=c.rgbRed; + if (c.rgbGreen < gg) gg=c.rgbGreen; + if (c.rgbBlue < bb) bb=c.rgbBlue; + } + } + c.rgbRed = (BYTE)(255-abs(r-rr)); + c.rgbGreen = (BYTE)(255-abs(g-gg)); + c.rgbBlue = (BYTE)(255-abs(b-bb)); + tmp.BlindSetPixelColor(x,y,c); + } + } + } + Transfer(tmp); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Blends two images + * \param imgsrc2: image to be mixed with this + * \param op: blending method; see ImageOpType + * \param lXOffset, lYOffset: image displacement + * \param bMixAlpha: if true and imgsrc2 has a valid alpha layer, it will be mixed in the destination image. + * \return true if everything is ok + * + * thanks to Mwolski + */ +// +void CxImage::Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset, long lYOffset, bool bMixAlpha) +{ + long lWide = min(GetWidth(),imgsrc2.GetWidth()-lXOffset); + long lHeight = min(GetHeight(),imgsrc2.GetHeight()-lYOffset); + + bool bEditAlpha = imgsrc2.AlphaIsValid() & bMixAlpha; + + if (bEditAlpha && AlphaIsValid()==false){ + AlphaCreate(); + } + + RGBQUAD rgbBackgrnd1 = GetTransColor(); + RGBQUAD rgb1, rgb2, rgbDest; + + for(long lY=0;lY + for(x = 0; x < width; x++) { + for(y = 0; y < height; y++) { + SetPixelColor(x + lXOffset, y + lYOffset, imagesrc2.BlindGetPixelColor(x, y)); + } + } + } +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Adjusts separately the red, green, and blue values in the image. + * \param r, g, b: can be from -255 to +255. + * \return true if everything is ok + */ +bool CxImage::ShiftRGB(long r, long g, long b) +{ + if (!pDib) return false; + RGBQUAD color; + if (head.biClrUsed==0){ + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; y + for (int i=0;i<256;i++) { + cTable[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); + } + + return Lut(cTable); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Adjusts the color balance indipendent for each color channel + * \param gammaR, gammaG, gammaB can be from 0.1 to 5. + * \return true if everything is ok + * \sa Gamma + */ +bool CxImage::GammaRGB(float gammaR, float gammaG, float gammaB) +{ + if (!pDib) return false; + + if (gammaR <= 0.0f) return false; + if (gammaG <= 0.0f) return false; + if (gammaB <= 0.0f) return false; + + double dinvgamma, dMax; + int i; + + dinvgamma = 1/gammaR; + dMax = pow(255.0, dinvgamma) / 255.0; + BYTE cTableR[256]; + for (i=0;i<256;i++) { + cTableR[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); + } + + dinvgamma = 1/gammaG; + dMax = pow(255.0, dinvgamma) / 255.0; + BYTE cTableG[256]; + for (i=0;i<256;i++) { + cTableG[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); + } + + dinvgamma = 1/gammaB; + dMax = pow(255.0, dinvgamma) / 255.0; + BYTE cTableB[256]; + for (i=0;i<256;i++) { + cTableB[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax))); + } + + return Lut(cTableR, cTableG, cTableB); +} +//////////////////////////////////////////////////////////////////////////////// + +//#if !defined (_WIN32_WCE) +/** + * Adjusts the intensity of each pixel to the median intensity of its surrounding pixels. + * \param Ksize: size of the kernel. + * \return true if everything is ok + */ +bool CxImage::Median(long Ksize) +{ + if (!pDib) return false; + + long k2 = Ksize/2; + long kmax= Ksize-k2; + long i,j,k; + + RGBQUAD* kernel = (RGBQUAD*)malloc(Ksize*Ksize*sizeof(RGBQUAD)); + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; y + for(long x=xmin; xGetWidth(); + h=srcReal->GetHeight(); + } else { + w=srcImag->GetWidth(); + h=srcImag->GetHeight(); + } + + bool bXpow2 = IsPowerof2(w); + bool bYpow2 = IsPowerof2(h); + //if bForceFFT, width AND height must be powers of 2 + if (bForceFFT && !(bXpow2 && bYpow2)) { + long i; + + i=0; + while((1< copy the image + if (srcReal && dstReal) tmpReal->Copy(*srcReal,true,false,false); + if (srcImag && dstImag) tmpImag->Copy(*srcImag,true,false,false); + + // dst&&src are empty -> create new one, else turn to GrayScale + if (srcReal==0 && dstReal==0){ + tmpReal = new CxImage(w,h,8); + tmpReal->Clear(0); + tmpReal->SetGrayPalette(); + } else { + if (!tmpReal->IsGrayScale()) tmpReal->GrayScale(); + } + if (srcImag==0 && dstImag==0){ + tmpImag = new CxImage(w,h,8); + tmpImag->Clear(0); + tmpImag->SetGrayPalette(); + } else { + if (!tmpImag->IsGrayScale()) tmpImag->GrayScale(); + } + + if (!(tmpReal->IsValid() && tmpImag->IsValid())){ + if (srcReal==0 && dstReal==0) delete tmpReal; + if (srcImag==0 && dstImag==0) delete tmpImag; + return false; + } + + //resample for FFT, if necessary + tmpReal->Resample(w,h,0); + tmpImag->Resample(w,h,0); + + //ok, here we have 2 (w x h), grayscale images ready for a FFT + + double* real; + double* imag; + long j,k,m; + + _complex **grid; + //double mean = tmpReal->Mean(); + /* Allocate memory for the grid */ + grid = (_complex **)malloc(w * sizeof(_complex)); + for (k=0;kGetPixelIndex(k,j)-128; + grid[k][j].y = tmpImag->GetPixelIndex(k,j)-128; + } + } + + //DFT buffers + double *real2,*imag2; + real2 = (double*)malloc(max(w,h) * sizeof(double)); + imag2 = (double*)malloc(max(w,h) * sizeof(double)); + + /* Transform the rows */ + real = (double *)malloc(w * sizeof(double)); + imag = (double *)malloc(w * sizeof(double)); + + m=0; + while((1<SetPixelIndex(k,j,(BYTE)max(0,min(255,(nn*(3+log(_cabs(grid[k][j]))))))); + if (grid[k][j].x==0){ + tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/0.0000000001)*nn))))); + } else { + tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/grid[k][j].x)*nn))))); + } + } else { + tmpReal->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].x*nn)))); + tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].y*nn)))); + } + } + } + + for (k=0;k> 1; + j = 0; + for (i=0;i>= 1; + } + j += k; + } + + /* Compute the FFT */ + c1 = -1.0; + c2 = 0.0; + l2 = 1; + for (l=0;lGetWidth(); + long h = r->GetHeight(); + + Create(w,h,24); + + g->Resample(w,h); + b->Resample(w,h); + + if (a) { + a->Resample(w,h); +#if CXIMAGE_SUPPORT_ALPHA + AlphaCreate(); +#endif //CXIMAGE_SUPPORT_ALPHA + } + + RGBQUAD c; + for (long y=0;y + for (long x=0;xGetPixelIndex(x,y); + c.rgbGreen=g->GetPixelIndex(x,y); + c.rgbBlue=b->GetPixelIndex(x,y); + switch (colorspace){ + case 1: + BlindSetPixelColor(x,y,HSLtoRGB(c)); + break; + case 2: + BlindSetPixelColor(x,y,YUVtoRGB(c)); + break; + case 3: + BlindSetPixelColor(x,y,YIQtoRGB(c)); + break; + case 4: + BlindSetPixelColor(x,y,XYZtoRGB(c)); + break; + default: + BlindSetPixelColor(x,y,c); + } +#if CXIMAGE_SUPPORT_ALPHA + if (a) AlphaSet(x,y,a->GetPixelIndex(x,y)); +#endif //CXIMAGE_SUPPORT_ALPHA + } + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Smart blurring to remove small defects, dithering or artifacts. + * \param radius: normally between 0.01 and 0.5 + * \param niterations: should be trimmed with radius, to avoid blurring should be (radius*niterations)<1 + * \param colorspace: 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ + * \return true if everything is ok + */ +bool CxImage::Repair(float radius, long niterations, long colorspace) +{ + if (!IsValid()) return false; + + long w = GetWidth(); + long h = GetHeight(); + + CxImage r,g,b; + + r.Create(w,h,8); + g.Create(w,h,8); + b.Create(w,h,8); + + switch (colorspace){ + case 1: + SplitHSL(&r,&g,&b); + break; + case 2: + SplitYUV(&r,&g,&b); + break; + case 3: + SplitYIQ(&r,&g,&b); + break; + case 4: + SplitXYZ(&r,&g,&b); + break; + default: + SplitRGB(&r,&g,&b); + } + + for (int i=0; iGetWidth()-1; + long h = ch->GetHeight()-1; + + double correction,ix,iy,ixx,ixy,iyy; + int x,y,xy0,xp1,xm1,yp1,ym1; + + for(x=1; xBlindGetPixelIndex(x,y); + xm1 = ch->BlindGetPixelIndex(x-1,y); + xp1 = ch->BlindGetPixelIndex(x+1,y); + ym1 = ch->BlindGetPixelIndex(x,y-1); + yp1 = ch->BlindGetPixelIndex(x,y+1); + + ix= (xp1-xm1)/2.0; + iy= (yp1-ym1)/2.0; + ixx= xp1 - 2.0 * xy0 + xm1; + iyy= yp1 - 2.0 * xy0 + ym1; + ixy=(ch->BlindGetPixelIndex(x+1,y+1) + ch->BlindGetPixelIndex(x-1,y-1) - + ch->BlindGetPixelIndex(x-1,y+1) - ch->BlindGetPixelIndex(x+1,y-1))/4.0; + + correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy); + + tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5)))); + } + } + + for (x=0;x<=w;x++){ + for(y=0; y<=h; y+=h){ + xy0 = ch->BlindGetPixelIndex(x,y); + xm1 = ch->GetPixelIndex(x-1,y); + xp1 = ch->GetPixelIndex(x+1,y); + ym1 = ch->GetPixelIndex(x,y-1); + yp1 = ch->GetPixelIndex(x,y+1); + + ix= (xp1-xm1)/2.0; + iy= (yp1-ym1)/2.0; + ixx= xp1 - 2.0 * xy0 + xm1; + iyy= yp1 - 2.0 * xy0 + ym1; + ixy=(ch->GetPixelIndex(x+1,y+1) + ch->GetPixelIndex(x-1,y-1) - + ch->GetPixelIndex(x-1,y+1) - ch->GetPixelIndex(x+1,y-1))/4.0; + + correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy); + + tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5)))); + } + } + for (x=0;x<=w;x+=w){ + for (y=0;y<=h;y++){ + xy0 = ch->BlindGetPixelIndex(x,y); + xm1 = ch->GetPixelIndex(x-1,y); + xp1 = ch->GetPixelIndex(x+1,y); + ym1 = ch->GetPixelIndex(x,y-1); + yp1 = ch->GetPixelIndex(x,y+1); + + ix= (xp1-xm1)/2.0; + iy= (yp1-ym1)/2.0; + ixx= xp1 - 2.0 * xy0 + xm1; + iyy= yp1 - 2.0 * xy0 + ym1; + ixy=(ch->GetPixelIndex(x+1,y+1) + ch->GetPixelIndex(x-1,y-1) - + ch->GetPixelIndex(x-1,y+1) - ch->GetPixelIndex(x+1,y-1))/4.0; + + correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy); + + tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5)))); + } + } + + ch->Transfer(tmp); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Enhance the variations between adjacent pixels. + * Similar results can be achieved using Filter(), + * but the algorithms are different both in Edge() and in Contour(). + * \return true if everything is ok + */ +bool CxImage::Contour() +{ + if (!pDib) return false; + + long Ksize = 3; + long k2 = Ksize/2; + long kmax= Ksize-k2; + long i,j,k; + BYTE maxr,maxg,maxb; + RGBQUAD pix1,pix2; + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; ymaxb) maxb = pix2.rgbBlue; + if ((pix2.rgbGreen-pix1.rgbGreen)>maxg) maxg = pix2.rgbGreen; + if ((pix2.rgbRed-pix1.rgbRed)>maxr) maxr = pix2.rgbRed; + } + } + pix1.rgbBlue=(BYTE)(255-maxb); + pix1.rgbGreen=(BYTE)(255-maxg); + pix1.rgbRed=(BYTE)(255-maxr); + tmp.BlindSetPixelColor(x,y,pix1); + } + } + } + Transfer(tmp); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Adds a random offset to each pixel in the image + * \param radius: maximum pixel displacement + * \return true if everything is ok + */ +bool CxImage::Jitter(long radius) +{ + if (!pDib) return false; + + long nx,ny; + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; y modified scaling, so that matrix_lenght = 1+2*radius parameter + */ + radius = (float)fabs(0.5*radius) + 0.25f; + + std_dev = radius; + radius = std_dev * 2; + + /* go out 'radius' in each direction */ + matrix_length = int (2 * ceil(radius-0.5) + 1); + if (matrix_length <= 0) matrix_length = 1; + matrix_midpoint = matrix_length/2 + 1; + *cmatrix_p = new float[matrix_length]; + cmatrix = *cmatrix_p; + + /* Now we fill the matrix by doing a numeric integration approximation + * from -2*std_dev to 2*std_dev, sampling 50 points per pixel. + * We do the bottom half, mirror it to the top half, then compute the + * center point. Otherwise asymmetric quantization errors will occur. + * The formula to integrate is e^-(x^2/2s^2). + */ + + /* first we do the top (right) half of matrix */ + for (i = matrix_length/2 + 1; i < matrix_length; i++) + { + float base_x = i - (float)floor((float)(matrix_length/2)) - 0.5f; + sum = 0; + for (j = 1; j <= 50; j++) + { + if ( base_x+0.02*j <= radius ) + sum += (float)exp (-(base_x+0.02*j)*(base_x+0.02*j) / + (2*std_dev*std_dev)); + } + cmatrix[i] = sum/50; + } + + /* mirror the thing to the bottom half */ + for (i=0; i<=matrix_length/2; i++) { + cmatrix[i] = cmatrix[matrix_length-1-i]; + } + + /* find center val -- calculate an odd number of quanta to make it symmetric, + * even if the center point is weighted slightly higher than others. */ + sum = 0; + for (j=0; j<=50; j++) + { + sum += (float)exp (-(0.5+0.02*j)*(0.5+0.02*j) / + (2*std_dev*std_dev)); + } + cmatrix[matrix_length/2] = sum/51; + + /* normalize the distribution by scaling the total sum to one */ + sum=0; + for (i=0; i y) + { + for (row = 0; row < y ; row++) + { + scale=0; + /* find the scale factor */ + for (j = 0; j < y ; j++) + { + /* if the index is in bounds, add it to the scale counter */ + if ((j + cmatrix_middle - row >= 0) && + (j + cmatrix_middle - row < cmatrix_length)) + scale += cmatrix[j + cmatrix_middle - row]; + } + for (i = 0; i= row - cmatrix_middle) && + (j <= row + cmatrix_middle)) + sum += cur_col[j*bytes + i] * cmatrix[j]; + } + dest_col[row*bytes + i] = (BYTE)(0.5f + sum / scale); + } + } + } + else + { + /* for the edge condition, we only use available info and scale to one */ + for (row = 0; row < cmatrix_middle; row++) + { + /* find scale factor */ + scale=0; + for (j = cmatrix_middle - row; j0; j--) + { + sum += *(ctable_p + *cur_col_p1); + cur_col_p1 += bytes; + ctable_p += 256; + } + cur_col_p++; + *(dest_col_p++) = (BYTE)(0.5f + sum); + } + } + + /* for the edge condition , we only use available info, and scale to one */ + for (; row < y; row++) + { + /* find scale factor */ + scale=0; + for (j = 0; j< y-row + cmatrix_middle; j++) + scale += cmatrix[j]; + for (i = 0; ihead.biWidth; + ymax = iSrc->head.biHeight; + + if (xmin==xmax || ymin==ymax) return; + + nmin = xmin * bytes; + nmax = xmax * bytes; + + CImageIterator itSrc(iSrc); + CImageIterator itTmp(iDst); + + double dbScaler = 100.0f/(ymax-ymin)/bytes; + + for (n=0; n=pivot){ + while (z1) ? ((m/bytes)/decay+1) : m/bytes; + if (m>max_depth) m = max_depth; + step = (BYTE)((pSrc[x+bytes]-pSrc[x])/(m+1)); + while (m-->1){ + pDst[x+m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); + } + } + //find lower corner + z=x+bytes; + if (pSrc[x]=pivot){ + while (z1) ? ((m/bytes)/decay+1) : m/bytes; + if (m>max_depth) m = max_depth; + step = (BYTE)((pSrc[x+bytes]-pSrc[x])/(m+1)); + while (m-->1){ + pDst[x+m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); + } + } + } + //scan right to left + for (x=nmax-1-n /*,i=(xmax-1)*/; x>0; x-=bytes /*,i--*/) + { + z=x-bytes; + pivot = pSrc[z]-threshold; + //find upper corner + if (pSrc[x]=pivot){ + while (z>n && pSrc2[z]1) ? ((m/bytes)/decay+1) : m/bytes; + if (m>max_depth) m = max_depth; + step = (BYTE)((pSrc[x-bytes]-pSrc[x])/(m+1)); + while (m-->1){ + pDst[x-m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); + } + } + //find lower corner + z=x-bytes; + if (pSrc[x]=pivot){ + while (z>n && pSrc3[z]1) ? ((m/bytes)/decay+1) : m/bytes; + if (m>max_depth) m = max_depth; + step = (BYTE)((pSrc[x-bytes]-pSrc[x])/(m+1)); + while (m-->1){ + pDst[x-m*bytes] = (BYTE)(pDst[x]+(step*(m+1))); + } + } + } + } + } +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \author [DP] + */ +bool CxImage::TextBlur(BYTE threshold, BYTE decay, BYTE max_depth, bool bBlurHorizontal, bool bBlurVertical, CxImage* iDst) +{ + if (!pDib) return false; + + RGBQUAD* pPalette=NULL; + WORD bpp = GetBpp(); + + //the routine is optimized for RGB or GrayScale images + if (!(head.biBitCount == 24 || IsGrayScale())){ + pPalette = new RGBQUAD[head.biClrUsed]; + memcpy(pPalette, GetPalette(),GetPaletteSize()); + if (!IncreaseBpp(24)) + return false; + } + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + if (bBlurHorizontal) + blur_text(threshold, decay, max_depth, this, &tmp, head.biBitCount>>3); + + if (bBlurVertical){ + CxImage src2(*this); + src2.RotateLeft(); + tmp.RotateLeft(); + blur_text(threshold, decay, max_depth, &src2, &tmp, head.biBitCount>>3); + tmp.RotateRight(); + } + +#if CXIMAGE_SUPPORT_SELECTION + //restore the non selected region + if (pSelection){ + for(long y=0; yTransfer(tmp); + else Transfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \author [nipper]; changes [DP] + */ +bool CxImage::GaussianBlur(float radius /*= 1.0f*/, CxImage* iDst /*= 0*/) +{ + if (!pDib) return false; + + RGBQUAD* pPalette=NULL; + WORD bpp = GetBpp(); + + //the routine is optimized for RGB or GrayScale images + if (!(head.biBitCount == 24 || IsGrayScale())){ + pPalette = new RGBQUAD[head.biClrUsed]; + memcpy(pPalette, GetPalette(),GetPaletteSize()); + if (!IncreaseBpp(24)) + return false; + } + + CxImage tmp_x(*this, false, true, true); + if (!tmp_x.IsValid()){ + strcpy(info.szLastError,tmp_x.GetLastError()); + return false; + } + + // generate convolution matrix and make sure it's smaller than each dimension + float *cmatrix = NULL; + int cmatrix_length = gen_convolve_matrix(radius, &cmatrix); + // generate lookup table + float *ctable = gen_lookup_table(cmatrix, cmatrix_length); + + long x,y; + int bypp = head.biBitCount>>3; + + CImageIterator itSrc(this); + CImageIterator itTmp(&tmp_x); + + double dbScaler = 50.0f/head.biHeight; + + // blur the rows + for (y=0;yTransfer(tmp_y); + else Transfer(tmp_y); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \author [DP],[nipper] + */ +bool CxImage::SelectiveBlur(float radius, BYTE threshold, CxImage* iDst) +{ + if (!pDib) return false; + + RGBQUAD* pPalette=NULL; + WORD bpp = GetBpp(); + + CxImage Tmp(*this, true, true, true); + if (!Tmp.IsValid()){ + strcpy(info.szLastError,Tmp.GetLastError()); + return false; + } + + //the routine is optimized for RGB or GrayScale images + if (!(head.biBitCount == 24 || IsGrayScale())){ + pPalette = new RGBQUAD[head.biClrUsed]; + memcpy(pPalette, GetPalette(),GetPaletteSize()); + if (!Tmp.IncreaseBpp(24)) + return false; + } + + CxImage Dst(Tmp, true, true, true); + if (!Dst.IsValid()){ + strcpy(info.szLastError,Dst.GetLastError()); + return false; + } + + //build the difference mask + BYTE thresh_dw = (BYTE)max( 0 ,(int)(128 - threshold)); + BYTE thresh_up = (BYTE)min(255,(int)(128 + threshold)); + long kernel[]={-100,-100,-100,-100,801,-100,-100,-100,-100}; + if (!Tmp.Filter(kernel,3,800,128)){ + strcpy(info.szLastError,Tmp.GetLastError()); + return false; + } + + //if the image has no selection, build a selection for the whole image + if (!Tmp.SelectionIsValid()){ + Tmp.SelectionCreate(); + Tmp.SelectionClear(255); + } + + long xmin,xmax,ymin,ymax; + xmin = Tmp.info.rSelectionBox.left; + xmax = Tmp.info.rSelectionBox.right; + ymin = Tmp.info.rSelectionBox.bottom; + ymax = Tmp.info.rSelectionBox.top; + + //modify the selection where the difference mask is over the threshold + for(long y=ymin; y thresh_up) || + (c.rgbGreen < thresh_dw || c.rgbGreen > thresh_up) || + (c.rgbBlue < thresh_dw || c.rgbBlue > thresh_up)) + { + Tmp.SelectionSet(x,y,0); + } + } + } + } + + //blur the image (only in the selected pixels) + Dst.SelectionCopy(Tmp); + if (!Dst.GaussianBlur(radius)){ + strcpy(info.szLastError,Dst.GetLastError()); + return false; + } + + //restore the original selection + Dst.SelectionCopy(*this); + + //if necessary, restore the original BPP and palette + if (pPalette){ + Dst.DecreaseBpp(bpp, false, pPalette); + delete [] pPalette; + } + + if (iDst) iDst->Transfer(Dst); + else Transfer(Dst); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * sharpen the image by subtracting a blurred copy from the original image. + * \param radius: width in pixels of the blurring effect. Range: >0; default = 5. + * \param amount: strength of the filter. Range: 0.0 (none) to 1.0 (max); default = 0.5 + * \param threshold: difference, between blurred and original pixel, to trigger the filter + * Range: 0 (always triggered) to 255 (never triggered); default = 0. + * \return true if everything is ok + * \author [nipper]; changes [DP] + */ +bool CxImage::UnsharpMask(float radius /*= 5.0*/, float amount /*= 0.5*/, int threshold /*= 0*/) +{ + if (!pDib) return false; + + RGBQUAD* pPalette=NULL; + WORD bpp = GetBpp(); + + //the routine is optimized for RGB or GrayScale images + if (!(head.biBitCount == 24 || IsGrayScale())){ + pPalette = new RGBQUAD[head.biClrUsed]; + memcpy(pPalette, GetPalette(),GetPaletteSize()); + if (!IncreaseBpp(24)) + return false; + } + + CxImage iDst; + if (!GaussianBlur(radius,&iDst)) + return false; + + CImageIterator itSrc(this); + CImageIterator itDst(&iDst); + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + if (xmin==xmax || ymin==ymax) + return false; + + double dbScaler = 100.0/(ymax-ymin); + int bypp = head.biBitCount>>3; + + // merge the source and destination (which currently contains + // the blurred version) images + for (long y=ymin; y + for(long x=xmin; x1.0f) strength = 1.0f; + + for(long y=ymin; ylevel){ + BlindSetPixelIndex(x,y,255-index); + } + } + } + } + } else { //PALETTE, full image + RGBQUAD* ppal=GetPalette(); + for(DWORD i=0;ilevel){ + ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue); + ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen); + ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed); + } + } else { + if (color.rgbBlue>level) ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue); + if (color.rgbGreen>level) ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen); + if (color.rgbRed>level) ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed); + } + } + } + } else { //RGB, selection + for(long y=ymin; ylevel){ + color.rgbRed = (BYTE)(255-color.rgbRed); + color.rgbGreen = (BYTE)(255-color.rgbGreen); + color.rgbBlue = (BYTE)(255-color.rgbBlue); + } + } else { + if (color.rgbBlue>level) color.rgbBlue =(BYTE)(255-color.rgbBlue); + if (color.rgbGreen>level) color.rgbGreen =(BYTE)(255-color.rgbGreen); + if (color.rgbRed>level) color.rgbRed =(BYTE)(255-color.rgbRed); + } + BlindSetPixelColor(x,y,color); + } + } + } + } + + //invert transparent color only in case of full image processing + if (pSelection==0 || (!IsGrayScale() && IsIndexed())){ + if (bLinkedChannels){ + if ((BYTE)RGB2GRAY(info.nBkgndColor.rgbRed,info.nBkgndColor.rgbGreen,info.nBkgndColor.rgbBlue)>level){ + info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); + info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); + info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); + } + } else { + if (info.nBkgndColor.rgbBlue>level) info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); + if (info.nBkgndColor.rgbGreen>level) info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); + if (info.nBkgndColor.rgbRed>level) info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Converts the RGB triplets to and from different colorspace + * \param dstColorSpace: destination colorspace; 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ + * \param srcColorSpace: source colorspace; 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ + * \return true if everything is ok + */ +bool CxImage::ConvertColorSpace(const long dstColorSpace, const long srcColorSpace) +{ + if (!pDib) + return false; + + if (dstColorSpace == srcColorSpace) + return true; + + long w = GetWidth(); + long h = GetHeight(); + + for (long y=0;yIsValid() || + !pContrastMask->IsGrayScale() || + pContrastMask->GetWidth() != GetWidth() || + pContrastMask->GetHeight() != GetHeight()){ + strcpy(info.szLastError,"OptimalThreshold invalid ContrastMask"); + return -1; + } + } + + long xmin,xmax,ymin,ymax; + if (pBox){ + xmin = max(pBox->left,0); + xmax = min(pBox->right,head.biWidth); + ymin = max(pBox->bottom,0); + ymax = min(pBox->top,head.biHeight); + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + if (xmin>=xmax || ymin>=ymax) + return -1; + + double p[256]; + memset(p, 0, 256*sizeof(double)); + //build histogram + for (long y = ymin; yGetBits(y) + xmin; + for (long x = xmin; x0 && p[gray_max]==0) gray_max--; + if (gray_min > gray_max) + return -1; + if (gray_min == gray_max){ + if (gray_min == 0) + return 0; + else + return gray_max-1; + } + + //compute total moments 0th,1st,2nd order + int i,k; + double w_tot = 0; + double m_tot = 0; + double q_tot = 0; + for (i = gray_min; i <= gray_max; i++){ + w_tot += p[i]; + m_tot += i*p[i]; + q_tot += i*i*p[i]; + } + + double L, L1max, L2max, L3max, L4max; //objective functions + int th1,th2,th3,th4; //optimal thresholds + L1max = L2max = L3max = L4max = 0; + th1 = th2 = th3 = th4 = -1; + + double w1, w2, m1, m2, q1, q2, s1, s2; + w1 = m1 = q1 = 0; + for (i = gray_min; i < gray_max; i++){ + w1 += p[i]; + w2 = w_tot - w1; + m1 += i*p[i]; + m2 = m_tot - m1; + q1 += i*i*p[i]; + q2 = q_tot - q1; + s1 = q1/w1-m1*m1/w1/w1; //s1 = q1/w1-pow(m1/w1,2); + s2 = q2/w2-m2*m2/w2/w2; //s2 = q2/w2-pow(m2/w2,2); + + //Otsu + L = -(s1*w1 + s2*w2); //implemented as definition + //L = w1 * w2 * (m2/w2 - m1/w1)*(m2/w2 - m1/w1); //implementation that doesn't need s1 & s2 + if (L1max < L || th1<0){ + L1max = L; + th1 = i; + } + + //Kittler and Illingworth + if (s1>0 && s2>0){ + L = w1*log(w1/sqrt(s1))+w2*log(w2/sqrt(s2)); + //L = w1*log(w1*w1/s1)+w2*log(w2*w2/s2); + if (L2max < L || th2<0){ + L2max = L; + th2 = i; + } + } + + //max entropy + L = 0; + for (k=gray_min;k<=i;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w1)/w1; + for (k;k<=gray_max;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w2)/w2; + if (L3max < L || th3<0){ + L3max = L; + th3 = i; + } + + //potential difference (based on Electrostatic Binarization method by J. Acharya & G. Sreechakra) + // L=-fabs(vdiff/vsum); è molto selettivo, sembra che L=-fabs(vdiff) o L=-(vsum) + // abbiano lo stesso valore di soglia... il che semplificherebbe molto la routine + double vdiff = 0; + for (k=gray_min;k<=i;k++) + vdiff += p[k]*(i-k)*(i-k); + double vsum = vdiff; + for (k;k<=gray_max;k++){ + double dv = p[k]*(k-i)*(k-i); + vdiff -= dv; + vsum += dv; + } + if (vsum>0) L = -fabs(vdiff/vsum); else L = 0; + if (L4max < L || th4<0){ + L4max = L; + th4 = i; + } + } + + int threshold; + switch (method){ + case 1: //Otsu + threshold = th1; + break; + case 2: //Kittler and Illingworth + threshold = th2; + break; + case 3: //max entropy + threshold = th3; + break; + case 4: //potential difference + threshold = th4; + break; + default: //auto + { + int nt = 0; + threshold = 0; + if (th1>=0) { threshold += th1; nt++;} + if (th2>=0) { threshold += th2; nt++;} + if (th3>=0) { threshold += th3; nt++;} + if (th4>=0) { threshold += th4; nt++;} + if (nt) + threshold /= nt; + else + threshold = (gray_min+gray_max)/2; + + /*better(?) but really expensive alternative: + n = 0:255; + pth1 = c1(th1)/sqrt(2*pi*s1(th1))*exp(-((n - m1(th1)).^2)/2/s1(th1)) + c2(th1)/sqrt(2*pi*s2(th1))*exp(-((n - m2(th1)).^2)/2/s2(th1)); + pth2 = c1(th2)/sqrt(2*pi*s1(th2))*exp(-((n - m1(th2)).^2)/2/s1(th2)) + c2(th2)/sqrt(2*pi*s2(th2))*exp(-((n - m2(th2)).^2)/2/s2(th2)); + ... + mse_th1 = sum((p-pth1).^2); + mse_th2 = sum((p-pth2).^2); + ... + select th# that gives minimum mse_th# + */ + + } + } + + if (threshold <= gray_min || threshold >= gray_max) + threshold = (gray_min+gray_max)/2; + + return threshold; +} +/////////////////////////////////////////////////////////////////////////////// +/** + * Converts the image to B&W, using an optimal threshold mask + * \param method: 0 = average all methods (default); 1 = Otsu; 2 = Kittler & Illingworth; 3 = max entropy; 4 = potential difference; + * \param nBoxSize: the image is divided into "nBoxSize x nBoxSize" blocks, from where the threshold is computed; min = 8; default = 64. + * \param pContrastMask: limit the computation only in regions with contrasted (!=0) pixels; default = 0. + * \param nBias: global offset added to the threshold mask; default = 0. + * \param fGlobalLocalBalance: balance between local and global threshold. default = 0.5 + * fGlobalLocalBalance can be from 0.0 (use only local threshold) to 1.0 (use only global threshold) + * the pContrastMask image must be grayscale with same with and height of the current image, + * \return true if everything is ok. + * \sa OptimalThreshold + */ +bool CxImage::AdaptiveThreshold(long method, long nBoxSize, CxImage* pContrastMask, long nBias, float fGlobalLocalBalance) +{ + if (!pDib) + return false; + + if (pContrastMask){ + if (!pContrastMask->IsValid() || + !pContrastMask->IsGrayScale() || + pContrastMask->GetWidth() != GetWidth() || + pContrastMask->GetHeight() != GetHeight()){ + strcpy(info.szLastError,"AdaptiveThreshold invalid ContrastMask"); + return false; + } + } + + if (nBoxSize<8) nBoxSize = 8; + if (fGlobalLocalBalance<0.0f) fGlobalLocalBalance = 0.0f; + if (fGlobalLocalBalance>1.0f) fGlobalLocalBalance = 1.0f; + + long mw = (head.biWidth + nBoxSize - 1)/nBoxSize; + long mh = (head.biHeight + nBoxSize - 1)/nBoxSize; + + CxImage mask(mw,mh,8); + if(!mask.GrayScale()) + return false; + + if(!GrayScale()) + return false; + + int globalthreshold = OptimalThreshold(method, 0, pContrastMask); + if (globalthreshold <0) + return false; + + for (long y=0; y +//////////////////////////////////////////////////////////////////////////////// +/** + * Flood Fill + * \param xStart, yStart: starting point + * \param cFillColor: filling color + * \param nTolerance: deviation from the starting point color + * \param nOpacity: can be from 0 (transparent) to 255 (opaque, default) + * \param bSelectFilledArea: if true, the pixels in the region are also set in the selection layer; default = false + * \param nSelectionLevel: if bSelectFilledArea is true, the selected pixels are set to nSelectionLevel; default = 255 + * Note: nOpacity=0 && bSelectFilledArea=true act as a "magic wand" + * \return true if everything is ok + */ +bool CxImage::FloodFill(const long xStart, const long yStart, const RGBQUAD cFillColor, const BYTE nTolerance, + BYTE nOpacity, const bool bSelectFilledArea, const BYTE nSelectionLevel) +{ + if (!pDib) + return false; + + if (!IsInside(xStart,yStart)) + return true; + +#if CXIMAGE_SUPPORT_SELECTION + if (!SelectionIsInside(xStart,yStart)) + return true; +#endif //CXIMAGE_SUPPORT_SELECTION + + RGBQUAD* pPalette=NULL; + WORD bpp = GetBpp(); + //nTolerance or nOpacity implemented only for grayscale or 24bpp images + if ((nTolerance || nOpacity != 255) && !(head.biBitCount == 24 || IsGrayScale())){ + pPalette = new RGBQUAD[head.biClrUsed]; + memcpy(pPalette, GetPalette(),GetPaletteSize()); + if (!IncreaseBpp(24)) + return false; + } + + BYTE* pFillMask = (BYTE*)calloc(head.biWidth * head.biHeight,1); + if (!pFillMask) + return false; + +//------------------------------------- Begin of Flood Fill + POINT offset[4] = {{-1,0},{0,-1},{1,0},{0,1}}; + std::queue q; + POINT point = {xStart,yStart}; + q.push(point); + + if (IsIndexed()){ //--- Generic indexed image, no tolerance OR Grayscale image with tolerance + BYTE idxRef = GetPixelIndex(xStart,yStart); + BYTE idxFill = GetNearestIndex(cFillColor); + BYTE idxMin = (BYTE)min(255, max(0,(int)(idxRef - nTolerance))); + BYTE idxMax = (BYTE)min(255, max(0,(int)(idxRef + nTolerance))); + + while(!q.empty()) + { + point = q.front(); + q.pop(); + + for (int z=0; z<4; z++){ + int x = point.x + offset[z].x; + int y = point.y + offset[z].y; + if(IsInside(x,y)){ +#if CXIMAGE_SUPPORT_SELECTION + if (BlindSelectionIsInside(x,y)) +#endif //CXIMAGE_SUPPORT_SELECTION + { + BYTE idx = BlindGetPixelIndex(x, y); + BYTE* pFill = pFillMask + x + y * head.biWidth; + if (*pFill==0 && idxMin <= idx && idx <= idxMax ) + { + if (nOpacity>0){ + if (nOpacity == 255) + BlindSetPixelIndex(x, y, idxFill); + else + BlindSetPixelIndex(x, y, (BYTE)((idxFill * nOpacity + idx * (255-nOpacity))>>8)); + } + POINT pt = {x,y}; + q.push(pt); + *pFill = 1; + } + } + } + } + } + } else { //--- RGB image + RGBQUAD cRef = GetPixelColor(xStart,yStart); + RGBQUAD cRefMin, cRefMax; + cRefMin.rgbRed = (BYTE)min(255, max(0,(int)(cRef.rgbRed - nTolerance))); + cRefMin.rgbGreen = (BYTE)min(255, max(0,(int)(cRef.rgbGreen - nTolerance))); + cRefMin.rgbBlue = (BYTE)min(255, max(0,(int)(cRef.rgbBlue - nTolerance))); + cRefMax.rgbRed = (BYTE)min(255, max(0,(int)(cRef.rgbRed + nTolerance))); + cRefMax.rgbGreen = (BYTE)min(255, max(0,(int)(cRef.rgbGreen + nTolerance))); + cRefMax.rgbBlue = (BYTE)min(255, max(0,(int)(cRef.rgbBlue + nTolerance))); + + while(!q.empty()) + { + point = q.front(); + q.pop(); + + for (int z=0; z<4; z++){ + int x = point.x + offset[z].x; + int y = point.y + offset[z].y; + if(IsInside(x,y)){ +#if CXIMAGE_SUPPORT_SELECTION + if (BlindSelectionIsInside(x,y)) +#endif //CXIMAGE_SUPPORT_SELECTION + { + RGBQUAD cc = BlindGetPixelColor(x, y); + BYTE* pFill = pFillMask + x + y * head.biWidth; + if (*pFill==0 && + cRefMin.rgbRed <= cc.rgbRed && cc.rgbRed <= cRefMax.rgbRed && + cRefMin.rgbGreen <= cc.rgbGreen && cc.rgbGreen <= cRefMax.rgbGreen && + cRefMin.rgbBlue <= cc.rgbBlue && cc.rgbBlue <= cRefMax.rgbBlue ) + { + if (nOpacity>0){ + if (nOpacity == 255) + BlindSetPixelColor(x, y, cFillColor); + else + { + cc.rgbRed = (BYTE)((cFillColor.rgbRed * nOpacity + cc.rgbRed * (255-nOpacity))>>8); + cc.rgbGreen = (BYTE)((cFillColor.rgbGreen * nOpacity + cc.rgbGreen * (255-nOpacity))>>8); + cc.rgbBlue = (BYTE)((cFillColor.rgbBlue * nOpacity + cc.rgbBlue * (255-nOpacity))>>8); + BlindSetPixelColor(x, y, cc); + } + } + POINT pt = {x,y}; + q.push(pt); + *pFill = 1; + } + } + } + } + } + } + if (pFillMask[xStart+yStart*head.biWidth] == 0 && nOpacity>0){ + if (nOpacity == 255) + BlindSetPixelColor(xStart, yStart, cFillColor); + else + { + RGBQUAD cc = BlindGetPixelColor(xStart, yStart); + cc.rgbRed = (BYTE)((cFillColor.rgbRed * nOpacity + cc.rgbRed * (255-nOpacity))>>8); + cc.rgbGreen = (BYTE)((cFillColor.rgbGreen * nOpacity + cc.rgbGreen * (255-nOpacity))>>8); + cc.rgbBlue = (BYTE)((cFillColor.rgbBlue * nOpacity + cc.rgbBlue * (255-nOpacity))>>8); + BlindSetPixelColor(xStart, yStart, cc); + } + } + pFillMask[xStart+yStart*head.biWidth] = 1; +//------------------------------------- End of Flood Fill + + //if necessary, restore the original BPP and palette + if (pPalette){ + DecreaseBpp(bpp, false, pPalette); + delete [] pPalette; + } + +#if CXIMAGE_SUPPORT_SELECTION + if (bSelectFilledArea){ + if (!SelectionIsValid()){ + if (!SelectionCreate()){ + return false; + } + SelectionClear(); + info.rSelectionBox.right = head.biWidth; + info.rSelectionBox.top = head.biHeight; + info.rSelectionBox.left = info.rSelectionBox.bottom = 0; + } + RECT r; + SelectionGetBox(r); + for (long y = r.bottom; y < r.top; y++){ + BYTE* pFill = pFillMask + r.left + y * head.biWidth; + for (long x = r.left; x - WMF/EMF support -#endif - -#if CXIMAGE_SUPPORT_JBG -#include "ximajbg.h" -#endif - -#if CXIMAGE_SUPPORT_JASPER -#include "ximajas.h" -#endif - -#if CXIMAGE_SUPPORT_SKA -#include "ximaska.h" -#endif - -#if CXIMAGE_SUPPORT_RAW -#include "ximaraw.h" -#endif - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::EncodeSafeCheck(CxFile *hFile) -{ - if (hFile==NULL) { - strcpy(info.szLastError,CXIMAGE_ERR_NOFILE); - return true; - } - - if (pDib==NULL){ - strcpy(info.szLastError,CXIMAGE_ERR_NOIMAGE); - return true; - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -//#ifdef WIN32 -//bool CxImage::Save(LPCWSTR filename, DWORD imagetype) -//{ -// FILE* hFile; //file handle to write the image -// if ((hFile=_wfopen(filename,L"wb"))==NULL) return false; -// bool bOK = Encode(hFile,imagetype); -// fclose(hFile); -// return bOK; -//} -//#endif //WIN32 -//////////////////////////////////////////////////////////////////////////////// -// For UNICODE support: char -> TCHAR -/** - * Saves to disk the image in a specific format. - * \param filename: file name - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - */ -bool CxImage::Save(const TCHAR * filename, DWORD imagetype) -{ - FILE* hFile; //file handle to write the image - -#ifdef WIN32 - if ((hFile=_tfopen(filename,_T("wb")))==NULL) return false; // For UNICODE support -#else - if ((hFile=fopen(filename,"wb"))==NULL) return false; -#endif - - bool bOK = Encode(hFile,imagetype); - fclose(hFile); - return bOK; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Saves to disk the image in a specific format. - * \param hFile: file handle, open and enabled for writing. - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - */ -bool CxImage::Encode(FILE *hFile, DWORD imagetype) -{ - CxIOFile file(hFile); - return Encode(&file,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Saves to memory buffer the image in a specific format. - * \param buffer: output memory buffer pointer. Must be NULL, - * the function allocates and fill the memory, - * the application must free the buffer, see also FreeMemory(). - * \param size: output memory buffer size. - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - */ -bool CxImage::Encode(BYTE * &buffer, long &size, DWORD imagetype) -{ - if (buffer!=NULL){ - strcpy(info.szLastError,"the buffer must be empty"); - return false; - } - CxMemFile file; - file.Open(); - if(Encode(&file,imagetype)){ - buffer=file.GetBuffer(); - size=file.Size(); - return true; - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Saves to disk the image in a specific format. - * \param hFile: file handle (CxMemFile or CxIOFile), with write access. - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - * \sa ENUM_CXIMAGE_FORMATS - */ -bool CxImage::Encode(CxFile *hFile, DWORD imagetype) -{ - -#if CXIMAGE_SUPPORT_BMP - - if (imagetype==CXIMAGE_FORMAT_BMP){ - CxImageBMP newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_ICO - if (imagetype==CXIMAGE_FORMAT_ICO){ - CxImageICO newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_TIF - if (imagetype==CXIMAGE_FORMAT_TIF){ - CxImageTIF newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_JPG - if (imagetype==CXIMAGE_FORMAT_JPG){ - CxImageJPG newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_GIF - if (imagetype==CXIMAGE_FORMAT_GIF){ - CxImageGIF newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_PNG - if (imagetype==CXIMAGE_FORMAT_PNG){ - CxImagePNG newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_MNG - if (imagetype==CXIMAGE_FORMAT_MNG){ - CxImageMNG newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_TGA - if (imagetype==CXIMAGE_FORMAT_TGA){ - CxImageTGA newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_PCX - if (imagetype==CXIMAGE_FORMAT_PCX){ - CxImagePCX newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_WBMP - if (imagetype==CXIMAGE_FORMAT_WBMP){ - CxImageWBMP newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS // - WMF/EMF support - if (imagetype==CXIMAGE_FORMAT_WMF){ - CxImageWMF newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_JBG - if (imagetype==CXIMAGE_FORMAT_JBG){ - CxImageJBG newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_JASPER - if ( - #if CXIMAGE_SUPPORT_JP2 - imagetype==CXIMAGE_FORMAT_JP2 || - #endif - #if CXIMAGE_SUPPORT_JPC - imagetype==CXIMAGE_FORMAT_JPC || - #endif - #if CXIMAGE_SUPPORT_PGX - imagetype==CXIMAGE_FORMAT_PGX || - #endif - #if CXIMAGE_SUPPORT_PNM - imagetype==CXIMAGE_FORMAT_PNM || - #endif - #if CXIMAGE_SUPPORT_RAS - imagetype==CXIMAGE_FORMAT_RAS || - #endif - false ){ - CxImageJAS newima; - newima.Ghost(this); - if (newima.Encode(hFile,imagetype)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif - -#if CXIMAGE_SUPPORT_SKA - if (imagetype==CXIMAGE_FORMAT_SKA){ - CxImageSKA newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif - -#if CXIMAGE_SUPPORT_RAW - if (imagetype==CXIMAGE_FORMAT_RAW){ - CxImageRAW newima; - newima.Ghost(this); - if (newima.Encode(hFile)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif - - strcpy(info.szLastError,"Encode: Unknown format"); - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Saves to disk or memory pagecount images, referenced by an array of CxImage pointers. - * \param hFile: file handle. - * \param pImages: array of CxImage pointers. - * \param pagecount: number of images. - * \param imagetype: can be CXIMAGE_FORMAT_TIF or CXIMAGE_FORMAT_GIF. - * \return true if everything is ok - */ -bool CxImage::Encode(FILE * hFile, CxImage ** pImages, int pagecount, DWORD imagetype) -{ - CxIOFile file(hFile); - return Encode(&file, pImages, pagecount,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Saves to disk or memory pagecount images, referenced by an array of CxImage pointers. - * \param hFile: file handle (CxMemFile or CxIOFile), with write access. - * \param pImages: array of CxImage pointers. - * \param pagecount: number of images. - * \param imagetype: can be CXIMAGE_FORMAT_TIF, CXIMAGE_FORMAT_GIF or CXIMAGE_FORMAT_ICO. - * \return true if everything is ok - */ -bool CxImage::Encode(CxFile * hFile, CxImage ** pImages, int pagecount, DWORD imagetype) -{ -#if CXIMAGE_SUPPORT_TIF - if (imagetype==CXIMAGE_FORMAT_TIF){ - CxImageTIF newima; - newima.Ghost(this); - if (newima.Encode(hFile,pImages,pagecount)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_GIF - if (imagetype==CXIMAGE_FORMAT_GIF){ - CxImageGIF newima; - newima.Ghost(this); - if (newima.Encode(hFile,pImages,pagecount)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_ICO - if (imagetype==CXIMAGE_FORMAT_ICO){ - CxImageICO newima; - newima.Ghost(this); - if (newima.Encode(hFile,pImages,pagecount)){ - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif - strcpy(info.szLastError,"Multipage Encode, Unsupported operation for this format"); - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * exports the image into a RGBA buffer, Useful for OpenGL applications. - * \param buffer: output memory buffer pointer. Must be NULL, - * the function allocates and fill the memory, - * the application must free the buffer, see also FreeMemory(). - * \param size: output memory buffer size. - * \param bFlipY: direction of Y axis. default = false. - * \return true if everything is ok - */ -bool CxImage::Encode2RGBA(BYTE * &buffer, long &size, bool bFlipY) -{ - if (buffer!=NULL){ - strcpy(info.szLastError,"the buffer must be empty"); - return false; - } - CxMemFile file; - file.Open(); - if(Encode2RGBA(&file,bFlipY)){ - buffer=file.GetBuffer(); - size=file.Size(); - return true; - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * exports the image into a RGBA buffer, Useful for OpenGL applications. - * \param hFile: file handle (CxMemFile or CxIOFile), with write access. - * \param bFlipY: direction of Y axis. default = false. - * \return true if everything is ok - */ -bool CxImage::Encode2RGBA(CxFile *hFile, bool bFlipY) -{ - if (EncodeSafeCheck(hFile)) return false; - - for (long y1 = 0; y1 < head.biHeight; y1++) { - long y = bFlipY ? head.biHeight - 1 - y1 : y1; - for(long x = 0; x < head.biWidth; x++) { - RGBQUAD color = BlindGetPixelColor(x,y); - hFile->PutC(color.rgbRed); - hFile->PutC(color.rgbGreen); - hFile->PutC(color.rgbBlue); - hFile->PutC(color.rgbReserved); - } - } - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -// For UNICODE support: char -> TCHAR -/** - * Reads from disk the image in a specific format. - * - If decoding fails using the specified image format, - * the function will try the automatic file format recognition. - * - * \param filename: file name - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - */ -bool CxImage::Load(const TCHAR * filename, DWORD imagetype) -//bool CxImage::Load(const char * filename, DWORD imagetype) -{ - /*FILE* hFile; //file handle to read the image - if ((hFile=fopen(filename,"rb"))==NULL) return false; - bool bOK = Decode(hFile,imagetype); - fclose(hFile);*/ - - /* automatic file type recognition */ - bool bOK = false; - if ( GetTypeIndexFromId(imagetype) ){ - FILE* hFile; //file handle to read the image - -#ifdef WIN32 - if ((hFile=_tfopen(filename,_T("rb")))==NULL) return false; // For UNICODE support -#else - if ((hFile=fopen(filename,"rb"))==NULL) return false; -#endif - - bOK = Decode(hFile,imagetype); - fclose(hFile); - if (bOK) return bOK; - } - - char szError[256]; - strcpy(szError,info.szLastError); //save the first error - - // if failed, try automatic recognition of the file... - FILE* hFile; - -#ifdef WIN32 - if ((hFile=_tfopen(filename,_T("rb")))==NULL) return false; // For UNICODE support -#else - if ((hFile=fopen(filename,"rb"))==NULL) return false; -#endif - - bOK = Decode(hFile,CXIMAGE_FORMAT_UNKNOWN); - fclose(hFile); - - if (!bOK && imagetype > 0) strcpy(info.szLastError,szError); //restore the first error - - return bOK; -} -//////////////////////////////////////////////////////////////////////////////// -#ifdef WIN32 -//bool CxImage::Load(LPCWSTR filename, DWORD imagetype) -//{ -// /*FILE* hFile; //file handle to read the image -// if ((hFile=_wfopen(filename, L"rb"))==NULL) return false; -// bool bOK = Decode(hFile,imagetype); -// fclose(hFile);*/ -// -// /* automatic file type recognition */ -// bool bOK = false; -// if ( GetTypeIndexFromId(imagetype) ){ -// FILE* hFile; //file handle to read the image -// if ((hFile=_wfopen(filename,L"rb"))==NULL) return false; -// bOK = Decode(hFile,imagetype); -// fclose(hFile); -// if (bOK) return bOK; -// } -// -// char szError[256]; -// strcpy(szError,info.szLastError); //save the first error -// -// // if failed, try automatic recognition of the file... -// FILE* hFile; //file handle to read the image -// if ((hFile=_wfopen(filename,L"rb"))==NULL) return false; -// bOK = Decode(hFile,CXIMAGE_FORMAT_UNKNOWN); -// fclose(hFile); -// -// if (!bOK && imagetype > 0) strcpy(info.szLastError,szError); //restore the first error -// -// return bOK; -//} -//////////////////////////////////////////////////////////////////////////////// -/** - * Loads an image from the application resources. - * \param hRes: the resource handle returned by FindResource(). - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS. - * \param hModule: NULL for internal resource, or external application/DLL hinstance returned by LoadLibray. - * \return true if everything is ok - */ -bool CxImage::LoadResource(HRSRC hRes, DWORD imagetype, HMODULE hModule) -{ - DWORD rsize=SizeofResource(hModule,hRes); - HGLOBAL hMem=::LoadResource(hModule,hRes); - if (hMem){ - char* lpVoid=(char*)LockResource(hMem); - if (lpVoid){ - // FILE* fTmp=tmpfile(); doesn't work with network - /*char tmpPath[MAX_PATH] = {0}; - char tmpFile[MAX_PATH] = {0}; - GetTempPath(MAX_PATH,tmpPath); - GetTempFileName(tmpPath,"IMG",0,tmpFile); - FILE* fTmp=fopen(tmpFile,"w+b"); - if (fTmp){ - fwrite(lpVoid,rsize,1,fTmp); - fseek(fTmp,0,SEEK_SET); - bool bOK = Decode(fTmp,imagetype); - fclose(fTmp); - DeleteFile(tmpFile); - return bOK; - }*/ - - CxMemFile fTmp((BYTE*)lpVoid,rsize); - return Decode(&fTmp,imagetype); - } - } else strcpy(info.szLastError,"Unable to load resource!"); - return false; -} -#endif //WIN32 -//////////////////////////////////////////////////////////////////////////////// -/** - * Constructor from file name, see Load() - * \param filename: file name - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - */ -// -// > filename: file name -// > imagetype: specify the image format (CXIMAGE_FORMAT_BMP,...) -// For UNICODE support: char -> TCHAR -CxImage::CxImage(const TCHAR * filename, DWORD imagetype) -//CxImage::CxImage(const char * filename, DWORD imagetype) -{ - Startup(imagetype); - Load(filename,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Constructor from file handle, see Decode() - * \param stream: file handle, with read access. - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - */ -CxImage::CxImage(FILE * stream, DWORD imagetype) -{ - Startup(imagetype); - Decode(stream,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Constructor from CxFile object, see Decode() - * \param stream: file handle (CxMemFile or CxIOFile), with read access. - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - */ -CxImage::CxImage(CxFile * stream, DWORD imagetype) -{ - Startup(imagetype); - Decode(stream,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Constructor from memory buffer, see Decode() - * \param buffer: memory buffer - * \param size: size of buffer - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - */ -CxImage::CxImage(BYTE * buffer, DWORD size, DWORD imagetype) -{ - Startup(imagetype); - CxMemFile stream(buffer,size); - Decode(&stream,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Loads an image from memory buffer - * \param buffer: memory buffer - * \param size: size of buffer - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - */ -bool CxImage::Decode(BYTE * buffer, DWORD size, DWORD imagetype) -{ - CxMemFile file(buffer,size); - return Decode(&file,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Loads an image from file handle. - * \param hFile: file handle, with read access. - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - */ -bool CxImage::Decode(FILE *hFile, DWORD imagetype) -{ - CxIOFile file(hFile); - return Decode(&file,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Loads an image from CxFile object - * \param hFile: file handle (CxMemFile or CxIOFile), with read access. - * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS - * \return true if everything is ok - * \sa ENUM_CXIMAGE_FORMATS - */ -bool CxImage::Decode(CxFile *hFile, DWORD imagetype) -{ - if (hFile == NULL){ - strcpy(info.szLastError,CXIMAGE_ERR_NOFILE); - return false; - } - - if (imagetype==CXIMAGE_FORMAT_UNKNOWN){ - DWORD pos = hFile->Tell(); -#if CXIMAGE_SUPPORT_BMP - { CxImageBMP newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_JPG - { CxImageJPG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_ICO - { CxImageICO newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_GIF - { CxImageGIF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_PNG - { CxImagePNG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_TIF - { CxImageTIF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_MNG - { CxImageMNG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_TGA - { CxImageTGA newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_PCX - { CxImagePCX newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_WBMP - { CxImageWBMP newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS - { CxImageWMF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_JBG - { CxImageJBG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_JASPER - { CxImageJAS newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_SKA - { CxImageSKA newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif -#if CXIMAGE_SUPPORT_RAW - { CxImageRAW newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } -#endif - } - -#if CXIMAGE_SUPPORT_BMP - if (imagetype==CXIMAGE_FORMAT_BMP){ - CxImageBMP newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_JPG - if (imagetype==CXIMAGE_FORMAT_JPG){ - CxImageJPG newima; - newima.CopyInfo(*this); // - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_ICO - if (imagetype==CXIMAGE_FORMAT_ICO){ - CxImageICO newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - info.nNumFrames = newima.info.nNumFrames; - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_GIF - if (imagetype==CXIMAGE_FORMAT_GIF){ - CxImageGIF newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - info.nNumFrames = newima.info.nNumFrames; - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_PNG - if (imagetype==CXIMAGE_FORMAT_PNG){ - CxImagePNG newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_TIF - if (imagetype==CXIMAGE_FORMAT_TIF){ - CxImageTIF newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - info.nNumFrames = newima.info.nNumFrames; - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_MNG - if (imagetype==CXIMAGE_FORMAT_MNG){ - CxImageMNG newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - info.nNumFrames = newima.info.nNumFrames; - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_TGA - if (imagetype==CXIMAGE_FORMAT_TGA){ - CxImageTGA newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_PCX - if (imagetype==CXIMAGE_FORMAT_PCX){ - CxImagePCX newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_WBMP - if (imagetype==CXIMAGE_FORMAT_WBMP){ - CxImageWBMP newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS // vho - WMF support - if (imagetype == CXIMAGE_FORMAT_WMF){ - CxImageWMF newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_JBG - if (imagetype==CXIMAGE_FORMAT_JBG){ - CxImageJBG newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_JASPER - if ( - #if CXIMAGE_SUPPORT_JP2 - imagetype==CXIMAGE_FORMAT_JP2 || - #endif - #if CXIMAGE_SUPPORT_JPC - imagetype==CXIMAGE_FORMAT_JPC || - #endif - #if CXIMAGE_SUPPORT_PGX - imagetype==CXIMAGE_FORMAT_PGX || - #endif - #if CXIMAGE_SUPPORT_PNM - imagetype==CXIMAGE_FORMAT_PNM || - #endif - #if CXIMAGE_SUPPORT_RAS - imagetype==CXIMAGE_FORMAT_RAS || - #endif - false ){ - CxImageJAS newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile,imagetype)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif -#if CXIMAGE_SUPPORT_SKA - if (imagetype==CXIMAGE_FORMAT_SKA){ - CxImageSKA newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif - -#if CXIMAGE_SUPPORT_RAW - if (imagetype==CXIMAGE_FORMAT_RAW){ - CxImageRAW newima; - newima.CopyInfo(*this); - if (newima.Decode(hFile)){ - Transfer(newima); - return true; - } else { - strcpy(info.szLastError,newima.GetLastError()); - return false; - } - } -#endif - - strcpy(info.szLastError,"Decode: Unknown or wrong format"); - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Loads an image from CxFile object - * \param hFile: file handle (CxMemFile or CxIOFile), with read access. - * \param imagetype: file format, default = 0 (CXIMAGE_FORMAT_UNKNOWN) - * \return : if imagetype is not 0, the function returns true when imagetype - * matches the file image format. If imagetype is 0, the function returns true - * when the file image format is recognized as a supported format. - * If the returned value is true, use GetHeight(), GetWidth() or GetType() - * to retrieve the basic image information. - * \sa ENUM_CXIMAGE_FORMATS - */ -bool CxImage::CheckFormat(CxFile * hFile, DWORD imagetype) -{ - SetType(CXIMAGE_FORMAT_UNKNOWN); - SetEscape(-1); - - if (!Decode(hFile,imagetype)) - return false; - - if (GetType() == CXIMAGE_FORMAT_UNKNOWN || GetType() != imagetype) - return false; - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::CheckFormat(BYTE * buffer, DWORD size, DWORD imagetype) -{ - if (buffer==NULL || size==NULL){ - strcpy(info.szLastError,"invalid or empty buffer"); - return false; - } - CxMemFile file(buffer,size); - return CheckFormat(&file,imagetype); -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// +// xImaCodec.cpp : Encode Decode functions +/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_JPG +#include "ximajpg.h" +#endif + +#if CXIMAGE_SUPPORT_GIF +#include "ximagif.h" +#endif + +#if CXIMAGE_SUPPORT_PNG +#include "ximapng.h" +#endif + +#if CXIMAGE_SUPPORT_MNG +#include "ximamng.h" +#endif + +#if CXIMAGE_SUPPORT_BMP +#include "ximabmp.h" +#endif + +#if CXIMAGE_SUPPORT_ICO +#include "ximaico.h" +#endif + +#if CXIMAGE_SUPPORT_TIF +#include "ximatif.h" +#endif + +#if CXIMAGE_SUPPORT_TGA +#include "ximatga.h" +#endif + +#if CXIMAGE_SUPPORT_PCX +#include "ximapcx.h" +#endif + +#if CXIMAGE_SUPPORT_WBMP +#include "ximawbmp.h" +#endif + +#if CXIMAGE_SUPPORT_WMF +#include "ximawmf.h" // - WMF/EMF support +#endif + +#if CXIMAGE_SUPPORT_JBG +#include "ximajbg.h" +#endif + +#if CXIMAGE_SUPPORT_JASPER +#include "ximajas.h" +#endif + +#if CXIMAGE_SUPPORT_SKA +#include "ximaska.h" +#endif + +#if CXIMAGE_SUPPORT_RAW +#include "ximaraw.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::EncodeSafeCheck(CxFile *hFile) +{ + if (hFile==NULL) { + strcpy(info.szLastError,CXIMAGE_ERR_NOFILE); + return true; + } + + if (pDib==NULL){ + strcpy(info.szLastError,CXIMAGE_ERR_NOIMAGE); + return true; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +//#ifdef WIN32 +//bool CxImage::Save(LPCWSTR filename, DWORD imagetype) +//{ +// FILE* hFile; //file handle to write the image +// if ((hFile=_wfopen(filename,L"wb"))==NULL) return false; +// bool bOK = Encode(hFile,imagetype); +// fclose(hFile); +// return bOK; +//} +//#endif //WIN32 +//////////////////////////////////////////////////////////////////////////////// +// For UNICODE support: char -> TCHAR +/** + * Saves to disk the image in a specific format. + * \param filename: file name + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + */ +bool CxImage::Save(const TCHAR * filename, DWORD imagetype) +{ + FILE* hFile; //file handle to write the image + +#ifdef WIN32 + if ((hFile=_tfopen(filename,_T("wb")))==NULL) return false; // For UNICODE support +#else + if ((hFile=fopen(filename,"wb"))==NULL) return false; +#endif + + bool bOK = Encode(hFile,imagetype); + fclose(hFile); + return bOK; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Saves to disk the image in a specific format. + * \param hFile: file handle, open and enabled for writing. + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + */ +bool CxImage::Encode(FILE *hFile, DWORD imagetype) +{ + CxIOFile file(hFile); + return Encode(&file,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Saves to memory buffer the image in a specific format. + * \param buffer: output memory buffer pointer. Must be NULL, + * the function allocates and fill the memory, + * the application must free the buffer, see also FreeMemory(). + * \param size: output memory buffer size. + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + */ +bool CxImage::Encode(BYTE * &buffer, long &size, DWORD imagetype) +{ + if (buffer!=NULL){ + strcpy(info.szLastError,"the buffer must be empty"); + return false; + } + CxMemFile file; + file.Open(); + if(Encode(&file,imagetype)){ + buffer=file.GetBuffer(); + size=file.Size(); + return true; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Saves to disk the image in a specific format. + * \param hFile: file handle (CxMemFile or CxIOFile), with write access. + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + * \sa ENUM_CXIMAGE_FORMATS + */ +bool CxImage::Encode(CxFile *hFile, DWORD imagetype) +{ + +#if CXIMAGE_SUPPORT_BMP + + if (imagetype==CXIMAGE_FORMAT_BMP){ + CxImageBMP newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_ICO + if (imagetype==CXIMAGE_FORMAT_ICO){ + CxImageICO newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_TIF + if (imagetype==CXIMAGE_FORMAT_TIF){ + CxImageTIF newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_JPG + if (imagetype==CXIMAGE_FORMAT_JPG){ + CxImageJPG newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_GIF + if (imagetype==CXIMAGE_FORMAT_GIF){ + CxImageGIF newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_PNG + if (imagetype==CXIMAGE_FORMAT_PNG){ + CxImagePNG newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_MNG + if (imagetype==CXIMAGE_FORMAT_MNG){ + CxImageMNG newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_TGA + if (imagetype==CXIMAGE_FORMAT_TGA){ + CxImageTGA newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_PCX + if (imagetype==CXIMAGE_FORMAT_PCX){ + CxImagePCX newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_WBMP + if (imagetype==CXIMAGE_FORMAT_WBMP){ + CxImageWBMP newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS // - WMF/EMF support + if (imagetype==CXIMAGE_FORMAT_WMF){ + CxImageWMF newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_JBG + if (imagetype==CXIMAGE_FORMAT_JBG){ + CxImageJBG newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_JASPER + if ( + #if CXIMAGE_SUPPORT_JP2 + imagetype==CXIMAGE_FORMAT_JP2 || + #endif + #if CXIMAGE_SUPPORT_JPC + imagetype==CXIMAGE_FORMAT_JPC || + #endif + #if CXIMAGE_SUPPORT_PGX + imagetype==CXIMAGE_FORMAT_PGX || + #endif + #if CXIMAGE_SUPPORT_PNM + imagetype==CXIMAGE_FORMAT_PNM || + #endif + #if CXIMAGE_SUPPORT_RAS + imagetype==CXIMAGE_FORMAT_RAS || + #endif + false ){ + CxImageJAS newima; + newima.Ghost(this); + if (newima.Encode(hFile,imagetype)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif + +#if CXIMAGE_SUPPORT_SKA + if (imagetype==CXIMAGE_FORMAT_SKA){ + CxImageSKA newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif + +#if CXIMAGE_SUPPORT_RAW + if (imagetype==CXIMAGE_FORMAT_RAW){ + CxImageRAW newima; + newima.Ghost(this); + if (newima.Encode(hFile)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif + + strcpy(info.szLastError,"Encode: Unknown format"); + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Saves to disk or memory pagecount images, referenced by an array of CxImage pointers. + * \param hFile: file handle. + * \param pImages: array of CxImage pointers. + * \param pagecount: number of images. + * \param imagetype: can be CXIMAGE_FORMAT_TIF or CXIMAGE_FORMAT_GIF. + * \return true if everything is ok + */ +bool CxImage::Encode(FILE * hFile, CxImage ** pImages, int pagecount, DWORD imagetype) +{ + CxIOFile file(hFile); + return Encode(&file, pImages, pagecount,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Saves to disk or memory pagecount images, referenced by an array of CxImage pointers. + * \param hFile: file handle (CxMemFile or CxIOFile), with write access. + * \param pImages: array of CxImage pointers. + * \param pagecount: number of images. + * \param imagetype: can be CXIMAGE_FORMAT_TIF, CXIMAGE_FORMAT_GIF or CXIMAGE_FORMAT_ICO. + * \return true if everything is ok + */ +bool CxImage::Encode(CxFile * hFile, CxImage ** pImages, int pagecount, DWORD imagetype) +{ +#if CXIMAGE_SUPPORT_TIF + if (imagetype==CXIMAGE_FORMAT_TIF){ + CxImageTIF newima; + newima.Ghost(this); + if (newima.Encode(hFile,pImages,pagecount)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_GIF + if (imagetype==CXIMAGE_FORMAT_GIF){ + CxImageGIF newima; + newima.Ghost(this); + if (newima.Encode(hFile,pImages,pagecount)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_ICO + if (imagetype==CXIMAGE_FORMAT_ICO){ + CxImageICO newima; + newima.Ghost(this); + if (newima.Encode(hFile,pImages,pagecount)){ + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif + strcpy(info.szLastError,"Multipage Encode, Unsupported operation for this format"); + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * exports the image into a RGBA buffer, Useful for OpenGL applications. + * \param buffer: output memory buffer pointer. Must be NULL, + * the function allocates and fill the memory, + * the application must free the buffer, see also FreeMemory(). + * \param size: output memory buffer size. + * \param bFlipY: direction of Y axis. default = false. + * \return true if everything is ok + */ +bool CxImage::Encode2RGBA(BYTE * &buffer, long &size, bool bFlipY) +{ + if (buffer!=NULL){ + strcpy(info.szLastError,"the buffer must be empty"); + return false; + } + CxMemFile file; + file.Open(); + if(Encode2RGBA(&file,bFlipY)){ + buffer=file.GetBuffer(); + size=file.Size(); + return true; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * exports the image into a RGBA buffer, Useful for OpenGL applications. + * \param hFile: file handle (CxMemFile or CxIOFile), with write access. + * \param bFlipY: direction of Y axis. default = false. + * \return true if everything is ok + */ +bool CxImage::Encode2RGBA(CxFile *hFile, bool bFlipY) +{ + if (EncodeSafeCheck(hFile)) return false; + + for (long y1 = 0; y1 < head.biHeight; y1++) { + long y = bFlipY ? head.biHeight - 1 - y1 : y1; + for(long x = 0; x < head.biWidth; x++) { + RGBQUAD color = BlindGetPixelColor(x,y); + hFile->PutC(color.rgbRed); + hFile->PutC(color.rgbGreen); + hFile->PutC(color.rgbBlue); + hFile->PutC(color.rgbReserved); + } + } + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +// For UNICODE support: char -> TCHAR +/** + * Reads from disk the image in a specific format. + * - If decoding fails using the specified image format, + * the function will try the automatic file format recognition. + * + * \param filename: file name + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + */ +bool CxImage::Load(const TCHAR * filename, DWORD imagetype) +//bool CxImage::Load(const char * filename, DWORD imagetype) +{ + /*FILE* hFile; //file handle to read the image + if ((hFile=fopen(filename,"rb"))==NULL) return false; + bool bOK = Decode(hFile,imagetype); + fclose(hFile);*/ + + /* automatic file type recognition */ + bool bOK = false; + if ( GetTypeIndexFromId(imagetype) ){ + FILE* hFile; //file handle to read the image + +#ifdef WIN32 + if ((hFile=_tfopen(filename,_T("rb")))==NULL) return false; // For UNICODE support +#else + if ((hFile=fopen(filename,"rb"))==NULL) return false; +#endif + + bOK = Decode(hFile,imagetype); + fclose(hFile); + if (bOK) return bOK; + } + + char szError[256]; + strcpy(szError,info.szLastError); //save the first error + + // if failed, try automatic recognition of the file... + FILE* hFile; + +#ifdef WIN32 + if ((hFile=_tfopen(filename,_T("rb")))==NULL) return false; // For UNICODE support +#else + if ((hFile=fopen(filename,"rb"))==NULL) return false; +#endif + + bOK = Decode(hFile,CXIMAGE_FORMAT_UNKNOWN); + fclose(hFile); + + if (!bOK && imagetype > 0) strcpy(info.szLastError,szError); //restore the first error + + return bOK; +} +//////////////////////////////////////////////////////////////////////////////// +#ifdef WIN32 +//bool CxImage::Load(LPCWSTR filename, DWORD imagetype) +//{ +// /*FILE* hFile; //file handle to read the image +// if ((hFile=_wfopen(filename, L"rb"))==NULL) return false; +// bool bOK = Decode(hFile,imagetype); +// fclose(hFile);*/ +// +// /* automatic file type recognition */ +// bool bOK = false; +// if ( GetTypeIndexFromId(imagetype) ){ +// FILE* hFile; //file handle to read the image +// if ((hFile=_wfopen(filename,L"rb"))==NULL) return false; +// bOK = Decode(hFile,imagetype); +// fclose(hFile); +// if (bOK) return bOK; +// } +// +// char szError[256]; +// strcpy(szError,info.szLastError); //save the first error +// +// // if failed, try automatic recognition of the file... +// FILE* hFile; //file handle to read the image +// if ((hFile=_wfopen(filename,L"rb"))==NULL) return false; +// bOK = Decode(hFile,CXIMAGE_FORMAT_UNKNOWN); +// fclose(hFile); +// +// if (!bOK && imagetype > 0) strcpy(info.szLastError,szError); //restore the first error +// +// return bOK; +//} +//////////////////////////////////////////////////////////////////////////////// +/** + * Loads an image from the application resources. + * \param hRes: the resource handle returned by FindResource(). + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS. + * \param hModule: NULL for internal resource, or external application/DLL hinstance returned by LoadLibray. + * \return true if everything is ok + */ +bool CxImage::LoadResource(HRSRC hRes, DWORD imagetype, HMODULE hModule) +{ + DWORD rsize=SizeofResource(hModule,hRes); + HGLOBAL hMem=::LoadResource(hModule,hRes); + if (hMem){ + char* lpVoid=(char*)LockResource(hMem); + if (lpVoid){ + // FILE* fTmp=tmpfile(); doesn't work with network + /*char tmpPath[MAX_PATH] = {0}; + char tmpFile[MAX_PATH] = {0}; + GetTempPath(MAX_PATH,tmpPath); + GetTempFileName(tmpPath,"IMG",0,tmpFile); + FILE* fTmp=fopen(tmpFile,"w+b"); + if (fTmp){ + fwrite(lpVoid,rsize,1,fTmp); + fseek(fTmp,0,SEEK_SET); + bool bOK = Decode(fTmp,imagetype); + fclose(fTmp); + DeleteFile(tmpFile); + return bOK; + }*/ + + CxMemFile fTmp((BYTE*)lpVoid,rsize); + return Decode(&fTmp,imagetype); + } + } else strcpy(info.szLastError,"Unable to load resource!"); + return false; +} +#endif //WIN32 +//////////////////////////////////////////////////////////////////////////////// +/** + * Constructor from file name, see Load() + * \param filename: file name + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + */ +// +// > filename: file name +// > imagetype: specify the image format (CXIMAGE_FORMAT_BMP,...) +// For UNICODE support: char -> TCHAR +CxImage::CxImage(const TCHAR * filename, DWORD imagetype) +//CxImage::CxImage(const char * filename, DWORD imagetype) +{ + Startup(imagetype); + Load(filename,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Constructor from file handle, see Decode() + * \param stream: file handle, with read access. + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + */ +CxImage::CxImage(FILE * stream, DWORD imagetype) +{ + Startup(imagetype); + Decode(stream,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Constructor from CxFile object, see Decode() + * \param stream: file handle (CxMemFile or CxIOFile), with read access. + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + */ +CxImage::CxImage(CxFile * stream, DWORD imagetype) +{ + Startup(imagetype); + Decode(stream,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Constructor from memory buffer, see Decode() + * \param buffer: memory buffer + * \param size: size of buffer + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + */ +CxImage::CxImage(BYTE * buffer, DWORD size, DWORD imagetype) +{ + Startup(imagetype); + CxMemFile stream(buffer,size); + Decode(&stream,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Loads an image from memory buffer + * \param buffer: memory buffer + * \param size: size of buffer + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + */ +bool CxImage::Decode(BYTE * buffer, DWORD size, DWORD imagetype) +{ + CxMemFile file(buffer,size); + return Decode(&file,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Loads an image from file handle. + * \param hFile: file handle, with read access. + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + */ +bool CxImage::Decode(FILE *hFile, DWORD imagetype) +{ + CxIOFile file(hFile); + return Decode(&file,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Loads an image from CxFile object + * \param hFile: file handle (CxMemFile or CxIOFile), with read access. + * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS + * \return true if everything is ok + * \sa ENUM_CXIMAGE_FORMATS + */ +bool CxImage::Decode(CxFile *hFile, DWORD imagetype) +{ + if (hFile == NULL){ + strcpy(info.szLastError,CXIMAGE_ERR_NOFILE); + return false; + } + + if (imagetype==CXIMAGE_FORMAT_UNKNOWN){ + DWORD pos = hFile->Tell(); +#if CXIMAGE_SUPPORT_BMP + { CxImageBMP newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_JPG + { CxImageJPG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_ICO + { CxImageICO newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_GIF + { CxImageGIF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_PNG + { CxImagePNG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_TIF + { CxImageTIF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_MNG + { CxImageMNG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_TGA + { CxImageTGA newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_PCX + { CxImagePCX newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_WBMP + { CxImageWBMP newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS + { CxImageWMF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_JBG + { CxImageJBG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_JASPER + { CxImageJAS newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_SKA + { CxImageSKA newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif +#if CXIMAGE_SUPPORT_RAW + { CxImageRAW newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); } +#endif + } + +#if CXIMAGE_SUPPORT_BMP + if (imagetype==CXIMAGE_FORMAT_BMP){ + CxImageBMP newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_JPG + if (imagetype==CXIMAGE_FORMAT_JPG){ + CxImageJPG newima; + newima.CopyInfo(*this); // + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_ICO + if (imagetype==CXIMAGE_FORMAT_ICO){ + CxImageICO newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + info.nNumFrames = newima.info.nNumFrames; + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_GIF + if (imagetype==CXIMAGE_FORMAT_GIF){ + CxImageGIF newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + info.nNumFrames = newima.info.nNumFrames; + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_PNG + if (imagetype==CXIMAGE_FORMAT_PNG){ + CxImagePNG newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_TIF + if (imagetype==CXIMAGE_FORMAT_TIF){ + CxImageTIF newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + info.nNumFrames = newima.info.nNumFrames; + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_MNG + if (imagetype==CXIMAGE_FORMAT_MNG){ + CxImageMNG newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + info.nNumFrames = newima.info.nNumFrames; + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_TGA + if (imagetype==CXIMAGE_FORMAT_TGA){ + CxImageTGA newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_PCX + if (imagetype==CXIMAGE_FORMAT_PCX){ + CxImagePCX newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_WBMP + if (imagetype==CXIMAGE_FORMAT_WBMP){ + CxImageWBMP newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS // vho - WMF support + if (imagetype == CXIMAGE_FORMAT_WMF){ + CxImageWMF newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_JBG + if (imagetype==CXIMAGE_FORMAT_JBG){ + CxImageJBG newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_JASPER + if ( + #if CXIMAGE_SUPPORT_JP2 + imagetype==CXIMAGE_FORMAT_JP2 || + #endif + #if CXIMAGE_SUPPORT_JPC + imagetype==CXIMAGE_FORMAT_JPC || + #endif + #if CXIMAGE_SUPPORT_PGX + imagetype==CXIMAGE_FORMAT_PGX || + #endif + #if CXIMAGE_SUPPORT_PNM + imagetype==CXIMAGE_FORMAT_PNM || + #endif + #if CXIMAGE_SUPPORT_RAS + imagetype==CXIMAGE_FORMAT_RAS || + #endif + false ){ + CxImageJAS newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile,imagetype)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif +#if CXIMAGE_SUPPORT_SKA + if (imagetype==CXIMAGE_FORMAT_SKA){ + CxImageSKA newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif + +#if CXIMAGE_SUPPORT_RAW + if (imagetype==CXIMAGE_FORMAT_RAW){ + CxImageRAW newima; + newima.CopyInfo(*this); + if (newima.Decode(hFile)){ + Transfer(newima); + return true; + } else { + strcpy(info.szLastError,newima.GetLastError()); + return false; + } + } +#endif + + strcpy(info.szLastError,"Decode: Unknown or wrong format"); + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Loads an image from CxFile object + * \param hFile: file handle (CxMemFile or CxIOFile), with read access. + * \param imagetype: file format, default = 0 (CXIMAGE_FORMAT_UNKNOWN) + * \return : if imagetype is not 0, the function returns true when imagetype + * matches the file image format. If imagetype is 0, the function returns true + * when the file image format is recognized as a supported format. + * If the returned value is true, use GetHeight(), GetWidth() or GetType() + * to retrieve the basic image information. + * \sa ENUM_CXIMAGE_FORMATS + */ +bool CxImage::CheckFormat(CxFile * hFile, DWORD imagetype) +{ + SetType(CXIMAGE_FORMAT_UNKNOWN); + SetEscape(-1); + + if (!Decode(hFile,imagetype)) + return false; + + if (GetType() == CXIMAGE_FORMAT_UNKNOWN || GetType() != imagetype) + return false; + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::CheckFormat(BYTE * buffer, DWORD size, DWORD imagetype) +{ + if (buffer==NULL || size==NULL){ + strcpy(info.szLastError,"invalid or empty buffer"); + return false; + } + CxMemFile file(buffer,size); + return CheckFormat(&file,imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// diff --git a/utilities/CxImage/ximaexif.cpp b/utilities/CxImage/ximaexif.cpp index 8d9404b..d36e20c 100644 --- a/utilities/CxImage/ximaexif.cpp +++ b/utilities/CxImage/ximaexif.cpp @@ -1,878 +1,878 @@ -/* - * File: ximaexif.cpp - * Purpose: EXIF reader - * 18/Aug/2002 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - * based on jhead-1.8 by Matthias Wandel - */ - -#include "ximajpg.h" - -#if CXIMAGEJPG_SUPPORT_EXIF - -//////////////////////////////////////////////////////////////////////////////// -CxImageJPG::CxExifInfo::CxExifInfo(EXIFINFO* info) -{ - if (info) { - m_exifinfo = info; - freeinfo = false; - } else { - m_exifinfo = new EXIFINFO; - memset(m_exifinfo,0,sizeof(EXIFINFO)); - freeinfo = true; - } - - m_szLastError[0]='\0'; - ExifImageWidth = MotorolaOrder = 0; - SectionsRead=0; - memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t)); -} -//////////////////////////////////////////////////////////////////////////////// -CxImageJPG::CxExifInfo::~CxExifInfo() -{ - for(int i=0;iGetC(); - - if (a != 0xff || hFile->GetC() != M_SOI){ - return FALSE; - } - - for(;;){ - int itemlen; - int marker = 0; - int ll,lh, got; - BYTE * Data; - - if (SectionsRead >= MAX_SECTIONS){ - strcpy(m_szLastError,"Too many sections in jpg file"); - return false; - } - - for (a=0;a<7;a++){ - marker = hFile->GetC(); - if (marker != 0xff) break; - - if (a >= 6){ - printf("too many padding bytes\n"); - return false; - } - } - - if (marker == 0xff){ - // 0xff is legal padding, but if we get that many, something's wrong. - strcpy(m_szLastError,"too many padding bytes!"); - return false; - } - - Sections[SectionsRead].Type = marker; - - // Read the length of the section. - lh = hFile->GetC(); - ll = hFile->GetC(); - - itemlen = (lh << 8) | ll; - - if (itemlen < 2){ - strcpy(m_szLastError,"invalid marker"); - return false; - } - - Sections[SectionsRead].Size = itemlen; - - Data = (BYTE *)malloc(itemlen); - if (Data == NULL){ - strcpy(m_szLastError,"Could not allocate memory"); - return false; - } - Sections[SectionsRead].Data = Data; - - // Store first two pre-read bytes. - Data[0] = (BYTE)lh; - Data[1] = (BYTE)ll; - - got = hFile->Read(Data+2, 1, itemlen-2); // Read the whole section. - if (got != itemlen-2){ - strcpy(m_szLastError,"Premature end of file?"); - return false; - } - SectionsRead += 1; - - switch(marker){ - - case M_SOS: // stop before hitting compressed data - // If reading entire image is requested, read the rest of the data. - if (nReadMode & EXIF_READ_IMAGE){ - int cp, ep, size; - // Determine how much file is left. - cp = hFile->Tell(); - hFile->Seek(0, SEEK_END); - ep = hFile->Tell(); - hFile->Seek(cp, SEEK_SET); - - size = ep-cp; - Data = (BYTE *)malloc(size); - if (Data == NULL){ - strcpy(m_szLastError,"could not allocate data for entire image"); - return false; - } - - got = hFile->Read(Data, 1, size); - if (got != size){ - strcpy(m_szLastError,"could not read the rest of the image"); - return false; - } - - Sections[SectionsRead].Data = Data; - Sections[SectionsRead].Size = size; - Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; - SectionsRead ++; - } - return true; - - case M_EOI: // in case it's a tables-only JPEG stream - printf("No image in jpeg!\n"); - return FALSE; - - case M_COM: // Comment section - if (HaveCom || ((nReadMode & EXIF_READ_EXIF) == 0)){ - // Discard this section. - free(Sections[--SectionsRead].Data); - Sections[SectionsRead].Data=0; - }else{ - process_COM(Data, itemlen); - HaveCom = TRUE; - } - break; - - case M_JFIF: - // Regular jpegs always have this tag, exif images have the exif - // marker instead, althogh ACDsee will write images with both markers. - // this program will re-create this marker on absence of exif marker. - // hence no need to keep the copy from the file. - free(Sections[--SectionsRead].Data); - Sections[SectionsRead].Data=0; - break; - - case M_EXIF: - // Seen files from some 'U-lead' software with Vivitar scanner - // that uses marker 31 for non exif stuff. Thus make sure - // it says 'Exif' in the section before treating it as exif. - if ((nReadMode & EXIF_READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ - m_exifinfo->IsExif = process_EXIF((BYTE *)Data+2, itemlen); - }else{ - // Discard this section. - free(Sections[--SectionsRead].Data); - Sections[SectionsRead].Data=0; - } - break; - - case M_SOF0: - case M_SOF1: - case M_SOF2: - case M_SOF3: - case M_SOF5: - case M_SOF6: - case M_SOF7: - case M_SOF9: - case M_SOF10: - case M_SOF11: - case M_SOF13: - case M_SOF14: - case M_SOF15: - process_SOFn(Data, marker); - break; - default: - // Skip any other sections. - //if (ShowTags) printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen); - break; - } - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/*-------------------------------------------------------------------------- - Process a EXIF marker - Describes all the drivel that most digital cameras include... ---------------------------------------------------------------------------*/ -bool CxImageJPG::CxExifInfo::process_EXIF(unsigned char * CharBuf, unsigned int length) -{ - m_exifinfo->FlashUsed = 0; - /* If it's from a digicam, and it used flash, it says so. */ - m_exifinfo->Comments[0] = '\0'; /* Initial value - null string */ - - ExifImageWidth = 0; - - { /* Check the EXIF header component */ - static const unsigned char ExifHeader[] = "Exif\0\0"; - if (memcmp(CharBuf+0, ExifHeader,6)){ - strcpy(m_szLastError,"Incorrect Exif header"); - return false; - } - } - - if (memcmp(CharBuf+6,"II",2) == 0){ - MotorolaOrder = 0; - }else{ - if (memcmp(CharBuf+6,"MM",2) == 0){ - MotorolaOrder = 1; - }else{ - strcpy(m_szLastError,"Invalid Exif alignment marker."); - return false; - } - } - - /* Check the next two values for correctness. */ - if (Get16u(CharBuf+8) != 0x2a){ - strcpy(m_szLastError,"Invalid Exif start (1)"); - return false; - } - - int FirstOffset = Get32u(CharBuf+10); - /* - if (FirstOffset < 8 || FirstOffset > 16){ - // I used to ensure this was set to 8 (website I used indicated its 8) - // but PENTAX Optio 230 has it set differently, and uses it as offset. (Sept 11 2002) - strcpy(m_szLastError,"Suspicious offset of first IFD value"); - return false; - }*/ - - unsigned char * LastExifRefd = CharBuf; - - /* First directory starts 16 bytes in. Offsets start at 8 bytes in. */ - if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd)) - return false; - - /* give a chance for a second directory */ - if (FirstOffset > 8) { - if (!ProcessExifDir(CharBuf+14+FirstOffset-8, CharBuf+6, length-6, m_exifinfo, &LastExifRefd)) - return false; - } - - /* This is how far the interesting (non thumbnail) part of the exif went. */ - // int ExifSettingsLength = LastExifRefd - CharBuf; - - /* Compute the CCD width, in milimeters. */ - if (m_exifinfo->FocalplaneXRes != 0){ - m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes); - } - - return true; -} -//-------------------------------------------------------------------------- -// Get 16 bits motorola order (always) for jpeg header stuff. -//-------------------------------------------------------------------------- -int CxImageJPG::CxExifInfo::Get16m(void * Short) -{ - return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1]; -} -//////////////////////////////////////////////////////////////////////////////// -/*-------------------------------------------------------------------------- - Convert a 16 bit unsigned value from file's native byte order ---------------------------------------------------------------------------*/ -int CxImageJPG::CxExifInfo::Get16u(void * Short) -{ - if (MotorolaOrder){ - return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1]; - }else{ - return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0]; - } -} -//////////////////////////////////////////////////////////////////////////////// -/*-------------------------------------------------------------------------- - Convert a 32 bit signed value from file's native byte order ---------------------------------------------------------------------------*/ -long CxImageJPG::CxExifInfo::Get32s(void * Long) -{ - if (MotorolaOrder){ - return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) - | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 ); - }else{ - return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) - | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 ); - } -} -//////////////////////////////////////////////////////////////////////////////// -/*-------------------------------------------------------------------------- - Convert a 32 bit unsigned value from file's native byte order ---------------------------------------------------------------------------*/ -unsigned long CxImageJPG::CxExifInfo::Get32u(void * Long) -{ - return (unsigned long)Get32s(Long) & 0xffffffff; -} -//////////////////////////////////////////////////////////////////////////////// - -/* Describes format descriptor */ -static const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; -#define NUM_FORMATS 12 - -#define FMT_BYTE 1 -#define FMT_STRING 2 -#define FMT_USHORT 3 -#define FMT_ULONG 4 -#define FMT_URATIONAL 5 -#define FMT_SBYTE 6 -#define FMT_UNDEFINED 7 -#define FMT_SSHORT 8 -#define FMT_SLONG 9 -#define FMT_SRATIONAL 10 -#define FMT_SINGLE 11 -#define FMT_DOUBLE 12 - -/* Describes tag values */ - -#define TAG_EXIF_VERSION 0x9000 -#define TAG_EXIF_OFFSET 0x8769 -#define TAG_INTEROP_OFFSET 0xa005 - -#define TAG_MAKE 0x010F -#define TAG_MODEL 0x0110 - -#define TAG_ORIENTATION 0x0112 -#define TAG_XRESOLUTION 0x011A -#define TAG_YRESOLUTION 0x011B -#define TAG_RESOLUTIONUNIT 0x0128 - -#define TAG_EXPOSURETIME 0x829A -#define TAG_FNUMBER 0x829D - -#define TAG_SHUTTERSPEED 0x9201 -#define TAG_APERTURE 0x9202 -#define TAG_BRIGHTNESS 0x9203 -#define TAG_MAXAPERTURE 0x9205 -#define TAG_FOCALLENGTH 0x920A - -#define TAG_DATETIME_ORIGINAL 0x9003 -#define TAG_USERCOMMENT 0x9286 - -#define TAG_SUBJECT_DISTANCE 0x9206 -#define TAG_FLASH 0x9209 - -#define TAG_FOCALPLANEXRES 0xa20E -#define TAG_FOCALPLANEYRES 0xa20F -#define TAG_FOCALPLANEUNITS 0xa210 -#define TAG_EXIF_IMAGEWIDTH 0xA002 -#define TAG_EXIF_IMAGELENGTH 0xA003 - -/* the following is added 05-jan-2001 vcs */ -#define TAG_EXPOSURE_BIAS 0x9204 -#define TAG_WHITEBALANCE 0x9208 -#define TAG_METERING_MODE 0x9207 -#define TAG_EXPOSURE_PROGRAM 0x8822 -#define TAG_ISO_EQUIVALENT 0x8827 -#define TAG_COMPRESSION_LEVEL 0x9102 - -#define TAG_THUMBNAIL_OFFSET 0x0201 -#define TAG_THUMBNAIL_LENGTH 0x0202 - - -/*-------------------------------------------------------------------------- - Process one of the nested EXIF directories. ---------------------------------------------------------------------------*/ -bool CxImageJPG::CxExifInfo::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, - EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP, int NestingLevel) -{ - int de; - int a; - int NumDirEntries; - unsigned ThumbnailOffset = 0; - unsigned ThumbnailSize = 0; - - if (NestingLevel > 4){ - strcpy(m_szLastError,"Maximum directory nesting exceeded (corrupt exif header)"); - return false; - } - - NumDirEntries = Get16u(DirStart); - - if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){ - strcpy(m_szLastError,"Illegally sized directory"); - return false; - } - - for (de=0;de= NUM_FORMATS) { - /* (-1) catches illegal zero case as unsigned underflows to positive large */ - strcpy(m_szLastError,"Illegal format code in EXIF dir"); - return false; - } - - ByteCount = Components * BytesPerFormat[Format]; - - if (ByteCount > 4){ - unsigned OffsetVal; - OffsetVal = Get32u(DirEntry+8); - /* If its bigger than 4 bytes, the dir entry contains an offset.*/ - if (OffsetVal+ByteCount > ExifLength){ - /* Bogus pointer offset and / or bytecount value */ - strcpy(m_szLastError,"Illegal pointer offset value in EXIF."); - return false; - } - ValuePtr = OffsetBase+OffsetVal; - }else{ - /* 4 bytes or less and value is in the dir entry itself */ - ValuePtr = DirEntry+8; - } - - if (*LastExifRefdP < ValuePtr+ByteCount){ - /* Keep track of last byte in the exif header that was - actually referenced. That way, we know where the - discardable thumbnail data begins. - */ - *LastExifRefdP = ValuePtr+ByteCount; - } - - /* Extract useful components of tag */ - switch(Tag){ - - case TAG_MAKE: - strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31); - break; - - case TAG_MODEL: - strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39); - break; - - case TAG_EXIF_VERSION: - strncpy(m_exifinfo->Version,(char*)ValuePtr, 4); - break; - - case TAG_DATETIME_ORIGINAL: - strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19); - break; - - case TAG_USERCOMMENT: - // Olympus has this padded with trailing spaces. Remove these first. - for (a=ByteCount;;){ - a--; - if (((char*)ValuePtr)[a] == ' '){ - ((char*)ValuePtr)[a] = '\0'; - }else{ - break; - } - if (a == 0) break; - } - - /* Copy the comment */ - if (memcmp(ValuePtr, "ASCII",5) == 0){ - for (a=5;a<10;a++){ - char c; - c = ((char*)ValuePtr)[a]; - if (c != '\0' && c != ' '){ - strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199); - break; - } - } - - }else{ - strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199); - } - break; - - case TAG_FNUMBER: - /* Simplest way of expressing aperture, so I trust it the most. - (overwrite previously computd value if there is one) - */ - m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_APERTURE: - case TAG_MAXAPERTURE: - /* More relevant info always comes earlier, so only - use this field if we don't have appropriate aperture - information yet. - */ - if (m_exifinfo->ApertureFNumber == 0){ - m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)*0.5); - } - break; - - case TAG_BRIGHTNESS: - m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_FOCALLENGTH: - /* Nice digital cameras actually save the focal length - as a function of how farthey are zoomed in. - */ - - m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_SUBJECT_DISTANCE: - /* Inidcates the distacne the autofocus camera is focused to. - Tends to be less accurate as distance increases. - */ - m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURETIME: - /* Simplest way of expressing exposure time, so I - trust it most. (overwrite previously computd value - if there is one) - */ - m_exifinfo->ExposureTime = - (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_SHUTTERSPEED: - /* More complicated way of expressing exposure time, - so only use this value if we don't already have it - from somewhere else. - */ - if (m_exifinfo->ExposureTime == 0){ - m_exifinfo->ExposureTime = (float) - (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f))); - } - break; - - case TAG_FLASH: - if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){ - m_exifinfo->FlashUsed = 1; - }else{ - m_exifinfo->FlashUsed = 0; - } - break; - - case TAG_ORIENTATION: - m_exifinfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format); - if (m_exifinfo->Orientation < 1 || m_exifinfo->Orientation > 8){ - strcpy(m_szLastError,"Undefined rotation value"); - m_exifinfo->Orientation = 0; - } - break; - - case TAG_EXIF_IMAGELENGTH: - case TAG_EXIF_IMAGEWIDTH: - /* Use largest of height and width to deal with images - that have been rotated to portrait format. - */ - a = (int)ConvertAnyFormat(ValuePtr, Format); - if (ExifImageWidth < a) ExifImageWidth = a; - break; - - case TAG_FOCALPLANEXRES: - m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_FOCALPLANEYRES: - m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_RESOLUTIONUNIT: - switch((int)ConvertAnyFormat(ValuePtr, Format)){ - case 1: m_exifinfo->ResolutionUnit = 1.0f; break; /* 1 inch */ - case 2: m_exifinfo->ResolutionUnit = 1.0f; break; - case 3: m_exifinfo->ResolutionUnit = 0.3937007874f; break; /* 1 centimeter*/ - case 4: m_exifinfo->ResolutionUnit = 0.03937007874f; break; /* 1 millimeter*/ - case 5: m_exifinfo->ResolutionUnit = 0.00003937007874f; /* 1 micrometer*/ - } - break; - - case TAG_FOCALPLANEUNITS: - switch((int)ConvertAnyFormat(ValuePtr, Format)){ - case 1: m_exifinfo->FocalplaneUnits = 1.0f; break; /* 1 inch */ - case 2: m_exifinfo->FocalplaneUnits = 1.0f; break; - case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; /* 1 centimeter*/ - case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break; /* 1 millimeter*/ - case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f; /* 1 micrometer*/ - } - break; - - // Remaining cases contributed by: Volker C. Schoech - - case TAG_EXPOSURE_BIAS: - m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_WHITEBALANCE: - m_exifinfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_METERING_MODE: - m_exifinfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURE_PROGRAM: - m_exifinfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_ISO_EQUIVALENT: - m_exifinfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); - if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200; - break; - - case TAG_COMPRESSION_LEVEL: - m_exifinfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_XRESOLUTION: - m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_YRESOLUTION: - m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_THUMBNAIL_OFFSET: - ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_THUMBNAIL_LENGTH: - ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); - break; - - } - - if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){ - unsigned char * SubdirStart; - unsigned Offset = Get32u(ValuePtr); - if (Offset>8){ - SubdirStart = OffsetBase + Offset; - if (SubdirStart < OffsetBase || - SubdirStart > OffsetBase+ExifLength){ - strcpy(m_szLastError,"Illegal subdirectory link"); - return false; - } - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1); - } - continue; - } - } - - - { - /* In addition to linking to subdirectories via exif tags, - there's also a potential link to another directory at the end - of each directory. This has got to be the result of a - committee! - */ - unsigned char * SubdirStart; - unsigned Offset; - Offset = Get16u(DirStart+2+12*NumDirEntries); - if (Offset){ - SubdirStart = OffsetBase + Offset; - if (SubdirStart < OffsetBase - || SubdirStart > OffsetBase+ExifLength){ - strcpy(m_szLastError,"Illegal subdirectory link"); - return false; - } - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1); - } - } - - - if (ThumbnailSize && ThumbnailOffset){ - if (ThumbnailSize + ThumbnailOffset <= ExifLength){ - /* The thumbnail pointer appears to be valid. Store it. */ - m_exifinfo->ThumbnailPointer = OffsetBase + ThumbnailOffset; - m_exifinfo->ThumbnailSize = ThumbnailSize; - } - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/*-------------------------------------------------------------------------- - Evaluate number, be it int, rational, or float from directory. ---------------------------------------------------------------------------*/ -double CxImageJPG::CxExifInfo::ConvertAnyFormat(void * ValuePtr, int Format) -{ - double Value; - Value = 0; - - switch(Format){ - case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; - case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break; - - case FMT_USHORT: Value = Get16u(ValuePtr); break; - case FMT_ULONG: Value = Get32u(ValuePtr); break; - - case FMT_URATIONAL: - case FMT_SRATIONAL: - { - int Num,Den; - Num = Get32s(ValuePtr); - Den = Get32s(4+(char *)ValuePtr); - if (Den == 0){ - Value = 0; - }else{ - Value = (double)Num/Den; - } - break; - } - - case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; - case FMT_SLONG: Value = Get32s(ValuePtr); break; - - /* Not sure if this is correct (never seen float used in Exif format) - */ - case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; - case FMT_DOUBLE: Value = *(double *)ValuePtr; break; - } - return Value; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageJPG::CxExifInfo::process_COM (const BYTE * Data, int length) -{ - int ch; - char Comment[MAX_COMMENT+1]; - int nch; - int a; - - nch = 0; - - if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure. - - for (a=2;aComments,Comment); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageJPG::CxExifInfo::process_SOFn (const BYTE * Data, int marker) -{ - int data_precision, num_components; - - data_precision = Data[2]; - m_exifinfo->Height = Get16m((void*)(Data+3)); - m_exifinfo->Width = Get16m((void*)(Data+5)); - num_components = Data[7]; - - if (num_components == 3){ - m_exifinfo->IsColor = 1; - }else{ - m_exifinfo->IsColor = 0; - } - - m_exifinfo->Process = marker; - - //if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n", - // ImageInfo.Width, ImageInfo.Height, num_components, data_precision); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * this will work only on a CxImageJPG object, if the image originally has valid EXIF data - \verbatim - CxImageJPG jpg; - CxIOFile in,out; - in.Open("D:\\exif_in.jpg","rb"); - out.Open("D:\\exif_out.jpg","w+b"); - jpg.Decode(&in); - if (jpg.IsValid()){ - jpg.RotateLeft(); - jpg.Encode(&out); - } - \endverbatim -*/ -bool CxImageJPG::CxExifInfo::EncodeExif(CxFile * hFile) -{ - int a; - - if (FindSection(M_SOS)==NULL){ - strcpy(m_szLastError,"Can't write exif : didn't read all"); - return false; - } - - // Initial static jpeg marker. - hFile->PutC(0xff); - hFile->PutC(0xd8); - - if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){ - // The image must start with an exif or jfif marker. If we threw those away, create one. - static BYTE JfifHead[18] = { - 0xff, M_JFIF, - 0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01, - 0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00 - }; - hFile->Write(JfifHead, 18, 1); - } - - // Write all the misc sections - for (a=0;aPutC(0xff); - hFile->PutC((unsigned char)(Sections[a].Type)); - hFile->Write(Sections[a].Data, Sections[a].Size, 1); - } - - // Write the remaining image data. - hFile->Write(Sections[a].Data, Sections[a].Size, 1); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageJPG::CxExifInfo::DiscardAllButExif() -{ - Section_t ExifKeeper; - Section_t CommentKeeper; - int a; - - memset(&ExifKeeper, 0, sizeof(ExifKeeper)); - memset(&CommentKeeper, 0, sizeof(ExifKeeper)); - - for (a=0;a + */ + +#include "ximajpg.h" + +#if CXIMAGEJPG_SUPPORT_EXIF + +//////////////////////////////////////////////////////////////////////////////// +CxImageJPG::CxExifInfo::CxExifInfo(EXIFINFO* info) +{ + if (info) { + m_exifinfo = info; + freeinfo = false; + } else { + m_exifinfo = new EXIFINFO; + memset(m_exifinfo,0,sizeof(EXIFINFO)); + freeinfo = true; + } + + m_szLastError[0]='\0'; + ExifImageWidth = MotorolaOrder = 0; + SectionsRead=0; + memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t)); +} +//////////////////////////////////////////////////////////////////////////////// +CxImageJPG::CxExifInfo::~CxExifInfo() +{ + for(int i=0;iGetC(); + + if (a != 0xff || hFile->GetC() != M_SOI){ + return FALSE; + } + + for(;;){ + int itemlen; + int marker = 0; + int ll,lh, got; + BYTE * Data; + + if (SectionsRead >= MAX_SECTIONS){ + strcpy(m_szLastError,"Too many sections in jpg file"); + return false; + } + + for (a=0;a<7;a++){ + marker = hFile->GetC(); + if (marker != 0xff) break; + + if (a >= 6){ + printf("too many padding bytes\n"); + return false; + } + } + + if (marker == 0xff){ + // 0xff is legal padding, but if we get that many, something's wrong. + strcpy(m_szLastError,"too many padding bytes!"); + return false; + } + + Sections[SectionsRead].Type = marker; + + // Read the length of the section. + lh = hFile->GetC(); + ll = hFile->GetC(); + + itemlen = (lh << 8) | ll; + + if (itemlen < 2){ + strcpy(m_szLastError,"invalid marker"); + return false; + } + + Sections[SectionsRead].Size = itemlen; + + Data = (BYTE *)malloc(itemlen); + if (Data == NULL){ + strcpy(m_szLastError,"Could not allocate memory"); + return false; + } + Sections[SectionsRead].Data = Data; + + // Store first two pre-read bytes. + Data[0] = (BYTE)lh; + Data[1] = (BYTE)ll; + + got = hFile->Read(Data+2, 1, itemlen-2); // Read the whole section. + if (got != itemlen-2){ + strcpy(m_szLastError,"Premature end of file?"); + return false; + } + SectionsRead += 1; + + switch(marker){ + + case M_SOS: // stop before hitting compressed data + // If reading entire image is requested, read the rest of the data. + if (nReadMode & EXIF_READ_IMAGE){ + int cp, ep, size; + // Determine how much file is left. + cp = hFile->Tell(); + hFile->Seek(0, SEEK_END); + ep = hFile->Tell(); + hFile->Seek(cp, SEEK_SET); + + size = ep-cp; + Data = (BYTE *)malloc(size); + if (Data == NULL){ + strcpy(m_szLastError,"could not allocate data for entire image"); + return false; + } + + got = hFile->Read(Data, 1, size); + if (got != size){ + strcpy(m_szLastError,"could not read the rest of the image"); + return false; + } + + Sections[SectionsRead].Data = Data; + Sections[SectionsRead].Size = size; + Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; + SectionsRead ++; + } + return true; + + case M_EOI: // in case it's a tables-only JPEG stream + printf("No image in jpeg!\n"); + return FALSE; + + case M_COM: // Comment section + if (HaveCom || ((nReadMode & EXIF_READ_EXIF) == 0)){ + // Discard this section. + free(Sections[--SectionsRead].Data); + Sections[SectionsRead].Data=0; + }else{ + process_COM(Data, itemlen); + HaveCom = TRUE; + } + break; + + case M_JFIF: + // Regular jpegs always have this tag, exif images have the exif + // marker instead, althogh ACDsee will write images with both markers. + // this program will re-create this marker on absence of exif marker. + // hence no need to keep the copy from the file. + free(Sections[--SectionsRead].Data); + Sections[SectionsRead].Data=0; + break; + + case M_EXIF: + // Seen files from some 'U-lead' software with Vivitar scanner + // that uses marker 31 for non exif stuff. Thus make sure + // it says 'Exif' in the section before treating it as exif. + if ((nReadMode & EXIF_READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){ + m_exifinfo->IsExif = process_EXIF((BYTE *)Data+2, itemlen); + }else{ + // Discard this section. + free(Sections[--SectionsRead].Data); + Sections[SectionsRead].Data=0; + } + break; + + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + process_SOFn(Data, marker); + break; + default: + // Skip any other sections. + //if (ShowTags) printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen); + break; + } + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/*-------------------------------------------------------------------------- + Process a EXIF marker + Describes all the drivel that most digital cameras include... +--------------------------------------------------------------------------*/ +bool CxImageJPG::CxExifInfo::process_EXIF(unsigned char * CharBuf, unsigned int length) +{ + m_exifinfo->FlashUsed = 0; + /* If it's from a digicam, and it used flash, it says so. */ + m_exifinfo->Comments[0] = '\0'; /* Initial value - null string */ + + ExifImageWidth = 0; + + { /* Check the EXIF header component */ + static const unsigned char ExifHeader[] = "Exif\0\0"; + if (memcmp(CharBuf+0, ExifHeader,6)){ + strcpy(m_szLastError,"Incorrect Exif header"); + return false; + } + } + + if (memcmp(CharBuf+6,"II",2) == 0){ + MotorolaOrder = 0; + }else{ + if (memcmp(CharBuf+6,"MM",2) == 0){ + MotorolaOrder = 1; + }else{ + strcpy(m_szLastError,"Invalid Exif alignment marker."); + return false; + } + } + + /* Check the next two values for correctness. */ + if (Get16u(CharBuf+8) != 0x2a){ + strcpy(m_szLastError,"Invalid Exif start (1)"); + return false; + } + + int FirstOffset = Get32u(CharBuf+10); + /* + if (FirstOffset < 8 || FirstOffset > 16){ + // I used to ensure this was set to 8 (website I used indicated its 8) + // but PENTAX Optio 230 has it set differently, and uses it as offset. (Sept 11 2002) + strcpy(m_szLastError,"Suspicious offset of first IFD value"); + return false; + }*/ + + unsigned char * LastExifRefd = CharBuf; + + /* First directory starts 16 bytes in. Offsets start at 8 bytes in. */ + if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd)) + return false; + + /* give a chance for a second directory */ + if (FirstOffset > 8) { + if (!ProcessExifDir(CharBuf+14+FirstOffset-8, CharBuf+6, length-6, m_exifinfo, &LastExifRefd)) + return false; + } + + /* This is how far the interesting (non thumbnail) part of the exif went. */ + // int ExifSettingsLength = LastExifRefd - CharBuf; + + /* Compute the CCD width, in milimeters. */ + if (m_exifinfo->FocalplaneXRes != 0){ + m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes); + } + + return true; +} +//-------------------------------------------------------------------------- +// Get 16 bits motorola order (always) for jpeg header stuff. +//-------------------------------------------------------------------------- +int CxImageJPG::CxExifInfo::Get16m(void * Short) +{ + return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1]; +} +//////////////////////////////////////////////////////////////////////////////// +/*-------------------------------------------------------------------------- + Convert a 16 bit unsigned value from file's native byte order +--------------------------------------------------------------------------*/ +int CxImageJPG::CxExifInfo::Get16u(void * Short) +{ + if (MotorolaOrder){ + return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1]; + }else{ + return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0]; + } +} +//////////////////////////////////////////////////////////////////////////////// +/*-------------------------------------------------------------------------- + Convert a 32 bit signed value from file's native byte order +--------------------------------------------------------------------------*/ +long CxImageJPG::CxExifInfo::Get32s(void * Long) +{ + if (MotorolaOrder){ + return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) + | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 ); + }else{ + return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) + | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 ); + } +} +//////////////////////////////////////////////////////////////////////////////// +/*-------------------------------------------------------------------------- + Convert a 32 bit unsigned value from file's native byte order +--------------------------------------------------------------------------*/ +unsigned long CxImageJPG::CxExifInfo::Get32u(void * Long) +{ + return (unsigned long)Get32s(Long) & 0xffffffff; +} +//////////////////////////////////////////////////////////////////////////////// + +/* Describes format descriptor */ +static const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; +#define NUM_FORMATS 12 + +#define FMT_BYTE 1 +#define FMT_STRING 2 +#define FMT_USHORT 3 +#define FMT_ULONG 4 +#define FMT_URATIONAL 5 +#define FMT_SBYTE 6 +#define FMT_UNDEFINED 7 +#define FMT_SSHORT 8 +#define FMT_SLONG 9 +#define FMT_SRATIONAL 10 +#define FMT_SINGLE 11 +#define FMT_DOUBLE 12 + +/* Describes tag values */ + +#define TAG_EXIF_VERSION 0x9000 +#define TAG_EXIF_OFFSET 0x8769 +#define TAG_INTEROP_OFFSET 0xa005 + +#define TAG_MAKE 0x010F +#define TAG_MODEL 0x0110 + +#define TAG_ORIENTATION 0x0112 +#define TAG_XRESOLUTION 0x011A +#define TAG_YRESOLUTION 0x011B +#define TAG_RESOLUTIONUNIT 0x0128 + +#define TAG_EXPOSURETIME 0x829A +#define TAG_FNUMBER 0x829D + +#define TAG_SHUTTERSPEED 0x9201 +#define TAG_APERTURE 0x9202 +#define TAG_BRIGHTNESS 0x9203 +#define TAG_MAXAPERTURE 0x9205 +#define TAG_FOCALLENGTH 0x920A + +#define TAG_DATETIME_ORIGINAL 0x9003 +#define TAG_USERCOMMENT 0x9286 + +#define TAG_SUBJECT_DISTANCE 0x9206 +#define TAG_FLASH 0x9209 + +#define TAG_FOCALPLANEXRES 0xa20E +#define TAG_FOCALPLANEYRES 0xa20F +#define TAG_FOCALPLANEUNITS 0xa210 +#define TAG_EXIF_IMAGEWIDTH 0xA002 +#define TAG_EXIF_IMAGELENGTH 0xA003 + +/* the following is added 05-jan-2001 vcs */ +#define TAG_EXPOSURE_BIAS 0x9204 +#define TAG_WHITEBALANCE 0x9208 +#define TAG_METERING_MODE 0x9207 +#define TAG_EXPOSURE_PROGRAM 0x8822 +#define TAG_ISO_EQUIVALENT 0x8827 +#define TAG_COMPRESSION_LEVEL 0x9102 + +#define TAG_THUMBNAIL_OFFSET 0x0201 +#define TAG_THUMBNAIL_LENGTH 0x0202 + + +/*-------------------------------------------------------------------------- + Process one of the nested EXIF directories. +--------------------------------------------------------------------------*/ +bool CxImageJPG::CxExifInfo::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, + EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP, int NestingLevel) +{ + int de; + int a; + int NumDirEntries; + unsigned ThumbnailOffset = 0; + unsigned ThumbnailSize = 0; + + if (NestingLevel > 4){ + strcpy(m_szLastError,"Maximum directory nesting exceeded (corrupt exif header)"); + return false; + } + + NumDirEntries = Get16u(DirStart); + + if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){ + strcpy(m_szLastError,"Illegally sized directory"); + return false; + } + + for (de=0;de= NUM_FORMATS) { + /* (-1) catches illegal zero case as unsigned underflows to positive large */ + strcpy(m_szLastError,"Illegal format code in EXIF dir"); + return false; + } + + ByteCount = Components * BytesPerFormat[Format]; + + if (ByteCount > 4){ + unsigned OffsetVal; + OffsetVal = Get32u(DirEntry+8); + /* If its bigger than 4 bytes, the dir entry contains an offset.*/ + if (OffsetVal+ByteCount > ExifLength){ + /* Bogus pointer offset and / or bytecount value */ + strcpy(m_szLastError,"Illegal pointer offset value in EXIF."); + return false; + } + ValuePtr = OffsetBase+OffsetVal; + }else{ + /* 4 bytes or less and value is in the dir entry itself */ + ValuePtr = DirEntry+8; + } + + if (*LastExifRefdP < ValuePtr+ByteCount){ + /* Keep track of last byte in the exif header that was + actually referenced. That way, we know where the + discardable thumbnail data begins. + */ + *LastExifRefdP = ValuePtr+ByteCount; + } + + /* Extract useful components of tag */ + switch(Tag){ + + case TAG_MAKE: + strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31); + break; + + case TAG_MODEL: + strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39); + break; + + case TAG_EXIF_VERSION: + strncpy(m_exifinfo->Version,(char*)ValuePtr, 4); + break; + + case TAG_DATETIME_ORIGINAL: + strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19); + break; + + case TAG_USERCOMMENT: + // Olympus has this padded with trailing spaces. Remove these first. + for (a=ByteCount;;){ + a--; + if (((char*)ValuePtr)[a] == ' '){ + ((char*)ValuePtr)[a] = '\0'; + }else{ + break; + } + if (a == 0) break; + } + + /* Copy the comment */ + if (memcmp(ValuePtr, "ASCII",5) == 0){ + for (a=5;a<10;a++){ + char c; + c = ((char*)ValuePtr)[a]; + if (c != '\0' && c != ' '){ + strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199); + break; + } + } + + }else{ + strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199); + } + break; + + case TAG_FNUMBER: + /* Simplest way of expressing aperture, so I trust it the most. + (overwrite previously computd value if there is one) + */ + m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_APERTURE: + case TAG_MAXAPERTURE: + /* More relevant info always comes earlier, so only + use this field if we don't have appropriate aperture + information yet. + */ + if (m_exifinfo->ApertureFNumber == 0){ + m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)*0.5); + } + break; + + case TAG_BRIGHTNESS: + m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_FOCALLENGTH: + /* Nice digital cameras actually save the focal length + as a function of how farthey are zoomed in. + */ + + m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_SUBJECT_DISTANCE: + /* Inidcates the distacne the autofocus camera is focused to. + Tends to be less accurate as distance increases. + */ + m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXPOSURETIME: + /* Simplest way of expressing exposure time, so I + trust it most. (overwrite previously computd value + if there is one) + */ + m_exifinfo->ExposureTime = + (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_SHUTTERSPEED: + /* More complicated way of expressing exposure time, + so only use this value if we don't already have it + from somewhere else. + */ + if (m_exifinfo->ExposureTime == 0){ + m_exifinfo->ExposureTime = (float) + (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f))); + } + break; + + case TAG_FLASH: + if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){ + m_exifinfo->FlashUsed = 1; + }else{ + m_exifinfo->FlashUsed = 0; + } + break; + + case TAG_ORIENTATION: + m_exifinfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format); + if (m_exifinfo->Orientation < 1 || m_exifinfo->Orientation > 8){ + strcpy(m_szLastError,"Undefined rotation value"); + m_exifinfo->Orientation = 0; + } + break; + + case TAG_EXIF_IMAGELENGTH: + case TAG_EXIF_IMAGEWIDTH: + /* Use largest of height and width to deal with images + that have been rotated to portrait format. + */ + a = (int)ConvertAnyFormat(ValuePtr, Format); + if (ExifImageWidth < a) ExifImageWidth = a; + break; + + case TAG_FOCALPLANEXRES: + m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_FOCALPLANEYRES: + m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_RESOLUTIONUNIT: + switch((int)ConvertAnyFormat(ValuePtr, Format)){ + case 1: m_exifinfo->ResolutionUnit = 1.0f; break; /* 1 inch */ + case 2: m_exifinfo->ResolutionUnit = 1.0f; break; + case 3: m_exifinfo->ResolutionUnit = 0.3937007874f; break; /* 1 centimeter*/ + case 4: m_exifinfo->ResolutionUnit = 0.03937007874f; break; /* 1 millimeter*/ + case 5: m_exifinfo->ResolutionUnit = 0.00003937007874f; /* 1 micrometer*/ + } + break; + + case TAG_FOCALPLANEUNITS: + switch((int)ConvertAnyFormat(ValuePtr, Format)){ + case 1: m_exifinfo->FocalplaneUnits = 1.0f; break; /* 1 inch */ + case 2: m_exifinfo->FocalplaneUnits = 1.0f; break; + case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; /* 1 centimeter*/ + case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break; /* 1 millimeter*/ + case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f; /* 1 micrometer*/ + } + break; + + // Remaining cases contributed by: Volker C. Schoech + + case TAG_EXPOSURE_BIAS: + m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_WHITEBALANCE: + m_exifinfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_METERING_MODE: + m_exifinfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXPOSURE_PROGRAM: + m_exifinfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_ISO_EQUIVALENT: + m_exifinfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); + if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200; + break; + + case TAG_COMPRESSION_LEVEL: + m_exifinfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_XRESOLUTION: + m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format); + break; + case TAG_YRESOLUTION: + m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_THUMBNAIL_OFFSET: + ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_THUMBNAIL_LENGTH: + ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); + break; + + } + + if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){ + unsigned char * SubdirStart; + unsigned Offset = Get32u(ValuePtr); + if (Offset>8){ + SubdirStart = OffsetBase + Offset; + if (SubdirStart < OffsetBase || + SubdirStart > OffsetBase+ExifLength){ + strcpy(m_szLastError,"Illegal subdirectory link"); + return false; + } + ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1); + } + continue; + } + } + + + { + /* In addition to linking to subdirectories via exif tags, + there's also a potential link to another directory at the end + of each directory. This has got to be the result of a + committee! + */ + unsigned char * SubdirStart; + unsigned Offset; + Offset = Get16u(DirStart+2+12*NumDirEntries); + if (Offset){ + SubdirStart = OffsetBase + Offset; + if (SubdirStart < OffsetBase + || SubdirStart > OffsetBase+ExifLength){ + strcpy(m_szLastError,"Illegal subdirectory link"); + return false; + } + ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1); + } + } + + + if (ThumbnailSize && ThumbnailOffset){ + if (ThumbnailSize + ThumbnailOffset <= ExifLength){ + /* The thumbnail pointer appears to be valid. Store it. */ + m_exifinfo->ThumbnailPointer = OffsetBase + ThumbnailOffset; + m_exifinfo->ThumbnailSize = ThumbnailSize; + } + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/*-------------------------------------------------------------------------- + Evaluate number, be it int, rational, or float from directory. +--------------------------------------------------------------------------*/ +double CxImageJPG::CxExifInfo::ConvertAnyFormat(void * ValuePtr, int Format) +{ + double Value; + Value = 0; + + switch(Format){ + case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; + case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break; + + case FMT_USHORT: Value = Get16u(ValuePtr); break; + case FMT_ULONG: Value = Get32u(ValuePtr); break; + + case FMT_URATIONAL: + case FMT_SRATIONAL: + { + int Num,Den; + Num = Get32s(ValuePtr); + Den = Get32s(4+(char *)ValuePtr); + if (Den == 0){ + Value = 0; + }else{ + Value = (double)Num/Den; + } + break; + } + + case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; + case FMT_SLONG: Value = Get32s(ValuePtr); break; + + /* Not sure if this is correct (never seen float used in Exif format) + */ + case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; + case FMT_DOUBLE: Value = *(double *)ValuePtr; break; + } + return Value; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageJPG::CxExifInfo::process_COM (const BYTE * Data, int length) +{ + int ch; + char Comment[MAX_COMMENT+1]; + int nch; + int a; + + nch = 0; + + if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure. + + for (a=2;aComments,Comment); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageJPG::CxExifInfo::process_SOFn (const BYTE * Data, int marker) +{ + int data_precision, num_components; + + data_precision = Data[2]; + m_exifinfo->Height = Get16m((void*)(Data+3)); + m_exifinfo->Width = Get16m((void*)(Data+5)); + num_components = Data[7]; + + if (num_components == 3){ + m_exifinfo->IsColor = 1; + }else{ + m_exifinfo->IsColor = 0; + } + + m_exifinfo->Process = marker; + + //if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n", + // ImageInfo.Width, ImageInfo.Height, num_components, data_precision); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * this will work only on a CxImageJPG object, if the image originally has valid EXIF data + \verbatim + CxImageJPG jpg; + CxIOFile in,out; + in.Open("D:\\exif_in.jpg","rb"); + out.Open("D:\\exif_out.jpg","w+b"); + jpg.Decode(&in); + if (jpg.IsValid()){ + jpg.RotateLeft(); + jpg.Encode(&out); + } + \endverbatim +*/ +bool CxImageJPG::CxExifInfo::EncodeExif(CxFile * hFile) +{ + int a; + + if (FindSection(M_SOS)==NULL){ + strcpy(m_szLastError,"Can't write exif : didn't read all"); + return false; + } + + // Initial static jpeg marker. + hFile->PutC(0xff); + hFile->PutC(0xd8); + + if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){ + // The image must start with an exif or jfif marker. If we threw those away, create one. + static BYTE JfifHead[18] = { + 0xff, M_JFIF, + 0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01, + 0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00 + }; + hFile->Write(JfifHead, 18, 1); + } + + // Write all the misc sections + for (a=0;aPutC(0xff); + hFile->PutC((unsigned char)(Sections[a].Type)); + hFile->Write(Sections[a].Data, Sections[a].Size, 1); + } + + // Write the remaining image data. + hFile->Write(Sections[a].Data, Sections[a].Size, 1); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageJPG::CxExifInfo::DiscardAllButExif() +{ + Section_t ExifKeeper; + Section_t CommentKeeper; + int a; + + memset(&ExifKeeper, 0, sizeof(ExifKeeper)); + memset(&CommentKeeper, 0, sizeof(ExifKeeper)); + + for (a=0;a Use it before Create() - */ -void CxImage::CopyInfo(const CxImage &src) -{ - if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO)); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa Copy - */ -CxImage& CxImage::operator = (const CxImage& isrc) -{ - if (this != &isrc) Copy(isrc); - return *this; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Initializes or rebuilds the image. - * \param dwWidth: width - * \param dwHeight: height - * \param wBpp: bit per pixel, can be 1, 4, 8, 24 - * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS - * \return pointer to the internal pDib object; NULL if an error occurs. - */ -void* CxImage::Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype) -{ - // destroy the existing image (if any) - if (!Destroy()) - return NULL; - - // prevent further actions if width or height are not vaild - if ((dwWidth == 0) || (dwHeight == 0)){ - strcpy(info.szLastError,"CxImage::Create : width and height must be greater than zero"); - return NULL; - } - - // Make sure bits per pixel is valid - if (wBpp <= 1) wBpp = 1; - else if (wBpp <= 4) wBpp = 4; - else if (wBpp <= 8) wBpp = 8; - else wBpp = 24; - - // limit memory requirements (and also a check for bad parameters) - if (((dwWidth*dwHeight*wBpp)>>3) > CXIMAGE_MAX_MEMORY || - ((dwWidth*dwHeight*wBpp)/wBpp) != (dwWidth*dwHeight)) - { - strcpy(info.szLastError,"CXIMAGE_MAX_MEMORY exceeded"); - return NULL; - } - - // set the correct bpp value - switch (wBpp){ - case 1: - head.biClrUsed = 2; break; - case 4: - head.biClrUsed = 16; break; - case 8: - head.biClrUsed = 256; break; - default: - head.biClrUsed = 0; - } - - //set the common image informations - info.dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4); - info.dwType = imagetype; - - // initialize BITMAPINFOHEADER - head.biSize = sizeof(BITMAPINFOHEADER); // - head.biWidth = dwWidth; // fill in width from parameter - head.biHeight = dwHeight; // fill in height from parameter - head.biPlanes = 1; // must be 1 - head.biBitCount = (WORD)wBpp; // from parameter - head.biCompression = BI_RGB; - head.biSizeImage = info.dwEffWidth * dwHeight; -// head.biXPelsPerMeter = 0; See SetXDPI -// head.biYPelsPerMeter = 0; See SetYDPI -// head.biClrImportant = 0; See SetClrImportant - - pDib = malloc(GetSize()); // alloc memory block to store our bitmap - if (!pDib){ - strcpy(info.szLastError,"CxImage::Create can't allocate memory"); - return NULL; - } - - //clear the palette - RGBQUAD* pal=GetPalette(); - if (pal) memset(pal,0,GetPaletteSize()); - //Destroy the existing selection -#if CXIMAGE_SUPPORT_SELECTION - if (pSelection) SelectionDelete(); -#endif //CXIMAGE_SUPPORT_SELECTION - //Destroy the existing alpha channel -#if CXIMAGE_SUPPORT_ALPHA - if (pAlpha) AlphaDelete(); -#endif //CXIMAGE_SUPPORT_ALPHA - - // use our bitmap info structure to fill in first part of - // our DIB with the BITMAPINFOHEADER - BITMAPINFOHEADER* lpbi; - lpbi = (BITMAPINFOHEADER*)(pDib); - *lpbi = head; - - info.pImage=GetBits(); - - return pDib; //return handle to the DIB -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return pointer to the image pixels. USE CAREFULLY - */ -BYTE* CxImage::GetBits(DWORD row) -{ - if (pDib){ - if (row) { - if (row<(DWORD)head.biHeight){ - return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize() + (info.dwEffWidth * row)); - } else { - return NULL; - } - } else { - return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize()); - } - } - return NULL; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return the size in bytes of the internal pDib object - */ -long CxImage::GetSize() -{ - return head.biSize + head.biSizeImage + GetPaletteSize(); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Checks if the coordinates are inside the image - * \return true if x and y are both inside the image - */ -bool CxImage::IsInside(long x, long y) -{ - return (0<=y && y 0) bval = 255; - } - if (GetBpp() == 4){ - bval = (BYTE)(17*(0x0F & bval)); - } - - memset(info.pImage,bval,head.biSizeImage); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Transfers the image from an existing source image. The source becomes empty. - * \return true if everything is ok - */ -bool CxImage::Transfer(CxImage &from, bool bTransferFrames /*=true*/) -{ - if (!Destroy()) - return false; - - memcpy(&head,&from.head,sizeof(BITMAPINFOHEADER)); - memcpy(&info,&from.info,sizeof(CXIMAGEINFO)); - - pDib = from.pDib; - pSelection = from.pSelection; - pAlpha = from.pAlpha; - ppLayers = from.ppLayers; - - memset(&from.head,0,sizeof(BITMAPINFOHEADER)); - memset(&from.info,0,sizeof(CXIMAGEINFO)); - from.pDib = from.pSelection = from.pAlpha = NULL; - from.ppLayers = NULL; - - if (bTransferFrames){ - DestroyFrames(); - ppFrames = from.ppFrames; - from.ppFrames = NULL; - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * (this) points to the same pDib owned by (*from), the image remains in (*from) - * but (this) has the access to the pixels. Use carefully !!! - */ -void CxImage::Ghost(const CxImage *from) -{ - if (from){ - memcpy(&head,&from->head,sizeof(BITMAPINFOHEADER)); - memcpy(&info,&from->info,sizeof(CXIMAGEINFO)); - pDib = from->pDib; - pSelection = from->pSelection; - pAlpha = from->pAlpha; - ppLayers = from->ppLayers; - ppFrames = from->ppFrames; - info.pGhost=(CxImage *)from; - } -} -//////////////////////////////////////////////////////////////////////////////// -/** - * turns a 16 or 32 bit bitfield image into a RGB image - */ -void CxImage::Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp) -{ - switch (bpp){ - case 16: - { - DWORD ns[3]={0,0,0}; - // compute the number of shift for each mask - for (int i=0;i<16;i++){ - if ((redmask>>i)&0x01) ns[0]++; - if ((greenmask>>i)&0x01) ns[1]++; - if ((bluemask>>i)&0x01) ns[2]++; - } - ns[1]+=ns[0]; ns[2]+=ns[1]; ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8; - // dword aligned width for 16 bit image - long effwidth2=(((head.biWidth + 1) / 2) * 4); - WORD w; - long y2,y3,x2,x3; - BYTE *p=info.pImage; - // scan the buffer in reverse direction to avoid reallocations - for (long y=head.biHeight-1; y>=0; y--){ - y2=effwidth2*y; - y3=info.dwEffWidth*y; - for (long x=head.biWidth-1; x>=0; x--){ - x2 = 2*x+y2; - x3 = 3*x+y3; - w = (WORD)(src[x2]+256*src[1+x2]); - p[ x3]=(BYTE)((w & bluemask)<>ns[1]); - p[2+x3]=(BYTE)((w & redmask)>>ns[2]); - } - } - break; - } - case 32: - { - DWORD ns[3]={0,0,0}; - // compute the number of shift for each mask - for (int i=8;i<32;i+=8){ - if (redmask>>i) ns[0]++; - if (greenmask>>i) ns[1]++; - if (bluemask>>i) ns[2]++; - } - // dword aligned width for 32 bit image - long effwidth4 = head.biWidth * 4; - long y4,y3,x4,x3; - BYTE *p=info.pImage; - // scan the buffer in reverse direction to avoid reallocations - for (long y=head.biHeight-1; y>=0; y--){ - y4=effwidth4*y; - y3=info.dwEffWidth*y; - for (long x=head.biWidth-1; x>=0; x--){ - x4 = 4*x+y4; - x3 = 3*x+y3; - p[ x3]=src[ns[2]+x4]; - p[1+x3]=src[ns[1]+x4]; - p[2+x3]=src[ns[0]+x4]; - } - } - } - - } - return; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Creates an image from a generic buffer - * \param pArray: source memory buffer - * \param dwWidth: image width - * \param dwHeight: image height - * \param dwBitsperpixel: can be 1,4,8,24,32 - * \param dwBytesperline: line alignment, in bytes, for a single row stored in pArray - * \param bFlipImage: tune this parameter if the image is upsidedown - * \return true if everything is ok - */ -bool CxImage::CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage) -{ - if (pArray==NULL) return false; - if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)|| - (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false; - - if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false; - - if (dwBitsperpixel<24) SetGrayPalette(); - -#if CXIMAGE_SUPPORT_ALPHA - if (dwBitsperpixel==32) AlphaCreate(); -#endif //CXIMAGE_SUPPORT_ALPHA - - BYTE *dst,*src; - - for (DWORD y = 0; yrgbRed,c1->rgbGreen,c1->rgbBlue); - int g2 = (int)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue); - - return (g1-g2); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * simply calls "if (memblock) free(memblock);". - * Useful when calling Encode for a memory buffer, - * from a DLL compiled with different memory management options. - * CxImage::FreeMemory will use the same memory environment used by Encode. - * \author [livecn] - */ -void CxImage::FreeMemory(void* memblock) -{ - if (memblock) - free(memblock); -} -//////////////////////////////////////////////////////////////////////////////// -//EOF +// ximage.cpp : main implementation file +/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +//////////////////////////////////////////////////////////////////////////////// +// CxImage +//////////////////////////////////////////////////////////////////////////////// +/** + * Initialize the internal structures + */ +void CxImage::Startup(DWORD imagetype) +{ + //init pointers + pDib = pSelection = pAlpha = NULL; + ppLayers = ppFrames = NULL; + //init structures + memset(&head,0,sizeof(BITMAPINFOHEADER)); + memset(&info,0,sizeof(CXIMAGEINFO)); + //init default attributes + info.dwType = imagetype; + info.fQuality = 90.0f; + info.nAlphaMax = 255; + info.nBkgndIndex = -1; + info.bEnabled = true; + SetXDPI(CXIMAGE_DEFAULT_DPI); + SetYDPI(CXIMAGE_DEFAULT_DPI); + + short test = 1; + info.bLittleEndianHost = (*((char *) &test) == 1); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Empty image constructor + * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS + */ +CxImage::CxImage(DWORD imagetype) +{ + Startup(imagetype); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Call this function to destroy image pixels, alpha channel, selection and sub layers. + * - Attributes are not erased, but IsValid returns false. + * + * \return true if everything is freed, false if the image is a Ghost + */ +bool CxImage::Destroy() +{ + //free this only if it's valid and it's not a ghost + if (info.pGhost==NULL){ + if (ppLayers) { + for(long n=0; n Use it before Create() + */ +void CxImage::CopyInfo(const CxImage &src) +{ + if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO)); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa Copy + */ +CxImage& CxImage::operator = (const CxImage& isrc) +{ + if (this != &isrc) Copy(isrc); + return *this; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Initializes or rebuilds the image. + * \param dwWidth: width + * \param dwHeight: height + * \param wBpp: bit per pixel, can be 1, 4, 8, 24 + * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS + * \return pointer to the internal pDib object; NULL if an error occurs. + */ +void* CxImage::Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype) +{ + // destroy the existing image (if any) + if (!Destroy()) + return NULL; + + // prevent further actions if width or height are not vaild + if ((dwWidth == 0) || (dwHeight == 0)){ + strcpy(info.szLastError,"CxImage::Create : width and height must be greater than zero"); + return NULL; + } + + // Make sure bits per pixel is valid + if (wBpp <= 1) wBpp = 1; + else if (wBpp <= 4) wBpp = 4; + else if (wBpp <= 8) wBpp = 8; + else wBpp = 24; + + // limit memory requirements (and also a check for bad parameters) + if (((dwWidth*dwHeight*wBpp)>>3) > CXIMAGE_MAX_MEMORY || + ((dwWidth*dwHeight*wBpp)/wBpp) != (dwWidth*dwHeight)) + { + strcpy(info.szLastError,"CXIMAGE_MAX_MEMORY exceeded"); + return NULL; + } + + // set the correct bpp value + switch (wBpp){ + case 1: + head.biClrUsed = 2; break; + case 4: + head.biClrUsed = 16; break; + case 8: + head.biClrUsed = 256; break; + default: + head.biClrUsed = 0; + } + + //set the common image informations + info.dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4); + info.dwType = imagetype; + + // initialize BITMAPINFOHEADER + head.biSize = sizeof(BITMAPINFOHEADER); // + head.biWidth = dwWidth; // fill in width from parameter + head.biHeight = dwHeight; // fill in height from parameter + head.biPlanes = 1; // must be 1 + head.biBitCount = (WORD)wBpp; // from parameter + head.biCompression = BI_RGB; + head.biSizeImage = info.dwEffWidth * dwHeight; +// head.biXPelsPerMeter = 0; See SetXDPI +// head.biYPelsPerMeter = 0; See SetYDPI +// head.biClrImportant = 0; See SetClrImportant + + pDib = malloc(GetSize()); // alloc memory block to store our bitmap + if (!pDib){ + strcpy(info.szLastError,"CxImage::Create can't allocate memory"); + return NULL; + } + + //clear the palette + RGBQUAD* pal=GetPalette(); + if (pal) memset(pal,0,GetPaletteSize()); + //Destroy the existing selection +#if CXIMAGE_SUPPORT_SELECTION + if (pSelection) SelectionDelete(); +#endif //CXIMAGE_SUPPORT_SELECTION + //Destroy the existing alpha channel +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha) AlphaDelete(); +#endif //CXIMAGE_SUPPORT_ALPHA + + // use our bitmap info structure to fill in first part of + // our DIB with the BITMAPINFOHEADER + BITMAPINFOHEADER* lpbi; + lpbi = (BITMAPINFOHEADER*)(pDib); + *lpbi = head; + + info.pImage=GetBits(); + + return pDib; //return handle to the DIB +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return pointer to the image pixels. USE CAREFULLY + */ +BYTE* CxImage::GetBits(DWORD row) +{ + if (pDib){ + if (row) { + if (row<(DWORD)head.biHeight){ + return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize() + (info.dwEffWidth * row)); + } else { + return NULL; + } + } else { + return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize()); + } + } + return NULL; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return the size in bytes of the internal pDib object + */ +long CxImage::GetSize() +{ + return head.biSize + head.biSizeImage + GetPaletteSize(); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Checks if the coordinates are inside the image + * \return true if x and y are both inside the image + */ +bool CxImage::IsInside(long x, long y) +{ + return (0<=y && y 0) bval = 255; + } + if (GetBpp() == 4){ + bval = (BYTE)(17*(0x0F & bval)); + } + + memset(info.pImage,bval,head.biSizeImage); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Transfers the image from an existing source image. The source becomes empty. + * \return true if everything is ok + */ +bool CxImage::Transfer(CxImage &from, bool bTransferFrames /*=true*/) +{ + if (!Destroy()) + return false; + + memcpy(&head,&from.head,sizeof(BITMAPINFOHEADER)); + memcpy(&info,&from.info,sizeof(CXIMAGEINFO)); + + pDib = from.pDib; + pSelection = from.pSelection; + pAlpha = from.pAlpha; + ppLayers = from.ppLayers; + + memset(&from.head,0,sizeof(BITMAPINFOHEADER)); + memset(&from.info,0,sizeof(CXIMAGEINFO)); + from.pDib = from.pSelection = from.pAlpha = NULL; + from.ppLayers = NULL; + + if (bTransferFrames){ + DestroyFrames(); + ppFrames = from.ppFrames; + from.ppFrames = NULL; + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * (this) points to the same pDib owned by (*from), the image remains in (*from) + * but (this) has the access to the pixels. Use carefully !!! + */ +void CxImage::Ghost(const CxImage *from) +{ + if (from){ + memcpy(&head,&from->head,sizeof(BITMAPINFOHEADER)); + memcpy(&info,&from->info,sizeof(CXIMAGEINFO)); + pDib = from->pDib; + pSelection = from->pSelection; + pAlpha = from->pAlpha; + ppLayers = from->ppLayers; + ppFrames = from->ppFrames; + info.pGhost=(CxImage *)from; + } +} +//////////////////////////////////////////////////////////////////////////////// +/** + * turns a 16 or 32 bit bitfield image into a RGB image + */ +void CxImage::Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp) +{ + switch (bpp){ + case 16: + { + DWORD ns[3]={0,0,0}; + // compute the number of shift for each mask + for (int i=0;i<16;i++){ + if ((redmask>>i)&0x01) ns[0]++; + if ((greenmask>>i)&0x01) ns[1]++; + if ((bluemask>>i)&0x01) ns[2]++; + } + ns[1]+=ns[0]; ns[2]+=ns[1]; ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8; + // dword aligned width for 16 bit image + long effwidth2=(((head.biWidth + 1) / 2) * 4); + WORD w; + long y2,y3,x2,x3; + BYTE *p=info.pImage; + // scan the buffer in reverse direction to avoid reallocations + for (long y=head.biHeight-1; y>=0; y--){ + y2=effwidth2*y; + y3=info.dwEffWidth*y; + for (long x=head.biWidth-1; x>=0; x--){ + x2 = 2*x+y2; + x3 = 3*x+y3; + w = (WORD)(src[x2]+256*src[1+x2]); + p[ x3]=(BYTE)((w & bluemask)<>ns[1]); + p[2+x3]=(BYTE)((w & redmask)>>ns[2]); + } + } + break; + } + case 32: + { + DWORD ns[3]={0,0,0}; + // compute the number of shift for each mask + for (int i=8;i<32;i+=8){ + if (redmask>>i) ns[0]++; + if (greenmask>>i) ns[1]++; + if (bluemask>>i) ns[2]++; + } + // dword aligned width for 32 bit image + long effwidth4 = head.biWidth * 4; + long y4,y3,x4,x3; + BYTE *p=info.pImage; + // scan the buffer in reverse direction to avoid reallocations + for (long y=head.biHeight-1; y>=0; y--){ + y4=effwidth4*y; + y3=info.dwEffWidth*y; + for (long x=head.biWidth-1; x>=0; x--){ + x4 = 4*x+y4; + x3 = 3*x+y3; + p[ x3]=src[ns[2]+x4]; + p[1+x3]=src[ns[1]+x4]; + p[2+x3]=src[ns[0]+x4]; + } + } + } + + } + return; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Creates an image from a generic buffer + * \param pArray: source memory buffer + * \param dwWidth: image width + * \param dwHeight: image height + * \param dwBitsperpixel: can be 1,4,8,24,32 + * \param dwBytesperline: line alignment, in bytes, for a single row stored in pArray + * \param bFlipImage: tune this parameter if the image is upsidedown + * \return true if everything is ok + */ +bool CxImage::CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage) +{ + if (pArray==NULL) return false; + if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)|| + (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false; + + if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false; + + if (dwBitsperpixel<24) SetGrayPalette(); + +#if CXIMAGE_SUPPORT_ALPHA + if (dwBitsperpixel==32) AlphaCreate(); +#endif //CXIMAGE_SUPPORT_ALPHA + + BYTE *dst,*src; + + for (DWORD y = 0; yrgbRed,c1->rgbGreen,c1->rgbBlue); + int g2 = (int)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue); + + return (g1-g2); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * simply calls "if (memblock) free(memblock);". + * Useful when calling Encode for a memory buffer, + * from a DLL compiled with different memory management options. + * CxImage::FreeMemory will use the same memory environment used by Encode. + * \author [livecn] + */ +void CxImage::FreeMemory(void* memblock) +{ + if (memblock) + free(memblock); +} +//////////////////////////////////////////////////////////////////////////////// +//EOF diff --git a/utilities/CxImage/ximage.h b/utilities/CxImage/ximage.h index 80ea914..17d6b9a 100644 --- a/utilities/CxImage/ximage.h +++ b/utilities/CxImage/ximage.h @@ -1,735 +1,735 @@ -/* - * File: ximage.h - * Purpose: General Purpose Image Class - */ -/* - -------------------------------------------------------------------------------- - - COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: - - CxImage version 6.0.0 02/Feb/2008 - - CxImage : Copyright (C) 2001 - 2008, Davide Pizzolato - - Original CImage and CImageIterator implementation are: - Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx) - - Covered code is provided under this license on an "as is" basis, without warranty - of any kind, either expressed or implied, including, without limitation, warranties - that the covered code is free of defects, merchantable, fit for a particular purpose - or non-infringing. The entire risk as to the quality and performance of the covered - code is with you. Should any covered code prove defective in any respect, you (not - the initial developer or any other contributor) assume the cost of any necessary - servicing, repair or correction. This disclaimer of warranty constitutes an essential - part of this license. No use of any covered code is authorized hereunder except under - this disclaimer. - - Permission is hereby granted to use, copy, modify, and distribute this - source code, or portions hereof, for any purpose, including commercial applications, - freely and without fee, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source distribution. - - -------------------------------------------------------------------------------- - - Other information about CxImage, and the latest version, can be found at the - CxImage home page: http://www.xdp.it/cximage/ - - -------------------------------------------------------------------------------- - */ -#if !defined(__CXIMAGE_H) -#define __CXIMAGE_H - -#if _MSC_VER > 1000 -#pragma once -#endif - -///////////////////////////////////////////////////////////////////////////// -#include "xfile.h" -#include "xiofile.h" -#include "xmemfile.h" -#include "ximadef.h" // adjust some #define - -/* see "ximacfg.h" for CxImage configuration options */ - -///////////////////////////////////////////////////////////////////////////// -// CxImage formats enumerator -enum ENUM_CXIMAGE_FORMATS{ -CXIMAGE_FORMAT_UNKNOWN = 0, -#if CXIMAGE_SUPPORT_BMP -CXIMAGE_FORMAT_BMP = 1, -#endif -#if CXIMAGE_SUPPORT_GIF -CXIMAGE_FORMAT_GIF = 2, -#endif -#if CXIMAGE_SUPPORT_JPG -CXIMAGE_FORMAT_JPG = 3, -#endif -#if CXIMAGE_SUPPORT_PNG -CXIMAGE_FORMAT_PNG = 4, -#endif -#if CXIMAGE_SUPPORT_ICO -CXIMAGE_FORMAT_ICO = 5, -#endif -#if CXIMAGE_SUPPORT_TIF -CXIMAGE_FORMAT_TIF = 6, -#endif -#if CXIMAGE_SUPPORT_TGA -CXIMAGE_FORMAT_TGA = 7, -#endif -#if CXIMAGE_SUPPORT_PCX -CXIMAGE_FORMAT_PCX = 8, -#endif -#if CXIMAGE_SUPPORT_WBMP -CXIMAGE_FORMAT_WBMP = 9, -#endif -#if CXIMAGE_SUPPORT_WMF -CXIMAGE_FORMAT_WMF = 10, -#endif -#if CXIMAGE_SUPPORT_JP2 -CXIMAGE_FORMAT_JP2 = 11, -#endif -#if CXIMAGE_SUPPORT_JPC -CXIMAGE_FORMAT_JPC = 12, -#endif -#if CXIMAGE_SUPPORT_PGX -CXIMAGE_FORMAT_PGX = 13, -#endif -#if CXIMAGE_SUPPORT_PNM -CXIMAGE_FORMAT_PNM = 14, -#endif -#if CXIMAGE_SUPPORT_RAS -CXIMAGE_FORMAT_RAS = 15, -#endif -#if CXIMAGE_SUPPORT_JBG -CXIMAGE_FORMAT_JBG = 16, -#endif -#if CXIMAGE_SUPPORT_MNG -CXIMAGE_FORMAT_MNG = 17, -#endif -#if CXIMAGE_SUPPORT_SKA -CXIMAGE_FORMAT_SKA = 18, -#endif -#if CXIMAGE_SUPPORT_RAW -CXIMAGE_FORMAT_RAW = 19, -#endif -CMAX_IMAGE_FORMATS = CXIMAGE_SUPPORT_BMP + CXIMAGE_SUPPORT_GIF + CXIMAGE_SUPPORT_JPG + - CXIMAGE_SUPPORT_PNG + CXIMAGE_SUPPORT_MNG + CXIMAGE_SUPPORT_ICO + - CXIMAGE_SUPPORT_TIF + CXIMAGE_SUPPORT_TGA + CXIMAGE_SUPPORT_PCX + - CXIMAGE_SUPPORT_WBMP+ CXIMAGE_SUPPORT_WMF + - CXIMAGE_SUPPORT_JBG + CXIMAGE_SUPPORT_JP2 + CXIMAGE_SUPPORT_JPC + - CXIMAGE_SUPPORT_PGX + CXIMAGE_SUPPORT_PNM + CXIMAGE_SUPPORT_RAS + - CXIMAGE_SUPPORT_SKA + CXIMAGE_SUPPORT_RAW + 1 -}; - -///////////////////////////////////////////////////////////////////////////// -// CxImage class -///////////////////////////////////////////////////////////////////////////// -class DLL_EXP CxImage -{ -//extensible information collector -typedef struct tagCxImageInfo { - DWORD dwEffWidth; ///< DWORD aligned scan line width - BYTE* pImage; ///< THE IMAGE BITS - CxImage* pGhost; ///< if this is a ghost, pGhost points to the body - CxImage* pParent; ///< if this is a layer, pParent points to the body - DWORD dwType; ///< original image format - char szLastError[256]; ///< debugging - long nProgress; ///< monitor - long nEscape; ///< escape - long nBkgndIndex; ///< used for GIF, PNG, MNG - RGBQUAD nBkgndColor; ///< used for RGB transparency - float fQuality; ///< used for JPEG, JPEG2000 (0.0f ... 100.0f) - BYTE nJpegScale; ///< used for JPEG [ignacio] - long nFrame; ///< used for TIF, GIF, MNG : actual frame - long nNumFrames; ///< used for TIF, GIF, MNG : total number of frames - DWORD dwFrameDelay; ///< used for GIF, MNG - long xDPI; ///< horizontal resolution - long yDPI; ///< vertical resolution - RECT rSelectionBox; ///< bounding rectangle - BYTE nAlphaMax; ///< max opacity (fade) - bool bAlphaPaletteEnabled; ///< true if alpha values in the palette are enabled. - bool bEnabled; ///< enables the painting functions - long xOffset; - long yOffset; - DWORD dwCodecOpt[CMAX_IMAGE_FORMATS]; ///< for GIF, TIF : 0=def.1=unc,2=fax3,3=fax4,4=pack,5=jpg - RGBQUAD last_c; ///< for GetNearestIndex optimization - BYTE last_c_index; - bool last_c_isvalid; - long nNumLayers; - DWORD dwFlags; ///< 0x??00000 = reserved, 0x00??0000 = blend mode, 0x0000???? = layer id - user flags - BYTE dispmeth; - bool bGetAllFrames; - bool bLittleEndianHost; - -} CXIMAGEINFO; - -public: - //public structures -struct rgb_color { BYTE r,g,b; }; - -#if CXIMAGE_SUPPORT_WINDOWS -// text placement data -// members must be initialized with the InitTextInfo(&this) function. -typedef struct tagCxTextInfo -{ -#if defined (_WIN32_WCE) - TCHAR text[256]; ///< text for windows CE -#else - TCHAR text[4096]; ///< text (char -> TCHAR for UNICODE [Cesar M]) -#endif - LOGFONT lfont; ///< font and codepage data - COLORREF fcolor; ///< foreground color - long align; ///< DT_CENTER, DT_RIGHT, DT_LEFT aligment for multiline text - BYTE smooth; ///< text smoothing option. Default is false. - BYTE opaque; ///< text has background or hasn't. Default is true. - ///< data for background (ignored if .opaque==FALSE) - COLORREF bcolor; ///< background color - float b_opacity; ///< opacity value for background between 0.0-1.0 Default is 0. (opaque) - BYTE b_outline; ///< outline width for background (zero: no outline) - BYTE b_round; ///< rounding radius for background rectangle. % of the height, between 0-50. Default is 10. - ///< (backgr. always has a frame: width = 3 pixel + 10% of height by default.) -} CXTEXTINFO; -#endif - -public: -/** \addtogroup Constructors */ //@{ - CxImage(DWORD imagetype = 0); - CxImage(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype = 0); - CxImage(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true); - CxImage(const TCHAR * filename, DWORD imagetype); // For UNICODE support: char -> TCHAR - CxImage(FILE * stream, DWORD imagetype); - CxImage(CxFile * stream, DWORD imagetype); - CxImage(BYTE * buffer, DWORD size, DWORD imagetype); - virtual ~CxImage() { DestroyFrames(); Destroy(); }; - CxImage& operator = (const CxImage&); -//@} - -/** \addtogroup Initialization */ //@{ - void* Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype = 0); - bool Destroy(); - bool DestroyFrames(); - void Clear(BYTE bval=0); - void Copy(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true); - bool Transfer(CxImage &from, bool bTransferFrames = true); - bool CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage); - bool CreateFromMatrix(BYTE** ppMatrix,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage); - void FreeMemory(void* memblock); - - DWORD Dump(BYTE * dst); - DWORD UnDump(const BYTE * src); - DWORD DumpSize(); - -//@} - -/** \addtogroup Attributes */ //@{ - long GetSize(); - BYTE* GetBits(DWORD row = 0); - BYTE GetColorType(); - void* GetDIB() const; - DWORD GetHeight() const; - DWORD GetWidth() const; - DWORD GetEffWidth() const; - DWORD GetNumColors() const; - WORD GetBpp() const; - DWORD GetType() const; - const char* GetLastError(); - static const TCHAR* GetVersion(); - static const float GetVersionNumber(); - - DWORD GetFrameDelay() const; - void SetFrameDelay(DWORD d); - - void GetOffset(long *x,long *y); - void SetOffset(long x,long y); - - BYTE GetJpegQuality() const; - void SetJpegQuality(BYTE q); - float GetJpegQualityF() const; - void SetJpegQualityF(float q); - - BYTE GetJpegScale() const; - void SetJpegScale(BYTE q); - - long GetXDPI() const; - long GetYDPI() const; - void SetXDPI(long dpi); - void SetYDPI(long dpi); - - DWORD GetClrImportant() const; - void SetClrImportant(DWORD ncolors = 0); - - long GetProgress() const; - long GetEscape() const; - void SetProgress(long p); - void SetEscape(long i); - - long GetTransIndex() const; - RGBQUAD GetTransColor(); - void SetTransIndex(long idx); - void SetTransColor(RGBQUAD rgb); - bool IsTransparent() const; - - DWORD GetCodecOption(DWORD imagetype = 0); - bool SetCodecOption(DWORD opt, DWORD imagetype = 0); - - DWORD GetFlags() const; - void SetFlags(DWORD flags, bool bLockReservedFlags = true); - - BYTE GetDisposalMethod() const; - void SetDisposalMethod(BYTE dm); - - bool SetType(DWORD type); - - static DWORD GetNumTypes(); - static DWORD GetTypeIdFromName(const TCHAR* ext); - static DWORD GetTypeIdFromIndex(const DWORD index); - static DWORD GetTypeIndexFromId(const DWORD id); - - bool GetRetreiveAllFrames() const; - void SetRetreiveAllFrames(bool flag); - CxImage * GetFrame(long nFrame) const; - - //void* GetUserData() const {return info.pUserData;} - //void SetUserData(void* pUserData) {info.pUserData = pUserData;} -//@} - -/** \addtogroup Palette - * These functions have no effects on RGB images and in this case the returned value is always 0. - * @{ */ - bool IsGrayScale(); - bool IsIndexed() const; - bool IsSamePalette(CxImage &img, bool bCheckAlpha = true); - DWORD GetPaletteSize(); - RGBQUAD* GetPalette() const; - RGBQUAD GetPaletteColor(BYTE idx); - bool GetPaletteColor(BYTE i, BYTE* r, BYTE* g, BYTE* b); - BYTE GetNearestIndex(RGBQUAD c); - void BlendPalette(COLORREF cr,long perc); - void SetGrayPalette(); - void SetPalette(DWORD n, BYTE *r, BYTE *g, BYTE *b); - void SetPalette(RGBQUAD* pPal,DWORD nColors=256); - void SetPalette(rgb_color *rgb,DWORD nColors=256); - void SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha=0); - void SetPaletteColor(BYTE idx, RGBQUAD c); - void SetPaletteColor(BYTE idx, COLORREF cr); - void SwapIndex(BYTE idx1, BYTE idx2); - void SwapRGB2BGR(); - void SetStdPalette(); -//@} - -/** \addtogroup Pixel */ //@{ - bool IsInside(long x, long y); - bool IsTransparent(long x,long y); - bool GetTransparentMask(CxImage* iDst = 0); - RGBQUAD GetPixelColor(long x,long y, bool bGetAlpha = true); - BYTE GetPixelIndex(long x,long y); - BYTE GetPixelGray(long x, long y); - void SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha = false); - void SetPixelColor(long x,long y,COLORREF cr); - void SetPixelIndex(long x,long y,BYTE i); - void DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha=false); - void DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr); - void BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha = false); -//@} - -protected: -/** \addtogroup Protected */ //@{ - BYTE BlindGetPixelIndex(const long x,const long y); - RGBQUAD BlindGetPixelColor(const long x,const long y, bool bGetAlpha = true); - void *BlindGetPixelPointer(const long x,const long y); - void BlindSetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha = false); - void BlindSetPixelIndex(long x,long y,BYTE i); -//@} - -public: - -#if CXIMAGE_SUPPORT_INTERPOLATION -/** \addtogroup Interpolation */ //@{ - //overflow methods: - enum OverflowMethod { - OM_COLOR=1, - OM_BACKGROUND=2, - OM_TRANSPARENT=3, - OM_WRAP=4, - OM_REPEAT=5, - OM_MIRROR=6 - }; - void OverflowCoordinates(float &x, float &y, OverflowMethod const ofMethod); - void OverflowCoordinates(long &x, long &y, OverflowMethod const ofMethod); - RGBQUAD GetPixelColorWithOverflow(long x, long y, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0); - //interpolation methods: - enum InterpolationMethod { - IM_NEAREST_NEIGHBOUR=1, - IM_BILINEAR =2, - IM_BSPLINE =3, - IM_BICUBIC =4, - IM_BICUBIC2 =5, - IM_LANCZOS =6, - IM_BOX =7, - IM_HERMITE =8, - IM_HAMMING =9, - IM_SINC =10, - IM_BLACKMAN =11, - IM_BESSEL =12, - IM_GAUSSIAN =13, - IM_QUADRATIC =14, - IM_MITCHELL =15, - IM_CATROM =16, - IM_HANNING =17, - IM_POWER =18 - }; - RGBQUAD GetPixelColorInterpolated(float x,float y, InterpolationMethod const inMethod=IM_BILINEAR, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0); - RGBQUAD GetAreaColorInterpolated(float const xc, float const yc, float const w, float const h, InterpolationMethod const inMethod, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0); -//@} - -protected: -/** \addtogroup Protected */ //@{ - void AddAveragingCont(RGBQUAD const &color, float const surf, float &rr, float &gg, float &bb, float &aa); -//@} - -/** \addtogroup Kernels */ //@{ -public: - static float KernelBSpline(const float x); - static float KernelLinear(const float t); - static float KernelCubic(const float t); - static float KernelGeneralizedCubic(const float t, const float a=-1); - static float KernelLanczosSinc(const float t, const float r = 3); - static float KernelBox(const float x); - static float KernelHermite(const float x); - static float KernelHamming(const float x); - static float KernelSinc(const float x); - static float KernelBlackman(const float x); - static float KernelBessel_J1(const float x); - static float KernelBessel_P1(const float x); - static float KernelBessel_Q1(const float x); - static float KernelBessel_Order1(float x); - static float KernelBessel(const float x); - static float KernelGaussian(const float x); - static float KernelQuadratic(const float x); - static float KernelMitchell(const float x); - static float KernelCatrom(const float x); - static float KernelHanning(const float x); - static float KernelPower(const float x, const float a = 2); -//@} -#endif //CXIMAGE_SUPPORT_INTERPOLATION - -/** \addtogroup Painting */ //@{ -#if CXIMAGE_SUPPORT_WINDOWS - long Blt(HDC pDC, long x=0, long y=0); - HBITMAP MakeBitmap(HDC hdc = NULL); - HANDLE CopyToHandle(); - bool CreateFromHANDLE(HANDLE hMem); //Windows objects (clipboard) - bool CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal=0); //Windows resource - bool CreateFromHICON(HICON hico); - long Draw(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1, RECT* pClipRect = 0, bool bSmooth = false); - long Draw(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false); - long Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop = SRCCOPY); - long Stretch(HDC hdc, const RECT& rect, DWORD dwRop = SRCCOPY); - long Tile(HDC hdc, RECT *rc); - long Draw2(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1); - long Draw2(HDC hdc, const RECT& rect); - //long DrawString(HDC hdc, long x, long y, const char* text, RGBQUAD color, const char* font, long lSize=0, long lWeight=400, BYTE bItalic=0, BYTE bUnderline=0, bool bSetAlpha=false); - long DrawString(HDC hdc, long x, long y, const TCHAR* text, RGBQUAD color, const TCHAR* font, long lSize=0, long lWeight=400, BYTE bItalic=0, BYTE bUnderline=0, bool bSetAlpha=false); - // extensions - long DrawStringEx(HDC hdc, long x, long y, CXTEXTINFO *pTextType, bool bSetAlpha=false ); - void InitTextInfo( CXTEXTINFO *txt ); -#endif //CXIMAGE_SUPPORT_WINDOWS -//@} - - // file operations -#if CXIMAGE_SUPPORT_DECODE -/** \addtogroup Decode */ //@{ -#ifdef WIN32 - //bool Load(LPCWSTR filename, DWORD imagetype=0); - bool LoadResource(HRSRC hRes, DWORD imagetype, HMODULE hModule=NULL); -#endif - // For UNICODE support: char -> TCHAR - bool Load(const TCHAR* filename, DWORD imagetype=0); - //bool Load(const char * filename, DWORD imagetype=0); - bool Decode(FILE * hFile, DWORD imagetype); - bool Decode(CxFile * hFile, DWORD imagetype); - bool Decode(BYTE * buffer, DWORD size, DWORD imagetype); - - bool CheckFormat(CxFile * hFile, DWORD imagetype = 0); - bool CheckFormat(BYTE * buffer, DWORD size, DWORD imagetype = 0); -//@} -#endif //CXIMAGE_SUPPORT_DECODE - -#if CXIMAGE_SUPPORT_ENCODE -protected: -/** \addtogroup Protected */ //@{ - bool EncodeSafeCheck(CxFile *hFile); -//@} - -public: -/** \addtogroup Encode */ //@{ -#ifdef WIN32 - //bool Save(LPCWSTR filename, DWORD imagetype=0); -#endif - // For UNICODE support: char -> TCHAR - bool Save(const TCHAR* filename, DWORD imagetype); - //bool Save(const char * filename, DWORD imagetype=0); - bool Encode(FILE * hFile, DWORD imagetype); - bool Encode(CxFile * hFile, DWORD imagetype); - bool Encode(CxFile * hFile, CxImage ** pImages, int pagecount, DWORD imagetype); - bool Encode(FILE *hFile, CxImage ** pImages, int pagecount, DWORD imagetype); - bool Encode(BYTE * &buffer, long &size, DWORD imagetype); - - bool Encode2RGBA(CxFile *hFile, bool bFlipY = false); - bool Encode2RGBA(BYTE * &buffer, long &size, bool bFlipY = false); -//@} -#endif //CXIMAGE_SUPPORT_ENCODE - -/** \addtogroup Attributes */ //@{ - //misc. - bool IsValid() const; - bool IsEnabled() const; - void Enable(bool enable=true); - - // frame operations - long GetNumFrames() const; - long GetFrame() const; - void SetFrame(long nFrame); -//@} - -#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS -/** \addtogroup BasicTransformations */ //@{ - bool GrayScale(); - bool Flip(bool bFlipSelection = false, bool bFlipAlpha = true); - bool Mirror(bool bMirrorSelection = false, bool bMirrorAlpha = true); - bool Negative(); - bool RotateLeft(CxImage* iDst = NULL); - bool RotateRight(CxImage* iDst = NULL); -//@} -#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS - -#if CXIMAGE_SUPPORT_TRANSFORMATION -/** \addtogroup Transformations */ //@{ - // image operations - bool Rotate(float angle, CxImage* iDst = NULL); - bool Rotate2(float angle, CxImage *iDst = NULL, InterpolationMethod inMethod=IM_BILINEAR, - OverflowMethod ofMethod=OM_BACKGROUND, RGBQUAD *replColor=0, - bool const optimizeRightAngles=true, bool const bKeepOriginalSize=false); - bool Rotate180(CxImage* iDst = NULL); - bool Resample(long newx, long newy, int mode = 1, CxImage* iDst = NULL); - bool Resample2(long newx, long newy, InterpolationMethod const inMethod=IM_BICUBIC2, - OverflowMethod const ofMethod=OM_REPEAT, CxImage* const iDst = NULL, - bool const disableAveraging=false); - bool DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal = 0, DWORD clrimportant = 0); - bool IncreaseBpp(DWORD nbit); - bool Dither(long method = 0); - bool Crop(long left, long top, long right, long bottom, CxImage* iDst = NULL); - bool Crop(const RECT& rect, CxImage* iDst = NULL); - bool CropRotatedRectangle( long topx, long topy, long width, long height, float angle, CxImage* iDst = NULL); - bool Skew(float xgain, float ygain, long xpivot=0, long ypivot=0, bool bEnableInterpolation = false); - bool Expand(long left, long top, long right, long bottom, RGBQUAD canvascolor, CxImage* iDst = 0); - bool Expand(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst = 0); - bool Thumbnail(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst = 0); - bool CircleTransform(int type,long rmax=0,float Koeff=1.0f); - bool RedEyeRemove(float strength = 0.8f); - bool QIShrink(long newx, long newy, CxImage* const iDst = NULL, bool bChangeBpp = false); - -//@} -#endif //CXIMAGE_SUPPORT_TRANSFORMATION - -#if CXIMAGE_SUPPORT_DSP -/** \addtogroup DSP */ //@{ - bool Contour(); - bool HistogramStretch(long method = 0, double threshold = 0); - bool HistogramEqualize(); - bool HistogramNormalize(); - bool HistogramRoot(); - bool HistogramLog(); - long Histogram(long* red, long* green = 0, long* blue = 0, long* gray = 0, long colorspace = 0); - bool Jitter(long radius=2); - bool Repair(float radius = 0.25f, long niterations = 1, long colorspace = 0); - bool Combine(CxImage* r,CxImage* g,CxImage* b,CxImage* a, long colorspace = 0); - bool FFT2(CxImage* srcReal, CxImage* srcImag, CxImage* dstReal, CxImage* dstImag, long direction = 1, bool bForceFFT = true, bool bMagnitude = true); - bool Noise(long level); - bool Median(long Ksize=3); - bool Gamma(float gamma); - bool GammaRGB(float gammaR, float gammaG, float gammaB); - bool ShiftRGB(long r, long g, long b); - bool Threshold(BYTE level); - bool Threshold(CxImage* pThresholdMask); - bool Threshold2(BYTE level, bool bDirection, RGBQUAD nBkgndColor, bool bSetAlpha = false); - bool Colorize(BYTE hue, BYTE sat, float blend = 1.0f); - bool Light(long brightness, long contrast = 0); - float Mean(); - bool Filter(long* kernel, long Ksize, long Kfactor, long Koffset); - bool Erode(long Ksize=2); - bool Dilate(long Ksize=2); - bool Edge(long Ksize=2); - void HuePalette(float correction=1); - enum ImageOpType { OpAdd, OpAnd, OpXor, OpOr, OpMask, OpSrcCopy, OpDstCopy, OpSub, OpSrcBlend, OpScreen, OpAvg }; - void Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset = 0, long lYOffset = 0, bool bMixAlpha = false); - void MixFrom(CxImage & imagesrc2, long lXOffset, long lYOffset); - bool UnsharpMask(float radius = 5.0f, float amount = 0.5f, int threshold = 0); - bool Lut(BYTE* pLut); - bool Lut(BYTE* pLutR, BYTE* pLutG, BYTE* pLutB, BYTE* pLutA = 0); - bool GaussianBlur(float radius = 1.0f, CxImage* iDst = 0); - bool TextBlur(BYTE threshold = 100, BYTE decay = 2, BYTE max_depth = 5, bool bBlurHorizontal = true, bool bBlurVertical = true, CxImage* iDst = 0); - bool SelectiveBlur(float radius = 1.0f, BYTE threshold = 25, CxImage* iDst = 0); - bool Solarize(BYTE level = 128, bool bLinkedChannels = true); - bool FloodFill(const long xStart, const long yStart, const RGBQUAD cFillColor, const BYTE tolerance = 0, - BYTE nOpacity = 255, const bool bSelectFilledArea = false, const BYTE nSelectionLevel = 255); - bool Saturate(const long saturation, const long colorspace = 1); - bool ConvertColorSpace(const long dstColorSpace, const long srcColorSpace); - int OptimalThreshold(long method = 0, RECT * pBox = 0, CxImage* pContrastMask = 0); - bool AdaptiveThreshold(long method = 0, long nBoxSize = 64, CxImage* pContrastMask = 0, long nBias = 0, float fGlobalLocalBalance = 0.5f); - -//@} - -protected: -/** \addtogroup Protected */ //@{ - bool IsPowerof2(long x); - bool FFT(int dir,int m,double *x,double *y); - bool DFT(int dir,long m,double *x1,double *y1,double *x2,double *y2); - bool RepairChannel(CxImage *ch, float radius); - // - int gen_convolve_matrix (float radius, float **cmatrix_p); - float* gen_lookup_table (float *cmatrix, int cmatrix_length); - void blur_line (float *ctable, float *cmatrix, int cmatrix_length, BYTE* cur_col, BYTE* dest_col, int y, long bytes); - void blur_text (BYTE threshold, BYTE decay, BYTE max_depth, CxImage* iSrc, CxImage* iDst, BYTE bytes); -//@} - -public: -/** \addtogroup ColorSpace */ //@{ - bool SplitRGB(CxImage* r,CxImage* g,CxImage* b); - bool SplitYUV(CxImage* y,CxImage* u,CxImage* v); - bool SplitHSL(CxImage* h,CxImage* s,CxImage* l); - bool SplitYIQ(CxImage* y,CxImage* i,CxImage* q); - bool SplitXYZ(CxImage* x,CxImage* y,CxImage* z); - bool SplitCMYK(CxImage* c,CxImage* m,CxImage* y,CxImage* k); - static RGBQUAD HSLtoRGB(COLORREF cHSLColor); - static RGBQUAD RGBtoHSL(RGBQUAD lRGBColor); - static RGBQUAD HSLtoRGB(RGBQUAD lHSLColor); - static RGBQUAD YUVtoRGB(RGBQUAD lYUVColor); - static RGBQUAD RGBtoYUV(RGBQUAD lRGBColor); - static RGBQUAD YIQtoRGB(RGBQUAD lYIQColor); - static RGBQUAD RGBtoYIQ(RGBQUAD lRGBColor); - static RGBQUAD XYZtoRGB(RGBQUAD lXYZColor); - static RGBQUAD RGBtoXYZ(RGBQUAD lRGBColor); -#endif //CXIMAGE_SUPPORT_DSP - static RGBQUAD RGBtoRGBQUAD(COLORREF cr); - static COLORREF RGBQUADtoRGB (RGBQUAD c); -//@} - -#if CXIMAGE_SUPPORT_SELECTION -/** \addtogroup Selection */ //@{ - bool SelectionClear(BYTE level = 0); - bool SelectionCreate(); - bool SelectionDelete(); - bool SelectionInvert(); - bool SelectionMirror(); - bool SelectionFlip(); - bool SelectionAddRect(RECT r, BYTE level = 255); - bool SelectionAddEllipse(RECT r, BYTE level = 255); - bool SelectionAddPolygon(POINT *points, long npoints, BYTE level = 255); - bool SelectionAddColor(RGBQUAD c, BYTE level = 255); - bool SelectionAddPixel(long x, long y, BYTE level = 255); - bool SelectionCopy(CxImage &from); - bool SelectionIsInside(long x, long y); - bool SelectionIsValid(); - void SelectionGetBox(RECT& r); - bool SelectionToHRGN(HRGN& region); - bool SelectionSplit(CxImage *dest); - BYTE SelectionGet(const long x,const long y); - bool SelectionSet(CxImage &from); - void SelectionRebuildBox(); - BYTE* SelectionGetPointer(const long x = 0,const long y = 0); -//@} - -protected: -/** \addtogroup Protected */ //@{ - bool BlindSelectionIsInside(long x, long y); - BYTE BlindSelectionGet(const long x,const long y); - void SelectionSet(const long x,const long y,const BYTE level); -//@} - -public: - -#endif //CXIMAGE_SUPPORT_SELECTION - -#if CXIMAGE_SUPPORT_ALPHA -/** \addtogroup Alpha */ //@{ - void AlphaClear(); - bool AlphaCreate(); - void AlphaDelete(); - void AlphaInvert(); - bool AlphaMirror(); - bool AlphaFlip(); - bool AlphaCopy(CxImage &from); - bool AlphaSplit(CxImage *dest); - void AlphaStrip(); - void AlphaSet(BYTE level); - bool AlphaSet(CxImage &from); - void AlphaSet(const long x,const long y,const BYTE level); - BYTE AlphaGet(const long x,const long y); - BYTE AlphaGetMax() const; - void AlphaSetMax(BYTE nAlphaMax); - bool AlphaIsValid(); - BYTE* AlphaGetPointer(const long x = 0,const long y = 0); - bool AlphaFromTransparency(); - - void AlphaPaletteClear(); - void AlphaPaletteEnable(bool enable=true); - bool AlphaPaletteIsEnabled(); - bool AlphaPaletteIsValid(); - bool AlphaPaletteSplit(CxImage *dest); -//@} - -protected: -/** \addtogroup Protected */ //@{ - BYTE BlindAlphaGet(const long x,const long y); -//@} -#endif //CXIMAGE_SUPPORT_ALPHA - -public: -#if CXIMAGE_SUPPORT_LAYERS -/** \addtogroup Layers */ //@{ - bool LayerCreate(long position = -1); - bool LayerDelete(long position = -1); - void LayerDeleteAll(); - CxImage* GetLayer(long position); - CxImage* GetParent() const; - long GetNumLayers() const; - long LayerDrawAll(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1, RECT* pClipRect = 0, bool bSmooth = false); - long LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false); -//@} -#endif //CXIMAGE_SUPPORT_LAYERS - -protected: -/** \addtogroup Protected */ //@{ - void Startup(DWORD imagetype = 0); - void CopyInfo(const CxImage &src); - void Ghost(const CxImage *src); - void RGBtoBGR(BYTE *buffer, int length); - static float HueToRGB(float n1,float n2, float hue); - void Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp); - static int CompareColors(const void *elem1, const void *elem2); - short ntohs(const short word); - long ntohl(const long dword); - void bihtoh(BITMAPINFOHEADER* bih); - - void* pDib; //contains the header, the palette, the pixels - BITMAPINFOHEADER head; //standard header - CXIMAGEINFO info; //extended information - BYTE* pSelection; //selected region - BYTE* pAlpha; //alpha channel - CxImage** ppLayers; //generic layers - CxImage** ppFrames; -//@} -}; - -//////////////////////////////////////////////////////////////////////////// -#endif // !defined(__CXIMAGE_H) +/* + * File: ximage.h + * Purpose: General Purpose Image Class + */ +/* + -------------------------------------------------------------------------------- + + COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + + CxImage version 6.0.0 02/Feb/2008 + + CxImage : Copyright (C) 2001 - 2008, Davide Pizzolato + + Original CImage and CImageIterator implementation are: + Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx) + + Covered code is provided under this license on an "as is" basis, without warranty + of any kind, either expressed or implied, including, without limitation, warranties + that the covered code is free of defects, merchantable, fit for a particular purpose + or non-infringing. The entire risk as to the quality and performance of the covered + code is with you. Should any covered code prove defective in any respect, you (not + the initial developer or any other contributor) assume the cost of any necessary + servicing, repair or correction. This disclaimer of warranty constitutes an essential + part of this license. No use of any covered code is authorized hereunder except under + this disclaimer. + + Permission is hereby granted to use, copy, modify, and distribute this + source code, or portions hereof, for any purpose, including commercial applications, + freely and without fee, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + + -------------------------------------------------------------------------------- + + Other information about CxImage, and the latest version, can be found at the + CxImage home page: http://www.xdp.it/cximage/ + + -------------------------------------------------------------------------------- + */ +#if !defined(__CXIMAGE_H) +#define __CXIMAGE_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +///////////////////////////////////////////////////////////////////////////// +#include "xfile.h" +#include "xiofile.h" +#include "xmemfile.h" +#include "ximadef.h" // adjust some #define + +/* see "ximacfg.h" for CxImage configuration options */ + +///////////////////////////////////////////////////////////////////////////// +// CxImage formats enumerator +enum ENUM_CXIMAGE_FORMATS{ +CXIMAGE_FORMAT_UNKNOWN = 0, +#if CXIMAGE_SUPPORT_BMP +CXIMAGE_FORMAT_BMP = 1, +#endif +#if CXIMAGE_SUPPORT_GIF +CXIMAGE_FORMAT_GIF = 2, +#endif +#if CXIMAGE_SUPPORT_JPG +CXIMAGE_FORMAT_JPG = 3, +#endif +#if CXIMAGE_SUPPORT_PNG +CXIMAGE_FORMAT_PNG = 4, +#endif +#if CXIMAGE_SUPPORT_ICO +CXIMAGE_FORMAT_ICO = 5, +#endif +#if CXIMAGE_SUPPORT_TIF +CXIMAGE_FORMAT_TIF = 6, +#endif +#if CXIMAGE_SUPPORT_TGA +CXIMAGE_FORMAT_TGA = 7, +#endif +#if CXIMAGE_SUPPORT_PCX +CXIMAGE_FORMAT_PCX = 8, +#endif +#if CXIMAGE_SUPPORT_WBMP +CXIMAGE_FORMAT_WBMP = 9, +#endif +#if CXIMAGE_SUPPORT_WMF +CXIMAGE_FORMAT_WMF = 10, +#endif +#if CXIMAGE_SUPPORT_JP2 +CXIMAGE_FORMAT_JP2 = 11, +#endif +#if CXIMAGE_SUPPORT_JPC +CXIMAGE_FORMAT_JPC = 12, +#endif +#if CXIMAGE_SUPPORT_PGX +CXIMAGE_FORMAT_PGX = 13, +#endif +#if CXIMAGE_SUPPORT_PNM +CXIMAGE_FORMAT_PNM = 14, +#endif +#if CXIMAGE_SUPPORT_RAS +CXIMAGE_FORMAT_RAS = 15, +#endif +#if CXIMAGE_SUPPORT_JBG +CXIMAGE_FORMAT_JBG = 16, +#endif +#if CXIMAGE_SUPPORT_MNG +CXIMAGE_FORMAT_MNG = 17, +#endif +#if CXIMAGE_SUPPORT_SKA +CXIMAGE_FORMAT_SKA = 18, +#endif +#if CXIMAGE_SUPPORT_RAW +CXIMAGE_FORMAT_RAW = 19, +#endif +CMAX_IMAGE_FORMATS = CXIMAGE_SUPPORT_BMP + CXIMAGE_SUPPORT_GIF + CXIMAGE_SUPPORT_JPG + + CXIMAGE_SUPPORT_PNG + CXIMAGE_SUPPORT_MNG + CXIMAGE_SUPPORT_ICO + + CXIMAGE_SUPPORT_TIF + CXIMAGE_SUPPORT_TGA + CXIMAGE_SUPPORT_PCX + + CXIMAGE_SUPPORT_WBMP+ CXIMAGE_SUPPORT_WMF + + CXIMAGE_SUPPORT_JBG + CXIMAGE_SUPPORT_JP2 + CXIMAGE_SUPPORT_JPC + + CXIMAGE_SUPPORT_PGX + CXIMAGE_SUPPORT_PNM + CXIMAGE_SUPPORT_RAS + + CXIMAGE_SUPPORT_SKA + CXIMAGE_SUPPORT_RAW + 1 +}; + +///////////////////////////////////////////////////////////////////////////// +// CxImage class +///////////////////////////////////////////////////////////////////////////// +class DLL_EXP CxImage +{ +//extensible information collector +typedef struct tagCxImageInfo { + DWORD dwEffWidth; ///< DWORD aligned scan line width + BYTE* pImage; ///< THE IMAGE BITS + CxImage* pGhost; ///< if this is a ghost, pGhost points to the body + CxImage* pParent; ///< if this is a layer, pParent points to the body + DWORD dwType; ///< original image format + char szLastError[256]; ///< debugging + long nProgress; ///< monitor + long nEscape; ///< escape + long nBkgndIndex; ///< used for GIF, PNG, MNG + RGBQUAD nBkgndColor; ///< used for RGB transparency + float fQuality; ///< used for JPEG, JPEG2000 (0.0f ... 100.0f) + BYTE nJpegScale; ///< used for JPEG [ignacio] + long nFrame; ///< used for TIF, GIF, MNG : actual frame + long nNumFrames; ///< used for TIF, GIF, MNG : total number of frames + DWORD dwFrameDelay; ///< used for GIF, MNG + long xDPI; ///< horizontal resolution + long yDPI; ///< vertical resolution + RECT rSelectionBox; ///< bounding rectangle + BYTE nAlphaMax; ///< max opacity (fade) + bool bAlphaPaletteEnabled; ///< true if alpha values in the palette are enabled. + bool bEnabled; ///< enables the painting functions + long xOffset; + long yOffset; + DWORD dwCodecOpt[CMAX_IMAGE_FORMATS]; ///< for GIF, TIF : 0=def.1=unc,2=fax3,3=fax4,4=pack,5=jpg + RGBQUAD last_c; ///< for GetNearestIndex optimization + BYTE last_c_index; + bool last_c_isvalid; + long nNumLayers; + DWORD dwFlags; ///< 0x??00000 = reserved, 0x00??0000 = blend mode, 0x0000???? = layer id - user flags + BYTE dispmeth; + bool bGetAllFrames; + bool bLittleEndianHost; + +} CXIMAGEINFO; + +public: + //public structures +struct rgb_color { BYTE r,g,b; }; + +#if CXIMAGE_SUPPORT_WINDOWS +// text placement data +// members must be initialized with the InitTextInfo(&this) function. +typedef struct tagCxTextInfo +{ +#if defined (_WIN32_WCE) + TCHAR text[256]; ///< text for windows CE +#else + TCHAR text[4096]; ///< text (char -> TCHAR for UNICODE [Cesar M]) +#endif + LOGFONT lfont; ///< font and codepage data + COLORREF fcolor; ///< foreground color + long align; ///< DT_CENTER, DT_RIGHT, DT_LEFT aligment for multiline text + BYTE smooth; ///< text smoothing option. Default is false. + BYTE opaque; ///< text has background or hasn't. Default is true. + ///< data for background (ignored if .opaque==FALSE) + COLORREF bcolor; ///< background color + float b_opacity; ///< opacity value for background between 0.0-1.0 Default is 0. (opaque) + BYTE b_outline; ///< outline width for background (zero: no outline) + BYTE b_round; ///< rounding radius for background rectangle. % of the height, between 0-50. Default is 10. + ///< (backgr. always has a frame: width = 3 pixel + 10% of height by default.) +} CXTEXTINFO; +#endif + +public: +/** \addtogroup Constructors */ //@{ + CxImage(DWORD imagetype = 0); + CxImage(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype = 0); + CxImage(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true); + CxImage(const TCHAR * filename, DWORD imagetype); // For UNICODE support: char -> TCHAR + CxImage(FILE * stream, DWORD imagetype); + CxImage(CxFile * stream, DWORD imagetype); + CxImage(BYTE * buffer, DWORD size, DWORD imagetype); + virtual ~CxImage() { DestroyFrames(); Destroy(); }; + CxImage& operator = (const CxImage&); +//@} + +/** \addtogroup Initialization */ //@{ + void* Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype = 0); + bool Destroy(); + bool DestroyFrames(); + void Clear(BYTE bval=0); + void Copy(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true); + bool Transfer(CxImage &from, bool bTransferFrames = true); + bool CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage); + bool CreateFromMatrix(BYTE** ppMatrix,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage); + void FreeMemory(void* memblock); + + DWORD Dump(BYTE * dst); + DWORD UnDump(const BYTE * src); + DWORD DumpSize(); + +//@} + +/** \addtogroup Attributes */ //@{ + long GetSize(); + BYTE* GetBits(DWORD row = 0); + BYTE GetColorType(); + void* GetDIB() const; + DWORD GetHeight() const; + DWORD GetWidth() const; + DWORD GetEffWidth() const; + DWORD GetNumColors() const; + WORD GetBpp() const; + DWORD GetType() const; + const char* GetLastError(); + static const TCHAR* GetVersion(); + static const float GetVersionNumber(); + + DWORD GetFrameDelay() const; + void SetFrameDelay(DWORD d); + + void GetOffset(long *x,long *y); + void SetOffset(long x,long y); + + BYTE GetJpegQuality() const; + void SetJpegQuality(BYTE q); + float GetJpegQualityF() const; + void SetJpegQualityF(float q); + + BYTE GetJpegScale() const; + void SetJpegScale(BYTE q); + + long GetXDPI() const; + long GetYDPI() const; + void SetXDPI(long dpi); + void SetYDPI(long dpi); + + DWORD GetClrImportant() const; + void SetClrImportant(DWORD ncolors = 0); + + long GetProgress() const; + long GetEscape() const; + void SetProgress(long p); + void SetEscape(long i); + + long GetTransIndex() const; + RGBQUAD GetTransColor(); + void SetTransIndex(long idx); + void SetTransColor(RGBQUAD rgb); + bool IsTransparent() const; + + DWORD GetCodecOption(DWORD imagetype = 0); + bool SetCodecOption(DWORD opt, DWORD imagetype = 0); + + DWORD GetFlags() const; + void SetFlags(DWORD flags, bool bLockReservedFlags = true); + + BYTE GetDisposalMethod() const; + void SetDisposalMethod(BYTE dm); + + bool SetType(DWORD type); + + static DWORD GetNumTypes(); + static DWORD GetTypeIdFromName(const TCHAR* ext); + static DWORD GetTypeIdFromIndex(const DWORD index); + static DWORD GetTypeIndexFromId(const DWORD id); + + bool GetRetreiveAllFrames() const; + void SetRetreiveAllFrames(bool flag); + CxImage * GetFrame(long nFrame) const; + + //void* GetUserData() const {return info.pUserData;} + //void SetUserData(void* pUserData) {info.pUserData = pUserData;} +//@} + +/** \addtogroup Palette + * These functions have no effects on RGB images and in this case the returned value is always 0. + * @{ */ + bool IsGrayScale(); + bool IsIndexed() const; + bool IsSamePalette(CxImage &img, bool bCheckAlpha = true); + DWORD GetPaletteSize(); + RGBQUAD* GetPalette() const; + RGBQUAD GetPaletteColor(BYTE idx); + bool GetPaletteColor(BYTE i, BYTE* r, BYTE* g, BYTE* b); + BYTE GetNearestIndex(RGBQUAD c); + void BlendPalette(COLORREF cr,long perc); + void SetGrayPalette(); + void SetPalette(DWORD n, BYTE *r, BYTE *g, BYTE *b); + void SetPalette(RGBQUAD* pPal,DWORD nColors=256); + void SetPalette(rgb_color *rgb,DWORD nColors=256); + void SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha=0); + void SetPaletteColor(BYTE idx, RGBQUAD c); + void SetPaletteColor(BYTE idx, COLORREF cr); + void SwapIndex(BYTE idx1, BYTE idx2); + void SwapRGB2BGR(); + void SetStdPalette(); +//@} + +/** \addtogroup Pixel */ //@{ + bool IsInside(long x, long y); + bool IsTransparent(long x,long y); + bool GetTransparentMask(CxImage* iDst = 0); + RGBQUAD GetPixelColor(long x,long y, bool bGetAlpha = true); + BYTE GetPixelIndex(long x,long y); + BYTE GetPixelGray(long x, long y); + void SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha = false); + void SetPixelColor(long x,long y,COLORREF cr); + void SetPixelIndex(long x,long y,BYTE i); + void DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha=false); + void DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr); + void BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha = false); +//@} + +protected: +/** \addtogroup Protected */ //@{ + BYTE BlindGetPixelIndex(const long x,const long y); + RGBQUAD BlindGetPixelColor(const long x,const long y, bool bGetAlpha = true); + void *BlindGetPixelPointer(const long x,const long y); + void BlindSetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha = false); + void BlindSetPixelIndex(long x,long y,BYTE i); +//@} + +public: + +#if CXIMAGE_SUPPORT_INTERPOLATION +/** \addtogroup Interpolation */ //@{ + //overflow methods: + enum OverflowMethod { + OM_COLOR=1, + OM_BACKGROUND=2, + OM_TRANSPARENT=3, + OM_WRAP=4, + OM_REPEAT=5, + OM_MIRROR=6 + }; + void OverflowCoordinates(float &x, float &y, OverflowMethod const ofMethod); + void OverflowCoordinates(long &x, long &y, OverflowMethod const ofMethod); + RGBQUAD GetPixelColorWithOverflow(long x, long y, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0); + //interpolation methods: + enum InterpolationMethod { + IM_NEAREST_NEIGHBOUR=1, + IM_BILINEAR =2, + IM_BSPLINE =3, + IM_BICUBIC =4, + IM_BICUBIC2 =5, + IM_LANCZOS =6, + IM_BOX =7, + IM_HERMITE =8, + IM_HAMMING =9, + IM_SINC =10, + IM_BLACKMAN =11, + IM_BESSEL =12, + IM_GAUSSIAN =13, + IM_QUADRATIC =14, + IM_MITCHELL =15, + IM_CATROM =16, + IM_HANNING =17, + IM_POWER =18 + }; + RGBQUAD GetPixelColorInterpolated(float x,float y, InterpolationMethod const inMethod=IM_BILINEAR, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0); + RGBQUAD GetAreaColorInterpolated(float const xc, float const yc, float const w, float const h, InterpolationMethod const inMethod, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0); +//@} + +protected: +/** \addtogroup Protected */ //@{ + void AddAveragingCont(RGBQUAD const &color, float const surf, float &rr, float &gg, float &bb, float &aa); +//@} + +/** \addtogroup Kernels */ //@{ +public: + static float KernelBSpline(const float x); + static float KernelLinear(const float t); + static float KernelCubic(const float t); + static float KernelGeneralizedCubic(const float t, const float a=-1); + static float KernelLanczosSinc(const float t, const float r = 3); + static float KernelBox(const float x); + static float KernelHermite(const float x); + static float KernelHamming(const float x); + static float KernelSinc(const float x); + static float KernelBlackman(const float x); + static float KernelBessel_J1(const float x); + static float KernelBessel_P1(const float x); + static float KernelBessel_Q1(const float x); + static float KernelBessel_Order1(float x); + static float KernelBessel(const float x); + static float KernelGaussian(const float x); + static float KernelQuadratic(const float x); + static float KernelMitchell(const float x); + static float KernelCatrom(const float x); + static float KernelHanning(const float x); + static float KernelPower(const float x, const float a = 2); +//@} +#endif //CXIMAGE_SUPPORT_INTERPOLATION + +/** \addtogroup Painting */ //@{ +#if CXIMAGE_SUPPORT_WINDOWS + long Blt(HDC pDC, long x=0, long y=0); + HBITMAP MakeBitmap(HDC hdc = NULL); + HANDLE CopyToHandle(); + bool CreateFromHANDLE(HANDLE hMem); //Windows objects (clipboard) + bool CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal=0); //Windows resource + bool CreateFromHICON(HICON hico); + long Draw(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1, RECT* pClipRect = 0, bool bSmooth = false); + long Draw(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false); + long Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop = SRCCOPY); + long Stretch(HDC hdc, const RECT& rect, DWORD dwRop = SRCCOPY); + long Tile(HDC hdc, RECT *rc); + long Draw2(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1); + long Draw2(HDC hdc, const RECT& rect); + //long DrawString(HDC hdc, long x, long y, const char* text, RGBQUAD color, const char* font, long lSize=0, long lWeight=400, BYTE bItalic=0, BYTE bUnderline=0, bool bSetAlpha=false); + long DrawString(HDC hdc, long x, long y, const TCHAR* text, RGBQUAD color, const TCHAR* font, long lSize=0, long lWeight=400, BYTE bItalic=0, BYTE bUnderline=0, bool bSetAlpha=false); + // extensions + long DrawStringEx(HDC hdc, long x, long y, CXTEXTINFO *pTextType, bool bSetAlpha=false ); + void InitTextInfo( CXTEXTINFO *txt ); +#endif //CXIMAGE_SUPPORT_WINDOWS +//@} + + // file operations +#if CXIMAGE_SUPPORT_DECODE +/** \addtogroup Decode */ //@{ +#ifdef WIN32 + //bool Load(LPCWSTR filename, DWORD imagetype=0); + bool LoadResource(HRSRC hRes, DWORD imagetype, HMODULE hModule=NULL); +#endif + // For UNICODE support: char -> TCHAR + bool Load(const TCHAR* filename, DWORD imagetype=0); + //bool Load(const char * filename, DWORD imagetype=0); + bool Decode(FILE * hFile, DWORD imagetype); + bool Decode(CxFile * hFile, DWORD imagetype); + bool Decode(BYTE * buffer, DWORD size, DWORD imagetype); + + bool CheckFormat(CxFile * hFile, DWORD imagetype = 0); + bool CheckFormat(BYTE * buffer, DWORD size, DWORD imagetype = 0); +//@} +#endif //CXIMAGE_SUPPORT_DECODE + +#if CXIMAGE_SUPPORT_ENCODE +protected: +/** \addtogroup Protected */ //@{ + bool EncodeSafeCheck(CxFile *hFile); +//@} + +public: +/** \addtogroup Encode */ //@{ +#ifdef WIN32 + //bool Save(LPCWSTR filename, DWORD imagetype=0); +#endif + // For UNICODE support: char -> TCHAR + bool Save(const TCHAR* filename, DWORD imagetype); + //bool Save(const char * filename, DWORD imagetype=0); + bool Encode(FILE * hFile, DWORD imagetype); + bool Encode(CxFile * hFile, DWORD imagetype); + bool Encode(CxFile * hFile, CxImage ** pImages, int pagecount, DWORD imagetype); + bool Encode(FILE *hFile, CxImage ** pImages, int pagecount, DWORD imagetype); + bool Encode(BYTE * &buffer, long &size, DWORD imagetype); + + bool Encode2RGBA(CxFile *hFile, bool bFlipY = false); + bool Encode2RGBA(BYTE * &buffer, long &size, bool bFlipY = false); +//@} +#endif //CXIMAGE_SUPPORT_ENCODE + +/** \addtogroup Attributes */ //@{ + //misc. + bool IsValid() const; + bool IsEnabled() const; + void Enable(bool enable=true); + + // frame operations + long GetNumFrames() const; + long GetFrame() const; + void SetFrame(long nFrame); +//@} + +#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS +/** \addtogroup BasicTransformations */ //@{ + bool GrayScale(); + bool Flip(bool bFlipSelection = false, bool bFlipAlpha = true); + bool Mirror(bool bMirrorSelection = false, bool bMirrorAlpha = true); + bool Negative(); + bool RotateLeft(CxImage* iDst = NULL); + bool RotateRight(CxImage* iDst = NULL); +//@} +#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS + +#if CXIMAGE_SUPPORT_TRANSFORMATION +/** \addtogroup Transformations */ //@{ + // image operations + bool Rotate(float angle, CxImage* iDst = NULL); + bool Rotate2(float angle, CxImage *iDst = NULL, InterpolationMethod inMethod=IM_BILINEAR, + OverflowMethod ofMethod=OM_BACKGROUND, RGBQUAD *replColor=0, + bool const optimizeRightAngles=true, bool const bKeepOriginalSize=false); + bool Rotate180(CxImage* iDst = NULL); + bool Resample(long newx, long newy, int mode = 1, CxImage* iDst = NULL); + bool Resample2(long newx, long newy, InterpolationMethod const inMethod=IM_BICUBIC2, + OverflowMethod const ofMethod=OM_REPEAT, CxImage* const iDst = NULL, + bool const disableAveraging=false); + bool DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal = 0, DWORD clrimportant = 0); + bool IncreaseBpp(DWORD nbit); + bool Dither(long method = 0); + bool Crop(long left, long top, long right, long bottom, CxImage* iDst = NULL); + bool Crop(const RECT& rect, CxImage* iDst = NULL); + bool CropRotatedRectangle( long topx, long topy, long width, long height, float angle, CxImage* iDst = NULL); + bool Skew(float xgain, float ygain, long xpivot=0, long ypivot=0, bool bEnableInterpolation = false); + bool Expand(long left, long top, long right, long bottom, RGBQUAD canvascolor, CxImage* iDst = 0); + bool Expand(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst = 0); + bool Thumbnail(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst = 0); + bool CircleTransform(int type,long rmax=0,float Koeff=1.0f); + bool RedEyeRemove(float strength = 0.8f); + bool QIShrink(long newx, long newy, CxImage* const iDst = NULL, bool bChangeBpp = false); + +//@} +#endif //CXIMAGE_SUPPORT_TRANSFORMATION + +#if CXIMAGE_SUPPORT_DSP +/** \addtogroup DSP */ //@{ + bool Contour(); + bool HistogramStretch(long method = 0, double threshold = 0); + bool HistogramEqualize(); + bool HistogramNormalize(); + bool HistogramRoot(); + bool HistogramLog(); + long Histogram(long* red, long* green = 0, long* blue = 0, long* gray = 0, long colorspace = 0); + bool Jitter(long radius=2); + bool Repair(float radius = 0.25f, long niterations = 1, long colorspace = 0); + bool Combine(CxImage* r,CxImage* g,CxImage* b,CxImage* a, long colorspace = 0); + bool FFT2(CxImage* srcReal, CxImage* srcImag, CxImage* dstReal, CxImage* dstImag, long direction = 1, bool bForceFFT = true, bool bMagnitude = true); + bool Noise(long level); + bool Median(long Ksize=3); + bool Gamma(float gamma); + bool GammaRGB(float gammaR, float gammaG, float gammaB); + bool ShiftRGB(long r, long g, long b); + bool Threshold(BYTE level); + bool Threshold(CxImage* pThresholdMask); + bool Threshold2(BYTE level, bool bDirection, RGBQUAD nBkgndColor, bool bSetAlpha = false); + bool Colorize(BYTE hue, BYTE sat, float blend = 1.0f); + bool Light(long brightness, long contrast = 0); + float Mean(); + bool Filter(long* kernel, long Ksize, long Kfactor, long Koffset); + bool Erode(long Ksize=2); + bool Dilate(long Ksize=2); + bool Edge(long Ksize=2); + void HuePalette(float correction=1); + enum ImageOpType { OpAdd, OpAnd, OpXor, OpOr, OpMask, OpSrcCopy, OpDstCopy, OpSub, OpSrcBlend, OpScreen, OpAvg }; + void Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset = 0, long lYOffset = 0, bool bMixAlpha = false); + void MixFrom(CxImage & imagesrc2, long lXOffset, long lYOffset); + bool UnsharpMask(float radius = 5.0f, float amount = 0.5f, int threshold = 0); + bool Lut(BYTE* pLut); + bool Lut(BYTE* pLutR, BYTE* pLutG, BYTE* pLutB, BYTE* pLutA = 0); + bool GaussianBlur(float radius = 1.0f, CxImage* iDst = 0); + bool TextBlur(BYTE threshold = 100, BYTE decay = 2, BYTE max_depth = 5, bool bBlurHorizontal = true, bool bBlurVertical = true, CxImage* iDst = 0); + bool SelectiveBlur(float radius = 1.0f, BYTE threshold = 25, CxImage* iDst = 0); + bool Solarize(BYTE level = 128, bool bLinkedChannels = true); + bool FloodFill(const long xStart, const long yStart, const RGBQUAD cFillColor, const BYTE tolerance = 0, + BYTE nOpacity = 255, const bool bSelectFilledArea = false, const BYTE nSelectionLevel = 255); + bool Saturate(const long saturation, const long colorspace = 1); + bool ConvertColorSpace(const long dstColorSpace, const long srcColorSpace); + int OptimalThreshold(long method = 0, RECT * pBox = 0, CxImage* pContrastMask = 0); + bool AdaptiveThreshold(long method = 0, long nBoxSize = 64, CxImage* pContrastMask = 0, long nBias = 0, float fGlobalLocalBalance = 0.5f); + +//@} + +protected: +/** \addtogroup Protected */ //@{ + bool IsPowerof2(long x); + bool FFT(int dir,int m,double *x,double *y); + bool DFT(int dir,long m,double *x1,double *y1,double *x2,double *y2); + bool RepairChannel(CxImage *ch, float radius); + // + int gen_convolve_matrix (float radius, float **cmatrix_p); + float* gen_lookup_table (float *cmatrix, int cmatrix_length); + void blur_line (float *ctable, float *cmatrix, int cmatrix_length, BYTE* cur_col, BYTE* dest_col, int y, long bytes); + void blur_text (BYTE threshold, BYTE decay, BYTE max_depth, CxImage* iSrc, CxImage* iDst, BYTE bytes); +//@} + +public: +/** \addtogroup ColorSpace */ //@{ + bool SplitRGB(CxImage* r,CxImage* g,CxImage* b); + bool SplitYUV(CxImage* y,CxImage* u,CxImage* v); + bool SplitHSL(CxImage* h,CxImage* s,CxImage* l); + bool SplitYIQ(CxImage* y,CxImage* i,CxImage* q); + bool SplitXYZ(CxImage* x,CxImage* y,CxImage* z); + bool SplitCMYK(CxImage* c,CxImage* m,CxImage* y,CxImage* k); + static RGBQUAD HSLtoRGB(COLORREF cHSLColor); + static RGBQUAD RGBtoHSL(RGBQUAD lRGBColor); + static RGBQUAD HSLtoRGB(RGBQUAD lHSLColor); + static RGBQUAD YUVtoRGB(RGBQUAD lYUVColor); + static RGBQUAD RGBtoYUV(RGBQUAD lRGBColor); + static RGBQUAD YIQtoRGB(RGBQUAD lYIQColor); + static RGBQUAD RGBtoYIQ(RGBQUAD lRGBColor); + static RGBQUAD XYZtoRGB(RGBQUAD lXYZColor); + static RGBQUAD RGBtoXYZ(RGBQUAD lRGBColor); +#endif //CXIMAGE_SUPPORT_DSP + static RGBQUAD RGBtoRGBQUAD(COLORREF cr); + static COLORREF RGBQUADtoRGB (RGBQUAD c); +//@} + +#if CXIMAGE_SUPPORT_SELECTION +/** \addtogroup Selection */ //@{ + bool SelectionClear(BYTE level = 0); + bool SelectionCreate(); + bool SelectionDelete(); + bool SelectionInvert(); + bool SelectionMirror(); + bool SelectionFlip(); + bool SelectionAddRect(RECT r, BYTE level = 255); + bool SelectionAddEllipse(RECT r, BYTE level = 255); + bool SelectionAddPolygon(POINT *points, long npoints, BYTE level = 255); + bool SelectionAddColor(RGBQUAD c, BYTE level = 255); + bool SelectionAddPixel(long x, long y, BYTE level = 255); + bool SelectionCopy(CxImage &from); + bool SelectionIsInside(long x, long y); + bool SelectionIsValid(); + void SelectionGetBox(RECT& r); + bool SelectionToHRGN(HRGN& region); + bool SelectionSplit(CxImage *dest); + BYTE SelectionGet(const long x,const long y); + bool SelectionSet(CxImage &from); + void SelectionRebuildBox(); + BYTE* SelectionGetPointer(const long x = 0,const long y = 0); +//@} + +protected: +/** \addtogroup Protected */ //@{ + bool BlindSelectionIsInside(long x, long y); + BYTE BlindSelectionGet(const long x,const long y); + void SelectionSet(const long x,const long y,const BYTE level); +//@} + +public: + +#endif //CXIMAGE_SUPPORT_SELECTION + +#if CXIMAGE_SUPPORT_ALPHA +/** \addtogroup Alpha */ //@{ + void AlphaClear(); + bool AlphaCreate(); + void AlphaDelete(); + void AlphaInvert(); + bool AlphaMirror(); + bool AlphaFlip(); + bool AlphaCopy(CxImage &from); + bool AlphaSplit(CxImage *dest); + void AlphaStrip(); + void AlphaSet(BYTE level); + bool AlphaSet(CxImage &from); + void AlphaSet(const long x,const long y,const BYTE level); + BYTE AlphaGet(const long x,const long y); + BYTE AlphaGetMax() const; + void AlphaSetMax(BYTE nAlphaMax); + bool AlphaIsValid(); + BYTE* AlphaGetPointer(const long x = 0,const long y = 0); + bool AlphaFromTransparency(); + + void AlphaPaletteClear(); + void AlphaPaletteEnable(bool enable=true); + bool AlphaPaletteIsEnabled(); + bool AlphaPaletteIsValid(); + bool AlphaPaletteSplit(CxImage *dest); +//@} + +protected: +/** \addtogroup Protected */ //@{ + BYTE BlindAlphaGet(const long x,const long y); +//@} +#endif //CXIMAGE_SUPPORT_ALPHA + +public: +#if CXIMAGE_SUPPORT_LAYERS +/** \addtogroup Layers */ //@{ + bool LayerCreate(long position = -1); + bool LayerDelete(long position = -1); + void LayerDeleteAll(); + CxImage* GetLayer(long position); + CxImage* GetParent() const; + long GetNumLayers() const; + long LayerDrawAll(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1, RECT* pClipRect = 0, bool bSmooth = false); + long LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false); +//@} +#endif //CXIMAGE_SUPPORT_LAYERS + +protected: +/** \addtogroup Protected */ //@{ + void Startup(DWORD imagetype = 0); + void CopyInfo(const CxImage &src); + void Ghost(const CxImage *src); + void RGBtoBGR(BYTE *buffer, int length); + static float HueToRGB(float n1,float n2, float hue); + void Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp); + static int CompareColors(const void *elem1, const void *elem2); + short ntohs(const short word); + long ntohl(const long dword); + void bihtoh(BITMAPINFOHEADER* bih); + + void* pDib; //contains the header, the palette, the pixels + BITMAPINFOHEADER head; //standard header + CXIMAGEINFO info; //extended information + BYTE* pSelection; //selected region + BYTE* pAlpha; //alpha channel + CxImage** ppLayers; //generic layers + CxImage** ppFrames; +//@} +}; + +//////////////////////////////////////////////////////////////////////////// +#endif // !defined(__CXIMAGE_H) diff --git a/utilities/CxImage/ximagif.cpp b/utilities/CxImage/ximagif.cpp index d119f0f..740717c 100644 --- a/utilities/CxImage/ximagif.cpp +++ b/utilities/CxImage/ximagif.cpp @@ -1,1640 +1,1640 @@ -/* - * File: ximagif.cpp - * Purpose: Platform Independent GIF Image Class Loader and Writer - * 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximagif.h" - -#if CXIMAGE_SUPPORT_GIF - -#include "ximaiter.h" - -#if defined (_WIN32_WCE) - #define assert(s) -#else - #include -#endif - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageGIF::Decode(CxFile *fp) -{ - /* AD - for transparency */ - struct_dscgif dscgif; - struct_image image; - struct_TabCol TabCol; - - if (fp == NULL) return false; - - fp->Read(&dscgif,/*sizeof(dscgif)*/13,1); - //if (strncmp(dscgif.header,"GIF8",3)!=0) { - if (strncmp(dscgif.header,"GIF8",4)!=0) return FALSE; - - // Avoid Byte order problem with Mac - dscgif.scrheight = ntohs(dscgif.scrheight); - dscgif.scrwidth = ntohs(dscgif.scrwidth); - - if (info.nEscape == -1) { - // Return output dimensions only - head.biWidth = dscgif.scrwidth; - head.biHeight = dscgif.scrheight; - info.dwType = CXIMAGE_FORMAT_GIF; - return true; - } - - /* AD - for interlace */ - TabCol.sogct = (short)(1 << ((dscgif.pflds & 0x07)+1)); - TabCol.colres = (short)(((dscgif.pflds & 0x70) >> 4) + 1); - - // assume that the image is a truecolor-gif if - // 1) no global color map found - // 2) (image.w, image.h) of the 1st image != (dscgif.scrwidth, dscgif.scrheight) - long bTrueColor=0; - CxImage* imaRGB=NULL; - - // Global colour map? - if (dscgif.pflds & 0x80) - fp->Read(TabCol.paleta,sizeof(struct rgb_color)*TabCol.sogct,1); - else - bTrueColor++; //first chance for a truecolor gif - - long first_transparent_index = 0; - - int iImage = 0; - info.nNumFrames=get_num_frames(fp,&TabCol,&dscgif); - - if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)) return false; - - //it cannot be a true color GIF with only one frame - if (info.nNumFrames == 1) - bTrueColor=0; - - char ch; - bool bPreviousWasNull = true; - int prevdispmeth = 0; - CxImage *previousFrame = NULL; - - for (BOOL bContinue = TRUE; bContinue; ) - { - if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;} - - if (info.nEscape > 0) return false; // - cancel decoding - if (bPreviousWasNull || ch==0) - { - switch (ch) - { - case '!': // extension - { - bContinue = DecodeExtension(fp); - break; - } - case ',': // image - { - assert(sizeof(image) == 9); - fp->Read(&image,sizeof(image),1); - //avoid byte order problems with Solaris - image.l = ntohs(image.l); - image.t = ntohs(image.t); - image.w = ntohs(image.w); - image.h = ntohs(image.h); - - if (((image.l + image.w) > dscgif.scrwidth)||((image.t + image.h) > dscgif.scrheight)) - break; - - // check if it could be a truecolor gif - if ((iImage==0) && (image.w != dscgif.scrwidth) && (image.h != dscgif.scrheight)) - bTrueColor++; - - rgb_color locpal[256]; //Local Palette - rgb_color* pcurpal = TabCol.paleta; //Current Palette - short palcount = TabCol.sogct; //Current Palette color count - - // Local colour map? - if (image.pf & 0x80) { - palcount = (short)(1 << ((image.pf & 0x07) +1)); - assert(3 == sizeof(struct rgb_color)); - fp->Read(locpal,sizeof(struct rgb_color)*palcount,1); - pcurpal = locpal; - } - - int bpp; // select the correct bit per pixel value - if (palcount <= 2) bpp = 1; - else if (palcount <= 16) bpp = 4; - else bpp = 8; - - CxImageGIF backimage; - backimage.CopyInfo(*this); - if (iImage==0){ - //first frame: build image background - backimage.Create(dscgif.scrwidth, dscgif.scrheight, bpp, CXIMAGE_FORMAT_GIF); - first_transparent_index = info.nBkgndIndex; - backimage.Clear((BYTE)gifgce.transpcolindex); - previousFrame = new CxImage(backimage); - previousFrame->SetRetreiveAllFrames(false); - } else { - //generic frame: handle disposal method from previous one - /*Values : 0 - No disposal specified. The decoder is - not required to take any action. - 1 - Do not dispose. The graphic is to be left - in place. - 2 - Restore to background color. The area used by the - graphic must be restored to the background color. - 3 - Restore to previous. The decoder is required to - restore the area overwritten by the graphic with - what was there prior to rendering the graphic. - */ - /* backimage.Copy(*this); - if (prevdispmeth==2){ - backimage.Clear((BYTE)first_transparent_index); - }*/ - if (prevdispmeth==2){ - backimage.Copy(*this,false,false,false); - backimage.Clear((BYTE)first_transparent_index); - } else if (prevdispmeth==3) { - backimage.Copy(*this,false,false,false); - backimage.Create(previousFrame->GetWidth(), - previousFrame->GetHeight(), - previousFrame->GetBpp(),CXIMAGE_FORMAT_GIF); - memcpy(backimage.GetDIB(),previousFrame->GetDIB(), - backimage.GetSize()); - backimage.AlphaSet(*previousFrame); - } else { - backimage.Copy(*this); - } - } - - //active frame - Create(image.w, image.h, bpp, CXIMAGE_FORMAT_GIF); - - if ((image.pf & 0x80) || (dscgif.pflds & 0x80)) { - unsigned char r[256], g[256], b[256]; - int i, has_white = 0; - - for (i=0; i < palcount; i++) { - r[i] = pcurpal[i].r; - g[i] = pcurpal[i].g; - b[i] = pcurpal[i].b; - if (RGB(r[i],g[i],b[i]) == 0xFFFFFF) has_white = 1; - } - - // Force transparency colour white... - //if (0) if (info.nBkgndIndex >= 0) - // r[info.nBkgndIndex] = g[info.nBkgndIndex] = b[info.nBkgndIndex] = 255; - // Fill in with white // AD - if (info.nBkgndIndex >= 0) { - while (i < 256) { - has_white = 1; - r[i] = g[i] = b[i] = 255; - i++; - } - } - - // Force last colour to white... // AD - //if ((info.nBkgndIndex >= 0) && !has_white) { - // r[255] = g[255] = b[255] = 255; - //} - - SetPalette((info.nBkgndIndex >= 0 ? 256 : palcount), r, g, b); - } - - CImageIterator* iter = new CImageIterator(this); - iter->Upset(); - int badcode=0; - ibf = GIFBUFTAM+1; - - interlaced = image.pf & 0x40; - iheight = image.h; - istep = 8; - iypos = 0; - ipass = 0; - - long pos_start = fp->Tell(); - //if (interlaced) log << "Interlaced" << endl; - decoder(fp, iter, image.w, badcode); - delete iter; - - if (info.nEscape) return false; // - cancel decoding - - if (bTrueColor<2 ){ //standard GIF: mix frame with background - backimage.GifMix(*this,image); - backimage.SetTransIndex(first_transparent_index); - backimage.SetPalette(GetPalette()); - Transfer(backimage,false); - } else { //it's a truecolor gif! - //force full image decoding - info.nFrame=info.nNumFrames-1; - //build the RGB image - if (imaRGB==NULL) imaRGB = new CxImage(dscgif.scrwidth,dscgif.scrheight,24,CXIMAGE_FORMAT_GIF); - //copy the partial image into the full RGB image - for(long y=0;ySetPixelColor(x+image.l,dscgif.scrheight-1-image.t-y,GetPixelColor(x,image.h-y-1)); - } - } - } - - prevdispmeth = (gifgce.flags >> 2) & 0x7; - - //restore the correct position in the file for the next image - if (badcode){ - seek_next_image(fp,pos_start); - } else { - fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR); - } - - if (info.bGetAllFrames && imaRGB == NULL) { - if (iImage == 0) { - DestroyFrames(); - ppFrames = new CxImage*[info.nNumFrames]; - for(int frameIdx = 0; frameIdx < info.nNumFrames; frameIdx++){ - ppFrames[frameIdx] = NULL; - } - } - ppFrames[iImage] = new CxImage(*this); - ppFrames[iImage]->SetRetreiveAllFrames(false); - } - if (prevdispmeth <= 1) { - delete previousFrame; - previousFrame = new CxImage(*this); - previousFrame->SetRetreiveAllFrames(false); - } - - if (info.nFrame==iImage) bContinue=false; else iImage++; - - break; - } - case ';': //terminator - bContinue=false; - break; - default: - bPreviousWasNull = (ch==0); - break; - } - } - } - - if (bTrueColor>=2 && imaRGB){ - if (gifgce.flags & 0x1){ - imaRGB->SetTransColor(GetPaletteColor((BYTE)info.nBkgndIndex)); - imaRGB->SetTransIndex(0); - } - Transfer(*imaRGB); - } - delete imaRGB; - - delete previousFrame; - - return true; - -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImageGIF::DecodeExtension(CxFile *fp) -{ - bool bContinue; - unsigned char count; - unsigned char fc; - - bContinue = (1 == fp->Read(&fc, sizeof(fc), 1)); - if (bContinue) { - /* AD - for transparency */ - if (fc == 0xF9) { - bContinue = (1 == fp->Read(&count, sizeof(count), 1)); - if (bContinue) { - assert(sizeof(gifgce) == 4); - bContinue = (count == fp->Read(&gifgce, 1, sizeof(gifgce))); - gifgce.delaytime = ntohs(gifgce.delaytime); // Avoid Byte order problem with Mac - if (bContinue) { - info.nBkgndIndex = (gifgce.flags & 0x1) ? gifgce.transpcolindex : -1; - info.dwFrameDelay = gifgce.delaytime; - SetDisposalMethod((gifgce.flags >> 2) & 0x7); - } } } - - if (fc == 0xFE) { // Comment block - bContinue = (1 == fp->Read(&count, sizeof(count), 1)); - if (bContinue) { - bContinue = (1 == fp->Read(m_comment, count, 1)); - m_comment[count]='\0'; - } } - - if (fc == 0xFF) { // Application Extension block - bContinue = (1 == fp->Read(&count, sizeof(count), 1)); - if (bContinue) { - bContinue = (count==11); - if (bContinue){ - char AppID[11]; - bContinue = (1 == fp->Read(AppID, count, 1)); - if (bContinue) { - bContinue = (1 == fp->Read(&count, sizeof(count), 1)); - if (bContinue) { - BYTE* dati = (BYTE*)malloc(count); - bContinue = (dati!=NULL); - if (bContinue){ - bContinue = (1 == fp->Read(dati, count, 1)); - if (count>2){ - m_loops = dati[1]+256*dati[2]; - } - } - free(dati); - } } } } } - - while (bContinue && fp->Read(&count, sizeof(count), 1) && count) { - //log << "Skipping " << count << " bytes" << endl; - fp->Seek(count, SEEK_CUR); - } - } - return bContinue; - -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// - -// - This external (machine specific) function is expected to return -// either the next BYTE from the GIF file, or a negative error number. -int CxImageGIF::get_byte(CxFile* file) -{ - if (ibf>=GIFBUFTAM){ - // FW 06/02/98 >>> - ibfmax = (int)file->Read( buf , 1 , GIFBUFTAM) ; - if( ibfmax < GIFBUFTAM ) buf[ ibfmax ] = 255 ; - // FW 06/02/98 <<< - ibf = 0; - } - if (ibf>=ibfmax) return -1; // avoid overflows - return buf[ibf++]; -} -//////////////////////////////////////////////////////////////////////////////// -/* - This function takes a full line of pixels (one BYTE per pixel) and - * displays them (or does whatever your program wants with them...). It - * should return zero, or negative if an error or some other event occurs - * which would require aborting the decode process... Note that the length - * passed will almost always be equal to the line length passed to the - * decoder function, with the sole exception occurring when an ending code - * occurs in an odd place in the GIF file... In any case, linelen will be - * equal to the number of pixels passed... -*/ -int CxImageGIF::out_line(CImageIterator* iter, unsigned char *pixels, int linelen) -{ - if (iter == NULL || pixels == NULL) - return -1; - - // for 1 & 4 bpp images, the pixels are compressed - if (head.biBitCount < 8){ - for(long x=0;x> 3); - if (head.biBitCount==4){ - pos = (BYTE)(4*(1-x%2)); - *iDst &= ~(0x0F<SetY(iheight-iypos-1); - iter->SetRow(pixels, linelen); - - if ((iypos += istep) >= iheight) { - do { - if (ipass++ > 0) istep /= 2; - iypos = istep / 2; - } - while (iypos > iheight); - } - return 0; - } else { - if (iter->ItOK()) { - iter->SetRow(pixels, linelen); - (void)iter->PrevRow(); - return 0; - } else { - // puts("chafeo"); - return -1; - } - } -} -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -// SaveFile - writes GIF87a gif file -// Randy Spann 6/15/97 -// R.Spann@ConnRiver.net -bool CxImageGIF::Encode(CxFile * fp) -{ - if (EncodeSafeCheck(fp)) return false; - - if(head.biBitCount > 8) { - //strcpy(info.szLastError,"GIF Images must be 8 bit or less"); - //return FALSE; - return EncodeRGB(fp); - } - - if ( GetNumFrames()>1 && ppFrames ) { - return Encode(fp, ppFrames, GetNumFrames() ); - } - - EncodeHeader(fp); - - EncodeExtension(fp); - - EncodeComment(fp); - - EncodeBody(fp); - - fp->PutC(';'); // Write the GIF file terminator - - return true; // done! -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImageGIF::Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap, bool bLocalDispMeth) -{ - cx_try { - if (fp==NULL) cx_throw("invalid file pointer"); - if (pImages==NULL || pagecount<=0 || pImages[0]==NULL) cx_throw("multipage GIF, no images!"); - - int i; - for (i=0; iIsValid())) - cx_throw("Empty image"); - if (pImages[i]->GetNumColors()==0) - cx_throw("CxImageGIF::Encode cannot create animated GIFs with a true color frame. Use DecreaseBpp before"); - } - - CxImageGIF ghost; - - //write the first image - ghost.Ghost(pImages[0]); - ghost.EncodeHeader(fp); - - if (m_loops!=1){ - ghost.SetLoops(max(0,m_loops-1)); - ghost.EncodeLoopExtension(fp); - } - - if (bLocalDispMeth) { - ghost.EncodeExtension(fp); - } else { - BYTE dm = ghost.GetDisposalMethod(); - ghost.SetDisposalMethod(GetDisposalMethod()); - ghost.EncodeExtension(fp); - ghost.SetDisposalMethod(dm); - } - - EncodeComment(fp); - - ghost.EncodeBody(fp); - - for (i=1; iPutC(';'); // Write the GIF file terminator - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - return false; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::EncodeHeader(CxFile *fp) -{ - fp->Write("GIF89a",1,6); //GIF Header - - Putword(head.biWidth,fp); //Logical screen descriptor - Putword(head.biHeight,fp); - - BYTE Flags; - if (head.biClrUsed==0){ - Flags=0x11; - } else { - Flags = 0x80; - Flags |=(head.biBitCount - 1) << 5; - Flags |=(head.biBitCount - 1); - } - - fp->PutC(Flags); //GIF "packed fields" - fp->PutC(0); //GIF "BackGround" - fp->PutC(0); //GIF "pixel aspect ratio" - - if (head.biClrUsed!=0){ - RGBQUAD* pPal = GetPalette(); - for(DWORD i=0; iPutC(pPal[i].rgbRed); - fp->PutC(pPal[i].rgbGreen); - fp->PutC(pPal[i].rgbBlue); - } - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::EncodeExtension(CxFile *fp) -{ - // TRK BEGIN : transparency - fp->PutC('!'); - fp->PutC(TRANSPARENCY_CODE); - - gifgce.flags = 0; - gifgce.flags |= ((info.nBkgndIndex != -1) ? 1 : 0); - gifgce.flags |= ((GetDisposalMethod() & 0x7) << 2); - gifgce.delaytime = (WORD)info.dwFrameDelay; - gifgce.transpcolindex = (BYTE)info.nBkgndIndex; - - //Invert byte order in case we use a byte order arch, then set it back - gifgce.delaytime = ntohs(gifgce.delaytime); - fp->PutC(sizeof(gifgce)); - fp->Write(&gifgce, sizeof(gifgce), 1); - gifgce.delaytime = ntohs(gifgce.delaytime); - - fp->PutC(0); - // TRK END -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::EncodeLoopExtension(CxFile *fp) -{ - fp->PutC('!'); //byte 1 : 33 (hex 0x21) GIF Extension code - fp->PutC(255); //byte 2 : 255 (hex 0xFF) Application Extension Label - fp->PutC(11); //byte 3 : 11 (hex (0x0B) Length of Application Block (eleven bytes of data to follow) - fp->Write("NETSCAPE2.0",11,1); - fp->PutC(3); //byte 15 : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow) - fp->PutC(1); //byte 16 : 1 (hex 0x01) - Putword(m_loops,fp); //bytes 17 to 18 : 0 to 65535, an unsigned integer in lo-hi byte format. - //This indicate the number of iterations the loop should be executed. - fp->PutC(0); //bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator. -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::EncodeBody(CxFile *fp, bool bLocalColorMap) -{ - curx = 0; - cury = head.biHeight - 1; //because we read the image bottom to top - CountDown = (long)head.biWidth * (long)head.biHeight; - - fp->PutC(','); - - Putword(info.xOffset,fp); - Putword(info.yOffset,fp); - Putword(head.biWidth,fp); - Putword(head.biHeight,fp); - - BYTE Flags=0x00; //non-interlaced (0x40 = interlaced) (0x80 = LocalColorMap) - if (bLocalColorMap) { Flags|=0x80; Flags|=head.biBitCount-1; } - fp->PutC(Flags); - - if (bLocalColorMap){ - Flags|=0x87; - RGBQUAD* pPal = GetPalette(); - for(DWORD i=0; iPutC(pPal[i].rgbRed); - fp->PutC(pPal[i].rgbGreen); - fp->PutC(pPal[i].rgbBlue); - } - } - - int InitCodeSize = head.biBitCount <=1 ? 2 : head.biBitCount; - // Write out the initial code size - fp->PutC((BYTE)InitCodeSize); - - // Go and actually compress the data - switch (GetCodecOption(CXIMAGE_FORMAT_GIF)) - { - case 1: //uncompressed - compressNONE(InitCodeSize+1, fp); - break; - case 2: //RLE - compressRLE(InitCodeSize+1, fp); - break; - default: //LZW - compressLZW(InitCodeSize+1, fp); - } - - // Write out a Zero-length packet (to end the series) - fp->PutC(0); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::EncodeComment(CxFile *fp) -{ - unsigned long n = (unsigned long) strlen(m_comment); - if (n>255) n=255; - if (n) { - fp->PutC('!'); //extension code: - fp->PutC(254); //comment extension - fp->PutC((BYTE)n); //size of comment - fp->Write(m_comment,n,1); - fp->PutC(0); //block terminator - } -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImageGIF::EncodeRGB(CxFile *fp) -{ - EncodeHeader(fp); - -// EncodeLoopExtension(fp); - - EncodeComment(fp); - - unsigned long w,h; - w=h=0; - const long cellw = 17; - const long cellh = 15; - CxImageGIF tmp; - for (long y=0;yPutC(';'); // Write the GIF file terminator - - return true; // done! -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -// Return the next pixel from the image -// fix for 1 & 4 bpp images -int CxImageGIF::GifNextPixel( ) -{ - if( CountDown == 0 ) return EOF; - --CountDown; - int r = GetPixelIndex(curx,cury); - // Bump the current X position - ++curx; - if( curx == head.biWidth ){ - curx = 0; - cury--; //bottom to top - } - return r; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::Putword(int w, CxFile *fp ) -{ - fp->PutC((BYTE)(w & 0xff)); - fp->PutC((BYTE)((w >> 8) & 0xff)); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::compressNONE( int init_bits, CxFile* outfile) -{ - register long c; - register long ent; - - // g_init_bits - initial number of bits - // g_outfile - pointer to output file - g_init_bits = init_bits; - g_outfile = outfile; - - // Set up the necessary values - cur_accum = cur_bits = clear_flg = 0; - maxcode = (short)MAXCODE(n_bits = g_init_bits); - code_int maxmaxcode = (code_int)1 << MAXBITSCODES; - - ClearCode = (1 << (init_bits - 1)); - EOFCode = ClearCode + 1; - free_ent = (short)(ClearCode + 2); - - a_count=0; - ent = GifNextPixel( ); - - output( (code_int)ClearCode ); - - while ( ent != EOF ) { - c = GifNextPixel(); - - output ( (code_int) ent ); - ent = c; - if ( free_ent < maxmaxcode ) { - free_ent++; - } else { - free_ent=(short)(ClearCode+2); - clear_flg=1; - output((code_int)ClearCode); - } - } - // Put out the final code. - output( (code_int) EOFCode ); -} -//////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************** - * - * GIFCOMPR.C - LZW GIF Image compression routines - * - ***************************************************************************/ - -void CxImageGIF::compressLZW( int init_bits, CxFile* outfile) -{ - register long fcode; - register long c; - register long ent; - register long hshift; - register long disp; - register long i; - - // g_init_bits - initial number of bits - // g_outfile - pointer to output file - g_init_bits = init_bits; - g_outfile = outfile; - - // Set up the necessary values - cur_accum = cur_bits = clear_flg = 0; - maxcode = (short)MAXCODE(n_bits = g_init_bits); - code_int maxmaxcode = (code_int)1 << MAXBITSCODES; - - ClearCode = (1 << (init_bits - 1)); - EOFCode = ClearCode + 1; - free_ent = (short)(ClearCode + 2); - - a_count=0; - ent = GifNextPixel( ); - - hshift = 0; - for ( fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L ) ++hshift; - hshift = 8 - hshift; /* set hash code range bound */ - cl_hash((long)HSIZE); /* clear hash table */ - output( (code_int)ClearCode ); - - while ( (c = GifNextPixel( )) != EOF ) { - - fcode = (long) (((long) c << MAXBITSCODES) + ent); - i = (((code_int)c << hshift) ^ ent); /* xor hashing */ - - if ( HashTabOf (i) == fcode ) { - ent = CodeTabOf (i); - continue; - } else if ( (long)HashTabOf (i) < 0 ) /* empty slot */ - goto nomatch; - disp = HSIZE - i; /* secondary hash (after G. Knott) */ - if ( i == 0 ) disp = 1; -probe: - if ( (i -= disp) < 0 ) i += HSIZE; - if ( HashTabOf (i) == fcode ) { ent = CodeTabOf (i); continue; } - if ( (long)HashTabOf (i) > 0 ) goto probe; -nomatch: - output ( (code_int) ent ); - ent = c; - if ( free_ent < maxmaxcode ) { - CodeTabOf (i) = free_ent++; /* code -> hashtable */ - HashTabOf (i) = fcode; - } else { - cl_hash((long)HSIZE); - free_ent=(short)(ClearCode+2); - clear_flg=1; - output((code_int)ClearCode); - } - } - // Put out the final code. - output( (code_int)ent ); - output( (code_int) EOFCode ); -} -//////////////////////////////////////////////////////////////////////////////// - -static const unsigned long code_mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, - 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, - 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::output( code_int code) -{ - cur_accum &= code_mask[ cur_bits ]; - - if( cur_bits > 0 ) - cur_accum |= ((long)code << cur_bits); - else - cur_accum = code; - - cur_bits += n_bits; - - while( cur_bits >= 8 ) { - char_out( (unsigned int)(cur_accum & 0xff) ); - cur_accum >>= 8; - cur_bits -= 8; - } - - /* - * If the next entry is going to be too big for the code size, - * then increase it, if possible. - */ - - if ( free_ent > maxcode || clear_flg ) { - if( clear_flg ) { - maxcode = (short)MAXCODE(n_bits = g_init_bits); - clear_flg = 0; - } else { - ++n_bits; - if ( n_bits == MAXBITSCODES ) - maxcode = (code_int)1 << MAXBITSCODES; /* should NEVER generate this code */ - else - maxcode = (short)MAXCODE(n_bits); - } - } - - if( code == EOFCode ) { - // At EOF, write the rest of the buffer. - while( cur_bits > 0 ) { - char_out( (unsigned int)(cur_accum & 0xff) ); - cur_accum >>= 8; - cur_bits -= 8; - } - - flush_char(); - g_outfile->Flush(); - - if(g_outfile->Error()) strcpy(info.szLastError,"Write Error in GIF file"); - } -} -//////////////////////////////////////////////////////////////////////////////// - -void CxImageGIF::cl_hash(long hsize) - -{ - register long *htab_p = htab+hsize; - - register long i; - register long m1 = -1L; - - i = hsize - 16; - - do { - *(htab_p-16)=m1; - *(htab_p-15)=m1; - *(htab_p-14)=m1; - *(htab_p-13)=m1; - *(htab_p-12)=m1; - *(htab_p-11)=m1; - *(htab_p-10)=m1; - *(htab_p-9)=m1; - *(htab_p-8)=m1; - *(htab_p-7)=m1; - *(htab_p-6)=m1; - *(htab_p-5)=m1; - *(htab_p-4)=m1; - *(htab_p-3)=m1; - *(htab_p-2)=m1; - *(htab_p-1)=m1; - - htab_p-=16; - } while ((i-=16) >=0); - - for (i+=16;i>0;--i) - *--htab_p=m1; -} - -/******************************************************************************* -* GIF specific -*******************************************************************************/ - -void CxImageGIF::char_out(int c) -{ - accum[a_count++]=(char)c; - if (a_count >=254) - flush_char(); -} - -void CxImageGIF::flush_char() -{ - if (a_count > 0) { - g_outfile->PutC((BYTE)a_count); - g_outfile->Write(accum,1,a_count); - a_count=0; - } -} - -/******************************************************************************* -* GIF decoder -*******************************************************************************/ -/* DECODE.C - An LZW decoder for GIF - * Copyright (C) 1987, by Steven A. Bennett - * Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra -* - * Permission is given by the author to freely redistribute and include - * this code in any program as long as this credit is given where due. - * - * In accordance with the above, I want to credit Steve Wilhite who wrote - * the code which this is heavily inspired by... - * - * GIF and 'Graphics Interchange Format' are trademarks (tm) of - * Compuserve, Incorporated, an H&R Block Company. - * - * Release Notes: This file contains a decoder routine for GIF images - * which is similar, structurally, to the original routine by Steve Wilhite. - * It is, however, somewhat noticably faster in most cases. - * - */ - -//////////////////////////////////////////////////////////////////////////////// - -short CxImageGIF::init_exp(short size) -{ - curr_size = (short)(size + 1); - top_slot = (short)(1 << curr_size); - clear = (short)(1 << size); - ending = (short)(clear + 1); - slot = newcodes = (short)(ending + 1); - navail_bytes = nbits_left = 0; - - memset(stack,0,MAX_CODES + 1); - memset(prefix,0,MAX_CODES + 1); - memset(suffix,0,MAX_CODES + 1); - return(0); -} -//////////////////////////////////////////////////////////////////////////////// - -/* get_next_code() - * - gets the next code from the GIF file. Returns the code, or else - * a negative number in case of file errors... - */ -short CxImageGIF::get_next_code(CxFile* file) -{ - short i, x; - DWORD ret; - - if (nbits_left == 0) { - if (navail_bytes <= 0) { - /* Out of bytes in current block, so read next block */ - pbytes = byte_buff; - if ((navail_bytes = (short)get_byte(file)) < 0) - return(navail_bytes); - else if (navail_bytes) { - for (i = 0; i < navail_bytes; ++i) { - if ((x = (short)get_byte(file)) < 0) return(x); - byte_buff[i] = (BYTE)x; - } - } - } - b1 = *pbytes++; - nbits_left = 8; - --navail_bytes; - } - - if (navail_bytes<0) return ending; // prevent deadlocks (thanks to Mike Melnikov) - - ret = b1 >> (8 - nbits_left); - while (curr_size > nbits_left){ - if (navail_bytes <= 0){ - /* Out of bytes in current block, so read next block*/ - pbytes = byte_buff; - if ((navail_bytes = (short)get_byte(file)) < 0) - return(navail_bytes); - else if (navail_bytes){ - for (i = 0; i < navail_bytes; ++i){ - if ((x = (short)get_byte(file)) < 0) return(x); - byte_buff[i] = (BYTE)x; - } - } - } - b1 = *pbytes++; - ret |= b1 << nbits_left; - nbits_left += 8; - --navail_bytes; - } - nbits_left = (short)(nbits_left-curr_size); - ret &= code_mask[curr_size]; - return((short)(ret)); -} -//////////////////////////////////////////////////////////////////////////////// - -/* short decoder(linewidth) - * short linewidth; * Pixels per line of image * - * - * - This function decodes an LZW image, according to the method used - * in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded - * will generate a call to out_line(), which is a user specific function - * to display a line of pixels. The function gets it's codes from - * get_next_code() which is responsible for reading blocks of data and - * seperating them into the proper size codes. Finally, get_byte() is - * the global routine to read the next BYTE from the GIF file. - * - * It is generally a good idea to have linewidth correspond to the actual - * width of a line (as specified in the Image header) to make your own - * code a bit simpler, but it isn't absolutely necessary. - * - * Returns: 0 if successful, else negative. (See ERRS.H) - * - */ -/* bad_code_count is incremented each time an out of range code is read. - * When this value is non-zero after a decode, your GIF file is probably - * corrupt in some way... - */ -short CxImageGIF::decoder(CxFile* file, CImageIterator* iter, short linewidth, int &bad_code_count) -{ - register BYTE *sp, *bufptr; - BYTE *buf; - register short code, fc, oc, bufcnt; - short c, size, ret; - - /* Initialize for decoding a new image... */ - bad_code_count = 0; - if ((size = (short)get_byte(file)) < 0) return(size); - if (size < 2 || 9 < size) return(BAD_CODE_SIZE); - // out_line = outline; - init_exp(size); - //printf("L %d %x\n",linewidth,size); - - /* Initialize in case they forgot to put in a clear code. - * (This shouldn't happen, but we'll try and decode it anyway...) - */ - oc = fc = 0; - - /* Allocate space for the decode buffer */ - if ((buf = new BYTE[linewidth + 1]) == NULL) return(OUT_OF_MEMORY); - - /* Set up the stack pointer and decode buffer pointer */ - sp = stack; - bufptr = buf; - bufcnt = linewidth; - - /* This is the main loop. For each code we get we pass through the - * linked list of prefix codes, pushing the corresponding "character" for - * each code onto the stack. When the list reaches a single "character" - * we push that on the stack too, and then start unstacking each - * character for output in the correct order. Special handling is - * included for the clear code, and the whole thing ends when we get - * an ending code. - */ - while ((c = get_next_code(file)) != ending) { - /* If we had a file error, return without completing the decode*/ - if (c < 0){ - delete [] buf; - return(0); - } - /* If the code is a clear code, reinitialize all necessary items.*/ - if (c == clear){ - curr_size = (short)(size + 1); - slot = newcodes; - top_slot = (short)(1 << curr_size); - - /* Continue reading codes until we get a non-clear code - * (Another unlikely, but possible case...) - */ - while ((c = get_next_code(file)) == clear); - - /* If we get an ending code immediately after a clear code - * (Yet another unlikely case), then break out of the loop. - */ - if (c == ending) break; - - /* Finally, if the code is beyond the range of already set codes, - * (This one had better NOT happen... I have no idea what will - * result from this, but I doubt it will look good...) then set it - * to color zero. - */ - if (c >= slot) c = 0; - oc = fc = c; - - /* And let us not forget to put the char into the buffer... And - * if, on the off chance, we were exactly one pixel from the end - * of the line, we have to send the buffer to the out_line() - * routine... - */ - *bufptr++ = (BYTE)c; - if (--bufcnt == 0) { - if (iter) { - if ((ret = (short)out_line(iter, buf, linewidth)) < 0) { - delete [] buf; - return(ret); - } - } - bufptr = buf; - bufcnt = linewidth; - } - } else { - /* In this case, it's not a clear code or an ending code, so - * it must be a code code... So we can now decode the code into - * a stack of character codes. (Clear as mud, right?) - */ - code = c; - - /* Here we go again with one of those off chances... If, on the - * off chance, the code we got is beyond the range of those already - * set up (Another thing which had better NOT happen...) we trick - * the decoder into thinking it actually got the last code read. - * (Hmmn... I'm not sure why this works... But it does...) - */ - if (code >= slot && sp<(stack+MAX_CODES-1)) { - if (code > slot) - ++bad_code_count; - code = oc; - *sp++ = (BYTE)fc; - } - - /* Here we scan back along the linked list of prefixes, pushing - * helpless characters (ie. suffixes) onto the stack as we do so. - */ - while (code >= newcodes && sp<(stack+MAX_CODES-1)) { - *sp++ = suffix[code]; - code = prefix[code]; - } - - /* Push the last character on the stack, and set up the new - * prefix and suffix, and if the required slot number is greater - * than that allowed by the current bit size, increase the bit - * size. (NOTE - If we are all full, we *don't* save the new - * suffix and prefix... I'm not certain if this is correct... - * it might be more proper to overwrite the last code... - */ - *sp++ = (BYTE)code; - if (slot < top_slot){ - suffix[slot] = (BYTE)(fc = (BYTE)code); - prefix[slot++] = oc; - oc = c; - } - if (slot >= top_slot){ - if (curr_size < 12) { - top_slot <<= 1; - ++curr_size; - } - } - - /* Now that we've pushed the decoded string (in reverse order) - * onto the stack, lets pop it off and put it into our decode - * buffer... And when the decode buffer is full, write another - * line... - */ - while (sp > stack) { - *bufptr++ = *(--sp); - if (--bufcnt == 0) { - if (iter) { - if ((ret = (short)out_line(iter, buf, linewidth)) < 0) { - delete [] buf; - return(ret); - } - } - bufptr = buf; - bufcnt = linewidth; - } - } - } - } - ret = 0; - if (bufcnt != linewidth && iter) - ret = (short)out_line(iter, buf, (linewidth - bufcnt)); - delete [] buf; - return(ret); -} -//////////////////////////////////////////////////////////////////////////////// -int CxImageGIF::get_num_frames(CxFile *fp,struct_TabCol* TabColSrc,struct_dscgif* dscgif) -{ - struct_image image; - - long pos=fp->Tell(); - int nframes=0; - - struct_TabCol TempTabCol; - memcpy(&TempTabCol,TabColSrc,sizeof(struct_TabCol)); - - char ch; - bool bPreviousWasNull = true; - - for (BOOL bContinue = TRUE; bContinue; ) - { - if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;} - - if (bPreviousWasNull || ch==0) - { - switch (ch) - { - case '!': // extension - { - DecodeExtension(fp); - break; - } - case ',': // image - { - - assert(sizeof(image) == 9); - //log << "Image header" << endl; - fp->Read(&image,sizeof(image),1); - - //avoid byte order problems with Solaris - image.l = ntohs(image.l); - image.t = ntohs(image.t); - image.w = ntohs(image.w); - image.h = ntohs(image.h); - - // in case of images with empty screen descriptor, give a last chance - if (dscgif->scrwidth==0 && dscgif->scrheight==0){ - dscgif->scrwidth = image.w; - dscgif->scrheight = image.h; - } - - if (((image.l + image.w) > dscgif->scrwidth)||((image.t + image.h) > dscgif->scrheight)) - break; - - nframes++; - - // Local colour map? - if (image.pf & 0x80) { - TempTabCol.sogct = (short)(1 << ((image.pf & 0x07) +1)); - assert(3 == sizeof(struct rgb_color)); - fp->Read(TempTabCol.paleta,sizeof(struct rgb_color)*TempTabCol.sogct,1); - //log << "Local colour map" << endl; - } - - int badcode=0; - ibf = GIFBUFTAM+1; - - interlaced = image.pf & 0x40; - iheight = image.h; - istep = 8; - iypos = 0; - ipass = 0; - - long pos_start = fp->Tell(); - - //if (interlaced) log << "Interlaced" << endl; - decoder(fp, 0, image.w, badcode); - - if (badcode){ - seek_next_image(fp,pos_start); - } else { - fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR); - } - - break; - } - case ';': //terminator - bContinue=false; - break; - default: - bPreviousWasNull = (ch==0); - break; - } - } - } - - fp->Seek(pos,SEEK_SET); - return nframes; -} -//////////////////////////////////////////////////////////////////////////////// -long CxImageGIF::seek_next_image(CxFile* fp, long position) -{ - fp->Seek(position, SEEK_SET); - char ch1,ch2; - ch1=ch2=0; - while(fp->Read(&ch2,sizeof(char),1)>0){ - if (ch1 == 0 && ch2 == ','){ - fp->Seek(-1,SEEK_CUR); - return fp->Tell(); - } else { - ch1 = ch2; - } - } - return -1; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::SetLoops(int loops) -{ m_loops=loops; } -//////////////////////////////////////////////////////////////////////////////// -long CxImageGIF::GetLoops() -{ return m_loops; } -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::SetComment(const char* sz_comment_in) -{ if (sz_comment_in) strncpy(m_comment,sz_comment_in,255); } -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::GetComment(char* sz_comment_out) -{ if (sz_comment_out) strncpy(sz_comment_out,m_comment,255); } -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::GifMix(CxImage & imgsrc2, struct_image & imgdesc) -{ - long ymin = max(0,(long)(GetHeight()-imgdesc.t - imgdesc.h)); - long ymax = GetHeight()-imgdesc.t; - long xmin = imgdesc.l; - long xmax = min(GetWidth(), (DWORD)(imgdesc.l + imgdesc.w)); - - long ibg2= imgsrc2.GetTransIndex(); - BYTE i2; - - for(long y = ymin; y < ymax; y++){ - for(long x = xmin; x < xmax; x++){ - i2 = imgsrc2.GetPixelIndex(x-xmin,y-ymin); - if(i2!=ibg2) SetPixelIndex(x,y,i2); - } - } -} -//////////////////////////////////////////////////////////////////////////////// -/*----------------------------------------------------------------------- - * - * miGIF Compression - mouse and ivo's GIF-compatible compression - * - * -run length encoding compression routines- - * - * Copyright (C) 1998 Hutchison Avenue Software Corporation - * http://www.hasc.com - * info@hasc.com - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, provided - * that the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation. This software is provided "AS IS." The Hutchison Avenue - * Software Corporation disclaims all warranties, either express or implied, - * including but not limited to implied warranties of merchantability and - * fitness for a particular purpose, with respect to this code and accompanying - * documentation. - * - * The miGIF compression routines do not, strictly speaking, generate files - * conforming to the GIF spec, since the image data is not LZW-compressed - * (this is the point: in order to avoid transgression of the Unisys patent - * on the LZW algorithm.) However, miGIF generates data streams that any - * reasonably sane LZW decompresser will decompress to what we want. - * - * miGIF compression uses run length encoding. It compresses horizontal runs - * of pixels of the same color. This type of compression gives good results - * on images with many runs, for example images with lines, text and solid - * shapes on a solid-colored background. It gives little or no compression - * on images with few runs, for example digital or scanned photos. - * - * der Mouse - * mouse@rodents.montreal.qc.ca - * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B - * - * ivo@hasc.com - * - * The Graphics Interchange Format(c) is the Copyright property of - * CompuServe Incorporated. GIF(sm) is a Service Mark property of - * CompuServe Incorporated. - * - */ -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_clear(struct_RLE* rle) -{ - rle->out_bits = rle->out_bits_init; - rle->out_bump = rle->out_bump_init; - rle->out_clear = rle->out_clear_init; - rle->out_count = 0; - rle->rl_table_max = 0; - rle->just_cleared = 1; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_flush(struct_RLE* rle) -{ - if (rle->rl_count == 1){ - rle_output_plain(rle->rl_pixel,rle); - rle->rl_count = 0; - return; - } - if (rle->just_cleared){ - rle_flush_fromclear(rle->rl_count,rle); - } else if ((rle->rl_table_max < 2) || (rle->rl_table_pixel != rle->rl_pixel)) { - rle_flush_clearorrep(rle->rl_count,rle); - } else { - rle_flush_withtable(rle->rl_count,rle); - } - rle->rl_count = 0; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_output_plain(int c,struct_RLE* rle) -{ - rle->just_cleared = 0; - rle_output(c,rle); - rle->out_count++; - if (rle->out_count >= rle->out_bump){ - rle->out_bits ++; - rle->out_bump += 1 << (rle->out_bits - 1); - } - if (rle->out_count >= rle->out_clear){ - rle_output(rle->code_clear,rle); - rle_clear(rle); - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_flush_fromclear(int count,struct_RLE* rle) -{ - int n; - - rle->out_clear = rle->max_ocodes; - rle->rl_table_pixel = rle->rl_pixel; - n = 1; - while (count > 0){ - if (n == 1){ - rle->rl_table_max = 1; - rle_output_plain(rle->rl_pixel,rle); - count --; - } else if (count >= n){ - rle->rl_table_max = n; - rle_output_plain(rle->rl_basecode+n-2,rle); - count -= n; - } else if (count == 1){ - rle->rl_table_max ++; - rle_output_plain(rle->rl_pixel,rle); - count = 0; - } else { - rle->rl_table_max ++; - rle_output_plain(rle->rl_basecode+count-2,rle); - count = 0; - } - if (rle->out_count == 0) n = 1; else n ++; - } - rle_reset_out_clear(rle); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_reset_out_clear(struct_RLE* rle) -{ - rle->out_clear = rle->out_clear_init; - if (rle->out_count >= rle->out_clear){ - rle_output(rle->code_clear,rle); - rle_clear(rle); - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_flush_withtable(int count, struct_RLE* rle) -{ - int repmax; - int repleft; - int leftover; - - repmax = count / rle->rl_table_max; - leftover = count % rle->rl_table_max; - repleft = (leftover ? 1 : 0); - if (rle->out_count+repmax+repleft > rle->max_ocodes){ - repmax = rle->max_ocodes - rle->out_count; - leftover = count - (repmax * rle->rl_table_max); - repleft = 1 + rle_compute_triangle_count(leftover,rle->max_ocodes); - } - if (1+rle_compute_triangle_count(count,rle->max_ocodes) < (unsigned int)(repmax+repleft)){ - rle_output(rle->code_clear,rle); - rle_clear(rle); - rle_flush_fromclear(count,rle); - return; - } - rle->out_clear = rle->max_ocodes; - for (;repmax>0;repmax--) rle_output_plain(rle->rl_basecode+rle->rl_table_max-2,rle); - if (leftover){ - if (rle->just_cleared){ - rle_flush_fromclear(leftover,rle); - } else if (leftover == 1){ - rle_output_plain(rle->rl_pixel,rle); - } else { - rle_output_plain(rle->rl_basecode+leftover-2,rle); - } - } - rle_reset_out_clear(rle); -} -//////////////////////////////////////////////////////////////////////////////// -unsigned int CxImageGIF::rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes) -{ - unsigned int perrep; - unsigned int cost; - - cost = 0; - perrep = (nrepcodes * (nrepcodes+1)) / 2; - while (count >= perrep){ - cost += nrepcodes; - count -= perrep; - } - if (count > 0){ - unsigned int n; - n = rle_isqrt(count); - while ((n*(n+1)) >= 2*count) n --; - while ((n*(n+1)) < 2*count) n ++; - cost += n; - } - return(cost); -} -//////////////////////////////////////////////////////////////////////////////// -unsigned int CxImageGIF::rle_isqrt(unsigned int x) -{ - unsigned int r; - unsigned int v; - - if (x < 2) return(x); - for (v=x,r=1;v;v>>=2,r<<=1) ; - for( ;; ) - { - v = ((x / r) + r) / 2; - if ((v == r) || (v == r+1)) return(r); - r = v; - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_flush_clearorrep(int count, struct_RLE* rle) -{ - int withclr; - withclr = 1 + rle_compute_triangle_count(count,rle->max_ocodes); - if (withclr < count) { - rle_output(rle->code_clear,rle); - rle_clear(rle); - rle_flush_fromclear(count,rle); - } else { - for (;count>0;count--) rle_output_plain(rle->rl_pixel,rle); - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_write_block(struct_RLE* rle) -{ - g_outfile->PutC((BYTE)rle->oblen); - g_outfile->Write(rle->oblock,1,rle->oblen); - rle->oblen = 0; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_block_out(unsigned char c, struct_RLE* rle) -{ - rle->oblock[rle->oblen++] = c; - if (rle->oblen >= 255) rle_write_block(rle); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_block_flush(struct_RLE* rle) -{ - if (rle->oblen > 0) rle_write_block(rle); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_output(int val, struct_RLE* rle) -{ - rle->obuf |= val << rle->obits; - rle->obits += rle->out_bits; - while (rle->obits >= 8){ - rle_block_out((unsigned char)(rle->obuf&0xff),rle); - rle->obuf >>= 8; - rle->obits -= 8; - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::rle_output_flush(struct_RLE* rle) -{ - if (rle->obits > 0) rle_block_out((unsigned char)(rle->obuf),rle); - rle_block_flush(rle); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageGIF::compressRLE( int init_bits, CxFile* outfile) -{ - g_init_bits = init_bits; - g_outfile = outfile; - - struct_RLE rle; - rle.code_clear = 1 << (init_bits - 1); - rle.code_eof = rle.code_clear + 1; - rle.rl_basecode = rle.code_eof + 1; - rle.out_bump_init = (1 << (init_bits - 1)) - 1; - rle.out_clear_init = (init_bits <= 3) ? 9 : (rle.out_bump_init-1); - rle.out_bits_init = init_bits; - rle.max_ocodes = (1 << MAXBITSCODES) - ((1 << (rle.out_bits_init - 1)) + 3); - rle.rl_count = 0; - rle_clear(&rle); - rle.obuf = 0; - rle.obits = 0; - rle.oblen = 0; - - rle_output(rle.code_clear,&rle); - - int c; - for( ;; ) - { - c = GifNextPixel(); - if ((rle.rl_count > 0) && (c != rle.rl_pixel)) rle_flush(&rle); - if (c == EOF) break; - if (rle.rl_pixel == c){ - rle.rl_count++; - } else { - rle.rl_pixel = c; - rle.rl_count = 1; - } - } - rle_output(rle.code_eof,&rle); - rle_output_flush(&rle); -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_GIF +/* + * File: ximagif.cpp + * Purpose: Platform Independent GIF Image Class Loader and Writer + * 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximagif.h" + +#if CXIMAGE_SUPPORT_GIF + +#include "ximaiter.h" + +#if defined (_WIN32_WCE) + #define assert(s) +#else + #include +#endif + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageGIF::Decode(CxFile *fp) +{ + /* AD - for transparency */ + struct_dscgif dscgif; + struct_image image; + struct_TabCol TabCol; + + if (fp == NULL) return false; + + fp->Read(&dscgif,/*sizeof(dscgif)*/13,1); + //if (strncmp(dscgif.header,"GIF8",3)!=0) { + if (strncmp(dscgif.header,"GIF8",4)!=0) return FALSE; + + // Avoid Byte order problem with Mac + dscgif.scrheight = ntohs(dscgif.scrheight); + dscgif.scrwidth = ntohs(dscgif.scrwidth); + + if (info.nEscape == -1) { + // Return output dimensions only + head.biWidth = dscgif.scrwidth; + head.biHeight = dscgif.scrheight; + info.dwType = CXIMAGE_FORMAT_GIF; + return true; + } + + /* AD - for interlace */ + TabCol.sogct = (short)(1 << ((dscgif.pflds & 0x07)+1)); + TabCol.colres = (short)(((dscgif.pflds & 0x70) >> 4) + 1); + + // assume that the image is a truecolor-gif if + // 1) no global color map found + // 2) (image.w, image.h) of the 1st image != (dscgif.scrwidth, dscgif.scrheight) + long bTrueColor=0; + CxImage* imaRGB=NULL; + + // Global colour map? + if (dscgif.pflds & 0x80) + fp->Read(TabCol.paleta,sizeof(struct rgb_color)*TabCol.sogct,1); + else + bTrueColor++; //first chance for a truecolor gif + + long first_transparent_index = 0; + + int iImage = 0; + info.nNumFrames=get_num_frames(fp,&TabCol,&dscgif); + + if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)) return false; + + //it cannot be a true color GIF with only one frame + if (info.nNumFrames == 1) + bTrueColor=0; + + char ch; + bool bPreviousWasNull = true; + int prevdispmeth = 0; + CxImage *previousFrame = NULL; + + for (BOOL bContinue = TRUE; bContinue; ) + { + if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;} + + if (info.nEscape > 0) return false; // - cancel decoding + if (bPreviousWasNull || ch==0) + { + switch (ch) + { + case '!': // extension + { + bContinue = DecodeExtension(fp); + break; + } + case ',': // image + { + assert(sizeof(image) == 9); + fp->Read(&image,sizeof(image),1); + //avoid byte order problems with Solaris + image.l = ntohs(image.l); + image.t = ntohs(image.t); + image.w = ntohs(image.w); + image.h = ntohs(image.h); + + if (((image.l + image.w) > dscgif.scrwidth)||((image.t + image.h) > dscgif.scrheight)) + break; + + // check if it could be a truecolor gif + if ((iImage==0) && (image.w != dscgif.scrwidth) && (image.h != dscgif.scrheight)) + bTrueColor++; + + rgb_color locpal[256]; //Local Palette + rgb_color* pcurpal = TabCol.paleta; //Current Palette + short palcount = TabCol.sogct; //Current Palette color count + + // Local colour map? + if (image.pf & 0x80) { + palcount = (short)(1 << ((image.pf & 0x07) +1)); + assert(3 == sizeof(struct rgb_color)); + fp->Read(locpal,sizeof(struct rgb_color)*palcount,1); + pcurpal = locpal; + } + + int bpp; // select the correct bit per pixel value + if (palcount <= 2) bpp = 1; + else if (palcount <= 16) bpp = 4; + else bpp = 8; + + CxImageGIF backimage; + backimage.CopyInfo(*this); + if (iImage==0){ + //first frame: build image background + backimage.Create(dscgif.scrwidth, dscgif.scrheight, bpp, CXIMAGE_FORMAT_GIF); + first_transparent_index = info.nBkgndIndex; + backimage.Clear((BYTE)gifgce.transpcolindex); + previousFrame = new CxImage(backimage); + previousFrame->SetRetreiveAllFrames(false); + } else { + //generic frame: handle disposal method from previous one + /*Values : 0 - No disposal specified. The decoder is + not required to take any action. + 1 - Do not dispose. The graphic is to be left + in place. + 2 - Restore to background color. The area used by the + graphic must be restored to the background color. + 3 - Restore to previous. The decoder is required to + restore the area overwritten by the graphic with + what was there prior to rendering the graphic. + */ + /* backimage.Copy(*this); + if (prevdispmeth==2){ + backimage.Clear((BYTE)first_transparent_index); + }*/ + if (prevdispmeth==2){ + backimage.Copy(*this,false,false,false); + backimage.Clear((BYTE)first_transparent_index); + } else if (prevdispmeth==3) { + backimage.Copy(*this,false,false,false); + backimage.Create(previousFrame->GetWidth(), + previousFrame->GetHeight(), + previousFrame->GetBpp(),CXIMAGE_FORMAT_GIF); + memcpy(backimage.GetDIB(),previousFrame->GetDIB(), + backimage.GetSize()); + backimage.AlphaSet(*previousFrame); + } else { + backimage.Copy(*this); + } + } + + //active frame + Create(image.w, image.h, bpp, CXIMAGE_FORMAT_GIF); + + if ((image.pf & 0x80) || (dscgif.pflds & 0x80)) { + unsigned char r[256], g[256], b[256]; + int i, has_white = 0; + + for (i=0; i < palcount; i++) { + r[i] = pcurpal[i].r; + g[i] = pcurpal[i].g; + b[i] = pcurpal[i].b; + if (RGB(r[i],g[i],b[i]) == 0xFFFFFF) has_white = 1; + } + + // Force transparency colour white... + //if (0) if (info.nBkgndIndex >= 0) + // r[info.nBkgndIndex] = g[info.nBkgndIndex] = b[info.nBkgndIndex] = 255; + // Fill in with white // AD + if (info.nBkgndIndex >= 0) { + while (i < 256) { + has_white = 1; + r[i] = g[i] = b[i] = 255; + i++; + } + } + + // Force last colour to white... // AD + //if ((info.nBkgndIndex >= 0) && !has_white) { + // r[255] = g[255] = b[255] = 255; + //} + + SetPalette((info.nBkgndIndex >= 0 ? 256 : palcount), r, g, b); + } + + CImageIterator* iter = new CImageIterator(this); + iter->Upset(); + int badcode=0; + ibf = GIFBUFTAM+1; + + interlaced = image.pf & 0x40; + iheight = image.h; + istep = 8; + iypos = 0; + ipass = 0; + + long pos_start = fp->Tell(); + //if (interlaced) log << "Interlaced" << endl; + decoder(fp, iter, image.w, badcode); + delete iter; + + if (info.nEscape) return false; // - cancel decoding + + if (bTrueColor<2 ){ //standard GIF: mix frame with background + backimage.GifMix(*this,image); + backimage.SetTransIndex(first_transparent_index); + backimage.SetPalette(GetPalette()); + Transfer(backimage,false); + } else { //it's a truecolor gif! + //force full image decoding + info.nFrame=info.nNumFrames-1; + //build the RGB image + if (imaRGB==NULL) imaRGB = new CxImage(dscgif.scrwidth,dscgif.scrheight,24,CXIMAGE_FORMAT_GIF); + //copy the partial image into the full RGB image + for(long y=0;ySetPixelColor(x+image.l,dscgif.scrheight-1-image.t-y,GetPixelColor(x,image.h-y-1)); + } + } + } + + prevdispmeth = (gifgce.flags >> 2) & 0x7; + + //restore the correct position in the file for the next image + if (badcode){ + seek_next_image(fp,pos_start); + } else { + fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR); + } + + if (info.bGetAllFrames && imaRGB == NULL) { + if (iImage == 0) { + DestroyFrames(); + ppFrames = new CxImage*[info.nNumFrames]; + for(int frameIdx = 0; frameIdx < info.nNumFrames; frameIdx++){ + ppFrames[frameIdx] = NULL; + } + } + ppFrames[iImage] = new CxImage(*this); + ppFrames[iImage]->SetRetreiveAllFrames(false); + } + if (prevdispmeth <= 1) { + delete previousFrame; + previousFrame = new CxImage(*this); + previousFrame->SetRetreiveAllFrames(false); + } + + if (info.nFrame==iImage) bContinue=false; else iImage++; + + break; + } + case ';': //terminator + bContinue=false; + break; + default: + bPreviousWasNull = (ch==0); + break; + } + } + } + + if (bTrueColor>=2 && imaRGB){ + if (gifgce.flags & 0x1){ + imaRGB->SetTransColor(GetPaletteColor((BYTE)info.nBkgndIndex)); + imaRGB->SetTransIndex(0); + } + Transfer(*imaRGB); + } + delete imaRGB; + + delete previousFrame; + + return true; + +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImageGIF::DecodeExtension(CxFile *fp) +{ + bool bContinue; + unsigned char count; + unsigned char fc; + + bContinue = (1 == fp->Read(&fc, sizeof(fc), 1)); + if (bContinue) { + /* AD - for transparency */ + if (fc == 0xF9) { + bContinue = (1 == fp->Read(&count, sizeof(count), 1)); + if (bContinue) { + assert(sizeof(gifgce) == 4); + bContinue = (count == fp->Read(&gifgce, 1, sizeof(gifgce))); + gifgce.delaytime = ntohs(gifgce.delaytime); // Avoid Byte order problem with Mac + if (bContinue) { + info.nBkgndIndex = (gifgce.flags & 0x1) ? gifgce.transpcolindex : -1; + info.dwFrameDelay = gifgce.delaytime; + SetDisposalMethod((gifgce.flags >> 2) & 0x7); + } } } + + if (fc == 0xFE) { // Comment block + bContinue = (1 == fp->Read(&count, sizeof(count), 1)); + if (bContinue) { + bContinue = (1 == fp->Read(m_comment, count, 1)); + m_comment[count]='\0'; + } } + + if (fc == 0xFF) { // Application Extension block + bContinue = (1 == fp->Read(&count, sizeof(count), 1)); + if (bContinue) { + bContinue = (count==11); + if (bContinue){ + char AppID[11]; + bContinue = (1 == fp->Read(AppID, count, 1)); + if (bContinue) { + bContinue = (1 == fp->Read(&count, sizeof(count), 1)); + if (bContinue) { + BYTE* dati = (BYTE*)malloc(count); + bContinue = (dati!=NULL); + if (bContinue){ + bContinue = (1 == fp->Read(dati, count, 1)); + if (count>2){ + m_loops = dati[1]+256*dati[2]; + } + } + free(dati); + } } } } } + + while (bContinue && fp->Read(&count, sizeof(count), 1) && count) { + //log << "Skipping " << count << " bytes" << endl; + fp->Seek(count, SEEK_CUR); + } + } + return bContinue; + +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// + +// - This external (machine specific) function is expected to return +// either the next BYTE from the GIF file, or a negative error number. +int CxImageGIF::get_byte(CxFile* file) +{ + if (ibf>=GIFBUFTAM){ + // FW 06/02/98 >>> + ibfmax = (int)file->Read( buf , 1 , GIFBUFTAM) ; + if( ibfmax < GIFBUFTAM ) buf[ ibfmax ] = 255 ; + // FW 06/02/98 <<< + ibf = 0; + } + if (ibf>=ibfmax) return -1; // avoid overflows + return buf[ibf++]; +} +//////////////////////////////////////////////////////////////////////////////// +/* - This function takes a full line of pixels (one BYTE per pixel) and + * displays them (or does whatever your program wants with them...). It + * should return zero, or negative if an error or some other event occurs + * which would require aborting the decode process... Note that the length + * passed will almost always be equal to the line length passed to the + * decoder function, with the sole exception occurring when an ending code + * occurs in an odd place in the GIF file... In any case, linelen will be + * equal to the number of pixels passed... +*/ +int CxImageGIF::out_line(CImageIterator* iter, unsigned char *pixels, int linelen) +{ + if (iter == NULL || pixels == NULL) + return -1; + + // for 1 & 4 bpp images, the pixels are compressed + if (head.biBitCount < 8){ + for(long x=0;x> 3); + if (head.biBitCount==4){ + pos = (BYTE)(4*(1-x%2)); + *iDst &= ~(0x0F<SetY(iheight-iypos-1); + iter->SetRow(pixels, linelen); + + if ((iypos += istep) >= iheight) { + do { + if (ipass++ > 0) istep /= 2; + iypos = istep / 2; + } + while (iypos > iheight); + } + return 0; + } else { + if (iter->ItOK()) { + iter->SetRow(pixels, linelen); + (void)iter->PrevRow(); + return 0; + } else { + // puts("chafeo"); + return -1; + } + } +} +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +// SaveFile - writes GIF87a gif file +// Randy Spann 6/15/97 +// R.Spann@ConnRiver.net +bool CxImageGIF::Encode(CxFile * fp) +{ + if (EncodeSafeCheck(fp)) return false; + + if(head.biBitCount > 8) { + //strcpy(info.szLastError,"GIF Images must be 8 bit or less"); + //return FALSE; + return EncodeRGB(fp); + } + + if ( GetNumFrames()>1 && ppFrames ) { + return Encode(fp, ppFrames, GetNumFrames() ); + } + + EncodeHeader(fp); + + EncodeExtension(fp); + + EncodeComment(fp); + + EncodeBody(fp); + + fp->PutC(';'); // Write the GIF file terminator + + return true; // done! +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImageGIF::Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap, bool bLocalDispMeth) +{ + cx_try { + if (fp==NULL) cx_throw("invalid file pointer"); + if (pImages==NULL || pagecount<=0 || pImages[0]==NULL) cx_throw("multipage GIF, no images!"); + + int i; + for (i=0; iIsValid())) + cx_throw("Empty image"); + if (pImages[i]->GetNumColors()==0) + cx_throw("CxImageGIF::Encode cannot create animated GIFs with a true color frame. Use DecreaseBpp before"); + } + + CxImageGIF ghost; + + //write the first image + ghost.Ghost(pImages[0]); + ghost.EncodeHeader(fp); + + if (m_loops!=1){ + ghost.SetLoops(max(0,m_loops-1)); + ghost.EncodeLoopExtension(fp); + } + + if (bLocalDispMeth) { + ghost.EncodeExtension(fp); + } else { + BYTE dm = ghost.GetDisposalMethod(); + ghost.SetDisposalMethod(GetDisposalMethod()); + ghost.EncodeExtension(fp); + ghost.SetDisposalMethod(dm); + } + + EncodeComment(fp); + + ghost.EncodeBody(fp); + + for (i=1; iPutC(';'); // Write the GIF file terminator + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + return false; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::EncodeHeader(CxFile *fp) +{ + fp->Write("GIF89a",1,6); //GIF Header + + Putword(head.biWidth,fp); //Logical screen descriptor + Putword(head.biHeight,fp); + + BYTE Flags; + if (head.biClrUsed==0){ + Flags=0x11; + } else { + Flags = 0x80; + Flags |=(head.biBitCount - 1) << 5; + Flags |=(head.biBitCount - 1); + } + + fp->PutC(Flags); //GIF "packed fields" + fp->PutC(0); //GIF "BackGround" + fp->PutC(0); //GIF "pixel aspect ratio" + + if (head.biClrUsed!=0){ + RGBQUAD* pPal = GetPalette(); + for(DWORD i=0; iPutC(pPal[i].rgbRed); + fp->PutC(pPal[i].rgbGreen); + fp->PutC(pPal[i].rgbBlue); + } + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::EncodeExtension(CxFile *fp) +{ + // TRK BEGIN : transparency + fp->PutC('!'); + fp->PutC(TRANSPARENCY_CODE); + + gifgce.flags = 0; + gifgce.flags |= ((info.nBkgndIndex != -1) ? 1 : 0); + gifgce.flags |= ((GetDisposalMethod() & 0x7) << 2); + gifgce.delaytime = (WORD)info.dwFrameDelay; + gifgce.transpcolindex = (BYTE)info.nBkgndIndex; + + //Invert byte order in case we use a byte order arch, then set it back + gifgce.delaytime = ntohs(gifgce.delaytime); + fp->PutC(sizeof(gifgce)); + fp->Write(&gifgce, sizeof(gifgce), 1); + gifgce.delaytime = ntohs(gifgce.delaytime); + + fp->PutC(0); + // TRK END +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::EncodeLoopExtension(CxFile *fp) +{ + fp->PutC('!'); //byte 1 : 33 (hex 0x21) GIF Extension code + fp->PutC(255); //byte 2 : 255 (hex 0xFF) Application Extension Label + fp->PutC(11); //byte 3 : 11 (hex (0x0B) Length of Application Block (eleven bytes of data to follow) + fp->Write("NETSCAPE2.0",11,1); + fp->PutC(3); //byte 15 : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow) + fp->PutC(1); //byte 16 : 1 (hex 0x01) + Putword(m_loops,fp); //bytes 17 to 18 : 0 to 65535, an unsigned integer in lo-hi byte format. + //This indicate the number of iterations the loop should be executed. + fp->PutC(0); //bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator. +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::EncodeBody(CxFile *fp, bool bLocalColorMap) +{ + curx = 0; + cury = head.biHeight - 1; //because we read the image bottom to top + CountDown = (long)head.biWidth * (long)head.biHeight; + + fp->PutC(','); + + Putword(info.xOffset,fp); + Putword(info.yOffset,fp); + Putword(head.biWidth,fp); + Putword(head.biHeight,fp); + + BYTE Flags=0x00; //non-interlaced (0x40 = interlaced) (0x80 = LocalColorMap) + if (bLocalColorMap) { Flags|=0x80; Flags|=head.biBitCount-1; } + fp->PutC(Flags); + + if (bLocalColorMap){ + Flags|=0x87; + RGBQUAD* pPal = GetPalette(); + for(DWORD i=0; iPutC(pPal[i].rgbRed); + fp->PutC(pPal[i].rgbGreen); + fp->PutC(pPal[i].rgbBlue); + } + } + + int InitCodeSize = head.biBitCount <=1 ? 2 : head.biBitCount; + // Write out the initial code size + fp->PutC((BYTE)InitCodeSize); + + // Go and actually compress the data + switch (GetCodecOption(CXIMAGE_FORMAT_GIF)) + { + case 1: //uncompressed + compressNONE(InitCodeSize+1, fp); + break; + case 2: //RLE + compressRLE(InitCodeSize+1, fp); + break; + default: //LZW + compressLZW(InitCodeSize+1, fp); + } + + // Write out a Zero-length packet (to end the series) + fp->PutC(0); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::EncodeComment(CxFile *fp) +{ + unsigned long n = (unsigned long) strlen(m_comment); + if (n>255) n=255; + if (n) { + fp->PutC('!'); //extension code: + fp->PutC(254); //comment extension + fp->PutC((BYTE)n); //size of comment + fp->Write(m_comment,n,1); + fp->PutC(0); //block terminator + } +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImageGIF::EncodeRGB(CxFile *fp) +{ + EncodeHeader(fp); + +// EncodeLoopExtension(fp); + + EncodeComment(fp); + + unsigned long w,h; + w=h=0; + const long cellw = 17; + const long cellh = 15; + CxImageGIF tmp; + for (long y=0;yPutC(';'); // Write the GIF file terminator + + return true; // done! +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +// Return the next pixel from the image +// fix for 1 & 4 bpp images +int CxImageGIF::GifNextPixel( ) +{ + if( CountDown == 0 ) return EOF; + --CountDown; + int r = GetPixelIndex(curx,cury); + // Bump the current X position + ++curx; + if( curx == head.biWidth ){ + curx = 0; + cury--; //bottom to top + } + return r; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::Putword(int w, CxFile *fp ) +{ + fp->PutC((BYTE)(w & 0xff)); + fp->PutC((BYTE)((w >> 8) & 0xff)); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::compressNONE( int init_bits, CxFile* outfile) +{ + register long c; + register long ent; + + // g_init_bits - initial number of bits + // g_outfile - pointer to output file + g_init_bits = init_bits; + g_outfile = outfile; + + // Set up the necessary values + cur_accum = cur_bits = clear_flg = 0; + maxcode = (short)MAXCODE(n_bits = g_init_bits); + code_int maxmaxcode = (code_int)1 << MAXBITSCODES; + + ClearCode = (1 << (init_bits - 1)); + EOFCode = ClearCode + 1; + free_ent = (short)(ClearCode + 2); + + a_count=0; + ent = GifNextPixel( ); + + output( (code_int)ClearCode ); + + while ( ent != EOF ) { + c = GifNextPixel(); + + output ( (code_int) ent ); + ent = c; + if ( free_ent < maxmaxcode ) { + free_ent++; + } else { + free_ent=(short)(ClearCode+2); + clear_flg=1; + output((code_int)ClearCode); + } + } + // Put out the final code. + output( (code_int) EOFCode ); +} +//////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************** + * + * GIFCOMPR.C - LZW GIF Image compression routines + * + ***************************************************************************/ + +void CxImageGIF::compressLZW( int init_bits, CxFile* outfile) +{ + register long fcode; + register long c; + register long ent; + register long hshift; + register long disp; + register long i; + + // g_init_bits - initial number of bits + // g_outfile - pointer to output file + g_init_bits = init_bits; + g_outfile = outfile; + + // Set up the necessary values + cur_accum = cur_bits = clear_flg = 0; + maxcode = (short)MAXCODE(n_bits = g_init_bits); + code_int maxmaxcode = (code_int)1 << MAXBITSCODES; + + ClearCode = (1 << (init_bits - 1)); + EOFCode = ClearCode + 1; + free_ent = (short)(ClearCode + 2); + + a_count=0; + ent = GifNextPixel( ); + + hshift = 0; + for ( fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L ) ++hshift; + hshift = 8 - hshift; /* set hash code range bound */ + cl_hash((long)HSIZE); /* clear hash table */ + output( (code_int)ClearCode ); + + while ( (c = GifNextPixel( )) != EOF ) { + + fcode = (long) (((long) c << MAXBITSCODES) + ent); + i = (((code_int)c << hshift) ^ ent); /* xor hashing */ + + if ( HashTabOf (i) == fcode ) { + ent = CodeTabOf (i); + continue; + } else if ( (long)HashTabOf (i) < 0 ) /* empty slot */ + goto nomatch; + disp = HSIZE - i; /* secondary hash (after G. Knott) */ + if ( i == 0 ) disp = 1; +probe: + if ( (i -= disp) < 0 ) i += HSIZE; + if ( HashTabOf (i) == fcode ) { ent = CodeTabOf (i); continue; } + if ( (long)HashTabOf (i) > 0 ) goto probe; +nomatch: + output ( (code_int) ent ); + ent = c; + if ( free_ent < maxmaxcode ) { + CodeTabOf (i) = free_ent++; /* code -> hashtable */ + HashTabOf (i) = fcode; + } else { + cl_hash((long)HSIZE); + free_ent=(short)(ClearCode+2); + clear_flg=1; + output((code_int)ClearCode); + } + } + // Put out the final code. + output( (code_int)ent ); + output( (code_int) EOFCode ); +} +//////////////////////////////////////////////////////////////////////////////// + +static const unsigned long code_mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, + 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::output( code_int code) +{ + cur_accum &= code_mask[ cur_bits ]; + + if( cur_bits > 0 ) + cur_accum |= ((long)code << cur_bits); + else + cur_accum = code; + + cur_bits += n_bits; + + while( cur_bits >= 8 ) { + char_out( (unsigned int)(cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; + } + + /* + * If the next entry is going to be too big for the code size, + * then increase it, if possible. + */ + + if ( free_ent > maxcode || clear_flg ) { + if( clear_flg ) { + maxcode = (short)MAXCODE(n_bits = g_init_bits); + clear_flg = 0; + } else { + ++n_bits; + if ( n_bits == MAXBITSCODES ) + maxcode = (code_int)1 << MAXBITSCODES; /* should NEVER generate this code */ + else + maxcode = (short)MAXCODE(n_bits); + } + } + + if( code == EOFCode ) { + // At EOF, write the rest of the buffer. + while( cur_bits > 0 ) { + char_out( (unsigned int)(cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; + } + + flush_char(); + g_outfile->Flush(); + + if(g_outfile->Error()) strcpy(info.szLastError,"Write Error in GIF file"); + } +} +//////////////////////////////////////////////////////////////////////////////// + +void CxImageGIF::cl_hash(long hsize) + +{ + register long *htab_p = htab+hsize; + + register long i; + register long m1 = -1L; + + i = hsize - 16; + + do { + *(htab_p-16)=m1; + *(htab_p-15)=m1; + *(htab_p-14)=m1; + *(htab_p-13)=m1; + *(htab_p-12)=m1; + *(htab_p-11)=m1; + *(htab_p-10)=m1; + *(htab_p-9)=m1; + *(htab_p-8)=m1; + *(htab_p-7)=m1; + *(htab_p-6)=m1; + *(htab_p-5)=m1; + *(htab_p-4)=m1; + *(htab_p-3)=m1; + *(htab_p-2)=m1; + *(htab_p-1)=m1; + + htab_p-=16; + } while ((i-=16) >=0); + + for (i+=16;i>0;--i) + *--htab_p=m1; +} + +/******************************************************************************* +* GIF specific +*******************************************************************************/ + +void CxImageGIF::char_out(int c) +{ + accum[a_count++]=(char)c; + if (a_count >=254) + flush_char(); +} + +void CxImageGIF::flush_char() +{ + if (a_count > 0) { + g_outfile->PutC((BYTE)a_count); + g_outfile->Write(accum,1,a_count); + a_count=0; + } +} + +/******************************************************************************* +* GIF decoder +*******************************************************************************/ +/* DECODE.C - An LZW decoder for GIF + * Copyright (C) 1987, by Steven A. Bennett + * Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra +* + * Permission is given by the author to freely redistribute and include + * this code in any program as long as this credit is given where due. + * + * In accordance with the above, I want to credit Steve Wilhite who wrote + * the code which this is heavily inspired by... + * + * GIF and 'Graphics Interchange Format' are trademarks (tm) of + * Compuserve, Incorporated, an H&R Block Company. + * + * Release Notes: This file contains a decoder routine for GIF images + * which is similar, structurally, to the original routine by Steve Wilhite. + * It is, however, somewhat noticably faster in most cases. + * + */ + +//////////////////////////////////////////////////////////////////////////////// + +short CxImageGIF::init_exp(short size) +{ + curr_size = (short)(size + 1); + top_slot = (short)(1 << curr_size); + clear = (short)(1 << size); + ending = (short)(clear + 1); + slot = newcodes = (short)(ending + 1); + navail_bytes = nbits_left = 0; + + memset(stack,0,MAX_CODES + 1); + memset(prefix,0,MAX_CODES + 1); + memset(suffix,0,MAX_CODES + 1); + return(0); +} +//////////////////////////////////////////////////////////////////////////////// + +/* get_next_code() + * - gets the next code from the GIF file. Returns the code, or else + * a negative number in case of file errors... + */ +short CxImageGIF::get_next_code(CxFile* file) +{ + short i, x; + DWORD ret; + + if (nbits_left == 0) { + if (navail_bytes <= 0) { + /* Out of bytes in current block, so read next block */ + pbytes = byte_buff; + if ((navail_bytes = (short)get_byte(file)) < 0) + return(navail_bytes); + else if (navail_bytes) { + for (i = 0; i < navail_bytes; ++i) { + if ((x = (short)get_byte(file)) < 0) return(x); + byte_buff[i] = (BYTE)x; + } + } + } + b1 = *pbytes++; + nbits_left = 8; + --navail_bytes; + } + + if (navail_bytes<0) return ending; // prevent deadlocks (thanks to Mike Melnikov) + + ret = b1 >> (8 - nbits_left); + while (curr_size > nbits_left){ + if (navail_bytes <= 0){ + /* Out of bytes in current block, so read next block*/ + pbytes = byte_buff; + if ((navail_bytes = (short)get_byte(file)) < 0) + return(navail_bytes); + else if (navail_bytes){ + for (i = 0; i < navail_bytes; ++i){ + if ((x = (short)get_byte(file)) < 0) return(x); + byte_buff[i] = (BYTE)x; + } + } + } + b1 = *pbytes++; + ret |= b1 << nbits_left; + nbits_left += 8; + --navail_bytes; + } + nbits_left = (short)(nbits_left-curr_size); + ret &= code_mask[curr_size]; + return((short)(ret)); +} +//////////////////////////////////////////////////////////////////////////////// + +/* short decoder(linewidth) + * short linewidth; * Pixels per line of image * + * + * - This function decodes an LZW image, according to the method used + * in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded + * will generate a call to out_line(), which is a user specific function + * to display a line of pixels. The function gets it's codes from + * get_next_code() which is responsible for reading blocks of data and + * seperating them into the proper size codes. Finally, get_byte() is + * the global routine to read the next BYTE from the GIF file. + * + * It is generally a good idea to have linewidth correspond to the actual + * width of a line (as specified in the Image header) to make your own + * code a bit simpler, but it isn't absolutely necessary. + * + * Returns: 0 if successful, else negative. (See ERRS.H) + * + */ +/* bad_code_count is incremented each time an out of range code is read. + * When this value is non-zero after a decode, your GIF file is probably + * corrupt in some way... + */ +short CxImageGIF::decoder(CxFile* file, CImageIterator* iter, short linewidth, int &bad_code_count) +{ + register BYTE *sp, *bufptr; + BYTE *buf; + register short code, fc, oc, bufcnt; + short c, size, ret; + + /* Initialize for decoding a new image... */ + bad_code_count = 0; + if ((size = (short)get_byte(file)) < 0) return(size); + if (size < 2 || 9 < size) return(BAD_CODE_SIZE); + // out_line = outline; + init_exp(size); + //printf("L %d %x\n",linewidth,size); + + /* Initialize in case they forgot to put in a clear code. + * (This shouldn't happen, but we'll try and decode it anyway...) + */ + oc = fc = 0; + + /* Allocate space for the decode buffer */ + if ((buf = new BYTE[linewidth + 1]) == NULL) return(OUT_OF_MEMORY); + + /* Set up the stack pointer and decode buffer pointer */ + sp = stack; + bufptr = buf; + bufcnt = linewidth; + + /* This is the main loop. For each code we get we pass through the + * linked list of prefix codes, pushing the corresponding "character" for + * each code onto the stack. When the list reaches a single "character" + * we push that on the stack too, and then start unstacking each + * character for output in the correct order. Special handling is + * included for the clear code, and the whole thing ends when we get + * an ending code. + */ + while ((c = get_next_code(file)) != ending) { + /* If we had a file error, return without completing the decode*/ + if (c < 0){ + delete [] buf; + return(0); + } + /* If the code is a clear code, reinitialize all necessary items.*/ + if (c == clear){ + curr_size = (short)(size + 1); + slot = newcodes; + top_slot = (short)(1 << curr_size); + + /* Continue reading codes until we get a non-clear code + * (Another unlikely, but possible case...) + */ + while ((c = get_next_code(file)) == clear); + + /* If we get an ending code immediately after a clear code + * (Yet another unlikely case), then break out of the loop. + */ + if (c == ending) break; + + /* Finally, if the code is beyond the range of already set codes, + * (This one had better NOT happen... I have no idea what will + * result from this, but I doubt it will look good...) then set it + * to color zero. + */ + if (c >= slot) c = 0; + oc = fc = c; + + /* And let us not forget to put the char into the buffer... And + * if, on the off chance, we were exactly one pixel from the end + * of the line, we have to send the buffer to the out_line() + * routine... + */ + *bufptr++ = (BYTE)c; + if (--bufcnt == 0) { + if (iter) { + if ((ret = (short)out_line(iter, buf, linewidth)) < 0) { + delete [] buf; + return(ret); + } + } + bufptr = buf; + bufcnt = linewidth; + } + } else { + /* In this case, it's not a clear code or an ending code, so + * it must be a code code... So we can now decode the code into + * a stack of character codes. (Clear as mud, right?) + */ + code = c; + + /* Here we go again with one of those off chances... If, on the + * off chance, the code we got is beyond the range of those already + * set up (Another thing which had better NOT happen...) we trick + * the decoder into thinking it actually got the last code read. + * (Hmmn... I'm not sure why this works... But it does...) + */ + if (code >= slot && sp<(stack+MAX_CODES-1)) { + if (code > slot) + ++bad_code_count; + code = oc; + *sp++ = (BYTE)fc; + } + + /* Here we scan back along the linked list of prefixes, pushing + * helpless characters (ie. suffixes) onto the stack as we do so. + */ + while (code >= newcodes && sp<(stack+MAX_CODES-1)) { + *sp++ = suffix[code]; + code = prefix[code]; + } + + /* Push the last character on the stack, and set up the new + * prefix and suffix, and if the required slot number is greater + * than that allowed by the current bit size, increase the bit + * size. (NOTE - If we are all full, we *don't* save the new + * suffix and prefix... I'm not certain if this is correct... + * it might be more proper to overwrite the last code... + */ + *sp++ = (BYTE)code; + if (slot < top_slot){ + suffix[slot] = (BYTE)(fc = (BYTE)code); + prefix[slot++] = oc; + oc = c; + } + if (slot >= top_slot){ + if (curr_size < 12) { + top_slot <<= 1; + ++curr_size; + } + } + + /* Now that we've pushed the decoded string (in reverse order) + * onto the stack, lets pop it off and put it into our decode + * buffer... And when the decode buffer is full, write another + * line... + */ + while (sp > stack) { + *bufptr++ = *(--sp); + if (--bufcnt == 0) { + if (iter) { + if ((ret = (short)out_line(iter, buf, linewidth)) < 0) { + delete [] buf; + return(ret); + } + } + bufptr = buf; + bufcnt = linewidth; + } + } + } + } + ret = 0; + if (bufcnt != linewidth && iter) + ret = (short)out_line(iter, buf, (linewidth - bufcnt)); + delete [] buf; + return(ret); +} +//////////////////////////////////////////////////////////////////////////////// +int CxImageGIF::get_num_frames(CxFile *fp,struct_TabCol* TabColSrc,struct_dscgif* dscgif) +{ + struct_image image; + + long pos=fp->Tell(); + int nframes=0; + + struct_TabCol TempTabCol; + memcpy(&TempTabCol,TabColSrc,sizeof(struct_TabCol)); + + char ch; + bool bPreviousWasNull = true; + + for (BOOL bContinue = TRUE; bContinue; ) + { + if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;} + + if (bPreviousWasNull || ch==0) + { + switch (ch) + { + case '!': // extension + { + DecodeExtension(fp); + break; + } + case ',': // image + { + + assert(sizeof(image) == 9); + //log << "Image header" << endl; + fp->Read(&image,sizeof(image),1); + + //avoid byte order problems with Solaris + image.l = ntohs(image.l); + image.t = ntohs(image.t); + image.w = ntohs(image.w); + image.h = ntohs(image.h); + + // in case of images with empty screen descriptor, give a last chance + if (dscgif->scrwidth==0 && dscgif->scrheight==0){ + dscgif->scrwidth = image.w; + dscgif->scrheight = image.h; + } + + if (((image.l + image.w) > dscgif->scrwidth)||((image.t + image.h) > dscgif->scrheight)) + break; + + nframes++; + + // Local colour map? + if (image.pf & 0x80) { + TempTabCol.sogct = (short)(1 << ((image.pf & 0x07) +1)); + assert(3 == sizeof(struct rgb_color)); + fp->Read(TempTabCol.paleta,sizeof(struct rgb_color)*TempTabCol.sogct,1); + //log << "Local colour map" << endl; + } + + int badcode=0; + ibf = GIFBUFTAM+1; + + interlaced = image.pf & 0x40; + iheight = image.h; + istep = 8; + iypos = 0; + ipass = 0; + + long pos_start = fp->Tell(); + + //if (interlaced) log << "Interlaced" << endl; + decoder(fp, 0, image.w, badcode); + + if (badcode){ + seek_next_image(fp,pos_start); + } else { + fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR); + } + + break; + } + case ';': //terminator + bContinue=false; + break; + default: + bPreviousWasNull = (ch==0); + break; + } + } + } + + fp->Seek(pos,SEEK_SET); + return nframes; +} +//////////////////////////////////////////////////////////////////////////////// +long CxImageGIF::seek_next_image(CxFile* fp, long position) +{ + fp->Seek(position, SEEK_SET); + char ch1,ch2; + ch1=ch2=0; + while(fp->Read(&ch2,sizeof(char),1)>0){ + if (ch1 == 0 && ch2 == ','){ + fp->Seek(-1,SEEK_CUR); + return fp->Tell(); + } else { + ch1 = ch2; + } + } + return -1; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::SetLoops(int loops) +{ m_loops=loops; } +//////////////////////////////////////////////////////////////////////////////// +long CxImageGIF::GetLoops() +{ return m_loops; } +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::SetComment(const char* sz_comment_in) +{ if (sz_comment_in) strncpy(m_comment,sz_comment_in,255); } +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::GetComment(char* sz_comment_out) +{ if (sz_comment_out) strncpy(sz_comment_out,m_comment,255); } +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::GifMix(CxImage & imgsrc2, struct_image & imgdesc) +{ + long ymin = max(0,(long)(GetHeight()-imgdesc.t - imgdesc.h)); + long ymax = GetHeight()-imgdesc.t; + long xmin = imgdesc.l; + long xmax = min(GetWidth(), (DWORD)(imgdesc.l + imgdesc.w)); + + long ibg2= imgsrc2.GetTransIndex(); + BYTE i2; + + for(long y = ymin; y < ymax; y++){ + for(long x = xmin; x < xmax; x++){ + i2 = imgsrc2.GetPixelIndex(x-xmin,y-ymin); + if(i2!=ibg2) SetPixelIndex(x,y,i2); + } + } +} +//////////////////////////////////////////////////////////////////////////////// +/*----------------------------------------------------------------------- + * + * miGIF Compression - mouse and ivo's GIF-compatible compression + * + * -run length encoding compression routines- + * + * Copyright (C) 1998 Hutchison Avenue Software Corporation + * http://www.hasc.com + * info@hasc.com + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "AS IS." The Hutchison Avenue + * Software Corporation disclaims all warranties, either express or implied, + * including but not limited to implied warranties of merchantability and + * fitness for a particular purpose, with respect to this code and accompanying + * documentation. + * + * The miGIF compression routines do not, strictly speaking, generate files + * conforming to the GIF spec, since the image data is not LZW-compressed + * (this is the point: in order to avoid transgression of the Unisys patent + * on the LZW algorithm.) However, miGIF generates data streams that any + * reasonably sane LZW decompresser will decompress to what we want. + * + * miGIF compression uses run length encoding. It compresses horizontal runs + * of pixels of the same color. This type of compression gives good results + * on images with many runs, for example images with lines, text and solid + * shapes on a solid-colored background. It gives little or no compression + * on images with few runs, for example digital or scanned photos. + * + * der Mouse + * mouse@rodents.montreal.qc.ca + * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B + * + * ivo@hasc.com + * + * The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated. + * + */ +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_clear(struct_RLE* rle) +{ + rle->out_bits = rle->out_bits_init; + rle->out_bump = rle->out_bump_init; + rle->out_clear = rle->out_clear_init; + rle->out_count = 0; + rle->rl_table_max = 0; + rle->just_cleared = 1; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_flush(struct_RLE* rle) +{ + if (rle->rl_count == 1){ + rle_output_plain(rle->rl_pixel,rle); + rle->rl_count = 0; + return; + } + if (rle->just_cleared){ + rle_flush_fromclear(rle->rl_count,rle); + } else if ((rle->rl_table_max < 2) || (rle->rl_table_pixel != rle->rl_pixel)) { + rle_flush_clearorrep(rle->rl_count,rle); + } else { + rle_flush_withtable(rle->rl_count,rle); + } + rle->rl_count = 0; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_output_plain(int c,struct_RLE* rle) +{ + rle->just_cleared = 0; + rle_output(c,rle); + rle->out_count++; + if (rle->out_count >= rle->out_bump){ + rle->out_bits ++; + rle->out_bump += 1 << (rle->out_bits - 1); + } + if (rle->out_count >= rle->out_clear){ + rle_output(rle->code_clear,rle); + rle_clear(rle); + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_flush_fromclear(int count,struct_RLE* rle) +{ + int n; + + rle->out_clear = rle->max_ocodes; + rle->rl_table_pixel = rle->rl_pixel; + n = 1; + while (count > 0){ + if (n == 1){ + rle->rl_table_max = 1; + rle_output_plain(rle->rl_pixel,rle); + count --; + } else if (count >= n){ + rle->rl_table_max = n; + rle_output_plain(rle->rl_basecode+n-2,rle); + count -= n; + } else if (count == 1){ + rle->rl_table_max ++; + rle_output_plain(rle->rl_pixel,rle); + count = 0; + } else { + rle->rl_table_max ++; + rle_output_plain(rle->rl_basecode+count-2,rle); + count = 0; + } + if (rle->out_count == 0) n = 1; else n ++; + } + rle_reset_out_clear(rle); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_reset_out_clear(struct_RLE* rle) +{ + rle->out_clear = rle->out_clear_init; + if (rle->out_count >= rle->out_clear){ + rle_output(rle->code_clear,rle); + rle_clear(rle); + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_flush_withtable(int count, struct_RLE* rle) +{ + int repmax; + int repleft; + int leftover; + + repmax = count / rle->rl_table_max; + leftover = count % rle->rl_table_max; + repleft = (leftover ? 1 : 0); + if (rle->out_count+repmax+repleft > rle->max_ocodes){ + repmax = rle->max_ocodes - rle->out_count; + leftover = count - (repmax * rle->rl_table_max); + repleft = 1 + rle_compute_triangle_count(leftover,rle->max_ocodes); + } + if (1+rle_compute_triangle_count(count,rle->max_ocodes) < (unsigned int)(repmax+repleft)){ + rle_output(rle->code_clear,rle); + rle_clear(rle); + rle_flush_fromclear(count,rle); + return; + } + rle->out_clear = rle->max_ocodes; + for (;repmax>0;repmax--) rle_output_plain(rle->rl_basecode+rle->rl_table_max-2,rle); + if (leftover){ + if (rle->just_cleared){ + rle_flush_fromclear(leftover,rle); + } else if (leftover == 1){ + rle_output_plain(rle->rl_pixel,rle); + } else { + rle_output_plain(rle->rl_basecode+leftover-2,rle); + } + } + rle_reset_out_clear(rle); +} +//////////////////////////////////////////////////////////////////////////////// +unsigned int CxImageGIF::rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes) +{ + unsigned int perrep; + unsigned int cost; + + cost = 0; + perrep = (nrepcodes * (nrepcodes+1)) / 2; + while (count >= perrep){ + cost += nrepcodes; + count -= perrep; + } + if (count > 0){ + unsigned int n; + n = rle_isqrt(count); + while ((n*(n+1)) >= 2*count) n --; + while ((n*(n+1)) < 2*count) n ++; + cost += n; + } + return(cost); +} +//////////////////////////////////////////////////////////////////////////////// +unsigned int CxImageGIF::rle_isqrt(unsigned int x) +{ + unsigned int r; + unsigned int v; + + if (x < 2) return(x); + for (v=x,r=1;v;v>>=2,r<<=1) ; + for( ;; ) + { + v = ((x / r) + r) / 2; + if ((v == r) || (v == r+1)) return(r); + r = v; + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_flush_clearorrep(int count, struct_RLE* rle) +{ + int withclr; + withclr = 1 + rle_compute_triangle_count(count,rle->max_ocodes); + if (withclr < count) { + rle_output(rle->code_clear,rle); + rle_clear(rle); + rle_flush_fromclear(count,rle); + } else { + for (;count>0;count--) rle_output_plain(rle->rl_pixel,rle); + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_write_block(struct_RLE* rle) +{ + g_outfile->PutC((BYTE)rle->oblen); + g_outfile->Write(rle->oblock,1,rle->oblen); + rle->oblen = 0; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_block_out(unsigned char c, struct_RLE* rle) +{ + rle->oblock[rle->oblen++] = c; + if (rle->oblen >= 255) rle_write_block(rle); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_block_flush(struct_RLE* rle) +{ + if (rle->oblen > 0) rle_write_block(rle); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_output(int val, struct_RLE* rle) +{ + rle->obuf |= val << rle->obits; + rle->obits += rle->out_bits; + while (rle->obits >= 8){ + rle_block_out((unsigned char)(rle->obuf&0xff),rle); + rle->obuf >>= 8; + rle->obits -= 8; + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::rle_output_flush(struct_RLE* rle) +{ + if (rle->obits > 0) rle_block_out((unsigned char)(rle->obuf),rle); + rle_block_flush(rle); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageGIF::compressRLE( int init_bits, CxFile* outfile) +{ + g_init_bits = init_bits; + g_outfile = outfile; + + struct_RLE rle; + rle.code_clear = 1 << (init_bits - 1); + rle.code_eof = rle.code_clear + 1; + rle.rl_basecode = rle.code_eof + 1; + rle.out_bump_init = (1 << (init_bits - 1)) - 1; + rle.out_clear_init = (init_bits <= 3) ? 9 : (rle.out_bump_init-1); + rle.out_bits_init = init_bits; + rle.max_ocodes = (1 << MAXBITSCODES) - ((1 << (rle.out_bits_init - 1)) + 3); + rle.rl_count = 0; + rle_clear(&rle); + rle.obuf = 0; + rle.obits = 0; + rle.oblen = 0; + + rle_output(rle.code_clear,&rle); + + int c; + for( ;; ) + { + c = GifNextPixel(); + if ((rle.rl_count > 0) && (c != rle.rl_pixel)) rle_flush(&rle); + if (c == EOF) break; + if (rle.rl_pixel == c){ + rle.rl_count++; + } else { + rle.rl_pixel = c; + rle.rl_count = 1; + } + } + rle_output(rle.code_eof,&rle); + rle_output_flush(&rle); +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_GIF diff --git a/utilities/CxImage/ximagif.h b/utilities/CxImage/ximagif.h index 86a3e58..702e345 100644 --- a/utilities/CxImage/ximagif.h +++ b/utilities/CxImage/ximagif.h @@ -1,242 +1,242 @@ -/* - * File: ximagif.h - * Purpose: GIF Image Class Loader and Writer - */ -/* ========================================================== - * CxImageGIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes - * - * original CImageGIF and CImageIterator implementation are: - * Copyright: (c) 1995, Alejandro Aguilar Sierra - * - * 6/15/97 Randy Spann: Added GIF87a writing support - * R.Spann@ConnRiver.net - * - * DECODE.C - An LZW decoder for GIF - * Copyright (C) 1987, by Steven A. Bennett - * Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra - * - * In accordance with the above, I want to credit Steve Wilhite who wrote - * the code which this is heavily inspired by... - * - * GIF and 'Graphics Interchange Format' are trademarks (tm) of - * Compuserve, Incorporated, an H&R Block Company. - * - * Release Notes: This file contains a decoder routine for GIF images - * which is similar, structurally, to the original routine by Steve Wilhite. - * It is, however, somewhat noticably faster in most cases. - * - * ========================================================== - */ - -#if !defined(__ximaGIF_h) -#define __ximaGIF_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_GIF - -typedef short int code_int; - -/* Various error codes used by decoder */ -#define OUT_OF_MEMORY -10 -#define BAD_CODE_SIZE -20 -#define READ_ERROR -1 -#define WRITE_ERROR -2 -#define OPEN_ERROR -3 -#define CREATE_ERROR -4 -#define MAX_CODES 4095 -#define GIFBUFTAM 16383 -#define TRANSPARENCY_CODE 0xF9 - -//LZW GIF Image compression -#define MAXBITSCODES 12 -#define HSIZE 5003 /* 80% occupancy */ -#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1) -#define HashTabOf(i) htab[i] -#define CodeTabOf(i) codetab[i] - - -class CImageIterator; -class DLL_EXP CxImageGIF: public CxImage -{ -#pragma pack(1) - -typedef struct tag_gifgce{ - BYTE flags; /*res:3|dispmeth:3|userinputflag:1|transpcolflag:1*/ - WORD delaytime; - BYTE transpcolindex; -} struct_gifgce; - -typedef struct tag_dscgif{ /* Logic Screen Descriptor */ - char header[6]; /* Firma and version */ - WORD scrwidth; - WORD scrheight; - char pflds; - char bcindx; - char pxasrat; -} struct_dscgif; - -typedef struct tag_image{ /* Image Descriptor */ - WORD l; - WORD t; - WORD w; - WORD h; - BYTE pf; -} struct_image; - -typedef struct tag_TabCol{ /* Tabla de colores */ - short colres; /* color resolution */ - short sogct; /* size of global color table */ - rgb_color paleta[256]; /* paleta */ -} struct_TabCol; - -typedef struct tag_RLE{ - int rl_pixel; - int rl_basecode; - int rl_count; - int rl_table_pixel; - int rl_table_max; - int just_cleared; - int out_bits; - int out_bits_init; - int out_count; - int out_bump; - int out_bump_init; - int out_clear; - int out_clear_init; - int max_ocodes; - int code_clear; - int code_eof; - unsigned int obuf; - int obits; - unsigned char oblock[256]; - int oblen; -} struct_RLE; -#pragma pack() - -public: - CxImageGIF(): CxImage(CXIMAGE_FORMAT_GIF) {m_loops=0; info.dispmeth=0; m_comment[0]='\0';} - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_GIF);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_GIF);} - - bool Decode(CxFile * fp); - bool Decode(FILE *fp) { CxIOFile file(fp); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * fp); - bool Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap = false, bool bLocalDispMeth = false); - bool Encode(FILE *fp) { CxIOFile file(fp); return Encode(&file); } - bool Encode(FILE *fp, CxImage ** pImages, int pagecount, bool bLocalColorMap = false) - { CxIOFile file(fp); return Encode(&file, pImages, pagecount, bLocalColorMap); } -#endif // CXIMAGE_SUPPORT_ENCODE - - void SetLoops(int loops); - long GetLoops(); - void SetComment(const char* sz_comment_in); - void GetComment(char* sz_comment_out); - -protected: - bool DecodeExtension(CxFile *fp); - void EncodeHeader(CxFile *fp); - void EncodeLoopExtension(CxFile *fp); - void EncodeExtension(CxFile *fp); - void EncodeBody(CxFile *fp, bool bLocalColorMap = false); - void EncodeComment(CxFile *fp); - bool EncodeRGB(CxFile *fp); - void GifMix(CxImage & imgsrc2, struct_image & imgdesc); - - struct_gifgce gifgce; - - int curx, cury; - long CountDown; - unsigned long cur_accum; - int cur_bits; - int interlaced, iypos, istep, iheight, ipass; - int ibf; - int ibfmax; - BYTE buf[GIFBUFTAM + 1]; -// Implementation - int GifNextPixel (); - void Putword (int w, CxFile* fp ); - void compressNONE (int init_bits, CxFile* outfile); - void compressLZW (int init_bits, CxFile* outfile); - void output (code_int code ); - void cl_hash (long hsize); - void char_out (int c); - void flush_char (); - short init_exp(short size); - short get_next_code(CxFile*); - short decoder(CxFile*, CImageIterator* iter, short linewidth, int &bad_code_count); - int get_byte(CxFile*); - int out_line(CImageIterator* iter, unsigned char *pixels, int linelen); - int get_num_frames(CxFile *f,struct_TabCol* TabColSrc,struct_dscgif* dscgif); - long seek_next_image(CxFile* fp, long position); - - short curr_size; /* The current code size */ - short clear; /* Value for a clear code */ - short ending; /* Value for a ending code */ - short newcodes; /* First available code */ - short top_slot; /* Highest code for current size */ - short slot; /* Last read code */ - - /* The following static variables are used - * for seperating out codes */ - short navail_bytes; /* # bytes left in block */ - short nbits_left; /* # bits left in current BYTE */ - BYTE b1; /* Current BYTE */ - BYTE byte_buff[257]; /* Current block */ - BYTE *pbytes; /* Pointer to next BYTE in block */ - /* The reason we have these seperated like this instead of using - * a structure like the original Wilhite code did, is because this - * stuff generally produces significantly faster code when compiled... - * This code is full of similar speedups... (For a good book on writing - * C for speed or for space optomisation, see Efficient C by Tom Plum, - * published by Plum-Hall Associates...) - */ - BYTE stack[MAX_CODES + 1]; /* Stack for storing pixels */ - BYTE suffix[MAX_CODES + 1]; /* Suffix table */ - WORD prefix[MAX_CODES + 1]; /* Prefix linked list */ - -//LZW GIF Image compression routines - long htab [HSIZE]; - unsigned short codetab [HSIZE]; - int n_bits; /* number of bits/code */ - code_int maxcode; /* maximum code, given n_bits */ - code_int free_ent; /* first unused entry */ - int clear_flg; - int g_init_bits; - CxFile* g_outfile; - int ClearCode; - int EOFCode; - - int a_count; - char accum[256]; - - char m_comment[256]; - int m_loops; - -//RLE compression routines - void compressRLE( int init_bits, CxFile* outfile); - void rle_clear(struct_RLE* rle); - void rle_flush(struct_RLE* rle); - void rle_flush_withtable(int count, struct_RLE* rle); - void rle_flush_clearorrep(int count, struct_RLE* rle); - void rle_flush_fromclear(int count,struct_RLE* rle); - void rle_output_plain(int c,struct_RLE* rle); - void rle_reset_out_clear(struct_RLE* rle); - unsigned int rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes); - unsigned int rle_isqrt(unsigned int x); - void rle_write_block(struct_RLE* rle); - void rle_block_out(unsigned char c, struct_RLE* rle); - void rle_block_flush(struct_RLE* rle); - void rle_output(int val, struct_RLE* rle); - void rle_output_flush(struct_RLE* rle); -}; - -#endif - -#endif +/* + * File: ximagif.h + * Purpose: GIF Image Class Loader and Writer + */ +/* ========================================================== + * CxImageGIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes + * + * original CImageGIF and CImageIterator implementation are: + * Copyright: (c) 1995, Alejandro Aguilar Sierra + * + * 6/15/97 Randy Spann: Added GIF87a writing support + * R.Spann@ConnRiver.net + * + * DECODE.C - An LZW decoder for GIF + * Copyright (C) 1987, by Steven A. Bennett + * Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra + * + * In accordance with the above, I want to credit Steve Wilhite who wrote + * the code which this is heavily inspired by... + * + * GIF and 'Graphics Interchange Format' are trademarks (tm) of + * Compuserve, Incorporated, an H&R Block Company. + * + * Release Notes: This file contains a decoder routine for GIF images + * which is similar, structurally, to the original routine by Steve Wilhite. + * It is, however, somewhat noticably faster in most cases. + * + * ========================================================== + */ + +#if !defined(__ximaGIF_h) +#define __ximaGIF_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_GIF + +typedef short int code_int; + +/* Various error codes used by decoder */ +#define OUT_OF_MEMORY -10 +#define BAD_CODE_SIZE -20 +#define READ_ERROR -1 +#define WRITE_ERROR -2 +#define OPEN_ERROR -3 +#define CREATE_ERROR -4 +#define MAX_CODES 4095 +#define GIFBUFTAM 16383 +#define TRANSPARENCY_CODE 0xF9 + +//LZW GIF Image compression +#define MAXBITSCODES 12 +#define HSIZE 5003 /* 80% occupancy */ +#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1) +#define HashTabOf(i) htab[i] +#define CodeTabOf(i) codetab[i] + + +class CImageIterator; +class DLL_EXP CxImageGIF: public CxImage +{ +#pragma pack(1) + +typedef struct tag_gifgce{ + BYTE flags; /*res:3|dispmeth:3|userinputflag:1|transpcolflag:1*/ + WORD delaytime; + BYTE transpcolindex; +} struct_gifgce; + +typedef struct tag_dscgif{ /* Logic Screen Descriptor */ + char header[6]; /* Firma and version */ + WORD scrwidth; + WORD scrheight; + char pflds; + char bcindx; + char pxasrat; +} struct_dscgif; + +typedef struct tag_image{ /* Image Descriptor */ + WORD l; + WORD t; + WORD w; + WORD h; + BYTE pf; +} struct_image; + +typedef struct tag_TabCol{ /* Tabla de colores */ + short colres; /* color resolution */ + short sogct; /* size of global color table */ + rgb_color paleta[256]; /* paleta */ +} struct_TabCol; + +typedef struct tag_RLE{ + int rl_pixel; + int rl_basecode; + int rl_count; + int rl_table_pixel; + int rl_table_max; + int just_cleared; + int out_bits; + int out_bits_init; + int out_count; + int out_bump; + int out_bump_init; + int out_clear; + int out_clear_init; + int max_ocodes; + int code_clear; + int code_eof; + unsigned int obuf; + int obits; + unsigned char oblock[256]; + int oblen; +} struct_RLE; +#pragma pack() + +public: + CxImageGIF(): CxImage(CXIMAGE_FORMAT_GIF) {m_loops=0; info.dispmeth=0; m_comment[0]='\0';} + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_GIF);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_GIF);} + + bool Decode(CxFile * fp); + bool Decode(FILE *fp) { CxIOFile file(fp); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * fp); + bool Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap = false, bool bLocalDispMeth = false); + bool Encode(FILE *fp) { CxIOFile file(fp); return Encode(&file); } + bool Encode(FILE *fp, CxImage ** pImages, int pagecount, bool bLocalColorMap = false) + { CxIOFile file(fp); return Encode(&file, pImages, pagecount, bLocalColorMap); } +#endif // CXIMAGE_SUPPORT_ENCODE + + void SetLoops(int loops); + long GetLoops(); + void SetComment(const char* sz_comment_in); + void GetComment(char* sz_comment_out); + +protected: + bool DecodeExtension(CxFile *fp); + void EncodeHeader(CxFile *fp); + void EncodeLoopExtension(CxFile *fp); + void EncodeExtension(CxFile *fp); + void EncodeBody(CxFile *fp, bool bLocalColorMap = false); + void EncodeComment(CxFile *fp); + bool EncodeRGB(CxFile *fp); + void GifMix(CxImage & imgsrc2, struct_image & imgdesc); + + struct_gifgce gifgce; + + int curx, cury; + long CountDown; + unsigned long cur_accum; + int cur_bits; + int interlaced, iypos, istep, iheight, ipass; + int ibf; + int ibfmax; + BYTE buf[GIFBUFTAM + 1]; +// Implementation + int GifNextPixel (); + void Putword (int w, CxFile* fp ); + void compressNONE (int init_bits, CxFile* outfile); + void compressLZW (int init_bits, CxFile* outfile); + void output (code_int code ); + void cl_hash (long hsize); + void char_out (int c); + void flush_char (); + short init_exp(short size); + short get_next_code(CxFile*); + short decoder(CxFile*, CImageIterator* iter, short linewidth, int &bad_code_count); + int get_byte(CxFile*); + int out_line(CImageIterator* iter, unsigned char *pixels, int linelen); + int get_num_frames(CxFile *f,struct_TabCol* TabColSrc,struct_dscgif* dscgif); + long seek_next_image(CxFile* fp, long position); + + short curr_size; /* The current code size */ + short clear; /* Value for a clear code */ + short ending; /* Value for a ending code */ + short newcodes; /* First available code */ + short top_slot; /* Highest code for current size */ + short slot; /* Last read code */ + + /* The following static variables are used + * for seperating out codes */ + short navail_bytes; /* # bytes left in block */ + short nbits_left; /* # bits left in current BYTE */ + BYTE b1; /* Current BYTE */ + BYTE byte_buff[257]; /* Current block */ + BYTE *pbytes; /* Pointer to next BYTE in block */ + /* The reason we have these seperated like this instead of using + * a structure like the original Wilhite code did, is because this + * stuff generally produces significantly faster code when compiled... + * This code is full of similar speedups... (For a good book on writing + * C for speed or for space optomisation, see Efficient C by Tom Plum, + * published by Plum-Hall Associates...) + */ + BYTE stack[MAX_CODES + 1]; /* Stack for storing pixels */ + BYTE suffix[MAX_CODES + 1]; /* Suffix table */ + WORD prefix[MAX_CODES + 1]; /* Prefix linked list */ + +//LZW GIF Image compression routines + long htab [HSIZE]; + unsigned short codetab [HSIZE]; + int n_bits; /* number of bits/code */ + code_int maxcode; /* maximum code, given n_bits */ + code_int free_ent; /* first unused entry */ + int clear_flg; + int g_init_bits; + CxFile* g_outfile; + int ClearCode; + int EOFCode; + + int a_count; + char accum[256]; + + char m_comment[256]; + int m_loops; + +//RLE compression routines + void compressRLE( int init_bits, CxFile* outfile); + void rle_clear(struct_RLE* rle); + void rle_flush(struct_RLE* rle); + void rle_flush_withtable(int count, struct_RLE* rle); + void rle_flush_clearorrep(int count, struct_RLE* rle); + void rle_flush_fromclear(int count,struct_RLE* rle); + void rle_output_plain(int c,struct_RLE* rle); + void rle_reset_out_clear(struct_RLE* rle); + unsigned int rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes); + unsigned int rle_isqrt(unsigned int x); + void rle_write_block(struct_RLE* rle); + void rle_block_out(unsigned char c, struct_RLE* rle); + void rle_block_flush(struct_RLE* rle); + void rle_output(int val, struct_RLE* rle); + void rle_output_flush(struct_RLE* rle); +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximahist.cpp b/utilities/CxImage/ximahist.cpp index 2b47d17..a2aed03 100644 --- a/utilities/CxImage/ximahist.cpp +++ b/utilities/CxImage/ximahist.cpp @@ -1,627 +1,627 @@ -// xImaHist.cpp : histogram functions -/* 28/01/2004 v1.00 - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_DSP - -//////////////////////////////////////////////////////////////////////////////// -long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace) -{ - if (!pDib) return 0; - RGBQUAD color; - - if (red) memset(red,0,256*sizeof(long)); - if (green) memset(green,0,256*sizeof(long)); - if (blue) memset(blue,0,256*sizeof(long)); - if (gray) memset(gray,0,256*sizeof(long)); - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - for(long y=ymin; yn) n=red[i]; - if (green && green[i]>n) n=green[i]; - if (blue && blue[i]>n) n=blue[i]; - if (gray && gray[i]>n) n=gray[i]; - } - - return n; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * HistogramStretch - * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels. - * \param threshold: minimum percentage level in the histogram to recognize it as meaningful. Range: 0.0 to 1.0; default = 0; typical = 0.005 (0.5%); - * \return true if everything is ok - * \author [dave] and [nipper]; changes [DP] - */ -bool CxImage::HistogramStretch(long method, double threshold) -{ - if (!pDib) return false; - - double dbScaler = 50.0/head.biHeight; - long x,y; - - if ((head.biBitCount==8) && IsGrayScale()){ - - double p[256]; - memset(p, 0, 256*sizeof(double)); - for (y=0; y0 && p[maxc]<=threshold) maxc--; - - if (minc == 0 && maxc == 255) return true; - if (minc >= maxc) return true; - - // calculate LUT - BYTE lut[256]; - for (x = 0; x <256; x++){ - lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); - } - - for (y=0; y - double p[256]; - memset(p, 0, 256*sizeof(double)); - for (y=0; y0 && p[maxc]<=threshold) maxc--; - - if (minc == 0 && maxc == 255) return true; - if (minc >= maxc) return true; - - // calculate LUT - BYTE lut[256]; - for (x = 0; x <256; x++){ - lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); - } - - // normalize image - for (y=0; y - double pR[256]; - memset(pR, 0, 256*sizeof(double)); - double pG[256]; - memset(pG, 0, 256*sizeof(double)); - double pB[256]; - memset(pB, 0, 256*sizeof(double)); - for (y=0; y0 && pR[maxR]<=threshold2) maxR--; - - maxh = 0; - for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y]; - threshold2 = threshold*maxh; - int minG = 0; - while (minG<255 && pG[minG]<=threshold2) minG++; - int maxG = 255; - while (maxG>0 && pG[maxG]<=threshold2) maxG--; - - maxh = 0; - for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y]; - threshold2 = threshold*maxh; - int minB = 0; - while (minB<255 && pB[minB]<=threshold2) minB++; - int maxB = 255; - while (maxB>0 && pB[maxB]<=threshold2) maxB--; - - if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255) - return true; - - // calculate LUT - BYTE lutR[256]; - BYTE range = maxR - minR; - if (range != 0) { - for (x = 0; x <256; x++){ - lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range))); - } - } else lutR[minR] = minR; - - BYTE lutG[256]; - range = maxG - minG; - if (range != 0) { - for (x = 0; x <256; x++){ - lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range))); - } - } else lutG[minG] = minG; - - BYTE lutB[256]; - range = maxB - minB; - if (range != 0) { - for (x = 0; x <256; x++){ - lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range))); - } - } else lutB[minB] = minB; - - // normalize image - for (y=0; y - double p[256]; - memset(p, 0, 256*sizeof(double)); - for (y=0; y0 && p[maxc]<=threshold) maxc--; - - if (minc == 0 && maxc == 255) return true; - if (minc >= maxc) return true; - - // calculate LUT - BYTE lut[256]; - for (x = 0; x <256; x++){ - lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); - } - - for(y=0; y : dave(at)posortho(dot)com -bool CxImage::HistogramEqualize() -{ - if (!pDib) return false; - - int histogram[256]; - int map[256]; - int equalize_map[256]; - int x, y, i, j; - RGBQUAD color; - RGBQUAD yuvClr; - unsigned int YVal, high, low; - - memset( &histogram, 0, sizeof(int) * 256 ); - memset( &map, 0, sizeof(int) * 256 ); - memset( &equalize_map, 0, sizeof(int) * 256 ); - - // form histogram - for(y=0; y < head.biHeight; y++){ - info.nProgress = (long)(50*y/head.biHeight); - if (info.nEscape) break; - for(x=0; x < head.biWidth; x++){ - color = BlindGetPixelColor( x, y ); - YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); - histogram[YVal]++; - } - } - - // integrate the histogram to get the equalization map. - j = 0; - for(i=0; i <= 255; i++){ - j += histogram[i]; - map[i] = j; - } - - // equalize - low = map[0]; - high = map[255]; - if (low == high) return false; - for( i = 0; i <= 255; i++ ){ - equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) ); - } - - // stretch the histogram - if(head.biClrUsed == 0){ // No Palette - for( y = 0; y < head.biHeight; y++ ){ - info.nProgress = (long)(50+50*y/head.biHeight); - if (info.nEscape) break; - for( x = 0; x < head.biWidth; x++ ){ - - color = BlindGetPixelColor( x, y ); - yuvClr = RGBtoYUV(color); - - yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed]; - - color = YUVtoRGB(yuvClr); - BlindSetPixelColor( x, y, color ); - } - } - } else { // Palette - for( i = 0; i < (int)head.biClrUsed; i++ ){ - - color = GetPaletteColor((BYTE)i); - yuvClr = RGBtoYUV(color); - - yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed]; - - color = YUVtoRGB(yuvClr); - SetPaletteColor( (BYTE)i, color ); - } - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -// HistogramNormalize function by : dave(at)posortho(dot)com -bool CxImage::HistogramNormalize() -{ - if (!pDib) return false; - - int histogram[256]; - int threshold_intensity, intense; - int x, y, i; - unsigned int normalize_map[256]; - unsigned int high, low, YVal; - - RGBQUAD color; - RGBQUAD yuvClr; - - memset( &histogram, 0, sizeof( int ) * 256 ); - memset( &normalize_map, 0, sizeof( unsigned int ) * 256 ); - - // form histogram - for(y=0; y < head.biHeight; y++){ - info.nProgress = (long)(50*y/head.biHeight); - if (info.nEscape) break; - for(x=0; x < head.biWidth; x++){ - color = BlindGetPixelColor( x, y ); - YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); - histogram[YVal]++; - } - } - - // find histogram boundaries by locating the 1 percent levels - threshold_intensity = ( head.biWidth * head.biHeight) / 100; - - intense = 0; - for( low = 0; low < 255; low++ ){ - intense += histogram[low]; - if( intense > threshold_intensity ) break; - } - - intense = 0; - for( high = 255; high != 0; high--){ - intense += histogram[ high ]; - if( intense > threshold_intensity ) break; - } - - if ( low == high ){ - // Unreasonable contrast; use zero threshold to determine boundaries. - threshold_intensity = 0; - intense = 0; - for( low = 0; low < 255; low++){ - intense += histogram[low]; - if( intense > threshold_intensity ) break; - } - intense = 0; - for( high = 255; high != 0; high-- ){ - intense += histogram [high ]; - if( intense > threshold_intensity ) break; - } - } - if( low == high ) return false; // zero span bound - - // Stretch the histogram to create the normalized image mapping. - for(i = 0; i <= 255; i++){ - if ( i < (int) low ){ - normalize_map[i] = 0; - } else { - if(i > (int) high) - normalize_map[i] = 255; - else - normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low ); - } - } - - // Normalize - if( head.biClrUsed == 0 ){ - for( y = 0; y < head.biHeight; y++ ){ - info.nProgress = (long)(50+50*y/head.biHeight); - if (info.nEscape) break; - for( x = 0; x < head.biWidth; x++ ){ - - color = BlindGetPixelColor( x, y ); - yuvClr = RGBtoYUV( color ); - - yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed]; - - color = YUVtoRGB( yuvClr ); - BlindSetPixelColor( x, y, color ); - } - } - } else { - for(i = 0; i < (int)head.biClrUsed; i++){ - - color = GetPaletteColor( (BYTE)i ); - yuvClr = RGBtoYUV( color ); - - yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed]; - - color = YUVtoRGB( yuvClr ); - SetPaletteColor( (BYTE)i, color ); - } - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -// HistogramLog function by : dave(at)posortho(dot)com -bool CxImage::HistogramLog() -{ - if (!pDib) return false; - - //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|); - int x, y, i; - RGBQUAD color; - RGBQUAD yuvClr; - - unsigned int YVal, high = 1; - - // Find Highest Luminance Value in the Image - if( head.biClrUsed == 0 ){ // No Palette - for(y=0; y < head.biHeight; y++){ - info.nProgress = (long)(50*y/head.biHeight); - if (info.nEscape) break; - for(x=0; x < head.biWidth; x++){ - color = BlindGetPixelColor( x, y ); - YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); - if (YVal > high ) high = YVal; - } - } - } else { // Palette - for(i = 0; i < (int)head.biClrUsed; i++){ - color = GetPaletteColor((BYTE)i); - YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); - if (YVal > high ) high = YVal; - } - } - - // Logarithm Operator - double k = 255.0 / ::log( 1.0 + (double)high ); - if( head.biClrUsed == 0 ){ - for( y = 0; y < head.biHeight; y++ ){ - info.nProgress = (long)(50+50*y/head.biHeight); - if (info.nEscape) break; - for( x = 0; x < head.biWidth; x++ ){ - - color = BlindGetPixelColor( x, y ); - yuvClr = RGBtoYUV( color ); - - yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); - - color = YUVtoRGB( yuvClr ); - BlindSetPixelColor( x, y, color ); - } - } - } else { - for(i = 0; i < (int)head.biClrUsed; i++){ - - color = GetPaletteColor( (BYTE)i ); - yuvClr = RGBtoYUV( color ); - - yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); - - color = YUVtoRGB( yuvClr ); - SetPaletteColor( (BYTE)i, color ); - } - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// HistogramRoot function by : dave(at)posortho(dot)com -bool CxImage::HistogramRoot() -{ - if (!pDib) return false; - //q(i,j) = sqrt(|p(i,j)|); - - int x, y, i; - RGBQUAD color; - RGBQUAD yuvClr; - double dtmp; - unsigned int YVal, high = 1; - - // Find Highest Luminance Value in the Image - if( head.biClrUsed == 0 ){ // No Palette - for(y=0; y < head.biHeight; y++){ - info.nProgress = (long)(50*y/head.biHeight); - if (info.nEscape) break; - for(x=0; x < head.biWidth; x++){ - color = BlindGetPixelColor( x, y ); - YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); - if (YVal > high ) high = YVal; - } - } - } else { // Palette - for(i = 0; i < (int)head.biClrUsed; i++){ - color = GetPaletteColor((BYTE)i); - YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); - if (YVal > high ) high = YVal; - } - } - - // Root Operator - double k = 128.0 / ::log( 1.0 + (double)high ); - if( head.biClrUsed == 0 ){ - for( y = 0; y < head.biHeight; y++ ){ - info.nProgress = (long)(50+50*y/head.biHeight); - if (info.nEscape) break; - for( x = 0; x < head.biWidth; x++ ){ - - color = BlindGetPixelColor( x, y ); - yuvClr = RGBtoYUV( color ); - - dtmp = k * ::sqrt( (double)yuvClr.rgbRed ); - if ( dtmp > 255.0 ) dtmp = 255.0; - if ( dtmp < 0 ) dtmp = 0; - yuvClr.rgbRed = (BYTE)dtmp; - - color = YUVtoRGB( yuvClr ); - BlindSetPixelColor( x, y, color ); - } - } - } else { - for(i = 0; i < (int)head.biClrUsed; i++){ - - color = GetPaletteColor( (BYTE)i ); - yuvClr = RGBtoYUV( color ); - - dtmp = k * ::sqrt( (double)yuvClr.rgbRed ); - if ( dtmp > 255.0 ) dtmp = 255.0; - if ( dtmp < 0 ) dtmp = 0; - yuvClr.rgbRed = (BYTE)dtmp; - - color = YUVtoRGB( yuvClr ); - SetPaletteColor( (BYTE)i, color ); - } - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif +// xImaHist.cpp : histogram functions +/* 28/01/2004 v1.00 - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_DSP + +//////////////////////////////////////////////////////////////////////////////// +long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace) +{ + if (!pDib) return 0; + RGBQUAD color; + + if (red) memset(red,0,256*sizeof(long)); + if (green) memset(green,0,256*sizeof(long)); + if (blue) memset(blue,0,256*sizeof(long)); + if (gray) memset(gray,0,256*sizeof(long)); + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + for(long y=ymin; yn) n=red[i]; + if (green && green[i]>n) n=green[i]; + if (blue && blue[i]>n) n=blue[i]; + if (gray && gray[i]>n) n=gray[i]; + } + + return n; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * HistogramStretch + * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels. + * \param threshold: minimum percentage level in the histogram to recognize it as meaningful. Range: 0.0 to 1.0; default = 0; typical = 0.005 (0.5%); + * \return true if everything is ok + * \author [dave] and [nipper]; changes [DP] + */ +bool CxImage::HistogramStretch(long method, double threshold) +{ + if (!pDib) return false; + + double dbScaler = 50.0/head.biHeight; + long x,y; + + if ((head.biBitCount==8) && IsGrayScale()){ + + double p[256]; + memset(p, 0, 256*sizeof(double)); + for (y=0; y0 && p[maxc]<=threshold) maxc--; + + if (minc == 0 && maxc == 255) return true; + if (minc >= maxc) return true; + + // calculate LUT + BYTE lut[256]; + for (x = 0; x <256; x++){ + lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); + } + + for (y=0; y + double p[256]; + memset(p, 0, 256*sizeof(double)); + for (y=0; y0 && p[maxc]<=threshold) maxc--; + + if (minc == 0 && maxc == 255) return true; + if (minc >= maxc) return true; + + // calculate LUT + BYTE lut[256]; + for (x = 0; x <256; x++){ + lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); + } + + // normalize image + for (y=0; y + double pR[256]; + memset(pR, 0, 256*sizeof(double)); + double pG[256]; + memset(pG, 0, 256*sizeof(double)); + double pB[256]; + memset(pB, 0, 256*sizeof(double)); + for (y=0; y0 && pR[maxR]<=threshold2) maxR--; + + maxh = 0; + for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y]; + threshold2 = threshold*maxh; + int minG = 0; + while (minG<255 && pG[minG]<=threshold2) minG++; + int maxG = 255; + while (maxG>0 && pG[maxG]<=threshold2) maxG--; + + maxh = 0; + for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y]; + threshold2 = threshold*maxh; + int minB = 0; + while (minB<255 && pB[minB]<=threshold2) minB++; + int maxB = 255; + while (maxB>0 && pB[maxB]<=threshold2) maxB--; + + if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255) + return true; + + // calculate LUT + BYTE lutR[256]; + BYTE range = maxR - minR; + if (range != 0) { + for (x = 0; x <256; x++){ + lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range))); + } + } else lutR[minR] = minR; + + BYTE lutG[256]; + range = maxG - minG; + if (range != 0) { + for (x = 0; x <256; x++){ + lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range))); + } + } else lutG[minG] = minG; + + BYTE lutB[256]; + range = maxB - minB; + if (range != 0) { + for (x = 0; x <256; x++){ + lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range))); + } + } else lutB[minB] = minB; + + // normalize image + for (y=0; y + double p[256]; + memset(p, 0, 256*sizeof(double)); + for (y=0; y0 && p[maxc]<=threshold) maxc--; + + if (minc == 0 && maxc == 255) return true; + if (minc >= maxc) return true; + + // calculate LUT + BYTE lut[256]; + for (x = 0; x <256; x++){ + lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc)))); + } + + for(y=0; y : dave(at)posortho(dot)com +bool CxImage::HistogramEqualize() +{ + if (!pDib) return false; + + int histogram[256]; + int map[256]; + int equalize_map[256]; + int x, y, i, j; + RGBQUAD color; + RGBQUAD yuvClr; + unsigned int YVal, high, low; + + memset( &histogram, 0, sizeof(int) * 256 ); + memset( &map, 0, sizeof(int) * 256 ); + memset( &equalize_map, 0, sizeof(int) * 256 ); + + // form histogram + for(y=0; y < head.biHeight; y++){ + info.nProgress = (long)(50*y/head.biHeight); + if (info.nEscape) break; + for(x=0; x < head.biWidth; x++){ + color = BlindGetPixelColor( x, y ); + YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); + histogram[YVal]++; + } + } + + // integrate the histogram to get the equalization map. + j = 0; + for(i=0; i <= 255; i++){ + j += histogram[i]; + map[i] = j; + } + + // equalize + low = map[0]; + high = map[255]; + if (low == high) return false; + for( i = 0; i <= 255; i++ ){ + equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) ); + } + + // stretch the histogram + if(head.biClrUsed == 0){ // No Palette + for( y = 0; y < head.biHeight; y++ ){ + info.nProgress = (long)(50+50*y/head.biHeight); + if (info.nEscape) break; + for( x = 0; x < head.biWidth; x++ ){ + + color = BlindGetPixelColor( x, y ); + yuvClr = RGBtoYUV(color); + + yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed]; + + color = YUVtoRGB(yuvClr); + BlindSetPixelColor( x, y, color ); + } + } + } else { // Palette + for( i = 0; i < (int)head.biClrUsed; i++ ){ + + color = GetPaletteColor((BYTE)i); + yuvClr = RGBtoYUV(color); + + yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed]; + + color = YUVtoRGB(yuvClr); + SetPaletteColor( (BYTE)i, color ); + } + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +// HistogramNormalize function by : dave(at)posortho(dot)com +bool CxImage::HistogramNormalize() +{ + if (!pDib) return false; + + int histogram[256]; + int threshold_intensity, intense; + int x, y, i; + unsigned int normalize_map[256]; + unsigned int high, low, YVal; + + RGBQUAD color; + RGBQUAD yuvClr; + + memset( &histogram, 0, sizeof( int ) * 256 ); + memset( &normalize_map, 0, sizeof( unsigned int ) * 256 ); + + // form histogram + for(y=0; y < head.biHeight; y++){ + info.nProgress = (long)(50*y/head.biHeight); + if (info.nEscape) break; + for(x=0; x < head.biWidth; x++){ + color = BlindGetPixelColor( x, y ); + YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); + histogram[YVal]++; + } + } + + // find histogram boundaries by locating the 1 percent levels + threshold_intensity = ( head.biWidth * head.biHeight) / 100; + + intense = 0; + for( low = 0; low < 255; low++ ){ + intense += histogram[low]; + if( intense > threshold_intensity ) break; + } + + intense = 0; + for( high = 255; high != 0; high--){ + intense += histogram[ high ]; + if( intense > threshold_intensity ) break; + } + + if ( low == high ){ + // Unreasonable contrast; use zero threshold to determine boundaries. + threshold_intensity = 0; + intense = 0; + for( low = 0; low < 255; low++){ + intense += histogram[low]; + if( intense > threshold_intensity ) break; + } + intense = 0; + for( high = 255; high != 0; high-- ){ + intense += histogram [high ]; + if( intense > threshold_intensity ) break; + } + } + if( low == high ) return false; // zero span bound + + // Stretch the histogram to create the normalized image mapping. + for(i = 0; i <= 255; i++){ + if ( i < (int) low ){ + normalize_map[i] = 0; + } else { + if(i > (int) high) + normalize_map[i] = 255; + else + normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low ); + } + } + + // Normalize + if( head.biClrUsed == 0 ){ + for( y = 0; y < head.biHeight; y++ ){ + info.nProgress = (long)(50+50*y/head.biHeight); + if (info.nEscape) break; + for( x = 0; x < head.biWidth; x++ ){ + + color = BlindGetPixelColor( x, y ); + yuvClr = RGBtoYUV( color ); + + yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed]; + + color = YUVtoRGB( yuvClr ); + BlindSetPixelColor( x, y, color ); + } + } + } else { + for(i = 0; i < (int)head.biClrUsed; i++){ + + color = GetPaletteColor( (BYTE)i ); + yuvClr = RGBtoYUV( color ); + + yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed]; + + color = YUVtoRGB( yuvClr ); + SetPaletteColor( (BYTE)i, color ); + } + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +// HistogramLog function by : dave(at)posortho(dot)com +bool CxImage::HistogramLog() +{ + if (!pDib) return false; + + //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|); + int x, y, i; + RGBQUAD color; + RGBQUAD yuvClr; + + unsigned int YVal, high = 1; + + // Find Highest Luminance Value in the Image + if( head.biClrUsed == 0 ){ // No Palette + for(y=0; y < head.biHeight; y++){ + info.nProgress = (long)(50*y/head.biHeight); + if (info.nEscape) break; + for(x=0; x < head.biWidth; x++){ + color = BlindGetPixelColor( x, y ); + YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); + if (YVal > high ) high = YVal; + } + } + } else { // Palette + for(i = 0; i < (int)head.biClrUsed; i++){ + color = GetPaletteColor((BYTE)i); + YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); + if (YVal > high ) high = YVal; + } + } + + // Logarithm Operator + double k = 255.0 / ::log( 1.0 + (double)high ); + if( head.biClrUsed == 0 ){ + for( y = 0; y < head.biHeight; y++ ){ + info.nProgress = (long)(50+50*y/head.biHeight); + if (info.nEscape) break; + for( x = 0; x < head.biWidth; x++ ){ + + color = BlindGetPixelColor( x, y ); + yuvClr = RGBtoYUV( color ); + + yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); + + color = YUVtoRGB( yuvClr ); + BlindSetPixelColor( x, y, color ); + } + } + } else { + for(i = 0; i < (int)head.biClrUsed; i++){ + + color = GetPaletteColor( (BYTE)i ); + yuvClr = RGBtoYUV( color ); + + yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) ); + + color = YUVtoRGB( yuvClr ); + SetPaletteColor( (BYTE)i, color ); + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// HistogramRoot function by : dave(at)posortho(dot)com +bool CxImage::HistogramRoot() +{ + if (!pDib) return false; + //q(i,j) = sqrt(|p(i,j)|); + + int x, y, i; + RGBQUAD color; + RGBQUAD yuvClr; + double dtmp; + unsigned int YVal, high = 1; + + // Find Highest Luminance Value in the Image + if( head.biClrUsed == 0 ){ // No Palette + for(y=0; y < head.biHeight; y++){ + info.nProgress = (long)(50*y/head.biHeight); + if (info.nEscape) break; + for(x=0; x < head.biWidth; x++){ + color = BlindGetPixelColor( x, y ); + YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); + if (YVal > high ) high = YVal; + } + } + } else { // Palette + for(i = 0; i < (int)head.biClrUsed; i++){ + color = GetPaletteColor((BYTE)i); + YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue); + if (YVal > high ) high = YVal; + } + } + + // Root Operator + double k = 128.0 / ::log( 1.0 + (double)high ); + if( head.biClrUsed == 0 ){ + for( y = 0; y < head.biHeight; y++ ){ + info.nProgress = (long)(50+50*y/head.biHeight); + if (info.nEscape) break; + for( x = 0; x < head.biWidth; x++ ){ + + color = BlindGetPixelColor( x, y ); + yuvClr = RGBtoYUV( color ); + + dtmp = k * ::sqrt( (double)yuvClr.rgbRed ); + if ( dtmp > 255.0 ) dtmp = 255.0; + if ( dtmp < 0 ) dtmp = 0; + yuvClr.rgbRed = (BYTE)dtmp; + + color = YUVtoRGB( yuvClr ); + BlindSetPixelColor( x, y, color ); + } + } + } else { + for(i = 0; i < (int)head.biClrUsed; i++){ + + color = GetPaletteColor( (BYTE)i ); + yuvClr = RGBtoYUV( color ); + + dtmp = k * ::sqrt( (double)yuvClr.rgbRed ); + if ( dtmp > 255.0 ) dtmp = 255.0; + if ( dtmp < 0 ) dtmp = 0; + yuvClr.rgbRed = (BYTE)dtmp; + + color = YUVtoRGB( yuvClr ); + SetPaletteColor( (BYTE)i, color ); + } + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif diff --git a/utilities/CxImage/ximaico.cpp b/utilities/CxImage/ximaico.cpp index 0cb3b06..8ae5047 100644 --- a/utilities/CxImage/ximaico.cpp +++ b/utilities/CxImage/ximaico.cpp @@ -1,472 +1,472 @@ -/* - * File: ximaico.cpp - * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version) - * 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximaico.h" - -#if CXIMAGE_SUPPORT_ICO - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageICO::Decode(CxFile *hFile) -{ - if (hFile==NULL) return false; - - DWORD off = hFile->Tell(); // - int page=info.nFrame; //internal icon structure indexes - - // read the first part of the header - ICONHEADER icon_header; - hFile->Read(&icon_header,sizeof(ICONHEADER),1); - - icon_header.idType = ntohs(icon_header.idType); - icon_header.idCount = ntohs(icon_header.idCount); - - // check if it's an icon or a cursor - if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) { - - info.nNumFrames = icon_header.idCount; - - // load the icon descriptions - ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY)); - int c; - for (c = 0; c < icon_header.idCount; c++) { - hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1); - - icon_list[c].wPlanes = ntohs(icon_list[c].wPlanes); - icon_list[c].wBitCount = ntohs(icon_list[c].wBitCount); - icon_list[c].dwBytesInRes = ntohl(icon_list[c].dwBytesInRes); - icon_list[c].dwImageOffset = ntohl(icon_list[c].dwImageOffset); - } - - if ((page>=0)&&(pageSeek(off + icon_list[page].dwImageOffset, SEEK_SET); - CxImage png; - png.SetEscape(-1); - if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){ - Transfer(png); - info.nNumFrames = icon_header.idCount; - } - } -#endif //CXIMAGE_SUPPORT_PNG - free(icon_list); - info.dwType = CXIMAGE_FORMAT_ICO; - return true; - } - - // get the bit count for the colors in the icon - BITMAPINFOHEADER bih; - hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET); - - if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0) - { // Vista icon support -#if CXIMAGE_SUPPORT_PNG - CxImage png; - if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){ - Transfer(png); - info.nNumFrames = icon_header.idCount; - } - SetType(CXIMAGE_FORMAT_ICO); -#endif //CXIMAGE_SUPPORT_PNG - } - else - { // standard icon - hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1); - - bihtoh(&bih); - - c = bih.biBitCount; - - // allocate memory for one icon - Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation - - // read the palette - RGBQUAD pal[256]; - if (bih.biClrUsed) - hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1); - else - hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1); - - SetPalette(pal,head.biClrUsed); //palette assign - - //read the icon - if (c<=24){ - hFile->Read(info.pImage, head.biSizeImage, 1); - } else { // 32 bit icon - BYTE* buf=(BYTE*)malloc(4*head.biHeight*head.biWidth); - BYTE* src = buf; - hFile->Read(buf, 4*head.biHeight*head.biWidth, 1); -#if CXIMAGE_SUPPORT_ALPHA - if (!AlphaIsValid()) AlphaCreate(); -#endif //CXIMAGE_SUPPORT_ALPHA - for (long y = 0; y < head.biHeight; y++) { - BYTE* dst = GetBits(y); - for(long x=0;xRead(mask, masksize, 1)){ - - bool bGoodMask=false; - for (int im=0;im>3)]>>(7-x%8))&0x01)){ - AlphaSet(x,y,0); - bNeedAlpha=true; - } - } - } - if (!bNeedAlpha) AlphaDelete(); -#endif //CXIMAGE_SUPPORT_ALPHA - - //check if there is only one transparent color - RGBQUAD cc,ct; - long* pcc = (long*)&cc; - long* pct = (long*)&ct; - int nTransColors=0; - int nTransIndex=0; - for (y = 0; y < head.biHeight; y++){ - for (x = 0; x < head.biWidth; x++){ - if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){ - cc = GetPixelColor(x,y,false); - if (nTransColors==0){ - nTransIndex = GetPixelIndex(x,y); - nTransColors++; - ct = cc; - } else { - if (*pct!=*pcc){ - nTransColors++; - } - } - } - } - } - if (nTransColors==1){ - SetTransColor(ct); - SetTransIndex(nTransIndex); -#if CXIMAGE_SUPPORT_ALPHA - AlphaDelete(); //because we have a unique transparent color in the image -#endif //CXIMAGE_SUPPORT_ALPHA - } - - // - Transparency support w/o Alpha support - if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha). - - // find a color index, which is not used in the image - // it is almost sure to find one, bcs. nobody uses all possible colors for an icon - - BYTE colorsUsed[256]; - memset(colorsUsed, 0, sizeof(colorsUsed)); - - for (y = 0; y < head.biHeight; y++){ - for (x = 0; x < head.biWidth; x++){ - colorsUsed[BlindGetPixelIndex(x,y)] = 1; - } - } - - int iTransIdx = -1; - for (x = (int)(head.biClrUsed-1); x>=0 ; x--){ - if (colorsUsed[x] == 0){ - iTransIdx = x; // this one is not in use. we may use it as transparent color - break; - } - } - - // Go thru image and set unused color as transparent index if needed - if (iTransIdx >= 0){ - bool bNeedTrans = false; - for (y = 0; y < head.biHeight; y++){ - for (x = 0; x < head.biWidth; x++){ - // AND mask (Each Byte represents 8 Pixels) - if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){ - // AND mask is set (!=0). This is a transparent part - SetPixelIndex(x, y, (BYTE)iTransIdx); - bNeedTrans = true; - } - } - } - // set transparent index if needed - if (bNeedTrans) SetTransIndex(iTransIdx); -#if CXIMAGE_SUPPORT_ALPHA - AlphaDelete(); //because we have a transparent color in the palette -#endif //CXIMAGE_SUPPORT_ALPHA - } - } - } else { - SetTransIndex(0); //empty mask, set black as transparent color - Negative(); - } - } - free(mask); - } - free(icon_list); - // icon has been loaded successfully! - return true; - } - free(icon_list); - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -// Thanks to -bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int nPageCount) -{ - cx_try - { - if (hFile==NULL) cx_throw("invalid file pointer"); - if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!"); - - int i; - for (i=0; iIsValid())) - cx_throw("Empty image"); - } - - CxImageICO ghost; - for (i=0; i255)||(head.biHeight>255)){ - strcpy(info.szLastError,"Can't save this image as icon"); - return false; - } -#endif - - //prepare the palette struct - RGBQUAD* pal=GetPalette(); - if (head.biBitCount<=8 && pal==NULL) return false; - - int maskwdt=((head.biWidth+31)/32)*4; //mask line width - int masksize=head.biHeight * maskwdt; //size of mask - int bitcount=head.biBitCount; - int imagesize=head.biSizeImage; -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid() && head.biClrUsed==0){ - bitcount=32; - imagesize=4*head.biHeight*head.biWidth; - } -#endif - - //fill the icon headers - int nPages = nPageCount; - if (nPages<1) nPages = 1; - - ICONHEADER icon_header={0,1,nPages}; - - if (!bAppend) - m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY); - - DWORD dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize; - - ICONDIRENTRY icon_list={ - (BYTE)head.biWidth, - (BYTE)head.biHeight, - (BYTE)head.biClrUsed, - 0, 0, - (WORD)bitcount, - dwBytesInRes, - m_dwImageOffset - }; - - BITMAPINFOHEADER bi={ - sizeof(BITMAPINFOHEADER), - head.biWidth, - 2*head.biHeight, - 1, - (WORD)bitcount, - 0, imagesize, - 0, 0, 0, 0 - }; - -#if CXIMAGE_SUPPORT_PNG // Vista icon support - CxImage png(*this); - CxMemFile memfile; - if (head.biWidth>255 || head.biHeight>255){ - icon_list.bWidth = icon_list.bHeight = 0; - memfile.Open(); - png.Encode(&memfile,CXIMAGE_FORMAT_PNG); - icon_list.dwBytesInRes = dwBytesInRes = memfile.Size(); - } -#endif //CXIMAGE_SUPPORT_PNG - - if (!bAppend){ - icon_header.idType = ntohs(icon_header.idType); - icon_header.idCount = ntohs(icon_header.idCount); - hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header - icon_header.idType = ntohs(icon_header.idType); - icon_header.idCount = ntohs(icon_header.idCount); - } - - - if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){ - icon_list.wPlanes = ntohs(icon_list.wPlanes); - icon_list.wBitCount = ntohs(icon_list.wBitCount); - icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes); - icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset); - hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry - icon_list.wPlanes = ntohs(icon_list.wPlanes); - icon_list.wBitCount = ntohs(icon_list.wBitCount); - icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes); - icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset); - - m_dwImageOffset += dwBytesInRes; //update offset for next header - } - - if ((bAppend && nPageCountWrite(memfile.GetBuffer(false),dwBytesInRes,1); - } else -#endif //CXIMAGE_SUPPORT_PNG - { // standard icon - bihtoh(&bi); - hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); //write the image header - bihtoh(&bi); - - bool bTransparent = info.nBkgndIndex >= 0; - RGBQUAD ct = GetTransColor(); - if (pal){ - if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,0,0,0,0); - hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette - if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,ct); - } - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid() && head.biClrUsed==0){ - BYTE* buf=(BYTE*)malloc(imagesize); - BYTE* dst = buf; - for (long y = 0; y < head.biHeight; y++) { - BYTE* src = GetBits(y); - for(long x=0;xWrite(buf,imagesize, 1); - free(buf); - } else { - hFile->Write(info.pImage,imagesize,1); //write image - } -#else - hFile->Write(info.pImage,imagesize,1); //write image -#endif - - //save transparency mask - BYTE* mask=(BYTE*)calloc(masksize,1); //create empty AND/XOR masks - if (!mask) return false; - - //prepare the variables to build the mask - BYTE* iDst; - int pos,i; - RGBQUAD c={0,0,0,0}; - long* pc = (long*)&c; - long* pct= (long*)&ct; -#if CXIMAGE_SUPPORT_ALPHA - bool bAlphaPaletteIsValid = AlphaPaletteIsValid(); - bool bAlphaIsValid = AlphaIsValid(); -#endif - //build the mask - for (int y = 0; y < head.biHeight; y++) { - for (int x = 0; x < head.biWidth; x++) { - i=0; -#if CXIMAGE_SUPPORT_ALPHA - if (bAlphaIsValid && AlphaGet(x,y)==0) i=1; - if (bAlphaPaletteIsValid && BlindGetPixelColor(x,y).rgbReserved==0) i=1; -#endif - c=GetPixelColor(x,y,false); - if (bTransparent && *pc==*pct) i=1; - iDst = mask + y*maskwdt + (x>>3); - pos = 7-x%8; - *iDst &= ~(0x01<Write(mask,masksize,1); - free(mask); - } - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ICO - +/* + * File: ximaico.cpp + * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version) + * 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximaico.h" + +#if CXIMAGE_SUPPORT_ICO + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageICO::Decode(CxFile *hFile) +{ + if (hFile==NULL) return false; + + DWORD off = hFile->Tell(); // + int page=info.nFrame; //internal icon structure indexes + + // read the first part of the header + ICONHEADER icon_header; + hFile->Read(&icon_header,sizeof(ICONHEADER),1); + + icon_header.idType = ntohs(icon_header.idType); + icon_header.idCount = ntohs(icon_header.idCount); + + // check if it's an icon or a cursor + if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) { + + info.nNumFrames = icon_header.idCount; + + // load the icon descriptions + ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY)); + int c; + for (c = 0; c < icon_header.idCount; c++) { + hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1); + + icon_list[c].wPlanes = ntohs(icon_list[c].wPlanes); + icon_list[c].wBitCount = ntohs(icon_list[c].wBitCount); + icon_list[c].dwBytesInRes = ntohl(icon_list[c].dwBytesInRes); + icon_list[c].dwImageOffset = ntohl(icon_list[c].dwImageOffset); + } + + if ((page>=0)&&(pageSeek(off + icon_list[page].dwImageOffset, SEEK_SET); + CxImage png; + png.SetEscape(-1); + if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){ + Transfer(png); + info.nNumFrames = icon_header.idCount; + } + } +#endif //CXIMAGE_SUPPORT_PNG + free(icon_list); + info.dwType = CXIMAGE_FORMAT_ICO; + return true; + } + + // get the bit count for the colors in the icon + BITMAPINFOHEADER bih; + hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET); + + if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0) + { // Vista icon support +#if CXIMAGE_SUPPORT_PNG + CxImage png; + if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){ + Transfer(png); + info.nNumFrames = icon_header.idCount; + } + SetType(CXIMAGE_FORMAT_ICO); +#endif //CXIMAGE_SUPPORT_PNG + } + else + { // standard icon + hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1); + + bihtoh(&bih); + + c = bih.biBitCount; + + // allocate memory for one icon + Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation + + // read the palette + RGBQUAD pal[256]; + if (bih.biClrUsed) + hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1); + else + hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1); + + SetPalette(pal,head.biClrUsed); //palette assign + + //read the icon + if (c<=24){ + hFile->Read(info.pImage, head.biSizeImage, 1); + } else { // 32 bit icon + BYTE* buf=(BYTE*)malloc(4*head.biHeight*head.biWidth); + BYTE* src = buf; + hFile->Read(buf, 4*head.biHeight*head.biWidth, 1); +#if CXIMAGE_SUPPORT_ALPHA + if (!AlphaIsValid()) AlphaCreate(); +#endif //CXIMAGE_SUPPORT_ALPHA + for (long y = 0; y < head.biHeight; y++) { + BYTE* dst = GetBits(y); + for(long x=0;xRead(mask, masksize, 1)){ + + bool bGoodMask=false; + for (int im=0;im>3)]>>(7-x%8))&0x01)){ + AlphaSet(x,y,0); + bNeedAlpha=true; + } + } + } + if (!bNeedAlpha) AlphaDelete(); +#endif //CXIMAGE_SUPPORT_ALPHA + + //check if there is only one transparent color + RGBQUAD cc,ct; + long* pcc = (long*)&cc; + long* pct = (long*)&ct; + int nTransColors=0; + int nTransIndex=0; + for (y = 0; y < head.biHeight; y++){ + for (x = 0; x < head.biWidth; x++){ + if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){ + cc = GetPixelColor(x,y,false); + if (nTransColors==0){ + nTransIndex = GetPixelIndex(x,y); + nTransColors++; + ct = cc; + } else { + if (*pct!=*pcc){ + nTransColors++; + } + } + } + } + } + if (nTransColors==1){ + SetTransColor(ct); + SetTransIndex(nTransIndex); +#if CXIMAGE_SUPPORT_ALPHA + AlphaDelete(); //because we have a unique transparent color in the image +#endif //CXIMAGE_SUPPORT_ALPHA + } + + // - Transparency support w/o Alpha support + if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha). + + // find a color index, which is not used in the image + // it is almost sure to find one, bcs. nobody uses all possible colors for an icon + + BYTE colorsUsed[256]; + memset(colorsUsed, 0, sizeof(colorsUsed)); + + for (y = 0; y < head.biHeight; y++){ + for (x = 0; x < head.biWidth; x++){ + colorsUsed[BlindGetPixelIndex(x,y)] = 1; + } + } + + int iTransIdx = -1; + for (x = (int)(head.biClrUsed-1); x>=0 ; x--){ + if (colorsUsed[x] == 0){ + iTransIdx = x; // this one is not in use. we may use it as transparent color + break; + } + } + + // Go thru image and set unused color as transparent index if needed + if (iTransIdx >= 0){ + bool bNeedTrans = false; + for (y = 0; y < head.biHeight; y++){ + for (x = 0; x < head.biWidth; x++){ + // AND mask (Each Byte represents 8 Pixels) + if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){ + // AND mask is set (!=0). This is a transparent part + SetPixelIndex(x, y, (BYTE)iTransIdx); + bNeedTrans = true; + } + } + } + // set transparent index if needed + if (bNeedTrans) SetTransIndex(iTransIdx); +#if CXIMAGE_SUPPORT_ALPHA + AlphaDelete(); //because we have a transparent color in the palette +#endif //CXIMAGE_SUPPORT_ALPHA + } + } + } else { + SetTransIndex(0); //empty mask, set black as transparent color + Negative(); + } + } + free(mask); + } + free(icon_list); + // icon has been loaded successfully! + return true; + } + free(icon_list); + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +// Thanks to +bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int nPageCount) +{ + cx_try + { + if (hFile==NULL) cx_throw("invalid file pointer"); + if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!"); + + int i; + for (i=0; iIsValid())) + cx_throw("Empty image"); + } + + CxImageICO ghost; + for (i=0; i255)||(head.biHeight>255)){ + strcpy(info.szLastError,"Can't save this image as icon"); + return false; + } +#endif + + //prepare the palette struct + RGBQUAD* pal=GetPalette(); + if (head.biBitCount<=8 && pal==NULL) return false; + + int maskwdt=((head.biWidth+31)/32)*4; //mask line width + int masksize=head.biHeight * maskwdt; //size of mask + int bitcount=head.biBitCount; + int imagesize=head.biSizeImage; +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid() && head.biClrUsed==0){ + bitcount=32; + imagesize=4*head.biHeight*head.biWidth; + } +#endif + + //fill the icon headers + int nPages = nPageCount; + if (nPages<1) nPages = 1; + + ICONHEADER icon_header={0,1,nPages}; + + if (!bAppend) + m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY); + + DWORD dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize; + + ICONDIRENTRY icon_list={ + (BYTE)head.biWidth, + (BYTE)head.biHeight, + (BYTE)head.biClrUsed, + 0, 0, + (WORD)bitcount, + dwBytesInRes, + m_dwImageOffset + }; + + BITMAPINFOHEADER bi={ + sizeof(BITMAPINFOHEADER), + head.biWidth, + 2*head.biHeight, + 1, + (WORD)bitcount, + 0, imagesize, + 0, 0, 0, 0 + }; + +#if CXIMAGE_SUPPORT_PNG // Vista icon support + CxImage png(*this); + CxMemFile memfile; + if (head.biWidth>255 || head.biHeight>255){ + icon_list.bWidth = icon_list.bHeight = 0; + memfile.Open(); + png.Encode(&memfile,CXIMAGE_FORMAT_PNG); + icon_list.dwBytesInRes = dwBytesInRes = memfile.Size(); + } +#endif //CXIMAGE_SUPPORT_PNG + + if (!bAppend){ + icon_header.idType = ntohs(icon_header.idType); + icon_header.idCount = ntohs(icon_header.idCount); + hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header + icon_header.idType = ntohs(icon_header.idType); + icon_header.idCount = ntohs(icon_header.idCount); + } + + + if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){ + icon_list.wPlanes = ntohs(icon_list.wPlanes); + icon_list.wBitCount = ntohs(icon_list.wBitCount); + icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes); + icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset); + hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry + icon_list.wPlanes = ntohs(icon_list.wPlanes); + icon_list.wBitCount = ntohs(icon_list.wBitCount); + icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes); + icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset); + + m_dwImageOffset += dwBytesInRes; //update offset for next header + } + + if ((bAppend && nPageCountWrite(memfile.GetBuffer(false),dwBytesInRes,1); + } else +#endif //CXIMAGE_SUPPORT_PNG + { // standard icon + bihtoh(&bi); + hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); //write the image header + bihtoh(&bi); + + bool bTransparent = info.nBkgndIndex >= 0; + RGBQUAD ct = GetTransColor(); + if (pal){ + if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,0,0,0,0); + hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette + if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,ct); + } + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid() && head.biClrUsed==0){ + BYTE* buf=(BYTE*)malloc(imagesize); + BYTE* dst = buf; + for (long y = 0; y < head.biHeight; y++) { + BYTE* src = GetBits(y); + for(long x=0;xWrite(buf,imagesize, 1); + free(buf); + } else { + hFile->Write(info.pImage,imagesize,1); //write image + } +#else + hFile->Write(info.pImage,imagesize,1); //write image +#endif + + //save transparency mask + BYTE* mask=(BYTE*)calloc(masksize,1); //create empty AND/XOR masks + if (!mask) return false; + + //prepare the variables to build the mask + BYTE* iDst; + int pos,i; + RGBQUAD c={0,0,0,0}; + long* pc = (long*)&c; + long* pct= (long*)&ct; +#if CXIMAGE_SUPPORT_ALPHA + bool bAlphaPaletteIsValid = AlphaPaletteIsValid(); + bool bAlphaIsValid = AlphaIsValid(); +#endif + //build the mask + for (int y = 0; y < head.biHeight; y++) { + for (int x = 0; x < head.biWidth; x++) { + i=0; +#if CXIMAGE_SUPPORT_ALPHA + if (bAlphaIsValid && AlphaGet(x,y)==0) i=1; + if (bAlphaPaletteIsValid && BlindGetPixelColor(x,y).rgbReserved==0) i=1; +#endif + c=GetPixelColor(x,y,false); + if (bTransparent && *pc==*pct) i=1; + iDst = mask + y*maskwdt + (x>>3); + pos = 7-x%8; + *iDst &= ~(0x01<Write(mask,masksize,1); + free(mask); + } + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ICO + diff --git a/utilities/CxImage/ximaico.h b/utilities/CxImage/ximaico.h index 837939a..86ef4ea 100644 --- a/utilities/CxImage/ximaico.h +++ b/utilities/CxImage/ximaico.h @@ -1,58 +1,58 @@ -/* - * File: ximaico.h - * Purpose: ICON Image Class Loader and Writer - */ -/* ========================================================== - * CxImageICO (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * ========================================================== - */ -#if !defined(__ximaICO_h) -#define __ximaICO_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_ICO - -class CxImageICO: public CxImage -{ -typedef struct tagIconDirectoryEntry { - BYTE bWidth; - BYTE bHeight; - BYTE bColorCount; - BYTE bReserved; - WORD wPlanes; - WORD wBitCount; - DWORD dwBytesInRes; - DWORD dwImageOffset; -} ICONDIRENTRY; - -typedef struct tagIconDir { - WORD idReserved; - WORD idType; - WORD idCount; -} ICONHEADER; - -public: - CxImageICO(): CxImage(CXIMAGE_FORMAT_ICO) {m_dwImageOffset=0;} - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile, bool bAppend=false, int nPageCount=0); - bool Encode(CxFile * hFile, CxImage ** pImages, int nPageCount); - bool Encode(FILE *hFile, bool bAppend=false, int nPageCount=0) - { CxIOFile file(hFile); return Encode(&file,bAppend,nPageCount); } - bool Encode(FILE *hFile, CxImage ** pImages, int nPageCount) - { CxIOFile file(hFile); return Encode(&file, pImages, nPageCount); } -#endif // CXIMAGE_SUPPORT_ENCODE -protected: - DWORD m_dwImageOffset; -}; - -#endif - -#endif +/* + * File: ximaico.h + * Purpose: ICON Image Class Loader and Writer + */ +/* ========================================================== + * CxImageICO (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * ========================================================== + */ +#if !defined(__ximaICO_h) +#define __ximaICO_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_ICO + +class CxImageICO: public CxImage +{ +typedef struct tagIconDirectoryEntry { + BYTE bWidth; + BYTE bHeight; + BYTE bColorCount; + BYTE bReserved; + WORD wPlanes; + WORD wBitCount; + DWORD dwBytesInRes; + DWORD dwImageOffset; +} ICONDIRENTRY; + +typedef struct tagIconDir { + WORD idReserved; + WORD idType; + WORD idCount; +} ICONHEADER; + +public: + CxImageICO(): CxImage(CXIMAGE_FORMAT_ICO) {m_dwImageOffset=0;} + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile, bool bAppend=false, int nPageCount=0); + bool Encode(CxFile * hFile, CxImage ** pImages, int nPageCount); + bool Encode(FILE *hFile, bool bAppend=false, int nPageCount=0) + { CxIOFile file(hFile); return Encode(&file,bAppend,nPageCount); } + bool Encode(FILE *hFile, CxImage ** pImages, int nPageCount) + { CxIOFile file(hFile); return Encode(&file, pImages, nPageCount); } +#endif // CXIMAGE_SUPPORT_ENCODE +protected: + DWORD m_dwImageOffset; +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximainfo.cpp b/utilities/CxImage/ximainfo.cpp index fd453f2..28cbad4 100644 --- a/utilities/CxImage/ximainfo.cpp +++ b/utilities/CxImage/ximainfo.cpp @@ -1,917 +1,917 @@ -// ximainfo.cpp : main attributes -/* 03/10/2004 v1.00 - Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" - -//////////////////////////////////////////////////////////////////////////////// -/** - * \return the color used for transparency, and/or for background color - */ -RGBQUAD CxImage::GetTransColor() -{ - if (head.biBitCount<24 && info.nBkgndIndex>=0) return GetPaletteColor((BYTE)info.nBkgndIndex); - return info.nBkgndColor; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Gets the index used for transparency. Returns -1 for no transparancy. - */ -long CxImage::GetTransIndex() const -{ - return info.nBkgndIndex; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets the index used for transparency with 1, 4 and 8 bpp images. Set to -1 to remove the effect. - */ -void CxImage::SetTransIndex(long idx) -{ - if (idx<(long)head.biClrUsed) - info.nBkgndIndex = idx; - else - info.nBkgndIndex = 0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets the color used for transparency with 24 bpp images. - * You must call SetTransIndex(0) to enable the effect, SetTransIndex(-1) to disable it. - */ -void CxImage::SetTransColor(RGBQUAD rgb) -{ - rgb.rgbReserved=0; - info.nBkgndColor = rgb; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::IsTransparent() const -{ - return info.nBkgndIndex>=0; // -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Returns true if the image has 256 colors or less. - */ -bool CxImage::IsIndexed() const -{ - return head.biClrUsed!=0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return 1 = indexed, 2 = RGB, 4 = RGBA - */ -BYTE CxImage::GetColorType() -{ - BYTE b = (BYTE)((head.biBitCount>8) ? 2 /*COLORTYPE_COLOR*/ : 1 /*COLORTYPE_PALETTE*/); -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) b = 4 /*COLORTYPE_ALPHA*/; -#endif //CXIMAGE_SUPPORT_ALPHA - return b; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return Resolution for TIFF, JPEG, PNG and BMP formats. - */ -long CxImage::GetXDPI() const -{ - return info.xDPI; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return Resolution for TIFF, JPEG, PNG and BMP formats. - */ -long CxImage::GetYDPI() const -{ - return info.yDPI; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Set resolution for TIFF, JPEG, PNG and BMP formats. - */ -void CxImage::SetXDPI(long dpi) -{ - if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI; - info.xDPI = dpi; - head.biXPelsPerMeter = (long) floor(dpi * 10000.0 / 254.0 + 0.5); - if (pDib) ((BITMAPINFOHEADER*)pDib)->biXPelsPerMeter = head.biXPelsPerMeter; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Set resolution for TIFF, JPEG, PNG and BMP formats. - */ -void CxImage::SetYDPI(long dpi) -{ - if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI; - info.yDPI = dpi; - head.biYPelsPerMeter = (long) floor(dpi * 10000.0 / 254.0 + 0.5); - if (pDib) ((BITMAPINFOHEADER*)pDib)->biYPelsPerMeter = head.biYPelsPerMeter; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa SetFlags - */ -DWORD CxImage::GetFlags() const -{ - return info.dwFlags; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Image flags, for future use - * \param flags - * - 0x??00000 = reserved for 16 bit, CMYK, multilayer - * - 0x00??0000 = blend modes - * - 0x0000???? = layer id or user flags - * - * \param bLockReservedFlags protects the "reserved" and "blend modes" flags - */ -void CxImage::SetFlags(DWORD flags, bool bLockReservedFlags) -{ - if (bLockReservedFlags) info.dwFlags = flags & 0x0000ffff; - else info.dwFlags = flags; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa SetCodecOption - */ -DWORD CxImage::GetCodecOption(DWORD imagetype) -{ - imagetype = GetTypeIndexFromId(imagetype); - if (imagetype==0){ - imagetype = GetTypeIndexFromId(GetType()); - } - return info.dwCodecOpt[imagetype]; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Encode option for GIF, TIF and JPG. - * - GIF : 0 = LZW (default), 1 = none, 2 = RLE. - * - TIF : 0 = automatic (default), or a valid compression code as defined in "tiff.h" (COMPRESSION_NONE = 1, COMPRESSION_CCITTRLE = 2, ...) - * - JPG : valid values stored in enum CODEC_OPTION ( ENCODE_BASELINE = 0x01, ENCODE_PROGRESSIVE = 0x10, ...) - * - RAW : valid values stored in enum CODEC_OPTION ( DECODE_QUALITY_LIN = 0x00, DECODE_QUALITY_VNG = 0x01, ...) - * - * \return true if everything is ok - */ -bool CxImage::SetCodecOption(DWORD opt, DWORD imagetype) -{ - imagetype = GetTypeIndexFromId(imagetype); - if (imagetype==0){ - imagetype = GetTypeIndexFromId(GetType()); - } - info.dwCodecOpt[imagetype] = opt; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return internal hDib object.. - */ -void* CxImage::GetDIB() const -{ - return pDib; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::GetHeight() const -{ - return head.biHeight; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::GetWidth() const -{ - return head.biWidth; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return DWORD aligned width of the image. - */ -DWORD CxImage::GetEffWidth() const -{ - return info.dwEffWidth; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return 2, 16, 256; 0 for RGB images. - */ -DWORD CxImage::GetNumColors() const -{ - return head.biClrUsed; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return: 1, 4, 8, 24. - */ -WORD CxImage::GetBpp() const -{ - return head.biBitCount; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return original image format - * \sa ENUM_CXIMAGE_FORMATS. - */ -DWORD CxImage::GetType() const -{ - return info.dwType; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * change image format identifier - * \sa ENUM_CXIMAGE_FORMATS. - */ -bool CxImage::SetType(DWORD type) -{ - switch (type){ -#if CXIMAGE_SUPPORT_BMP - case CXIMAGE_FORMAT_BMP: -#endif -#if CXIMAGE_SUPPORT_GIF - case CXIMAGE_FORMAT_GIF: -#endif -#if CXIMAGE_SUPPORT_JPG - case CXIMAGE_FORMAT_JPG: -#endif -#if CXIMAGE_SUPPORT_PNG - case CXIMAGE_FORMAT_PNG: -#endif -#if CXIMAGE_SUPPORT_MNG - case CXIMAGE_FORMAT_MNG: -#endif -#if CXIMAGE_SUPPORT_ICO - case CXIMAGE_FORMAT_ICO: -#endif -#if CXIMAGE_SUPPORT_TIF - case CXIMAGE_FORMAT_TIF: -#endif -#if CXIMAGE_SUPPORT_TGA - case CXIMAGE_FORMAT_TGA: -#endif -#if CXIMAGE_SUPPORT_PCX - case CXIMAGE_FORMAT_PCX: -#endif -#if CXIMAGE_SUPPORT_WBMP - case CXIMAGE_FORMAT_WBMP: -#endif -#if CXIMAGE_SUPPORT_WMF - case CXIMAGE_FORMAT_WMF: -#endif -#if CXIMAGE_SUPPORT_JBG - case CXIMAGE_FORMAT_JBG: -#endif -#if CXIMAGE_SUPPORT_JP2 - case CXIMAGE_FORMAT_JP2: -#endif -#if CXIMAGE_SUPPORT_JPC - case CXIMAGE_FORMAT_JPC: -#endif -#if CXIMAGE_SUPPORT_PGX - case CXIMAGE_FORMAT_PGX: -#endif -#if CXIMAGE_SUPPORT_PNM - case CXIMAGE_FORMAT_PNM: -#endif -#if CXIMAGE_SUPPORT_RAS - case CXIMAGE_FORMAT_RAS: -#endif -#if CXIMAGE_SUPPORT_SKA - case CXIMAGE_FORMAT_SKA: -#endif -#if CXIMAGE_SUPPORT_RAW - case CXIMAGE_FORMAT_RAW: -#endif - info.dwType = type; - return true; - } - info.dwType = CXIMAGE_FORMAT_UNKNOWN; - return false; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::GetNumTypes() -{ - return CMAX_IMAGE_FORMATS-1; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::GetTypeIdFromName(const TCHAR* ext) -{ -#if CXIMAGE_SUPPORT_BMP - if (_tcsnicmp(ext,_T("bmp"),3)==0 ) return CXIMAGE_FORMAT_BMP; -#endif -#if CXIMAGE_SUPPORT_JPG - if (_tcsnicmp(ext,_T("jpg"),3)==0 || - _tcsnicmp(ext,_T("jpe"),3)==0 || - _tcsnicmp(ext,_T("jfi"),3)==0 ) return CXIMAGE_FORMAT_JPG; -#endif -#if CXIMAGE_SUPPORT_GIF - if (_tcsnicmp(ext,_T("gif"),3)==0 ) return CXIMAGE_FORMAT_GIF; -#endif -#if CXIMAGE_SUPPORT_PNG - if (_tcsnicmp(ext,_T("png"),3)==0 ) return CXIMAGE_FORMAT_PNG; -#endif -#if CXIMAGE_SUPPORT_ICO - if (_tcsnicmp(ext,_T("ico"),3)==0 || - _tcsnicmp(ext,_T("cur"),3)==0 ) return CXIMAGE_FORMAT_ICO; -#endif -#if CXIMAGE_SUPPORT_TIF - if (_tcsnicmp(ext,_T("tif"),3)==0 ) return CXIMAGE_FORMAT_TIF; -#endif -#if CXIMAGE_SUPPORT_TGA - if (_tcsnicmp(ext,_T("tga"),3)==0 ) return CXIMAGE_FORMAT_TGA; -#endif -#if CXIMAGE_SUPPORT_PCX - if (_tcsnicmp(ext,_T("pcx"),3)==0 ) return CXIMAGE_FORMAT_PCX; -#endif -#if CXIMAGE_SUPPORT_WBMP - if (_tcsnicmp(ext,_T("wbm"),3)==0 ) return CXIMAGE_FORMAT_WBMP; -#endif -#if CXIMAGE_SUPPORT_WMF - if (_tcsnicmp(ext,_T("wmf"),3)==0 || - _tcsnicmp(ext,_T("emf"),3)==0 ) return CXIMAGE_FORMAT_WMF; -#endif -#if CXIMAGE_SUPPORT_JP2 - if (_tcsnicmp(ext,_T("jp2"),3)==0 || - _tcsnicmp(ext,_T("j2k"),3)==0 ) return CXIMAGE_FORMAT_JP2; -#endif -#if CXIMAGE_SUPPORT_JPC - if (_tcsnicmp(ext,_T("jpc"),3)==0 || - _tcsnicmp(ext,_T("j2c"),3)==0 ) return CXIMAGE_FORMAT_JPC; -#endif -#if CXIMAGE_SUPPORT_PGX - if (_tcsnicmp(ext,_T("pgx"),3)==0 ) return CXIMAGE_FORMAT_PGX; -#endif -#if CXIMAGE_SUPPORT_RAS - if (_tcsnicmp(ext,_T("ras"),3)==0 ) return CXIMAGE_FORMAT_RAS; -#endif -#if CXIMAGE_SUPPORT_PNM - if (_tcsnicmp(ext,_T("pnm"),3)==0 || - _tcsnicmp(ext,_T("pgm"),3)==0 || - _tcsnicmp(ext,_T("ppm"),3)==0 ) return CXIMAGE_FORMAT_PNM; -#endif -#if CXIMAGE_SUPPORT_JBG - if (_tcsnicmp(ext,_T("jbg"),3)==0 ) return CXIMAGE_FORMAT_JBG; -#endif -#if CXIMAGE_SUPPORT_MNG - if (_tcsnicmp(ext,_T("mng"),3)==0 || - _tcsnicmp(ext,_T("jng"),3)==0 ) return CXIMAGE_FORMAT_MNG; -#endif -#if CXIMAGE_SUPPORT_SKA - if (_tcsnicmp(ext,_T("ska"),3)==0 ) return CXIMAGE_FORMAT_SKA; -#endif -#if CXIMAGE_SUPPORT_RAW - if (_tcsnicmp(ext,_T("nef"),3)==0 || - _tcsnicmp(ext,_T("crw"),3)==0 || - _tcsnicmp(ext,_T("cr2"),3)==0 || - _tcsnicmp(ext,_T("dng"),3)==0 || - _tcsnicmp(ext,_T("arw"),3)==0 || - _tcsnicmp(ext,_T("erf"),3)==0 || - _tcsnicmp(ext,_T("3fr"),3)==0 || - _tcsnicmp(ext,_T("dcr"),3)==0 || - _tcsnicmp(ext,_T("raw"),3)==0 || - _tcsnicmp(ext,_T("x3f"),3)==0 || - _tcsnicmp(ext,_T("mef"),3)==0 || - _tcsnicmp(ext,_T("raf"),3)==0 || - _tcsnicmp(ext,_T("mrw"),3)==0 || - _tcsnicmp(ext,_T("pef"),3)==0 || - _tcsnicmp(ext,_T("sr2"),3)==0 || - _tcsnicmp(ext,_T("orf"),3)==0 ) return CXIMAGE_FORMAT_RAW; -#endif - - return CXIMAGE_FORMAT_UNKNOWN; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::GetTypeIdFromIndex(const DWORD index) -{ - DWORD n; - - n=0; if (index == n) return CXIMAGE_FORMAT_UNKNOWN; -#if CXIMAGE_SUPPORT_BMP - n++; if (index == n) return CXIMAGE_FORMAT_BMP; -#endif -#if CXIMAGE_SUPPORT_GIF - n++; if (index == n) return CXIMAGE_FORMAT_GIF; -#endif -#if CXIMAGE_SUPPORT_JPG - n++; if (index == n) return CXIMAGE_FORMAT_JPG; -#endif -#if CXIMAGE_SUPPORT_PNG - n++; if (index == n) return CXIMAGE_FORMAT_PNG; -#endif -#if CXIMAGE_SUPPORT_ICO - n++; if (index == n) return CXIMAGE_FORMAT_ICO; -#endif -#if CXIMAGE_SUPPORT_TIF - n++; if (index == n) return CXIMAGE_FORMAT_TIF; -#endif -#if CXIMAGE_SUPPORT_TGA - n++; if (index == n) return CXIMAGE_FORMAT_TGA; -#endif -#if CXIMAGE_SUPPORT_PCX - n++; if (index == n) return CXIMAGE_FORMAT_PCX; -#endif -#if CXIMAGE_SUPPORT_WBMP - n++; if (index == n) return CXIMAGE_FORMAT_WBMP; -#endif -#if CXIMAGE_SUPPORT_WMF - n++; if (index == n) return CXIMAGE_FORMAT_WMF; -#endif -#if CXIMAGE_SUPPORT_JP2 - n++; if (index == n) return CXIMAGE_FORMAT_JP2; -#endif -#if CXIMAGE_SUPPORT_JPC - n++; if (index == n) return CXIMAGE_FORMAT_JPC; -#endif -#if CXIMAGE_SUPPORT_PGX - n++; if (index == n) return CXIMAGE_FORMAT_PGX; -#endif -#if CXIMAGE_SUPPORT_PNM - n++; if (index == n) return CXIMAGE_FORMAT_PNM; -#endif -#if CXIMAGE_SUPPORT_RAS - n++; if (index == n) return CXIMAGE_FORMAT_RAS; -#endif -#if CXIMAGE_SUPPORT_JBG - n++; if (index == n) return CXIMAGE_FORMAT_JBG; -#endif -#if CXIMAGE_SUPPORT_MNG - n++; if (index == n) return CXIMAGE_FORMAT_MNG; -#endif -#if CXIMAGE_SUPPORT_SKA - n++; if (index == n) return CXIMAGE_FORMAT_SKA; -#endif -#if CXIMAGE_SUPPORT_RAW - n++; if (index == n) return CXIMAGE_FORMAT_RAW; -#endif - - return CXIMAGE_FORMAT_UNKNOWN; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::GetTypeIndexFromId(const DWORD id) -{ - DWORD n; - - n=0; if (id == CXIMAGE_FORMAT_UNKNOWN) return n; -#if CXIMAGE_SUPPORT_BMP - n++; if (id == CXIMAGE_FORMAT_BMP) return n; -#endif -#if CXIMAGE_SUPPORT_GIF - n++; if (id == CXIMAGE_FORMAT_GIF) return n; -#endif -#if CXIMAGE_SUPPORT_JPG - n++; if (id == CXIMAGE_FORMAT_JPG) return n; -#endif -#if CXIMAGE_SUPPORT_PNG - n++; if (id == CXIMAGE_FORMAT_PNG) return n; -#endif -#if CXIMAGE_SUPPORT_ICO - n++; if (id == CXIMAGE_FORMAT_ICO) return n; -#endif -#if CXIMAGE_SUPPORT_TIF - n++; if (id == CXIMAGE_FORMAT_TIF) return n; -#endif -#if CXIMAGE_SUPPORT_TGA - n++; if (id == CXIMAGE_FORMAT_TGA) return n; -#endif -#if CXIMAGE_SUPPORT_PCX - n++; if (id == CXIMAGE_FORMAT_PCX) return n; -#endif -#if CXIMAGE_SUPPORT_WBMP - n++; if (id == CXIMAGE_FORMAT_WBMP) return n; -#endif -#if CXIMAGE_SUPPORT_WMF - n++; if (id == CXIMAGE_FORMAT_WMF) return n; -#endif -#if CXIMAGE_SUPPORT_JP2 - n++; if (id == CXIMAGE_FORMAT_JP2) return n; -#endif -#if CXIMAGE_SUPPORT_JPC - n++; if (id == CXIMAGE_FORMAT_JPC) return n; -#endif -#if CXIMAGE_SUPPORT_PGX - n++; if (id == CXIMAGE_FORMAT_PGX) return n; -#endif -#if CXIMAGE_SUPPORT_PNM - n++; if (id == CXIMAGE_FORMAT_PNM) return n; -#endif -#if CXIMAGE_SUPPORT_RAS - n++; if (id == CXIMAGE_FORMAT_RAS) return n; -#endif -#if CXIMAGE_SUPPORT_JBG - n++; if (id == CXIMAGE_FORMAT_JBG) return n; -#endif -#if CXIMAGE_SUPPORT_MNG - n++; if (id == CXIMAGE_FORMAT_MNG) return n; -#endif -#if CXIMAGE_SUPPORT_SKA - n++; if (id == CXIMAGE_FORMAT_SKA) return n; -#endif -#if CXIMAGE_SUPPORT_RAW - n++; if (id == CXIMAGE_FORMAT_RAW) return n; -#endif - - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return current frame delay in milliseconds. Only for GIF and MNG formats. - */ -DWORD CxImage::GetFrameDelay() const -{ - return info.dwFrameDelay; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets current frame delay. Only for GIF format. - * \param d = delay in milliseconds - */ -void CxImage::SetFrameDelay(DWORD d) -{ - info.dwFrameDelay=d; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::GetOffset(long *x,long *y) -{ - *x=info.xOffset; - *y=info.yOffset; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::SetOffset(long x,long y) -{ - info.xOffset=x; - info.yOffset=y; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa SetJpegQuality, GetJpegQualityF - * \author [DP]; changes [Stefan Schürmans] - */ -BYTE CxImage::GetJpegQuality() const -{ - return (BYTE)(info.fQuality + 0.5f); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa SetJpegQuality, GetJpegQuality - * \author [Stefan Schürmans] - */ -float CxImage::GetJpegQualityF() const -{ - return info.fQuality; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * quality level for JPEG and JPEG2000 - * \param q: can be from 0 to 100 - * \author [DP]; changes [Stefan Schürmans] - */ -void CxImage::SetJpegQuality(BYTE q){ - info.fQuality = (float)q; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * quality level for JPEG and JPEG2000 - * necessary for JPEG2000 when quality is between 0.0 and 1.0 - * \param q: can be from 0.0 to 100.0 - * \author [Stefan Schürmans] - */ -void CxImage::SetJpegQualityF(float q){ - if (q>0) info.fQuality = q; - else info.fQuality = 0.0f; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa SetJpegScale - */ -BYTE CxImage::GetJpegScale() const -{ - return info.nJpegScale; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * scaling down during JPEG decoding valid numbers are 1, 2, 4, 8 - * \author [ignacio] - */ -void CxImage::SetJpegScale(BYTE q){ - info.nJpegScale = q; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Used to monitor the slow loops. - * \return value is from 0 to 100. - * \sa SetProgress - */ -long CxImage::GetProgress() const -{ - return info.nProgress; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return the escape code. - * \sa SetEscape - */ -long CxImage::GetEscape() const -{ - return info.nEscape; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Forces the value of the internal progress variable. - * \param p should be from 0 to 100. - * \sa GetProgress - */ -void CxImage::SetProgress(long p) -{ - info.nProgress = p; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Used to quit the slow loops or the codecs. - * - SetEscape(-1) before Decode forces the function to exit, right after - * the image width and height are available ( for bmp, jpg, gif, tif ) - */ -void CxImage::SetEscape(long i) -{ - info.nEscape = i; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Checks if the image is correctly initializated. - */ -bool CxImage::IsValid() const -{ - return pDib!=0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * True if the image is enabled for painting. - */ -bool CxImage::IsEnabled() const -{ - return info.bEnabled; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Enables/disables the image. - */ -void CxImage::Enable(bool enable) -{ - info.bEnabled=enable; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * This function must be used after a Decode() / Load() call. - * Use the sequence SetFrame(-1); Load(...); GetNumFrames(); - * to get the number of images without loading the first image. - * \return the number of images in the file. - */ -long CxImage::GetNumFrames() const -{ - return info.nNumFrames; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return the current selected image (zero-based index). - */ -long CxImage::GetFrame() const -{ - return info.nFrame; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets the image number that the next Decode() / Load() call will load - */ -void CxImage::SetFrame(long nFrame){ - info.nFrame=nFrame; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets the method for drawing the frame related to others - * \sa GetDisposalMethod - */ -void CxImage::SetDisposalMethod(BYTE dm) -{ info.dispmeth=dm; } -//////////////////////////////////////////////////////////////////////////////// -/** - * Gets the method for drawing the frame related to others - * Values : 0 - No disposal specified. The decoder is - * not required to take any action. - * 1 - Do not dispose. The graphic is to be left - * in place. - * 2 - Restore to background color. The area used by the - * graphic must be restored to the background color. - * 3 - Restore to previous. The decoder is required to - * restore the area overwritten by the graphic with - * what was there prior to rendering the graphic. - * 4-7 - To be defined. - */ -BYTE CxImage::GetDisposalMethod() const -{ return info.dispmeth; } -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::GetRetreiveAllFrames() const -{ return info.bGetAllFrames; } -//////////////////////////////////////////////////////////////////////////////// -void CxImage::SetRetreiveAllFrames(bool flag) -{ info.bGetAllFrames = flag; } -//////////////////////////////////////////////////////////////////////////////// -CxImage * CxImage::GetFrame(long nFrame) const -{ - if ( ppFrames == NULL) return NULL; - if ( info.nNumFrames == 0) return NULL; - if ( nFrame >= info.nNumFrames ) return NULL; - if ( nFrame < 0) nFrame = info.nNumFrames - 1; - return ppFrames[nFrame]; -} -//////////////////////////////////////////////////////////////////////////////// -short CxImage::ntohs(const short word) -{ - if (info.bLittleEndianHost) return word; - return ( (word & 0xff) << 8 ) | ( (word >> 8) & 0xff ); -} -//////////////////////////////////////////////////////////////////////////////// -long CxImage::ntohl(const long dword) -{ - if (info.bLittleEndianHost) return dword; - return ((dword & 0xff) << 24 ) | ((dword & 0xff00) << 8 ) | - ((dword >> 8) & 0xff00) | ((dword >> 24) & 0xff); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::bihtoh(BITMAPINFOHEADER* bih) -{ - bih->biSize = ntohl(bih->biSize); - bih->biWidth = ntohl(bih->biWidth); - bih->biHeight = ntohl(bih->biHeight); - bih->biPlanes = ntohs(bih->biPlanes); - bih->biBitCount = ntohs(bih->biBitCount); - bih->biCompression = ntohl(bih->biCompression); - bih->biSizeImage = ntohl(bih->biSizeImage); - bih->biXPelsPerMeter = ntohl(bih->biXPelsPerMeter); - bih->biYPelsPerMeter = ntohl(bih->biYPelsPerMeter); - bih->biClrUsed = ntohl(bih->biClrUsed); - bih->biClrImportant = ntohl(bih->biClrImportant); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Returns the last reported error. - */ -const char* CxImage::GetLastError() -{ - return info.szLastError; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::DumpSize() -{ - DWORD n; - n = sizeof(BITMAPINFOHEADER) + sizeof(CXIMAGEINFO) + GetSize(); - - if (pAlpha){ - n += 1 + head.biWidth * head.biHeight; - } else n++; - - if (pSelection){ - n += 1 + head.biWidth * head.biHeight; - } else n++; - - if (ppLayers){ - for (long m=0; mDumpSize(); - } - } - } else n++; - - if (ppFrames){ - for (long m=0; mDumpSize(); - } - } - } else n++; - - return n; -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::Dump(BYTE * dst) -{ - if (!dst) return 0; - - memcpy(dst,&head,sizeof(BITMAPINFOHEADER)); - dst += sizeof(BITMAPINFOHEADER); - - memcpy(dst,&info,sizeof(CXIMAGEINFO)); - dst += sizeof(CXIMAGEINFO); - - memcpy(dst,pDib,GetSize()); - dst += GetSize(); - - if (pAlpha){ - memset(dst++, 1, 1); - memcpy(dst,pAlpha,head.biWidth * head.biHeight); - dst += head.biWidth * head.biHeight; - } else { - memset(dst++, 0, 1); - } - - if (pSelection){ - memset(dst++, 1, 1); - memcpy(dst,pSelection,head.biWidth * head.biHeight); - dst += head.biWidth * head.biHeight; - } else { - memset(dst++, 0, 1); - } - - if (ppLayers){ - memset(dst++, 1, 1); - for (long m=0; mDump(dst); - } - } - } else { - memset(dst++, 0, 1); - } - - if (ppFrames){ - memset(dst++, 1, 1); - for (long m=0; mDump(dst); - } - } - } else { - memset(dst++, 0, 1); - } - - return DumpSize(); -} -//////////////////////////////////////////////////////////////////////////////// -DWORD CxImage::UnDump(const BYTE * src) -{ - if (!src) - return 0; - if (!Destroy()) - return 0; - if (!DestroyFrames()) - return 0; - - DWORD n = 0; - - memcpy(&head,src,sizeof(BITMAPINFOHEADER)); - n += sizeof(BITMAPINFOHEADER); - - memcpy(&info,&src[n],sizeof(CXIMAGEINFO)); - n += sizeof(CXIMAGEINFO); - - if (!Create(head.biWidth, head.biHeight, head.biBitCount, info.dwType)) - return 0; - - memcpy(pDib,&src[n],GetSize()); - n += GetSize(); - - if (src[n++]){ - if (AlphaCreate()){ - memcpy(pAlpha, &src[n], head.biWidth * head.biHeight); - } - n += head.biWidth * head.biHeight; - } - - if (src[n++]){ - RECT box = info.rSelectionBox; - if (SelectionCreate()){ - info.rSelectionBox = box; - memcpy(pSelection, &src[n], head.biWidth * head.biHeight); - } - n += head.biWidth * head.biHeight; - } - - if (src[n++]){ - ppLayers = new CxImage*[info.nNumLayers]; - for (long m=0; mUnDump(&src[n]); - } - } - - if (src[n++]){ - ppFrames = new CxImage*[info.nNumFrames]; - for (long m=0; mUnDump(&src[n]); - } - } - - return n; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \return A.BBCCCDDDD - * - A = main version - * - BB = main revision - * - CCC = minor revision (letter) - * - DDDD = experimental revision - */ -const float CxImage::GetVersionNumber() -{ - return 6.000000015f; -} -//////////////////////////////////////////////////////////////////////////////// -const TCHAR* CxImage::GetVersion() -{ - static const TCHAR CxImageVersion[] = _T("CxImage 6.0.0"); - return (CxImageVersion); -} -//////////////////////////////////////////////////////////////////////////////// +// ximainfo.cpp : main attributes +/* 03/10/2004 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +//////////////////////////////////////////////////////////////////////////////// +/** + * \return the color used for transparency, and/or for background color + */ +RGBQUAD CxImage::GetTransColor() +{ + if (head.biBitCount<24 && info.nBkgndIndex>=0) return GetPaletteColor((BYTE)info.nBkgndIndex); + return info.nBkgndColor; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Gets the index used for transparency. Returns -1 for no transparancy. + */ +long CxImage::GetTransIndex() const +{ + return info.nBkgndIndex; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Sets the index used for transparency with 1, 4 and 8 bpp images. Set to -1 to remove the effect. + */ +void CxImage::SetTransIndex(long idx) +{ + if (idx<(long)head.biClrUsed) + info.nBkgndIndex = idx; + else + info.nBkgndIndex = 0; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Sets the color used for transparency with 24 bpp images. + * You must call SetTransIndex(0) to enable the effect, SetTransIndex(-1) to disable it. + */ +void CxImage::SetTransColor(RGBQUAD rgb) +{ + rgb.rgbReserved=0; + info.nBkgndColor = rgb; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::IsTransparent() const +{ + return info.nBkgndIndex>=0; // +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Returns true if the image has 256 colors or less. + */ +bool CxImage::IsIndexed() const +{ + return head.biClrUsed!=0; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return 1 = indexed, 2 = RGB, 4 = RGBA + */ +BYTE CxImage::GetColorType() +{ + BYTE b = (BYTE)((head.biBitCount>8) ? 2 /*COLORTYPE_COLOR*/ : 1 /*COLORTYPE_PALETTE*/); +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) b = 4 /*COLORTYPE_ALPHA*/; +#endif //CXIMAGE_SUPPORT_ALPHA + return b; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return Resolution for TIFF, JPEG, PNG and BMP formats. + */ +long CxImage::GetXDPI() const +{ + return info.xDPI; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return Resolution for TIFF, JPEG, PNG and BMP formats. + */ +long CxImage::GetYDPI() const +{ + return info.yDPI; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Set resolution for TIFF, JPEG, PNG and BMP formats. + */ +void CxImage::SetXDPI(long dpi) +{ + if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI; + info.xDPI = dpi; + head.biXPelsPerMeter = (long) floor(dpi * 10000.0 / 254.0 + 0.5); + if (pDib) ((BITMAPINFOHEADER*)pDib)->biXPelsPerMeter = head.biXPelsPerMeter; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Set resolution for TIFF, JPEG, PNG and BMP formats. + */ +void CxImage::SetYDPI(long dpi) +{ + if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI; + info.yDPI = dpi; + head.biYPelsPerMeter = (long) floor(dpi * 10000.0 / 254.0 + 0.5); + if (pDib) ((BITMAPINFOHEADER*)pDib)->biYPelsPerMeter = head.biYPelsPerMeter; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa SetFlags + */ +DWORD CxImage::GetFlags() const +{ + return info.dwFlags; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Image flags, for future use + * \param flags + * - 0x??00000 = reserved for 16 bit, CMYK, multilayer + * - 0x00??0000 = blend modes + * - 0x0000???? = layer id or user flags + * + * \param bLockReservedFlags protects the "reserved" and "blend modes" flags + */ +void CxImage::SetFlags(DWORD flags, bool bLockReservedFlags) +{ + if (bLockReservedFlags) info.dwFlags = flags & 0x0000ffff; + else info.dwFlags = flags; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa SetCodecOption + */ +DWORD CxImage::GetCodecOption(DWORD imagetype) +{ + imagetype = GetTypeIndexFromId(imagetype); + if (imagetype==0){ + imagetype = GetTypeIndexFromId(GetType()); + } + return info.dwCodecOpt[imagetype]; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Encode option for GIF, TIF and JPG. + * - GIF : 0 = LZW (default), 1 = none, 2 = RLE. + * - TIF : 0 = automatic (default), or a valid compression code as defined in "tiff.h" (COMPRESSION_NONE = 1, COMPRESSION_CCITTRLE = 2, ...) + * - JPG : valid values stored in enum CODEC_OPTION ( ENCODE_BASELINE = 0x01, ENCODE_PROGRESSIVE = 0x10, ...) + * - RAW : valid values stored in enum CODEC_OPTION ( DECODE_QUALITY_LIN = 0x00, DECODE_QUALITY_VNG = 0x01, ...) + * + * \return true if everything is ok + */ +bool CxImage::SetCodecOption(DWORD opt, DWORD imagetype) +{ + imagetype = GetTypeIndexFromId(imagetype); + if (imagetype==0){ + imagetype = GetTypeIndexFromId(GetType()); + } + info.dwCodecOpt[imagetype] = opt; + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return internal hDib object.. + */ +void* CxImage::GetDIB() const +{ + return pDib; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::GetHeight() const +{ + return head.biHeight; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::GetWidth() const +{ + return head.biWidth; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return DWORD aligned width of the image. + */ +DWORD CxImage::GetEffWidth() const +{ + return info.dwEffWidth; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return 2, 16, 256; 0 for RGB images. + */ +DWORD CxImage::GetNumColors() const +{ + return head.biClrUsed; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return: 1, 4, 8, 24. + */ +WORD CxImage::GetBpp() const +{ + return head.biBitCount; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return original image format + * \sa ENUM_CXIMAGE_FORMATS. + */ +DWORD CxImage::GetType() const +{ + return info.dwType; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * change image format identifier + * \sa ENUM_CXIMAGE_FORMATS. + */ +bool CxImage::SetType(DWORD type) +{ + switch (type){ +#if CXIMAGE_SUPPORT_BMP + case CXIMAGE_FORMAT_BMP: +#endif +#if CXIMAGE_SUPPORT_GIF + case CXIMAGE_FORMAT_GIF: +#endif +#if CXIMAGE_SUPPORT_JPG + case CXIMAGE_FORMAT_JPG: +#endif +#if CXIMAGE_SUPPORT_PNG + case CXIMAGE_FORMAT_PNG: +#endif +#if CXIMAGE_SUPPORT_MNG + case CXIMAGE_FORMAT_MNG: +#endif +#if CXIMAGE_SUPPORT_ICO + case CXIMAGE_FORMAT_ICO: +#endif +#if CXIMAGE_SUPPORT_TIF + case CXIMAGE_FORMAT_TIF: +#endif +#if CXIMAGE_SUPPORT_TGA + case CXIMAGE_FORMAT_TGA: +#endif +#if CXIMAGE_SUPPORT_PCX + case CXIMAGE_FORMAT_PCX: +#endif +#if CXIMAGE_SUPPORT_WBMP + case CXIMAGE_FORMAT_WBMP: +#endif +#if CXIMAGE_SUPPORT_WMF + case CXIMAGE_FORMAT_WMF: +#endif +#if CXIMAGE_SUPPORT_JBG + case CXIMAGE_FORMAT_JBG: +#endif +#if CXIMAGE_SUPPORT_JP2 + case CXIMAGE_FORMAT_JP2: +#endif +#if CXIMAGE_SUPPORT_JPC + case CXIMAGE_FORMAT_JPC: +#endif +#if CXIMAGE_SUPPORT_PGX + case CXIMAGE_FORMAT_PGX: +#endif +#if CXIMAGE_SUPPORT_PNM + case CXIMAGE_FORMAT_PNM: +#endif +#if CXIMAGE_SUPPORT_RAS + case CXIMAGE_FORMAT_RAS: +#endif +#if CXIMAGE_SUPPORT_SKA + case CXIMAGE_FORMAT_SKA: +#endif +#if CXIMAGE_SUPPORT_RAW + case CXIMAGE_FORMAT_RAW: +#endif + info.dwType = type; + return true; + } + info.dwType = CXIMAGE_FORMAT_UNKNOWN; + return false; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::GetNumTypes() +{ + return CMAX_IMAGE_FORMATS-1; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::GetTypeIdFromName(const TCHAR* ext) +{ +#if CXIMAGE_SUPPORT_BMP + if (_tcsnicmp(ext,_T("bmp"),3)==0 ) return CXIMAGE_FORMAT_BMP; +#endif +#if CXIMAGE_SUPPORT_JPG + if (_tcsnicmp(ext,_T("jpg"),3)==0 || + _tcsnicmp(ext,_T("jpe"),3)==0 || + _tcsnicmp(ext,_T("jfi"),3)==0 ) return CXIMAGE_FORMAT_JPG; +#endif +#if CXIMAGE_SUPPORT_GIF + if (_tcsnicmp(ext,_T("gif"),3)==0 ) return CXIMAGE_FORMAT_GIF; +#endif +#if CXIMAGE_SUPPORT_PNG + if (_tcsnicmp(ext,_T("png"),3)==0 ) return CXIMAGE_FORMAT_PNG; +#endif +#if CXIMAGE_SUPPORT_ICO + if (_tcsnicmp(ext,_T("ico"),3)==0 || + _tcsnicmp(ext,_T("cur"),3)==0 ) return CXIMAGE_FORMAT_ICO; +#endif +#if CXIMAGE_SUPPORT_TIF + if (_tcsnicmp(ext,_T("tif"),3)==0 ) return CXIMAGE_FORMAT_TIF; +#endif +#if CXIMAGE_SUPPORT_TGA + if (_tcsnicmp(ext,_T("tga"),3)==0 ) return CXIMAGE_FORMAT_TGA; +#endif +#if CXIMAGE_SUPPORT_PCX + if (_tcsnicmp(ext,_T("pcx"),3)==0 ) return CXIMAGE_FORMAT_PCX; +#endif +#if CXIMAGE_SUPPORT_WBMP + if (_tcsnicmp(ext,_T("wbm"),3)==0 ) return CXIMAGE_FORMAT_WBMP; +#endif +#if CXIMAGE_SUPPORT_WMF + if (_tcsnicmp(ext,_T("wmf"),3)==0 || + _tcsnicmp(ext,_T("emf"),3)==0 ) return CXIMAGE_FORMAT_WMF; +#endif +#if CXIMAGE_SUPPORT_JP2 + if (_tcsnicmp(ext,_T("jp2"),3)==0 || + _tcsnicmp(ext,_T("j2k"),3)==0 ) return CXIMAGE_FORMAT_JP2; +#endif +#if CXIMAGE_SUPPORT_JPC + if (_tcsnicmp(ext,_T("jpc"),3)==0 || + _tcsnicmp(ext,_T("j2c"),3)==0 ) return CXIMAGE_FORMAT_JPC; +#endif +#if CXIMAGE_SUPPORT_PGX + if (_tcsnicmp(ext,_T("pgx"),3)==0 ) return CXIMAGE_FORMAT_PGX; +#endif +#if CXIMAGE_SUPPORT_RAS + if (_tcsnicmp(ext,_T("ras"),3)==0 ) return CXIMAGE_FORMAT_RAS; +#endif +#if CXIMAGE_SUPPORT_PNM + if (_tcsnicmp(ext,_T("pnm"),3)==0 || + _tcsnicmp(ext,_T("pgm"),3)==0 || + _tcsnicmp(ext,_T("ppm"),3)==0 ) return CXIMAGE_FORMAT_PNM; +#endif +#if CXIMAGE_SUPPORT_JBG + if (_tcsnicmp(ext,_T("jbg"),3)==0 ) return CXIMAGE_FORMAT_JBG; +#endif +#if CXIMAGE_SUPPORT_MNG + if (_tcsnicmp(ext,_T("mng"),3)==0 || + _tcsnicmp(ext,_T("jng"),3)==0 ) return CXIMAGE_FORMAT_MNG; +#endif +#if CXIMAGE_SUPPORT_SKA + if (_tcsnicmp(ext,_T("ska"),3)==0 ) return CXIMAGE_FORMAT_SKA; +#endif +#if CXIMAGE_SUPPORT_RAW + if (_tcsnicmp(ext,_T("nef"),3)==0 || + _tcsnicmp(ext,_T("crw"),3)==0 || + _tcsnicmp(ext,_T("cr2"),3)==0 || + _tcsnicmp(ext,_T("dng"),3)==0 || + _tcsnicmp(ext,_T("arw"),3)==0 || + _tcsnicmp(ext,_T("erf"),3)==0 || + _tcsnicmp(ext,_T("3fr"),3)==0 || + _tcsnicmp(ext,_T("dcr"),3)==0 || + _tcsnicmp(ext,_T("raw"),3)==0 || + _tcsnicmp(ext,_T("x3f"),3)==0 || + _tcsnicmp(ext,_T("mef"),3)==0 || + _tcsnicmp(ext,_T("raf"),3)==0 || + _tcsnicmp(ext,_T("mrw"),3)==0 || + _tcsnicmp(ext,_T("pef"),3)==0 || + _tcsnicmp(ext,_T("sr2"),3)==0 || + _tcsnicmp(ext,_T("orf"),3)==0 ) return CXIMAGE_FORMAT_RAW; +#endif + + return CXIMAGE_FORMAT_UNKNOWN; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::GetTypeIdFromIndex(const DWORD index) +{ + DWORD n; + + n=0; if (index == n) return CXIMAGE_FORMAT_UNKNOWN; +#if CXIMAGE_SUPPORT_BMP + n++; if (index == n) return CXIMAGE_FORMAT_BMP; +#endif +#if CXIMAGE_SUPPORT_GIF + n++; if (index == n) return CXIMAGE_FORMAT_GIF; +#endif +#if CXIMAGE_SUPPORT_JPG + n++; if (index == n) return CXIMAGE_FORMAT_JPG; +#endif +#if CXIMAGE_SUPPORT_PNG + n++; if (index == n) return CXIMAGE_FORMAT_PNG; +#endif +#if CXIMAGE_SUPPORT_ICO + n++; if (index == n) return CXIMAGE_FORMAT_ICO; +#endif +#if CXIMAGE_SUPPORT_TIF + n++; if (index == n) return CXIMAGE_FORMAT_TIF; +#endif +#if CXIMAGE_SUPPORT_TGA + n++; if (index == n) return CXIMAGE_FORMAT_TGA; +#endif +#if CXIMAGE_SUPPORT_PCX + n++; if (index == n) return CXIMAGE_FORMAT_PCX; +#endif +#if CXIMAGE_SUPPORT_WBMP + n++; if (index == n) return CXIMAGE_FORMAT_WBMP; +#endif +#if CXIMAGE_SUPPORT_WMF + n++; if (index == n) return CXIMAGE_FORMAT_WMF; +#endif +#if CXIMAGE_SUPPORT_JP2 + n++; if (index == n) return CXIMAGE_FORMAT_JP2; +#endif +#if CXIMAGE_SUPPORT_JPC + n++; if (index == n) return CXIMAGE_FORMAT_JPC; +#endif +#if CXIMAGE_SUPPORT_PGX + n++; if (index == n) return CXIMAGE_FORMAT_PGX; +#endif +#if CXIMAGE_SUPPORT_PNM + n++; if (index == n) return CXIMAGE_FORMAT_PNM; +#endif +#if CXIMAGE_SUPPORT_RAS + n++; if (index == n) return CXIMAGE_FORMAT_RAS; +#endif +#if CXIMAGE_SUPPORT_JBG + n++; if (index == n) return CXIMAGE_FORMAT_JBG; +#endif +#if CXIMAGE_SUPPORT_MNG + n++; if (index == n) return CXIMAGE_FORMAT_MNG; +#endif +#if CXIMAGE_SUPPORT_SKA + n++; if (index == n) return CXIMAGE_FORMAT_SKA; +#endif +#if CXIMAGE_SUPPORT_RAW + n++; if (index == n) return CXIMAGE_FORMAT_RAW; +#endif + + return CXIMAGE_FORMAT_UNKNOWN; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::GetTypeIndexFromId(const DWORD id) +{ + DWORD n; + + n=0; if (id == CXIMAGE_FORMAT_UNKNOWN) return n; +#if CXIMAGE_SUPPORT_BMP + n++; if (id == CXIMAGE_FORMAT_BMP) return n; +#endif +#if CXIMAGE_SUPPORT_GIF + n++; if (id == CXIMAGE_FORMAT_GIF) return n; +#endif +#if CXIMAGE_SUPPORT_JPG + n++; if (id == CXIMAGE_FORMAT_JPG) return n; +#endif +#if CXIMAGE_SUPPORT_PNG + n++; if (id == CXIMAGE_FORMAT_PNG) return n; +#endif +#if CXIMAGE_SUPPORT_ICO + n++; if (id == CXIMAGE_FORMAT_ICO) return n; +#endif +#if CXIMAGE_SUPPORT_TIF + n++; if (id == CXIMAGE_FORMAT_TIF) return n; +#endif +#if CXIMAGE_SUPPORT_TGA + n++; if (id == CXIMAGE_FORMAT_TGA) return n; +#endif +#if CXIMAGE_SUPPORT_PCX + n++; if (id == CXIMAGE_FORMAT_PCX) return n; +#endif +#if CXIMAGE_SUPPORT_WBMP + n++; if (id == CXIMAGE_FORMAT_WBMP) return n; +#endif +#if CXIMAGE_SUPPORT_WMF + n++; if (id == CXIMAGE_FORMAT_WMF) return n; +#endif +#if CXIMAGE_SUPPORT_JP2 + n++; if (id == CXIMAGE_FORMAT_JP2) return n; +#endif +#if CXIMAGE_SUPPORT_JPC + n++; if (id == CXIMAGE_FORMAT_JPC) return n; +#endif +#if CXIMAGE_SUPPORT_PGX + n++; if (id == CXIMAGE_FORMAT_PGX) return n; +#endif +#if CXIMAGE_SUPPORT_PNM + n++; if (id == CXIMAGE_FORMAT_PNM) return n; +#endif +#if CXIMAGE_SUPPORT_RAS + n++; if (id == CXIMAGE_FORMAT_RAS) return n; +#endif +#if CXIMAGE_SUPPORT_JBG + n++; if (id == CXIMAGE_FORMAT_JBG) return n; +#endif +#if CXIMAGE_SUPPORT_MNG + n++; if (id == CXIMAGE_FORMAT_MNG) return n; +#endif +#if CXIMAGE_SUPPORT_SKA + n++; if (id == CXIMAGE_FORMAT_SKA) return n; +#endif +#if CXIMAGE_SUPPORT_RAW + n++; if (id == CXIMAGE_FORMAT_RAW) return n; +#endif + + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return current frame delay in milliseconds. Only for GIF and MNG formats. + */ +DWORD CxImage::GetFrameDelay() const +{ + return info.dwFrameDelay; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Sets current frame delay. Only for GIF format. + * \param d = delay in milliseconds + */ +void CxImage::SetFrameDelay(DWORD d) +{ + info.dwFrameDelay=d; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::GetOffset(long *x,long *y) +{ + *x=info.xOffset; + *y=info.yOffset; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::SetOffset(long x,long y) +{ + info.xOffset=x; + info.yOffset=y; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa SetJpegQuality, GetJpegQualityF + * \author [DP]; changes [Stefan Schürmans] + */ +BYTE CxImage::GetJpegQuality() const +{ + return (BYTE)(info.fQuality + 0.5f); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa SetJpegQuality, GetJpegQuality + * \author [Stefan Schürmans] + */ +float CxImage::GetJpegQualityF() const +{ + return info.fQuality; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * quality level for JPEG and JPEG2000 + * \param q: can be from 0 to 100 + * \author [DP]; changes [Stefan Schürmans] + */ +void CxImage::SetJpegQuality(BYTE q){ + info.fQuality = (float)q; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * quality level for JPEG and JPEG2000 + * necessary for JPEG2000 when quality is between 0.0 and 1.0 + * \param q: can be from 0.0 to 100.0 + * \author [Stefan Schürmans] + */ +void CxImage::SetJpegQualityF(float q){ + if (q>0) info.fQuality = q; + else info.fQuality = 0.0f; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa SetJpegScale + */ +BYTE CxImage::GetJpegScale() const +{ + return info.nJpegScale; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * scaling down during JPEG decoding valid numbers are 1, 2, 4, 8 + * \author [ignacio] + */ +void CxImage::SetJpegScale(BYTE q){ + info.nJpegScale = q; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Used to monitor the slow loops. + * \return value is from 0 to 100. + * \sa SetProgress + */ +long CxImage::GetProgress() const +{ + return info.nProgress; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return the escape code. + * \sa SetEscape + */ +long CxImage::GetEscape() const +{ + return info.nEscape; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Forces the value of the internal progress variable. + * \param p should be from 0 to 100. + * \sa GetProgress + */ +void CxImage::SetProgress(long p) +{ + info.nProgress = p; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Used to quit the slow loops or the codecs. + * - SetEscape(-1) before Decode forces the function to exit, right after + * the image width and height are available ( for bmp, jpg, gif, tif ) + */ +void CxImage::SetEscape(long i) +{ + info.nEscape = i; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Checks if the image is correctly initializated. + */ +bool CxImage::IsValid() const +{ + return pDib!=0; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * True if the image is enabled for painting. + */ +bool CxImage::IsEnabled() const +{ + return info.bEnabled; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Enables/disables the image. + */ +void CxImage::Enable(bool enable) +{ + info.bEnabled=enable; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * This function must be used after a Decode() / Load() call. + * Use the sequence SetFrame(-1); Load(...); GetNumFrames(); + * to get the number of images without loading the first image. + * \return the number of images in the file. + */ +long CxImage::GetNumFrames() const +{ + return info.nNumFrames; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return the current selected image (zero-based index). + */ +long CxImage::GetFrame() const +{ + return info.nFrame; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Sets the image number that the next Decode() / Load() call will load + */ +void CxImage::SetFrame(long nFrame){ + info.nFrame=nFrame; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Sets the method for drawing the frame related to others + * \sa GetDisposalMethod + */ +void CxImage::SetDisposalMethod(BYTE dm) +{ info.dispmeth=dm; } +//////////////////////////////////////////////////////////////////////////////// +/** + * Gets the method for drawing the frame related to others + * Values : 0 - No disposal specified. The decoder is + * not required to take any action. + * 1 - Do not dispose. The graphic is to be left + * in place. + * 2 - Restore to background color. The area used by the + * graphic must be restored to the background color. + * 3 - Restore to previous. The decoder is required to + * restore the area overwritten by the graphic with + * what was there prior to rendering the graphic. + * 4-7 - To be defined. + */ +BYTE CxImage::GetDisposalMethod() const +{ return info.dispmeth; } +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::GetRetreiveAllFrames() const +{ return info.bGetAllFrames; } +//////////////////////////////////////////////////////////////////////////////// +void CxImage::SetRetreiveAllFrames(bool flag) +{ info.bGetAllFrames = flag; } +//////////////////////////////////////////////////////////////////////////////// +CxImage * CxImage::GetFrame(long nFrame) const +{ + if ( ppFrames == NULL) return NULL; + if ( info.nNumFrames == 0) return NULL; + if ( nFrame >= info.nNumFrames ) return NULL; + if ( nFrame < 0) nFrame = info.nNumFrames - 1; + return ppFrames[nFrame]; +} +//////////////////////////////////////////////////////////////////////////////// +short CxImage::ntohs(const short word) +{ + if (info.bLittleEndianHost) return word; + return ( (word & 0xff) << 8 ) | ( (word >> 8) & 0xff ); +} +//////////////////////////////////////////////////////////////////////////////// +long CxImage::ntohl(const long dword) +{ + if (info.bLittleEndianHost) return dword; + return ((dword & 0xff) << 24 ) | ((dword & 0xff00) << 8 ) | + ((dword >> 8) & 0xff00) | ((dword >> 24) & 0xff); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::bihtoh(BITMAPINFOHEADER* bih) +{ + bih->biSize = ntohl(bih->biSize); + bih->biWidth = ntohl(bih->biWidth); + bih->biHeight = ntohl(bih->biHeight); + bih->biPlanes = ntohs(bih->biPlanes); + bih->biBitCount = ntohs(bih->biBitCount); + bih->biCompression = ntohl(bih->biCompression); + bih->biSizeImage = ntohl(bih->biSizeImage); + bih->biXPelsPerMeter = ntohl(bih->biXPelsPerMeter); + bih->biYPelsPerMeter = ntohl(bih->biYPelsPerMeter); + bih->biClrUsed = ntohl(bih->biClrUsed); + bih->biClrImportant = ntohl(bih->biClrImportant); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Returns the last reported error. + */ +const char* CxImage::GetLastError() +{ + return info.szLastError; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::DumpSize() +{ + DWORD n; + n = sizeof(BITMAPINFOHEADER) + sizeof(CXIMAGEINFO) + GetSize(); + + if (pAlpha){ + n += 1 + head.biWidth * head.biHeight; + } else n++; + + if (pSelection){ + n += 1 + head.biWidth * head.biHeight; + } else n++; + + if (ppLayers){ + for (long m=0; mDumpSize(); + } + } + } else n++; + + if (ppFrames){ + for (long m=0; mDumpSize(); + } + } + } else n++; + + return n; +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::Dump(BYTE * dst) +{ + if (!dst) return 0; + + memcpy(dst,&head,sizeof(BITMAPINFOHEADER)); + dst += sizeof(BITMAPINFOHEADER); + + memcpy(dst,&info,sizeof(CXIMAGEINFO)); + dst += sizeof(CXIMAGEINFO); + + memcpy(dst,pDib,GetSize()); + dst += GetSize(); + + if (pAlpha){ + memset(dst++, 1, 1); + memcpy(dst,pAlpha,head.biWidth * head.biHeight); + dst += head.biWidth * head.biHeight; + } else { + memset(dst++, 0, 1); + } + + if (pSelection){ + memset(dst++, 1, 1); + memcpy(dst,pSelection,head.biWidth * head.biHeight); + dst += head.biWidth * head.biHeight; + } else { + memset(dst++, 0, 1); + } + + if (ppLayers){ + memset(dst++, 1, 1); + for (long m=0; mDump(dst); + } + } + } else { + memset(dst++, 0, 1); + } + + if (ppFrames){ + memset(dst++, 1, 1); + for (long m=0; mDump(dst); + } + } + } else { + memset(dst++, 0, 1); + } + + return DumpSize(); +} +//////////////////////////////////////////////////////////////////////////////// +DWORD CxImage::UnDump(const BYTE * src) +{ + if (!src) + return 0; + if (!Destroy()) + return 0; + if (!DestroyFrames()) + return 0; + + DWORD n = 0; + + memcpy(&head,src,sizeof(BITMAPINFOHEADER)); + n += sizeof(BITMAPINFOHEADER); + + memcpy(&info,&src[n],sizeof(CXIMAGEINFO)); + n += sizeof(CXIMAGEINFO); + + if (!Create(head.biWidth, head.biHeight, head.biBitCount, info.dwType)) + return 0; + + memcpy(pDib,&src[n],GetSize()); + n += GetSize(); + + if (src[n++]){ + if (AlphaCreate()){ + memcpy(pAlpha, &src[n], head.biWidth * head.biHeight); + } + n += head.biWidth * head.biHeight; + } + + if (src[n++]){ + RECT box = info.rSelectionBox; + if (SelectionCreate()){ + info.rSelectionBox = box; + memcpy(pSelection, &src[n], head.biWidth * head.biHeight); + } + n += head.biWidth * head.biHeight; + } + + if (src[n++]){ + ppLayers = new CxImage*[info.nNumLayers]; + for (long m=0; mUnDump(&src[n]); + } + } + + if (src[n++]){ + ppFrames = new CxImage*[info.nNumFrames]; + for (long m=0; mUnDump(&src[n]); + } + } + + return n; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \return A.BBCCCDDDD + * - A = main version + * - BB = main revision + * - CCC = minor revision (letter) + * - DDDD = experimental revision + */ +const float CxImage::GetVersionNumber() +{ + return 6.000000015f; +} +//////////////////////////////////////////////////////////////////////////////// +const TCHAR* CxImage::GetVersion() +{ + static const TCHAR CxImageVersion[] = _T("CxImage 6.0.0"); + return (CxImageVersion); +} +//////////////////////////////////////////////////////////////////////////////// diff --git a/utilities/CxImage/ximaint.cpp b/utilities/CxImage/ximaint.cpp index 89e1bac..989d76c 100644 --- a/utilities/CxImage/ximaint.cpp +++ b/utilities/CxImage/ximaint.cpp @@ -1,1056 +1,1056 @@ -// xImaInt.cpp : interpolation functions -/* 02/2004 - Branko Brevensek - * CxImage version 6.0.0 02/Feb/2008 - Davide Pizzolato - www.xdp.it - */ - -#include "ximage.h" -#include "ximath.h" - -#if CXIMAGE_SUPPORT_INTERPOLATION - -//////////////////////////////////////////////////////////////////////////////// -/** - * Recalculates coordinates according to specified overflow method. - * If pixel (x,y) lies within image, nothing changes. - * - * \param x, y - coordinates of pixel - * \param ofMethod - overflow method - * - * \return x, y - new coordinates (pixel (x,y) now lies inside image) - * - * \author ***bd*** 2.2004 - */ -void CxImage::OverflowCoordinates(long &x, long &y, OverflowMethod const ofMethod) -{ - if (IsInside(x,y)) return; //if pixel is within bounds, no change - switch (ofMethod) { - case OM_REPEAT: - //clip coordinates - x=max(x,0); x=min(x, head.biWidth-1); - y=max(y,0); y=min(y, head.biHeight-1); - break; - case OM_WRAP: - //wrap coordinates - x = x % head.biWidth; - y = y % head.biHeight; - if (x<0) x = head.biWidth + x; - if (y<0) y = head.biHeight + y; - break; - case OM_MIRROR: - //mirror pixels near border - if (x<0) x=((-x) % head.biWidth); - else if (x>=head.biWidth) x=head.biWidth-(x % head.biWidth + 1); - if (y<0) y=((-y) % head.biHeight); - else if (y>=head.biHeight) y=head.biHeight-(y % head.biHeight + 1); - break; - default: - return; - }//switch -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * See OverflowCoordinates for integer version - * \author ***bd*** 2.2004 - */ -void CxImage::OverflowCoordinates(float &x, float &y, OverflowMethod const ofMethod) -{ - if (x>=0 && x=0 && y=head.biWidth) x=head.biWidth-((float)fmod(x, (float) head.biWidth) + 1); - if (y<0) y=(float)fmod(-y, (float) head.biHeight); - else if (y>=head.biHeight) y=head.biHeight-((float)fmod(y, (float) head.biHeight) + 1); - break; - default: - return; - }//switch -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Method return pixel color. Different methods are implemented for out of bounds pixels. - * If an image has alpha channel, alpha value is returned in .RGBReserved. - * - * \param x,y : pixel coordinates - * \param ofMethod : out-of-bounds method: - * - OF_WRAP - wrap over to pixels on other side of the image - * - OF_REPEAT - repeat last pixel on the edge - * - OF_COLOR - return input value of color - * - OF_BACKGROUND - return background color (if not set, return input color) - * - OF_TRANSPARENT - return transparent pixel - * - * \param rplColor : input color (returned for out-of-bound coordinates in OF_COLOR mode and if other mode is not applicable) - * - * \return color : color of pixel - * \author ***bd*** 2.2004 - */ -RGBQUAD CxImage::GetPixelColorWithOverflow(long x, long y, OverflowMethod const ofMethod, RGBQUAD* const rplColor) -{ - RGBQUAD color; //color to return - if ((!IsInside(x,y)) || pDib==NULL) { //is pixel within bouns?: - //pixel is out of bounds or no DIB - if (rplColor!=NULL) - color=*rplColor; - else { - color.rgbRed=color.rgbGreen=color.rgbBlue=255; color.rgbReserved=0; //default replacement colour: white transparent - }//if - if (pDib==NULL) return color; - //pixel is out of bounds: - switch (ofMethod) { - case OM_TRANSPARENT: -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) { - //alpha transparency is supported and image has alpha layer - color.rgbReserved=0; - } else { -#endif //CXIMAGE_SUPPORT_ALPHA - //no alpha transparency - if (GetTransIndex()>=0) { - color=GetTransColor(); //single color transparency enabled (return transparent color) - }//if -#if CXIMAGE_SUPPORT_ALPHA - }//if -#endif //CXIMAGE_SUPPORT_ALPHA - return color; - case OM_BACKGROUND: - //return background color (if it exists, otherwise input value) - if (info.nBkgndIndex >= 0) { - if (head.biBitCount<24) color = GetPaletteColor((BYTE)info.nBkgndIndex); - else color = info.nBkgndColor; - }//if - return color; - case OM_REPEAT: - case OM_WRAP: - case OM_MIRROR: - OverflowCoordinates(x,y,ofMethod); - break; - default: - //simply return replacement color (OM_COLOR and others) - return color; - }//switch - }//if - //just return specified pixel (it's within bounds) - return BlindGetPixelColor(x,y); -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * This method reconstructs image according to chosen interpolation method and then returns pixel (x,y). - * (x,y) can lie between actual image pixels. If (x,y) lies outside of image, method returns value - * according to overflow method. - * This method is very useful for geometrical image transformations, where destination pixel - * can often assume color value lying between source pixels. - * - * \param (x,y) - coordinates of pixel to return - * GPCI method recreates "analogue" image back from digital data, so x and y - * are float values and color value of point (1.1,1) will generally not be same - * as (1,1). Center of first pixel is at (0,0) and center of pixel right to it is (1,0). - * (0.5,0) is half way between these two pixels. - * \param inMethod - interpolation (reconstruction) method (kernel) to use: - * - IM_NEAREST_NEIGHBOUR - returns colour of nearest lying pixel (causes stairy look of - * processed images) - * - IM_BILINEAR - interpolates colour from four neighbouring pixels (softens image a bit) - * - IM_BICUBIC - interpolates from 16 neighbouring pixels (can produce "halo" artifacts) - * - IM_BICUBIC2 - interpolates from 16 neighbouring pixels (perhaps a bit less halo artifacts - than IM_BICUBIC) - * - IM_BSPLINE - interpolates from 16 neighbouring pixels (softens image, washes colours) - * (As far as I know, image should be prefiltered for this method to give - * good results... some other time :) ) - * This method uses bicubic interpolation kernel from CXImage 5.99a and older - * versions. - * - IM_LANCZOS - interpolates from 12*12 pixels (slow, ringing artifacts) - * - * \param ofMethod - overflow method (see comments at GetPixelColorWithOverflow) - * \param rplColor - pointer to color used for out of borders pixels in OM_COLOR mode - * (and other modes if colour can't calculated in a specified way) - * - * \return interpolated color value (including interpolated alpha value, if image has alpha layer) - * - * \author ***bd*** 2.2004 - */ -RGBQUAD CxImage::GetPixelColorInterpolated( - float x,float y, - InterpolationMethod const inMethod, - OverflowMethod const ofMethod, - RGBQUAD* const rplColor) -{ - //calculate nearest pixel - int xi=(int)(x); if (x<0) xi--; //these replace (incredibly slow) floor (Visual c++ 2003, AMD Athlon) - int yi=(int)(y); if (y<0) yi--; - RGBQUAD color; //calculated colour - - switch (inMethod) { - case IM_NEAREST_NEIGHBOUR: - return GetPixelColorWithOverflow((long)(x+0.5f), (long)(y+0.5f), ofMethod, rplColor); - default: { - //IM_BILINEAR: bilinear interpolation - if (xi<-1 || xi>=head.biWidth || yi<-1 || yi>=head.biHeight) { //all 4 points are outside bounds?: - switch (ofMethod) { - case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND: - //we don't need to interpolate anything with all points outside in this case - return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor); - default: - //recalculate coordinates and use faster method later on - OverflowCoordinates(x,y,ofMethod); - xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi - yi=(int)(y); if (y<0) yi--; - }//switch - }//if - //get four neighbouring pixels - if ((xi+1)=0 && (yi+1)=0 && head.biClrUsed==0) { - //all pixels are inside RGB24 image... optimize reading (and use fixed point arithmetic) - WORD wt1=(WORD)((x-xi)*256.0f), wt2=(WORD)((y-yi)*256.0f); - WORD wd=wt1*wt2>>8; - WORD wb=wt1-wd; - WORD wc=wt2-wd; - WORD wa=256-wt1-wc; - WORD wrr,wgg,wbb; - BYTE *pxptr=(BYTE*)info.pImage+yi*info.dwEffWidth+xi*3; - wbb=wa*(*pxptr++); wgg=wa*(*pxptr++); wrr=wa*(*pxptr++); - wbb+=wb*(*pxptr++); wgg+=wb*(*pxptr++); wrr+=wb*(*pxptr); - pxptr+=(info.dwEffWidth-5); //move to next row - wbb+=wc*(*pxptr++); wgg+=wc*(*pxptr++); wrr+=wc*(*pxptr++); - wbb+=wd*(*pxptr++); wgg+=wd*(*pxptr++); wrr+=wd*(*pxptr); - color.rgbRed=(BYTE) (wrr>>8); color.rgbGreen=(BYTE) (wgg>>8); color.rgbBlue=(BYTE) (wbb>>8); -#if CXIMAGE_SUPPORT_ALPHA - if (pAlpha) { - WORD waa; - //image has alpha layer... we have to do the same for alpha data - pxptr=AlphaGetPointer(xi,yi); //pointer to first byte - waa=wa*(*pxptr++); waa+=wb*(*pxptr); //first two pixels - pxptr+=(head.biWidth-1); //move to next row - waa+=wc*(*pxptr++); waa+=wd*(*pxptr); //and second row pixels - color.rgbReserved=(BYTE) (waa>>8); - } else -#endif - { //Alpha not supported or no alpha at all - color.rgbReserved = 0; - } - return color; - } else { - //default (slower) way to get pixels (not RGB24 or some pixels out of borders) - float t1=x-xi, t2=y-yi; - float d=t1*t2; - float b=t1-d; - float c=t2-d; - float a=1-t1-c; - RGBQUAD rgb11,rgb21,rgb12,rgb22; - rgb11=GetPixelColorWithOverflow(xi, yi, ofMethod, rplColor); - rgb21=GetPixelColorWithOverflow(xi+1, yi, ofMethod, rplColor); - rgb12=GetPixelColorWithOverflow(xi, yi+1, ofMethod, rplColor); - rgb22=GetPixelColorWithOverflow(xi+1, yi+1, ofMethod, rplColor); - //calculate linear interpolation - color.rgbRed=(BYTE) (a*rgb11.rgbRed+b*rgb21.rgbRed+c*rgb12.rgbRed+d*rgb22.rgbRed); - color.rgbGreen=(BYTE) (a*rgb11.rgbGreen+b*rgb21.rgbGreen+c*rgb12.rgbGreen+d*rgb22.rgbGreen); - color.rgbBlue=(BYTE) (a*rgb11.rgbBlue+b*rgb21.rgbBlue+c*rgb12.rgbBlue+d*rgb22.rgbBlue); -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) - color.rgbReserved=(BYTE) (a*rgb11.rgbReserved+b*rgb21.rgbReserved+c*rgb12.rgbReserved+d*rgb22.rgbReserved); - else -#endif - { //Alpha not supported or no alpha at all - color.rgbReserved = 0; - } - return color; - }//if - }//default - case IM_BICUBIC: - case IM_BICUBIC2: - case IM_BSPLINE: - case IM_BOX: - case IM_HERMITE: - case IM_HAMMING: - case IM_SINC: - case IM_BLACKMAN: - case IM_BESSEL: - case IM_GAUSSIAN: - case IM_QUADRATIC: - case IM_MITCHELL: - case IM_CATROM: - case IM_HANNING: - case IM_POWER: - //bicubic interpolation(s) - if (((xi+2)<0) || ((xi-1)>=head.biWidth) || ((yi+2)<0) || ((yi-1)>=head.biHeight)) { //all points are outside bounds?: - switch (ofMethod) { - case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND: - //we don't need to interpolate anything with all points outside in this case - return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor); - break; - default: - //recalculate coordinates and use faster method later on - OverflowCoordinates(x,y,ofMethod); - xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi - yi=(int)(y); if (y<0) yi--; - }//switch - }//if - - //some variables needed from here on - int xii,yii; //x any y integer indexes for loops - float kernel, kernelyc; //kernel cache - float kernelx[12], kernely[4]; //precalculated kernel values - float rr,gg,bb,aa; //accumulated color values - //calculate multiplication factors for all pixels - int i; - switch (inMethod) { - case IM_BICUBIC: - for (i=0; i<4; i++) { - kernelx[i]=KernelCubic((float)(xi+i-1-x)); - kernely[i]=KernelCubic((float)(yi+i-1-y)); - }//for i - break; - case IM_BICUBIC2: - for (i=0; i<4; i++) { - kernelx[i]=KernelGeneralizedCubic((float)(xi+i-1-x), -0.5); - kernely[i]=KernelGeneralizedCubic((float)(yi+i-1-y), -0.5); - }//for i - break; - case IM_BSPLINE: - for (i=0; i<4; i++) { - kernelx[i]=KernelBSpline((float)(xi+i-1-x)); - kernely[i]=KernelBSpline((float)(yi+i-1-y)); - }//for i - break; - case IM_BOX: - for (i=0; i<4; i++) { - kernelx[i]=KernelBox((float)(xi+i-1-x)); - kernely[i]=KernelBox((float)(yi+i-1-y)); - }//for i - break; - case IM_HERMITE: - for (i=0; i<4; i++) { - kernelx[i]=KernelHermite((float)(xi+i-1-x)); - kernely[i]=KernelHermite((float)(yi+i-1-y)); - }//for i - break; - case IM_HAMMING: - for (i=0; i<4; i++) { - kernelx[i]=KernelHamming((float)(xi+i-1-x)); - kernely[i]=KernelHamming((float)(yi+i-1-y)); - }//for i - break; - case IM_SINC: - for (i=0; i<4; i++) { - kernelx[i]=KernelSinc((float)(xi+i-1-x)); - kernely[i]=KernelSinc((float)(yi+i-1-y)); - }//for i - break; - case IM_BLACKMAN: - for (i=0; i<4; i++) { - kernelx[i]=KernelBlackman((float)(xi+i-1-x)); - kernely[i]=KernelBlackman((float)(yi+i-1-y)); - }//for i - break; - case IM_BESSEL: - for (i=0; i<4; i++) { - kernelx[i]=KernelBessel((float)(xi+i-1-x)); - kernely[i]=KernelBessel((float)(yi+i-1-y)); - }//for i - break; - case IM_GAUSSIAN: - for (i=0; i<4; i++) { - kernelx[i]=KernelGaussian((float)(xi+i-1-x)); - kernely[i]=KernelGaussian((float)(yi+i-1-y)); - }//for i - break; - case IM_QUADRATIC: - for (i=0; i<4; i++) { - kernelx[i]=KernelQuadratic((float)(xi+i-1-x)); - kernely[i]=KernelQuadratic((float)(yi+i-1-y)); - }//for i - break; - case IM_MITCHELL: - for (i=0; i<4; i++) { - kernelx[i]=KernelMitchell((float)(xi+i-1-x)); - kernely[i]=KernelMitchell((float)(yi+i-1-y)); - }//for i - break; - case IM_CATROM: - for (i=0; i<4; i++) { - kernelx[i]=KernelCatrom((float)(xi+i-1-x)); - kernely[i]=KernelCatrom((float)(yi+i-1-y)); - }//for i - break; - case IM_HANNING: - for (i=0; i<4; i++) { - kernelx[i]=KernelHanning((float)(xi+i-1-x)); - kernely[i]=KernelHanning((float)(yi+i-1-y)); - }//for i - break; - case IM_POWER: - for (i=0; i<4; i++) { - kernelx[i]=KernelPower((float)(xi+i-1-x)); - kernely[i]=KernelPower((float)(yi+i-1-y)); - }//for i - break; - }//switch - rr=gg=bb=aa=0; - if (((xi+2)=1 && ((yi+2)=1) && !IsIndexed()) { - //optimized interpolation (faster pixel reads) for RGB24 images with all pixels inside bounds - BYTE *pxptr, *pxptra; - for (yii=yi-1; yii255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr; - if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg; - if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb; -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) { - if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa; - } else -#endif - { //Alpha not supported or no alpha at all - color.rgbReserved = 0; - } - return color; - case IM_LANCZOS: - //lanczos window (16*16) sinc interpolation - if (((xi+6)<0) || ((xi-5)>=head.biWidth) || ((yi+6)<0) || ((yi-5)>=head.biHeight)) { - //all points are outside bounds - switch (ofMethod) { - case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND: - //we don't need to interpolate anything with all points outside in this case - return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor); - break; - default: - //recalculate coordinates and use faster method later on - OverflowCoordinates(x,y,ofMethod); - xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi - yi=(int)(y); if (y<0) yi--; - }//switch - }//if - - for (xii=xi-5; xii=0) && ((yi+6)=0) && !IsIndexed()) { - //optimized interpolation (faster pixel reads) for RGB24 images with all pixels inside bounds - BYTE *pxptr, *pxptra; - for (yii=yi-5; yii255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr; - if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg; - if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb; -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) { - if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa; - } else -#endif - { //Alpha not supported or no alpha at all - color.rgbReserved = 0; - } - return color; - }//switch -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Helper function for GetAreaColorInterpolated. - * Adds 'surf' portion of image pixel with color 'color' to (rr,gg,bb,aa). - */ -void CxImage::AddAveragingCont(RGBQUAD const &color, float const surf, float &rr, float &gg, float &bb, float &aa) -{ - rr+=color.rgbRed*surf; - gg+=color.rgbGreen*surf; - bb+=color.rgbBlue*surf; -#if CXIMAGE_SUPPORT_ALPHA - aa+=color.rgbReserved*surf; -#endif -} -//////////////////////////////////////////////////////////////////////////////// -/** - * This method is similar to GetPixelColorInterpolated, but this method also properly handles - * subsampling. - * If you need to sample original image with interval of more than 1 pixel (as when shrinking an image), - * you should use this method instead of GetPixelColorInterpolated or aliasing will occur. - * When area width and height are both less than pixel, this method gets pixel color by interpolating - * color of frame center with selected (inMethod) interpolation by calling GetPixelColorInterpolated. - * If width and height are more than 1, method calculates color by averaging color of pixels within area. - * Interpolation method is not used in this case. Pixel color is interpolated by averaging instead. - * If only one of both is more than 1, method uses combination of interpolation and averaging. - * Chosen interpolation method is used, but since it is averaged later on, there is little difference - * between IM_BILINEAR (perhaps best for this case) and better methods. IM_NEAREST_NEIGHBOUR again - * leads to aliasing artifacts. - * This method is a bit slower than GetPixelColorInterpolated and when aliasing is not a problem, you should - * simply use the later. - * - * \param xc, yc - center of (rectangular) area - * \param w, h - width and height of area - * \param inMethod - interpolation method that is used, when interpolation is used (see above) - * \param ofMethod - overflow method used when retrieving individual pixel colors - * \param rplColor - replacement colour to use, in OM_COLOR - * - * \author ***bd*** 2.2004 - */ -RGBQUAD CxImage::GetAreaColorInterpolated( - float const xc, float const yc, float const w, float const h, - InterpolationMethod const inMethod, - OverflowMethod const ofMethod, - RGBQUAD* const rplColor) -{ - RGBQUAD color; //calculated colour - - if (h<=1 && w<=1) { - //both width and height are less than one... we will use interpolation of center point - return GetPixelColorInterpolated(xc, yc, inMethod, ofMethod, rplColor); - } else { - //area is wider and/or taller than one pixel: - CxRect2 area(xc-w/2.0f, yc-h/2.0f, xc+w/2.0f, yc+h/2.0f); //area - int xi1=(int)(area.botLeft.x+0.49999999f); //low x - int yi1=(int)(area.botLeft.y+0.49999999f); //low y - - - int xi2=(int)(area.topRight.x+0.5f); //top x - int yi2=(int)(area.topRight.y+0.5f); //top y (for loops) - - float rr,gg,bb,aa; //red, green, blue and alpha components - rr=gg=bb=aa=0; - int x,y; //loop counters - float s=0; //surface of all pixels - float cps; //surface of current crosssection - if (h>1 && w>1) { - //width and height of area are greater than one pixel, so we can employ "ordinary" averaging - CxRect2 intBL, intTR; //bottom left and top right intersection - intBL=area.CrossSection(CxRect2(((float)xi1)-0.5f, ((float)yi1)-0.5f, ((float)xi1)+0.5f, ((float)yi1)+0.5f)); - intTR=area.CrossSection(CxRect2(((float)xi2)-0.5f, ((float)yi2)-0.5f, ((float)xi2)+0.5f, ((float)yi2)+0.5f)); - float wBL, wTR, hBL, hTR; - wBL=intBL.Width(); //width of bottom left pixel-area intersection - hBL=intBL.Height(); //height of bottom left... - wTR=intTR.Width(); //width of top right... - hTR=intTR.Height(); //height of top right... - - AddAveragingCont(GetPixelColorWithOverflow(xi1,yi1,ofMethod,rplColor), wBL*hBL, rr, gg, bb, aa); //bottom left pixel - AddAveragingCont(GetPixelColorWithOverflow(xi2,yi1,ofMethod,rplColor), wTR*hBL, rr, gg, bb, aa); //bottom right pixel - AddAveragingCont(GetPixelColorWithOverflow(xi1,yi2,ofMethod,rplColor), wBL*hTR, rr, gg, bb, aa); //top left pixel - AddAveragingCont(GetPixelColorWithOverflow(xi2,yi2,ofMethod,rplColor), wTR*hTR, rr, gg, bb, aa); //top right pixel - //bottom and top row - for (x=xi1+1; x255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr; - if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg; - if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb; -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) { - if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa; - }//if -#endif - }//if - return color; -} - -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBSpline(const float x) -{ - if (x>2.0f) return 0.0f; - // thanks to Kristian Kratzenstein - float a, b, c, d; - float xm1 = x - 1.0f; // Was calculatet anyway cause the "if((x-1.0f) < 0)" - float xp1 = x + 1.0f; - float xp2 = x + 2.0f; - - if ((xp2) <= 0.0f) a = 0.0f; else a = xp2*xp2*xp2; // Only float, not float -> double -> float - if ((xp1) <= 0.0f) b = 0.0f; else b = xp1*xp1*xp1; - if (x <= 0) c = 0.0f; else c = x*x*x; - if ((xm1) <= 0.0f) d = 0.0f; else d = xm1*xm1*xm1; - - return (0.16666666666666666667f * (a - (4.0f * b) + (6.0f * c) - (4.0f * d))); - - /* equivalent - if (x < -2.0) - return(0.0f); - if (x < -1.0) - return((2.0f+x)*(2.0f+x)*(2.0f+x)*0.16666666666666666667f); - if (x < 0.0) - return((4.0f+x*x*(-6.0f-3.0f*x))*0.16666666666666666667f); - if (x < 1.0) - return((4.0f+x*x*(-6.0f+3.0f*x))*0.16666666666666666667f); - if (x < 2.0) - return((2.0f-x)*(2.0f-x)*(2.0f-x)*0.16666666666666666667f); - return(0.0f); - */ -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Bilinear interpolation kernel: - \verbatim - / - | 1-t , if 0 <= t <= 1 - h(t) = | t+1 , if -1 <= t < 0 - | 0 , otherwise - \ - \endverbatim - * ***bd*** 2.2004 - */ -float CxImage::KernelLinear(const float t) -{ -// if (0<=t && t<=1) return 1-t; -// if (-1<=t && t<0) return 1+t; -// return 0; - - // - if (t < -1.0f) - return 0.0f; - if (t < 0.0f) - return 1.0f+t; - if (t < 1.0f) - return 1.0f-t; - return 0.0f; -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Bicubic interpolation kernel (a=-1): - \verbatim - / - | 1-2|t|**2+|t|**3 , if |t| < 1 - h(t) = | 4-8|t|+5|t|**2-|t|**3 , if 1<=|t|<2 - | 0 , otherwise - \ - \endverbatim - * ***bd*** 2.2004 - */ -float CxImage::KernelCubic(const float t) -{ - float abs_t = (float)fabs(t); - float abs_t_sq = abs_t * abs_t; - if (abs_t<1) return 1-2*abs_t_sq+abs_t_sq*abs_t; - if (abs_t<2) return 4 - 8*abs_t +5*abs_t_sq - abs_t_sq*abs_t; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Bicubic kernel (for a=-1 it is the same as BicubicKernel): - \verbatim - / - | (a+2)|t|**3 - (a+3)|t|**2 + 1 , |t| <= 1 - h(t) = | a|t|**3 - 5a|t|**2 + 8a|t| - 4a , 1 < |t| <= 2 - | 0 , otherwise - \ - \endverbatim - * Often used values for a are -1 and -1/2. - */ -float CxImage::KernelGeneralizedCubic(const float t, const float a) -{ - float abs_t = (float)fabs(t); - float abs_t_sq = abs_t * abs_t; - if (abs_t<1) return (a+2)*abs_t_sq*abs_t - (a+3)*abs_t_sq + 1; - if (abs_t<2) return a*abs_t_sq*abs_t - 5*a*abs_t_sq + 8*a*abs_t - 4*a; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Lanczos windowed sinc interpolation kernel with radius r. - \verbatim - / - h(t) = | sinc(t)*sinc(t/r) , if |t| r) return 0; - if (t==0) return 1; - float pit=PI*t; - float pitd=pit/r; - return (float)((sin(pit)/pit) * (sin(pitd)/pitd)); -} - -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBox(const float x) -{ - if (x < -0.5f) - return 0.0f; - if (x < 0.5f) - return 1.0f; - return 0.0f; -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelHermite(const float x) -{ - if (x < -1.0f) - return 0.0f; - if (x < 0.0f) - return (-2.0f*x-3.0f)*x*x+1.0f; - if (x < 1.0f) - return (2.0f*x-3.0f)*x*x+1.0f; - return 0.0f; -// if (fabs(x)>1) return 0.0f; -// return(0.5f+0.5f*(float)cos(PI*x)); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelHanning(const float x) -{ - if (fabs(x)>1) return 0.0f; - return (0.5f+0.5f*(float)cos(PI*x))*((float)sin(PI*x)/(PI*x)); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelHamming(const float x) -{ - if (x < -1.0f) - return 0.0f; - if (x < 0.0f) - return 0.92f*(-2.0f*x-3.0f)*x*x+1.0f; - if (x < 1.0f) - return 0.92f*(2.0f*x-3.0f)*x*x+1.0f; - return 0.0f; -// if (fabs(x)>1) return 0.0f; -// return(0.54f+0.46f*(float)cos(PI*x)); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelSinc(const float x) -{ - if (x == 0.0) - return(1.0); - return((float)sin(PI*x)/(PI*x)); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBlackman(const float x) -{ - //if (fabs(x)>1) return 0.0f; - return (0.42f+0.5f*(float)cos(PI*x)+0.08f*(float)cos(2.0f*PI*x)); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBessel_J1(const float x) -{ - double p, q; - - register long i; - - static const double - Pone[] = - { - 0.581199354001606143928050809e+21, - -0.6672106568924916298020941484e+20, - 0.2316433580634002297931815435e+19, - -0.3588817569910106050743641413e+17, - 0.2908795263834775409737601689e+15, - -0.1322983480332126453125473247e+13, - 0.3413234182301700539091292655e+10, - -0.4695753530642995859767162166e+7, - 0.270112271089232341485679099e+4 - }, - Qone[] = - { - 0.11623987080032122878585294e+22, - 0.1185770712190320999837113348e+20, - 0.6092061398917521746105196863e+17, - 0.2081661221307607351240184229e+15, - 0.5243710262167649715406728642e+12, - 0.1013863514358673989967045588e+10, - 0.1501793594998585505921097578e+7, - 0.1606931573481487801970916749e+4, - 0.1e+1 - }; - - p = Pone[8]; - q = Qone[8]; - for (i=7; i >= 0; i--) - { - p = p*x*x+Pone[i]; - q = q*x*x+Qone[i]; - } - return (float)(p/q); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBessel_P1(const float x) -{ - double p, q; - - register long i; - - static const double - Pone[] = - { - 0.352246649133679798341724373e+5, - 0.62758845247161281269005675e+5, - 0.313539631109159574238669888e+5, - 0.49854832060594338434500455e+4, - 0.2111529182853962382105718e+3, - 0.12571716929145341558495e+1 - }, - Qone[] = - { - 0.352246649133679798068390431e+5, - 0.626943469593560511888833731e+5, - 0.312404063819041039923015703e+5, - 0.4930396490181088979386097e+4, - 0.2030775189134759322293574e+3, - 0.1e+1 - }; - - p = Pone[5]; - q = Qone[5]; - for (i=4; i >= 0; i--) - { - p = p*(8.0/x)*(8.0/x)+Pone[i]; - q = q*(8.0/x)*(8.0/x)+Qone[i]; - } - return (float)(p/q); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBessel_Q1(const float x) -{ - double p, q; - - register long i; - - static const double - Pone[] = - { - 0.3511751914303552822533318e+3, - 0.7210391804904475039280863e+3, - 0.4259873011654442389886993e+3, - 0.831898957673850827325226e+2, - 0.45681716295512267064405e+1, - 0.3532840052740123642735e-1 - }, - Qone[] = - { - 0.74917374171809127714519505e+4, - 0.154141773392650970499848051e+5, - 0.91522317015169922705904727e+4, - 0.18111867005523513506724158e+4, - 0.1038187585462133728776636e+3, - 0.1e+1 - }; - - p = Pone[5]; - q = Qone[5]; - for (i=4; i >= 0; i--) - { - p = p*(8.0/x)*(8.0/x)+Pone[i]; - q = q*(8.0/x)*(8.0/x)+Qone[i]; - } - return (float)(p/q); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBessel_Order1(float x) -{ - float p, q; - - if (x == 0.0) - return (0.0f); - p = x; - if (x < 0.0) - x=(-x); - if (x < 8.0) - return(p*KernelBessel_J1(x)); - q = (float)sqrt(2.0f/(PI*x))*(float)(KernelBessel_P1(x)*(1.0f/sqrt(2.0f)*(sin(x)-cos(x)))-8.0f/x*KernelBessel_Q1(x)* - (-1.0f/sqrt(2.0f)*(sin(x)+cos(x)))); - if (p < 0.0f) - q = (-q); - return (q); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelBessel(const float x) -{ - if (x == 0.0f) - return(PI/4.0f); - return(KernelBessel_Order1(PI*x)/(2.0f*x)); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelGaussian(const float x) -{ - return (float)(exp(-2.0f*x*x)*0.79788456080287f/*sqrt(2.0f/PI)*/); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelQuadratic(const float x) -{ - if (x < -1.5f) - return(0.0f); - if (x < -0.5f) - return(0.5f*(x+1.5f)*(x+1.5f)); - if (x < 0.5f) - return(0.75f-x*x); - if (x < 1.5f) - return(0.5f*(x-1.5f)*(x-1.5f)); - return(0.0f); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelMitchell(const float x) -{ -#define KM_B (1.0f/3.0f) -#define KM_C (1.0f/3.0f) -#define KM_P0 (( 6.0f - 2.0f * KM_B ) / 6.0f) -#define KM_P2 ((-18.0f + 12.0f * KM_B + 6.0f * KM_C) / 6.0f) -#define KM_P3 (( 12.0f - 9.0f * KM_B - 6.0f * KM_C) / 6.0f) -#define KM_Q0 (( 8.0f * KM_B + 24.0f * KM_C) / 6.0f) -#define KM_Q1 ((-12.0f * KM_B - 48.0f * KM_C) / 6.0f) -#define KM_Q2 (( 6.0f * KM_B + 30.0f * KM_C) / 6.0f) -#define KM_Q3 (( -1.0f * KM_B - 6.0f * KM_C) / 6.0f) - - if (x < -2.0) - return(0.0f); - if (x < -1.0) - return(KM_Q0-x*(KM_Q1-x*(KM_Q2-x*KM_Q3))); - if (x < 0.0f) - return(KM_P0+x*x*(KM_P2-x*KM_P3)); - if (x < 1.0f) - return(KM_P0+x*x*(KM_P2+x*KM_P3)); - if (x < 2.0f) - return(KM_Q0+x*(KM_Q1+x*(KM_Q2+x*KM_Q3))); - return(0.0f); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelCatrom(const float x) -{ - if (x < -2.0) - return(0.0f); - if (x < -1.0) - return(0.5f*(4.0f+x*(8.0f+x*(5.0f+x)))); - if (x < 0.0) - return(0.5f*(2.0f+x*x*(-5.0f-3.0f*x))); - if (x < 1.0) - return(0.5f*(2.0f+x*x*(-5.0f+3.0f*x))); - if (x < 2.0) - return(0.5f*(4.0f+x*(-8.0f+x*(5.0f-x)))); - return(0.0f); -} -//////////////////////////////////////////////////////////////////////////////// -float CxImage::KernelPower(const float x, const float a) -{ - if (fabs(x)>1) return 0.0f; - return (1.0f - (float)fabs(pow(x,a))); -} -//////////////////////////////////////////////////////////////////////////////// - -#endif +// xImaInt.cpp : interpolation functions +/* 02/2004 - Branko Brevensek + * CxImage version 6.0.0 02/Feb/2008 - Davide Pizzolato - www.xdp.it + */ + +#include "ximage.h" +#include "ximath.h" + +#if CXIMAGE_SUPPORT_INTERPOLATION + +//////////////////////////////////////////////////////////////////////////////// +/** + * Recalculates coordinates according to specified overflow method. + * If pixel (x,y) lies within image, nothing changes. + * + * \param x, y - coordinates of pixel + * \param ofMethod - overflow method + * + * \return x, y - new coordinates (pixel (x,y) now lies inside image) + * + * \author ***bd*** 2.2004 + */ +void CxImage::OverflowCoordinates(long &x, long &y, OverflowMethod const ofMethod) +{ + if (IsInside(x,y)) return; //if pixel is within bounds, no change + switch (ofMethod) { + case OM_REPEAT: + //clip coordinates + x=max(x,0); x=min(x, head.biWidth-1); + y=max(y,0); y=min(y, head.biHeight-1); + break; + case OM_WRAP: + //wrap coordinates + x = x % head.biWidth; + y = y % head.biHeight; + if (x<0) x = head.biWidth + x; + if (y<0) y = head.biHeight + y; + break; + case OM_MIRROR: + //mirror pixels near border + if (x<0) x=((-x) % head.biWidth); + else if (x>=head.biWidth) x=head.biWidth-(x % head.biWidth + 1); + if (y<0) y=((-y) % head.biHeight); + else if (y>=head.biHeight) y=head.biHeight-(y % head.biHeight + 1); + break; + default: + return; + }//switch +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * See OverflowCoordinates for integer version + * \author ***bd*** 2.2004 + */ +void CxImage::OverflowCoordinates(float &x, float &y, OverflowMethod const ofMethod) +{ + if (x>=0 && x=0 && y=head.biWidth) x=head.biWidth-((float)fmod(x, (float) head.biWidth) + 1); + if (y<0) y=(float)fmod(-y, (float) head.biHeight); + else if (y>=head.biHeight) y=head.biHeight-((float)fmod(y, (float) head.biHeight) + 1); + break; + default: + return; + }//switch +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Method return pixel color. Different methods are implemented for out of bounds pixels. + * If an image has alpha channel, alpha value is returned in .RGBReserved. + * + * \param x,y : pixel coordinates + * \param ofMethod : out-of-bounds method: + * - OF_WRAP - wrap over to pixels on other side of the image + * - OF_REPEAT - repeat last pixel on the edge + * - OF_COLOR - return input value of color + * - OF_BACKGROUND - return background color (if not set, return input color) + * - OF_TRANSPARENT - return transparent pixel + * + * \param rplColor : input color (returned for out-of-bound coordinates in OF_COLOR mode and if other mode is not applicable) + * + * \return color : color of pixel + * \author ***bd*** 2.2004 + */ +RGBQUAD CxImage::GetPixelColorWithOverflow(long x, long y, OverflowMethod const ofMethod, RGBQUAD* const rplColor) +{ + RGBQUAD color; //color to return + if ((!IsInside(x,y)) || pDib==NULL) { //is pixel within bouns?: + //pixel is out of bounds or no DIB + if (rplColor!=NULL) + color=*rplColor; + else { + color.rgbRed=color.rgbGreen=color.rgbBlue=255; color.rgbReserved=0; //default replacement colour: white transparent + }//if + if (pDib==NULL) return color; + //pixel is out of bounds: + switch (ofMethod) { + case OM_TRANSPARENT: +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) { + //alpha transparency is supported and image has alpha layer + color.rgbReserved=0; + } else { +#endif //CXIMAGE_SUPPORT_ALPHA + //no alpha transparency + if (GetTransIndex()>=0) { + color=GetTransColor(); //single color transparency enabled (return transparent color) + }//if +#if CXIMAGE_SUPPORT_ALPHA + }//if +#endif //CXIMAGE_SUPPORT_ALPHA + return color; + case OM_BACKGROUND: + //return background color (if it exists, otherwise input value) + if (info.nBkgndIndex >= 0) { + if (head.biBitCount<24) color = GetPaletteColor((BYTE)info.nBkgndIndex); + else color = info.nBkgndColor; + }//if + return color; + case OM_REPEAT: + case OM_WRAP: + case OM_MIRROR: + OverflowCoordinates(x,y,ofMethod); + break; + default: + //simply return replacement color (OM_COLOR and others) + return color; + }//switch + }//if + //just return specified pixel (it's within bounds) + return BlindGetPixelColor(x,y); +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * This method reconstructs image according to chosen interpolation method and then returns pixel (x,y). + * (x,y) can lie between actual image pixels. If (x,y) lies outside of image, method returns value + * according to overflow method. + * This method is very useful for geometrical image transformations, where destination pixel + * can often assume color value lying between source pixels. + * + * \param (x,y) - coordinates of pixel to return + * GPCI method recreates "analogue" image back from digital data, so x and y + * are float values and color value of point (1.1,1) will generally not be same + * as (1,1). Center of first pixel is at (0,0) and center of pixel right to it is (1,0). + * (0.5,0) is half way between these two pixels. + * \param inMethod - interpolation (reconstruction) method (kernel) to use: + * - IM_NEAREST_NEIGHBOUR - returns colour of nearest lying pixel (causes stairy look of + * processed images) + * - IM_BILINEAR - interpolates colour from four neighbouring pixels (softens image a bit) + * - IM_BICUBIC - interpolates from 16 neighbouring pixels (can produce "halo" artifacts) + * - IM_BICUBIC2 - interpolates from 16 neighbouring pixels (perhaps a bit less halo artifacts + than IM_BICUBIC) + * - IM_BSPLINE - interpolates from 16 neighbouring pixels (softens image, washes colours) + * (As far as I know, image should be prefiltered for this method to give + * good results... some other time :) ) + * This method uses bicubic interpolation kernel from CXImage 5.99a and older + * versions. + * - IM_LANCZOS - interpolates from 12*12 pixels (slow, ringing artifacts) + * + * \param ofMethod - overflow method (see comments at GetPixelColorWithOverflow) + * \param rplColor - pointer to color used for out of borders pixels in OM_COLOR mode + * (and other modes if colour can't calculated in a specified way) + * + * \return interpolated color value (including interpolated alpha value, if image has alpha layer) + * + * \author ***bd*** 2.2004 + */ +RGBQUAD CxImage::GetPixelColorInterpolated( + float x,float y, + InterpolationMethod const inMethod, + OverflowMethod const ofMethod, + RGBQUAD* const rplColor) +{ + //calculate nearest pixel + int xi=(int)(x); if (x<0) xi--; //these replace (incredibly slow) floor (Visual c++ 2003, AMD Athlon) + int yi=(int)(y); if (y<0) yi--; + RGBQUAD color; //calculated colour + + switch (inMethod) { + case IM_NEAREST_NEIGHBOUR: + return GetPixelColorWithOverflow((long)(x+0.5f), (long)(y+0.5f), ofMethod, rplColor); + default: { + //IM_BILINEAR: bilinear interpolation + if (xi<-1 || xi>=head.biWidth || yi<-1 || yi>=head.biHeight) { //all 4 points are outside bounds?: + switch (ofMethod) { + case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND: + //we don't need to interpolate anything with all points outside in this case + return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor); + default: + //recalculate coordinates and use faster method later on + OverflowCoordinates(x,y,ofMethod); + xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi + yi=(int)(y); if (y<0) yi--; + }//switch + }//if + //get four neighbouring pixels + if ((xi+1)=0 && (yi+1)=0 && head.biClrUsed==0) { + //all pixels are inside RGB24 image... optimize reading (and use fixed point arithmetic) + WORD wt1=(WORD)((x-xi)*256.0f), wt2=(WORD)((y-yi)*256.0f); + WORD wd=wt1*wt2>>8; + WORD wb=wt1-wd; + WORD wc=wt2-wd; + WORD wa=256-wt1-wc; + WORD wrr,wgg,wbb; + BYTE *pxptr=(BYTE*)info.pImage+yi*info.dwEffWidth+xi*3; + wbb=wa*(*pxptr++); wgg=wa*(*pxptr++); wrr=wa*(*pxptr++); + wbb+=wb*(*pxptr++); wgg+=wb*(*pxptr++); wrr+=wb*(*pxptr); + pxptr+=(info.dwEffWidth-5); //move to next row + wbb+=wc*(*pxptr++); wgg+=wc*(*pxptr++); wrr+=wc*(*pxptr++); + wbb+=wd*(*pxptr++); wgg+=wd*(*pxptr++); wrr+=wd*(*pxptr); + color.rgbRed=(BYTE) (wrr>>8); color.rgbGreen=(BYTE) (wgg>>8); color.rgbBlue=(BYTE) (wbb>>8); +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha) { + WORD waa; + //image has alpha layer... we have to do the same for alpha data + pxptr=AlphaGetPointer(xi,yi); //pointer to first byte + waa=wa*(*pxptr++); waa+=wb*(*pxptr); //first two pixels + pxptr+=(head.biWidth-1); //move to next row + waa+=wc*(*pxptr++); waa+=wd*(*pxptr); //and second row pixels + color.rgbReserved=(BYTE) (waa>>8); + } else +#endif + { //Alpha not supported or no alpha at all + color.rgbReserved = 0; + } + return color; + } else { + //default (slower) way to get pixels (not RGB24 or some pixels out of borders) + float t1=x-xi, t2=y-yi; + float d=t1*t2; + float b=t1-d; + float c=t2-d; + float a=1-t1-c; + RGBQUAD rgb11,rgb21,rgb12,rgb22; + rgb11=GetPixelColorWithOverflow(xi, yi, ofMethod, rplColor); + rgb21=GetPixelColorWithOverflow(xi+1, yi, ofMethod, rplColor); + rgb12=GetPixelColorWithOverflow(xi, yi+1, ofMethod, rplColor); + rgb22=GetPixelColorWithOverflow(xi+1, yi+1, ofMethod, rplColor); + //calculate linear interpolation + color.rgbRed=(BYTE) (a*rgb11.rgbRed+b*rgb21.rgbRed+c*rgb12.rgbRed+d*rgb22.rgbRed); + color.rgbGreen=(BYTE) (a*rgb11.rgbGreen+b*rgb21.rgbGreen+c*rgb12.rgbGreen+d*rgb22.rgbGreen); + color.rgbBlue=(BYTE) (a*rgb11.rgbBlue+b*rgb21.rgbBlue+c*rgb12.rgbBlue+d*rgb22.rgbBlue); +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) + color.rgbReserved=(BYTE) (a*rgb11.rgbReserved+b*rgb21.rgbReserved+c*rgb12.rgbReserved+d*rgb22.rgbReserved); + else +#endif + { //Alpha not supported or no alpha at all + color.rgbReserved = 0; + } + return color; + }//if + }//default + case IM_BICUBIC: + case IM_BICUBIC2: + case IM_BSPLINE: + case IM_BOX: + case IM_HERMITE: + case IM_HAMMING: + case IM_SINC: + case IM_BLACKMAN: + case IM_BESSEL: + case IM_GAUSSIAN: + case IM_QUADRATIC: + case IM_MITCHELL: + case IM_CATROM: + case IM_HANNING: + case IM_POWER: + //bicubic interpolation(s) + if (((xi+2)<0) || ((xi-1)>=head.biWidth) || ((yi+2)<0) || ((yi-1)>=head.biHeight)) { //all points are outside bounds?: + switch (ofMethod) { + case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND: + //we don't need to interpolate anything with all points outside in this case + return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor); + break; + default: + //recalculate coordinates and use faster method later on + OverflowCoordinates(x,y,ofMethod); + xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi + yi=(int)(y); if (y<0) yi--; + }//switch + }//if + + //some variables needed from here on + int xii,yii; //x any y integer indexes for loops + float kernel, kernelyc; //kernel cache + float kernelx[12], kernely[4]; //precalculated kernel values + float rr,gg,bb,aa; //accumulated color values + //calculate multiplication factors for all pixels + int i; + switch (inMethod) { + case IM_BICUBIC: + for (i=0; i<4; i++) { + kernelx[i]=KernelCubic((float)(xi+i-1-x)); + kernely[i]=KernelCubic((float)(yi+i-1-y)); + }//for i + break; + case IM_BICUBIC2: + for (i=0; i<4; i++) { + kernelx[i]=KernelGeneralizedCubic((float)(xi+i-1-x), -0.5); + kernely[i]=KernelGeneralizedCubic((float)(yi+i-1-y), -0.5); + }//for i + break; + case IM_BSPLINE: + for (i=0; i<4; i++) { + kernelx[i]=KernelBSpline((float)(xi+i-1-x)); + kernely[i]=KernelBSpline((float)(yi+i-1-y)); + }//for i + break; + case IM_BOX: + for (i=0; i<4; i++) { + kernelx[i]=KernelBox((float)(xi+i-1-x)); + kernely[i]=KernelBox((float)(yi+i-1-y)); + }//for i + break; + case IM_HERMITE: + for (i=0; i<4; i++) { + kernelx[i]=KernelHermite((float)(xi+i-1-x)); + kernely[i]=KernelHermite((float)(yi+i-1-y)); + }//for i + break; + case IM_HAMMING: + for (i=0; i<4; i++) { + kernelx[i]=KernelHamming((float)(xi+i-1-x)); + kernely[i]=KernelHamming((float)(yi+i-1-y)); + }//for i + break; + case IM_SINC: + for (i=0; i<4; i++) { + kernelx[i]=KernelSinc((float)(xi+i-1-x)); + kernely[i]=KernelSinc((float)(yi+i-1-y)); + }//for i + break; + case IM_BLACKMAN: + for (i=0; i<4; i++) { + kernelx[i]=KernelBlackman((float)(xi+i-1-x)); + kernely[i]=KernelBlackman((float)(yi+i-1-y)); + }//for i + break; + case IM_BESSEL: + for (i=0; i<4; i++) { + kernelx[i]=KernelBessel((float)(xi+i-1-x)); + kernely[i]=KernelBessel((float)(yi+i-1-y)); + }//for i + break; + case IM_GAUSSIAN: + for (i=0; i<4; i++) { + kernelx[i]=KernelGaussian((float)(xi+i-1-x)); + kernely[i]=KernelGaussian((float)(yi+i-1-y)); + }//for i + break; + case IM_QUADRATIC: + for (i=0; i<4; i++) { + kernelx[i]=KernelQuadratic((float)(xi+i-1-x)); + kernely[i]=KernelQuadratic((float)(yi+i-1-y)); + }//for i + break; + case IM_MITCHELL: + for (i=0; i<4; i++) { + kernelx[i]=KernelMitchell((float)(xi+i-1-x)); + kernely[i]=KernelMitchell((float)(yi+i-1-y)); + }//for i + break; + case IM_CATROM: + for (i=0; i<4; i++) { + kernelx[i]=KernelCatrom((float)(xi+i-1-x)); + kernely[i]=KernelCatrom((float)(yi+i-1-y)); + }//for i + break; + case IM_HANNING: + for (i=0; i<4; i++) { + kernelx[i]=KernelHanning((float)(xi+i-1-x)); + kernely[i]=KernelHanning((float)(yi+i-1-y)); + }//for i + break; + case IM_POWER: + for (i=0; i<4; i++) { + kernelx[i]=KernelPower((float)(xi+i-1-x)); + kernely[i]=KernelPower((float)(yi+i-1-y)); + }//for i + break; + }//switch + rr=gg=bb=aa=0; + if (((xi+2)=1 && ((yi+2)=1) && !IsIndexed()) { + //optimized interpolation (faster pixel reads) for RGB24 images with all pixels inside bounds + BYTE *pxptr, *pxptra; + for (yii=yi-1; yii255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr; + if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg; + if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb; +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) { + if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa; + } else +#endif + { //Alpha not supported or no alpha at all + color.rgbReserved = 0; + } + return color; + case IM_LANCZOS: + //lanczos window (16*16) sinc interpolation + if (((xi+6)<0) || ((xi-5)>=head.biWidth) || ((yi+6)<0) || ((yi-5)>=head.biHeight)) { + //all points are outside bounds + switch (ofMethod) { + case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND: + //we don't need to interpolate anything with all points outside in this case + return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor); + break; + default: + //recalculate coordinates and use faster method later on + OverflowCoordinates(x,y,ofMethod); + xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi + yi=(int)(y); if (y<0) yi--; + }//switch + }//if + + for (xii=xi-5; xii=0) && ((yi+6)=0) && !IsIndexed()) { + //optimized interpolation (faster pixel reads) for RGB24 images with all pixels inside bounds + BYTE *pxptr, *pxptra; + for (yii=yi-5; yii255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr; + if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg; + if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb; +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) { + if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa; + } else +#endif + { //Alpha not supported or no alpha at all + color.rgbReserved = 0; + } + return color; + }//switch +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Helper function for GetAreaColorInterpolated. + * Adds 'surf' portion of image pixel with color 'color' to (rr,gg,bb,aa). + */ +void CxImage::AddAveragingCont(RGBQUAD const &color, float const surf, float &rr, float &gg, float &bb, float &aa) +{ + rr+=color.rgbRed*surf; + gg+=color.rgbGreen*surf; + bb+=color.rgbBlue*surf; +#if CXIMAGE_SUPPORT_ALPHA + aa+=color.rgbReserved*surf; +#endif +} +//////////////////////////////////////////////////////////////////////////////// +/** + * This method is similar to GetPixelColorInterpolated, but this method also properly handles + * subsampling. + * If you need to sample original image with interval of more than 1 pixel (as when shrinking an image), + * you should use this method instead of GetPixelColorInterpolated or aliasing will occur. + * When area width and height are both less than pixel, this method gets pixel color by interpolating + * color of frame center with selected (inMethod) interpolation by calling GetPixelColorInterpolated. + * If width and height are more than 1, method calculates color by averaging color of pixels within area. + * Interpolation method is not used in this case. Pixel color is interpolated by averaging instead. + * If only one of both is more than 1, method uses combination of interpolation and averaging. + * Chosen interpolation method is used, but since it is averaged later on, there is little difference + * between IM_BILINEAR (perhaps best for this case) and better methods. IM_NEAREST_NEIGHBOUR again + * leads to aliasing artifacts. + * This method is a bit slower than GetPixelColorInterpolated and when aliasing is not a problem, you should + * simply use the later. + * + * \param xc, yc - center of (rectangular) area + * \param w, h - width and height of area + * \param inMethod - interpolation method that is used, when interpolation is used (see above) + * \param ofMethod - overflow method used when retrieving individual pixel colors + * \param rplColor - replacement colour to use, in OM_COLOR + * + * \author ***bd*** 2.2004 + */ +RGBQUAD CxImage::GetAreaColorInterpolated( + float const xc, float const yc, float const w, float const h, + InterpolationMethod const inMethod, + OverflowMethod const ofMethod, + RGBQUAD* const rplColor) +{ + RGBQUAD color; //calculated colour + + if (h<=1 && w<=1) { + //both width and height are less than one... we will use interpolation of center point + return GetPixelColorInterpolated(xc, yc, inMethod, ofMethod, rplColor); + } else { + //area is wider and/or taller than one pixel: + CxRect2 area(xc-w/2.0f, yc-h/2.0f, xc+w/2.0f, yc+h/2.0f); //area + int xi1=(int)(area.botLeft.x+0.49999999f); //low x + int yi1=(int)(area.botLeft.y+0.49999999f); //low y + + + int xi2=(int)(area.topRight.x+0.5f); //top x + int yi2=(int)(area.topRight.y+0.5f); //top y (for loops) + + float rr,gg,bb,aa; //red, green, blue and alpha components + rr=gg=bb=aa=0; + int x,y; //loop counters + float s=0; //surface of all pixels + float cps; //surface of current crosssection + if (h>1 && w>1) { + //width and height of area are greater than one pixel, so we can employ "ordinary" averaging + CxRect2 intBL, intTR; //bottom left and top right intersection + intBL=area.CrossSection(CxRect2(((float)xi1)-0.5f, ((float)yi1)-0.5f, ((float)xi1)+0.5f, ((float)yi1)+0.5f)); + intTR=area.CrossSection(CxRect2(((float)xi2)-0.5f, ((float)yi2)-0.5f, ((float)xi2)+0.5f, ((float)yi2)+0.5f)); + float wBL, wTR, hBL, hTR; + wBL=intBL.Width(); //width of bottom left pixel-area intersection + hBL=intBL.Height(); //height of bottom left... + wTR=intTR.Width(); //width of top right... + hTR=intTR.Height(); //height of top right... + + AddAveragingCont(GetPixelColorWithOverflow(xi1,yi1,ofMethod,rplColor), wBL*hBL, rr, gg, bb, aa); //bottom left pixel + AddAveragingCont(GetPixelColorWithOverflow(xi2,yi1,ofMethod,rplColor), wTR*hBL, rr, gg, bb, aa); //bottom right pixel + AddAveragingCont(GetPixelColorWithOverflow(xi1,yi2,ofMethod,rplColor), wBL*hTR, rr, gg, bb, aa); //top left pixel + AddAveragingCont(GetPixelColorWithOverflow(xi2,yi2,ofMethod,rplColor), wTR*hTR, rr, gg, bb, aa); //top right pixel + //bottom and top row + for (x=xi1+1; x255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr; + if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg; + if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb; +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) { + if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa; + }//if +#endif + }//if + return color; +} + +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBSpline(const float x) +{ + if (x>2.0f) return 0.0f; + // thanks to Kristian Kratzenstein + float a, b, c, d; + float xm1 = x - 1.0f; // Was calculatet anyway cause the "if((x-1.0f) < 0)" + float xp1 = x + 1.0f; + float xp2 = x + 2.0f; + + if ((xp2) <= 0.0f) a = 0.0f; else a = xp2*xp2*xp2; // Only float, not float -> double -> float + if ((xp1) <= 0.0f) b = 0.0f; else b = xp1*xp1*xp1; + if (x <= 0) c = 0.0f; else c = x*x*x; + if ((xm1) <= 0.0f) d = 0.0f; else d = xm1*xm1*xm1; + + return (0.16666666666666666667f * (a - (4.0f * b) + (6.0f * c) - (4.0f * d))); + + /* equivalent + if (x < -2.0) + return(0.0f); + if (x < -1.0) + return((2.0f+x)*(2.0f+x)*(2.0f+x)*0.16666666666666666667f); + if (x < 0.0) + return((4.0f+x*x*(-6.0f-3.0f*x))*0.16666666666666666667f); + if (x < 1.0) + return((4.0f+x*x*(-6.0f+3.0f*x))*0.16666666666666666667f); + if (x < 2.0) + return((2.0f-x)*(2.0f-x)*(2.0f-x)*0.16666666666666666667f); + return(0.0f); + */ +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Bilinear interpolation kernel: + \verbatim + / + | 1-t , if 0 <= t <= 1 + h(t) = | t+1 , if -1 <= t < 0 + | 0 , otherwise + \ + \endverbatim + * ***bd*** 2.2004 + */ +float CxImage::KernelLinear(const float t) +{ +// if (0<=t && t<=1) return 1-t; +// if (-1<=t && t<0) return 1+t; +// return 0; + + // + if (t < -1.0f) + return 0.0f; + if (t < 0.0f) + return 1.0f+t; + if (t < 1.0f) + return 1.0f-t; + return 0.0f; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Bicubic interpolation kernel (a=-1): + \verbatim + / + | 1-2|t|**2+|t|**3 , if |t| < 1 + h(t) = | 4-8|t|+5|t|**2-|t|**3 , if 1<=|t|<2 + | 0 , otherwise + \ + \endverbatim + * ***bd*** 2.2004 + */ +float CxImage::KernelCubic(const float t) +{ + float abs_t = (float)fabs(t); + float abs_t_sq = abs_t * abs_t; + if (abs_t<1) return 1-2*abs_t_sq+abs_t_sq*abs_t; + if (abs_t<2) return 4 - 8*abs_t +5*abs_t_sq - abs_t_sq*abs_t; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Bicubic kernel (for a=-1 it is the same as BicubicKernel): + \verbatim + / + | (a+2)|t|**3 - (a+3)|t|**2 + 1 , |t| <= 1 + h(t) = | a|t|**3 - 5a|t|**2 + 8a|t| - 4a , 1 < |t| <= 2 + | 0 , otherwise + \ + \endverbatim + * Often used values for a are -1 and -1/2. + */ +float CxImage::KernelGeneralizedCubic(const float t, const float a) +{ + float abs_t = (float)fabs(t); + float abs_t_sq = abs_t * abs_t; + if (abs_t<1) return (a+2)*abs_t_sq*abs_t - (a+3)*abs_t_sq + 1; + if (abs_t<2) return a*abs_t_sq*abs_t - 5*a*abs_t_sq + 8*a*abs_t - 4*a; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Lanczos windowed sinc interpolation kernel with radius r. + \verbatim + / + h(t) = | sinc(t)*sinc(t/r) , if |t| r) return 0; + if (t==0) return 1; + float pit=PI*t; + float pitd=pit/r; + return (float)((sin(pit)/pit) * (sin(pitd)/pitd)); +} + +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBox(const float x) +{ + if (x < -0.5f) + return 0.0f; + if (x < 0.5f) + return 1.0f; + return 0.0f; +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelHermite(const float x) +{ + if (x < -1.0f) + return 0.0f; + if (x < 0.0f) + return (-2.0f*x-3.0f)*x*x+1.0f; + if (x < 1.0f) + return (2.0f*x-3.0f)*x*x+1.0f; + return 0.0f; +// if (fabs(x)>1) return 0.0f; +// return(0.5f+0.5f*(float)cos(PI*x)); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelHanning(const float x) +{ + if (fabs(x)>1) return 0.0f; + return (0.5f+0.5f*(float)cos(PI*x))*((float)sin(PI*x)/(PI*x)); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelHamming(const float x) +{ + if (x < -1.0f) + return 0.0f; + if (x < 0.0f) + return 0.92f*(-2.0f*x-3.0f)*x*x+1.0f; + if (x < 1.0f) + return 0.92f*(2.0f*x-3.0f)*x*x+1.0f; + return 0.0f; +// if (fabs(x)>1) return 0.0f; +// return(0.54f+0.46f*(float)cos(PI*x)); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelSinc(const float x) +{ + if (x == 0.0) + return(1.0); + return((float)sin(PI*x)/(PI*x)); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBlackman(const float x) +{ + //if (fabs(x)>1) return 0.0f; + return (0.42f+0.5f*(float)cos(PI*x)+0.08f*(float)cos(2.0f*PI*x)); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBessel_J1(const float x) +{ + double p, q; + + register long i; + + static const double + Pone[] = + { + 0.581199354001606143928050809e+21, + -0.6672106568924916298020941484e+20, + 0.2316433580634002297931815435e+19, + -0.3588817569910106050743641413e+17, + 0.2908795263834775409737601689e+15, + -0.1322983480332126453125473247e+13, + 0.3413234182301700539091292655e+10, + -0.4695753530642995859767162166e+7, + 0.270112271089232341485679099e+4 + }, + Qone[] = + { + 0.11623987080032122878585294e+22, + 0.1185770712190320999837113348e+20, + 0.6092061398917521746105196863e+17, + 0.2081661221307607351240184229e+15, + 0.5243710262167649715406728642e+12, + 0.1013863514358673989967045588e+10, + 0.1501793594998585505921097578e+7, + 0.1606931573481487801970916749e+4, + 0.1e+1 + }; + + p = Pone[8]; + q = Qone[8]; + for (i=7; i >= 0; i--) + { + p = p*x*x+Pone[i]; + q = q*x*x+Qone[i]; + } + return (float)(p/q); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBessel_P1(const float x) +{ + double p, q; + + register long i; + + static const double + Pone[] = + { + 0.352246649133679798341724373e+5, + 0.62758845247161281269005675e+5, + 0.313539631109159574238669888e+5, + 0.49854832060594338434500455e+4, + 0.2111529182853962382105718e+3, + 0.12571716929145341558495e+1 + }, + Qone[] = + { + 0.352246649133679798068390431e+5, + 0.626943469593560511888833731e+5, + 0.312404063819041039923015703e+5, + 0.4930396490181088979386097e+4, + 0.2030775189134759322293574e+3, + 0.1e+1 + }; + + p = Pone[5]; + q = Qone[5]; + for (i=4; i >= 0; i--) + { + p = p*(8.0/x)*(8.0/x)+Pone[i]; + q = q*(8.0/x)*(8.0/x)+Qone[i]; + } + return (float)(p/q); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBessel_Q1(const float x) +{ + double p, q; + + register long i; + + static const double + Pone[] = + { + 0.3511751914303552822533318e+3, + 0.7210391804904475039280863e+3, + 0.4259873011654442389886993e+3, + 0.831898957673850827325226e+2, + 0.45681716295512267064405e+1, + 0.3532840052740123642735e-1 + }, + Qone[] = + { + 0.74917374171809127714519505e+4, + 0.154141773392650970499848051e+5, + 0.91522317015169922705904727e+4, + 0.18111867005523513506724158e+4, + 0.1038187585462133728776636e+3, + 0.1e+1 + }; + + p = Pone[5]; + q = Qone[5]; + for (i=4; i >= 0; i--) + { + p = p*(8.0/x)*(8.0/x)+Pone[i]; + q = q*(8.0/x)*(8.0/x)+Qone[i]; + } + return (float)(p/q); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBessel_Order1(float x) +{ + float p, q; + + if (x == 0.0) + return (0.0f); + p = x; + if (x < 0.0) + x=(-x); + if (x < 8.0) + return(p*KernelBessel_J1(x)); + q = (float)sqrt(2.0f/(PI*x))*(float)(KernelBessel_P1(x)*(1.0f/sqrt(2.0f)*(sin(x)-cos(x)))-8.0f/x*KernelBessel_Q1(x)* + (-1.0f/sqrt(2.0f)*(sin(x)+cos(x)))); + if (p < 0.0f) + q = (-q); + return (q); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelBessel(const float x) +{ + if (x == 0.0f) + return(PI/4.0f); + return(KernelBessel_Order1(PI*x)/(2.0f*x)); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelGaussian(const float x) +{ + return (float)(exp(-2.0f*x*x)*0.79788456080287f/*sqrt(2.0f/PI)*/); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelQuadratic(const float x) +{ + if (x < -1.5f) + return(0.0f); + if (x < -0.5f) + return(0.5f*(x+1.5f)*(x+1.5f)); + if (x < 0.5f) + return(0.75f-x*x); + if (x < 1.5f) + return(0.5f*(x-1.5f)*(x-1.5f)); + return(0.0f); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelMitchell(const float x) +{ +#define KM_B (1.0f/3.0f) +#define KM_C (1.0f/3.0f) +#define KM_P0 (( 6.0f - 2.0f * KM_B ) / 6.0f) +#define KM_P2 ((-18.0f + 12.0f * KM_B + 6.0f * KM_C) / 6.0f) +#define KM_P3 (( 12.0f - 9.0f * KM_B - 6.0f * KM_C) / 6.0f) +#define KM_Q0 (( 8.0f * KM_B + 24.0f * KM_C) / 6.0f) +#define KM_Q1 ((-12.0f * KM_B - 48.0f * KM_C) / 6.0f) +#define KM_Q2 (( 6.0f * KM_B + 30.0f * KM_C) / 6.0f) +#define KM_Q3 (( -1.0f * KM_B - 6.0f * KM_C) / 6.0f) + + if (x < -2.0) + return(0.0f); + if (x < -1.0) + return(KM_Q0-x*(KM_Q1-x*(KM_Q2-x*KM_Q3))); + if (x < 0.0f) + return(KM_P0+x*x*(KM_P2-x*KM_P3)); + if (x < 1.0f) + return(KM_P0+x*x*(KM_P2+x*KM_P3)); + if (x < 2.0f) + return(KM_Q0+x*(KM_Q1+x*(KM_Q2+x*KM_Q3))); + return(0.0f); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelCatrom(const float x) +{ + if (x < -2.0) + return(0.0f); + if (x < -1.0) + return(0.5f*(4.0f+x*(8.0f+x*(5.0f+x)))); + if (x < 0.0) + return(0.5f*(2.0f+x*x*(-5.0f-3.0f*x))); + if (x < 1.0) + return(0.5f*(2.0f+x*x*(-5.0f+3.0f*x))); + if (x < 2.0) + return(0.5f*(4.0f+x*(-8.0f+x*(5.0f-x)))); + return(0.0f); +} +//////////////////////////////////////////////////////////////////////////////// +float CxImage::KernelPower(const float x, const float a) +{ + if (fabs(x)>1) return 0.0f; + return (1.0f - (float)fabs(pow(x,a))); +} +//////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/utilities/CxImage/ximaiter.h b/utilities/CxImage/ximaiter.h index 3e5bff9..9788919 100644 --- a/utilities/CxImage/ximaiter.h +++ b/utilities/CxImage/ximaiter.h @@ -1,253 +1,253 @@ -/* - * File: ImaIter.h - * Purpose: Declaration of the Platform Independent Image Base Class - * Author: Alejandro Aguilar Sierra - * Created: 1995 - * Copyright: (c) 1995, Alejandro Aguilar Sierra - * - * 07/08/2001 Davide Pizzolato - www.xdp.it - * - removed slow loops - * - added safe checks - * - * Permission is given by the author to freely redistribute and include - * this code in any program as long as this credit is given where due. - * - * COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY - * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES - * THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE - * OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED - * CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT - * THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY - * SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL - * PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER - * THIS DISCLAIMER. - * - * Use at your own risk! - * ========================================================== - */ - -#if !defined(__ImaIter_h) -#define __ImaIter_h - -#include "ximage.h" -#include "ximadef.h" - -class CImageIterator -{ -friend class CxImage; -protected: - int Itx, Ity; // Counters - int Stepx, Stepy; - BYTE* IterImage; // Image pointer - CxImage *ima; -public: - // Constructors - CImageIterator ( void ); - CImageIterator ( CxImage *image ); - operator CxImage* (); - - // Iterators - BOOL ItOK (); - void Reset (); - void Upset (); - void SetRow(BYTE *buf, int n); - void GetRow(BYTE *buf, int n); - BYTE GetByte( ) { return IterImage[Itx]; } - void SetByte(BYTE b) { IterImage[Itx] = b; } - BYTE* GetRow(void); - BYTE* GetRow(int n); - BOOL NextRow(); - BOOL PrevRow(); - BOOL NextByte(); - BOOL PrevByte(); - - void SetSteps(int x, int y=0) { Stepx = x; Stepy = y; } - void GetSteps(int *x, int *y) { *x = Stepx; *y = Stepy; } - BOOL NextStep(); - BOOL PrevStep(); - - void SetY(int y); /* AD - for interlace */ - int GetY() {return Ity;} - BOOL GetCol(BYTE* pCol, DWORD x); - BOOL SetCol(BYTE* pCol, DWORD x); -}; - -///////////////////////////////////////////////////////////////////// -inline -CImageIterator::CImageIterator(void) -{ - ima = 0; - IterImage = 0; - Itx = Ity = 0; - Stepx = Stepy = 0; -} -///////////////////////////////////////////////////////////////////// -inline -CImageIterator::CImageIterator(CxImage *imageImpl): ima(imageImpl) -{ - if (ima) IterImage = ima->GetBits(); - Itx = Ity = 0; - Stepx = Stepy = 0; -} -///////////////////////////////////////////////////////////////////// -inline -CImageIterator::operator CxImage* () -{ - return ima; -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::ItOK () -{ - if (ima) return ima->IsInside(Itx, Ity); - else return FALSE; -} -///////////////////////////////////////////////////////////////////// -inline void CImageIterator::Reset() -{ - if (ima) IterImage = ima->GetBits(); - else IterImage=0; - Itx = Ity = 0; -} -///////////////////////////////////////////////////////////////////// -inline void CImageIterator::Upset() -{ - Itx = 0; - Ity = ima->GetHeight()-1; - IterImage = ima->GetBits() + ima->GetEffWidth()*(ima->GetHeight()-1); -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::NextRow() -{ - if (++Ity >= (int)ima->GetHeight()) return 0; - IterImage += ima->GetEffWidth(); - return 1; -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::PrevRow() -{ - if (--Ity < 0) return 0; - IterImage -= ima->GetEffWidth(); - return 1; -} -/* AD - for interlace */ -inline void CImageIterator::SetY(int y) -{ - if ((y < 0) || (y > (int)ima->GetHeight())) return; - Ity = y; - IterImage = ima->GetBits() + ima->GetEffWidth()*y; -} -///////////////////////////////////////////////////////////////////// -inline void CImageIterator::SetRow(BYTE *buf, int n) -{ - if (n<0) n = (int)ima->GetEffWidth(); - else n = min(n,(int)ima->GetEffWidth()); - - if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0)) memcpy(IterImage,buf,n); -} -///////////////////////////////////////////////////////////////////// -inline void CImageIterator::GetRow(BYTE *buf, int n) -{ - if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0)) - memcpy(buf,IterImage,min(n,(int)ima->GetEffWidth())); -} -///////////////////////////////////////////////////////////////////// -inline BYTE* CImageIterator::GetRow() -{ - return IterImage; -} -///////////////////////////////////////////////////////////////////// -inline BYTE* CImageIterator::GetRow(int n) -{ - SetY(n); - return IterImage; -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::NextByte() -{ - if (++Itx < (int)ima->GetEffWidth()) return 1; - else - if (++Ity < (int)ima->GetHeight()){ - IterImage += ima->GetEffWidth(); - Itx = 0; - return 1; - } else - return 0; -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::PrevByte() -{ - if (--Itx >= 0) return 1; - else - if (--Ity >= 0){ - IterImage -= ima->GetEffWidth(); - Itx = 0; - return 1; - } else - return 0; -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::NextStep() -{ - Itx += Stepx; - if (Itx < (int)ima->GetEffWidth()) return 1; - else { - Ity += Stepy; - if (Ity < (int)ima->GetHeight()){ - IterImage += ima->GetEffWidth(); - Itx = 0; - return 1; - } else - return 0; - } -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::PrevStep() -{ - Itx -= Stepx; - if (Itx >= 0) return 1; - else { - Ity -= Stepy; - if (Ity >= 0 && Ity < (int)ima->GetHeight()) { - IterImage -= ima->GetEffWidth(); - Itx = 0; - return 1; - } else - return 0; - } -} -///////////////////////////////////////////////////////////////////// -inline BOOL CImageIterator::GetCol(BYTE* pCol, DWORD x) -{ - if ((pCol==0)||(ima->GetBpp()<8)||(x>=ima->GetWidth())) - return 0; - DWORD h = ima->GetHeight(); - //DWORD line = ima->GetEffWidth(); - BYTE bytes = (BYTE)(ima->GetBpp()>>3); - BYTE* pSrc; - for (DWORD y=0;yGetBits(y) + x*bytes; - for (BYTE w=0;wGetBpp()<8)||(x>=ima->GetWidth())) - return 0; - DWORD h = ima->GetHeight(); - //DWORD line = ima->GetEffWidth(); - BYTE bytes = (BYTE)(ima->GetBpp()>>3); - BYTE* pSrc; - for (DWORD y=0;yGetBits(y) + x*bytes; - for (BYTE w=0;w + * + * 07/08/2001 Davide Pizzolato - www.xdp.it + * - removed slow loops + * - added safe checks + * + * Permission is given by the author to freely redistribute and include + * this code in any program as long as this credit is given where due. + * + * COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY + * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES + * THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE + * OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED + * CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT + * THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY + * SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL + * PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER + * THIS DISCLAIMER. + * + * Use at your own risk! + * ========================================================== + */ + +#if !defined(__ImaIter_h) +#define __ImaIter_h + +#include "ximage.h" +#include "ximadef.h" + +class CImageIterator +{ +friend class CxImage; +protected: + int Itx, Ity; // Counters + int Stepx, Stepy; + BYTE* IterImage; // Image pointer + CxImage *ima; +public: + // Constructors + CImageIterator ( void ); + CImageIterator ( CxImage *image ); + operator CxImage* (); + + // Iterators + BOOL ItOK (); + void Reset (); + void Upset (); + void SetRow(BYTE *buf, int n); + void GetRow(BYTE *buf, int n); + BYTE GetByte( ) { return IterImage[Itx]; } + void SetByte(BYTE b) { IterImage[Itx] = b; } + BYTE* GetRow(void); + BYTE* GetRow(int n); + BOOL NextRow(); + BOOL PrevRow(); + BOOL NextByte(); + BOOL PrevByte(); + + void SetSteps(int x, int y=0) { Stepx = x; Stepy = y; } + void GetSteps(int *x, int *y) { *x = Stepx; *y = Stepy; } + BOOL NextStep(); + BOOL PrevStep(); + + void SetY(int y); /* AD - for interlace */ + int GetY() {return Ity;} + BOOL GetCol(BYTE* pCol, DWORD x); + BOOL SetCol(BYTE* pCol, DWORD x); +}; + +///////////////////////////////////////////////////////////////////// +inline +CImageIterator::CImageIterator(void) +{ + ima = 0; + IterImage = 0; + Itx = Ity = 0; + Stepx = Stepy = 0; +} +///////////////////////////////////////////////////////////////////// +inline +CImageIterator::CImageIterator(CxImage *imageImpl): ima(imageImpl) +{ + if (ima) IterImage = ima->GetBits(); + Itx = Ity = 0; + Stepx = Stepy = 0; +} +///////////////////////////////////////////////////////////////////// +inline +CImageIterator::operator CxImage* () +{ + return ima; +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::ItOK () +{ + if (ima) return ima->IsInside(Itx, Ity); + else return FALSE; +} +///////////////////////////////////////////////////////////////////// +inline void CImageIterator::Reset() +{ + if (ima) IterImage = ima->GetBits(); + else IterImage=0; + Itx = Ity = 0; +} +///////////////////////////////////////////////////////////////////// +inline void CImageIterator::Upset() +{ + Itx = 0; + Ity = ima->GetHeight()-1; + IterImage = ima->GetBits() + ima->GetEffWidth()*(ima->GetHeight()-1); +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::NextRow() +{ + if (++Ity >= (int)ima->GetHeight()) return 0; + IterImage += ima->GetEffWidth(); + return 1; +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::PrevRow() +{ + if (--Ity < 0) return 0; + IterImage -= ima->GetEffWidth(); + return 1; +} +/* AD - for interlace */ +inline void CImageIterator::SetY(int y) +{ + if ((y < 0) || (y > (int)ima->GetHeight())) return; + Ity = y; + IterImage = ima->GetBits() + ima->GetEffWidth()*y; +} +///////////////////////////////////////////////////////////////////// +inline void CImageIterator::SetRow(BYTE *buf, int n) +{ + if (n<0) n = (int)ima->GetEffWidth(); + else n = min(n,(int)ima->GetEffWidth()); + + if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0)) memcpy(IterImage,buf,n); +} +///////////////////////////////////////////////////////////////////// +inline void CImageIterator::GetRow(BYTE *buf, int n) +{ + if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0)) + memcpy(buf,IterImage,min(n,(int)ima->GetEffWidth())); +} +///////////////////////////////////////////////////////////////////// +inline BYTE* CImageIterator::GetRow() +{ + return IterImage; +} +///////////////////////////////////////////////////////////////////// +inline BYTE* CImageIterator::GetRow(int n) +{ + SetY(n); + return IterImage; +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::NextByte() +{ + if (++Itx < (int)ima->GetEffWidth()) return 1; + else + if (++Ity < (int)ima->GetHeight()){ + IterImage += ima->GetEffWidth(); + Itx = 0; + return 1; + } else + return 0; +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::PrevByte() +{ + if (--Itx >= 0) return 1; + else + if (--Ity >= 0){ + IterImage -= ima->GetEffWidth(); + Itx = 0; + return 1; + } else + return 0; +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::NextStep() +{ + Itx += Stepx; + if (Itx < (int)ima->GetEffWidth()) return 1; + else { + Ity += Stepy; + if (Ity < (int)ima->GetHeight()){ + IterImage += ima->GetEffWidth(); + Itx = 0; + return 1; + } else + return 0; + } +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::PrevStep() +{ + Itx -= Stepx; + if (Itx >= 0) return 1; + else { + Ity -= Stepy; + if (Ity >= 0 && Ity < (int)ima->GetHeight()) { + IterImage -= ima->GetEffWidth(); + Itx = 0; + return 1; + } else + return 0; + } +} +///////////////////////////////////////////////////////////////////// +inline BOOL CImageIterator::GetCol(BYTE* pCol, DWORD x) +{ + if ((pCol==0)||(ima->GetBpp()<8)||(x>=ima->GetWidth())) + return 0; + DWORD h = ima->GetHeight(); + //DWORD line = ima->GetEffWidth(); + BYTE bytes = (BYTE)(ima->GetBpp()>>3); + BYTE* pSrc; + for (DWORD y=0;yGetBits(y) + x*bytes; + for (BYTE w=0;wGetBpp()<8)||(x>=ima->GetWidth())) + return 0; + DWORD h = ima->GetHeight(); + //DWORD line = ima->GetEffWidth(); + BYTE bytes = (BYTE)(ima->GetBpp()>>3); + BYTE* pSrc; + for (DWORD y=0;yGetBits(y) + x*bytes; + for (BYTE w=0;wnumcmpts_ > 64 || image->numcmpts_ < 0) - cx_throw("error: too many components"); - - // 01/Jan/2005: Always force conversion to sRGB. Seems to be required for many types of JPEG2000 file. - // if (depth!=1 && depth!=4 && depth!=8) - if (image->numcmpts_>=3 && depth <=8) - { - jas_image_t *newimage; - jas_cmprof_t *outprof; - //jas_eprintf("forcing conversion to sRGB\n"); - outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB); - if (!outprof) { - cx_throw("cannot create sRGB profile"); - } - newimage = jas_image_chclrspc(image, outprof, JAS_CMXFORM_INTENT_PER); - if (!newimage) { - jas_cmprof_destroy(outprof); // 01/Jan/2005: Destroy color profile on error. - cx_throw("cannot convert to sRGB"); - } - jas_image_destroy(image); - jas_cmprof_destroy(outprof); - image = newimage; - } - - bufs = (jas_matrix_t **)calloc(image->numcmpts_, sizeof(jas_matrix_t**)); - for (i = 0; i < image->numcmpts_; ++i) { - bufs[i] = jas_matrix_create(1, w); - if (!bufs[i]) { - cx_throw("error: cannot allocate memory"); - } - } - - int nshift = (depth>8) ? (depth-8) : 0; - - if (image->numcmpts_==3 && - image->cmpts_[0]->width_ == image->cmpts_[1]->width_ && - image->cmpts_[1]->width_ == image->cmpts_[2]->width_ && - image->cmpts_[0]->height_ == image->cmpts_[1]->height_ && - image->cmpts_[1]->height_ == image->cmpts_[2]->height_ && - image->cmpts_[0]->prec_ == image->cmpts_[1]->prec_ && - image->cmpts_[1]->prec_ == image->cmpts_[2]->prec_ ) - { - - if(!Create(w,h,24,fmt)) - cx_throw(""); - - RGBQUAD c; - for (y=0; ynumcmpts_; ++cmptno) { - jas_image_readcmpt(image, cmptno, 0, y, w, 1, bufs[cmptno]); - } - - for (x=0; x>nshift)); - c.rgbGreen = (BYTE)((jas_matrix_getv(bufs[1], x)>>nshift)); - c.rgbBlue = (BYTE)((jas_matrix_getv(bufs[2], x)>>nshift)); - SetPixelColor(x,h-1-y,c); - } - } - } else { - info.nNumFrames = image->numcmpts_; - if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)){ - cx_throw("wrong frame!"); - } - for (cmptno=0; cmptno<=info.nFrame; cmptno++) { - w = jas_image_cmptwidth(image,cmptno); - h = jas_image_cmptheight(image,cmptno); - depth = jas_image_cmptprec(image,cmptno); - if (depth>8) depth=8; - if(!Create(w,h,depth,imagetype)) - cx_throw(""); - SetGrayPalette(); - for (y=0; y>nshift))); - } - } - } - } - - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (info.nEscape == -1 && fmt>0){ - error = 0; - } else { - error = 1; - } - } - - if (bufs) { - for (i = 0; i < image->numcmpts_; ++i){ if (bufs[i]) jas_matrix_destroy(bufs[i]);} - free(bufs); - } - jas_cleanup(); - if (image) jas_image_destroy(image); - if (in) jas_stream_close(in); - return (error==0); -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageJAS::Encode(CxFile * hFile, DWORD imagetype) -{ - if (EncodeSafeCheck(hFile)) return false; - - if (head.biClrUsed!=0 && !IsGrayScale()){ - strcpy(info.szLastError,"JasPer can save only RGB or GrayScale images"); - return false; - } - - jas_image_t *image=0; - jas_stream_t *out=0; - jas_matrix_t *cmpts[3]; - long x,y,yflip,error=0; - uint_fast16_t cmptno, numcmpts=0; - jas_image_cmptparm_t cmptparms[3], *cmptparm; - - cx_try { - - if (jas_init()) - cx_throw("cannot initialize jasper"); - - out = jas_stream_fdopen(0, "wb"); - if (!out) - cx_throw("error: cannot open standard output"); - - CxFileJas src(hFile,out); - - numcmpts = head.biClrUsed==0 ? 3 : 1; - - for (cmptno = 0, cmptparm = cmptparms; cmptno < numcmpts; ++cmptno, ++cmptparm) { - cmptparm->tlx = 0; - cmptparm->tly = 0; - cmptparm->hstep = 1; - cmptparm->vstep = 1; - cmptparm->width = head.biWidth; - cmptparm->height = head.biHeight; - cmptparm->prec = 8; - cmptparm->sgnd = false; - } - - /* Create image object. */ - image = jas_image_create(numcmpts, cmptparms, JAS_CLRSPC_UNKNOWN); - if (!image) - cx_throw("error : jas_image_create"); - - if (numcmpts == 3) { - jas_image_setclrspc(image, JAS_CLRSPC_SRGB); - jas_image_setcmpttype(image, 0, - JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); - jas_image_setcmpttype(image, 1, - JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); - jas_image_setcmpttype(image, 2, - JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); - } else { - jas_image_setclrspc(image, JAS_CLRSPC_SGRAY); - jas_image_setcmpttype(image, 0, - JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); - } - - - for (x = 0; x < numcmpts; ++x) { cmpts[x] = 0; } - /* Create temporary matrices to hold component data. */ - for (x = 0; x < numcmpts; ++x) { - cmpts[x] = jas_matrix_create(1, head.biWidth); - if (!cmpts[x]) { - cx_throw("error : can't allocate memory"); - } - } - - RGBQUAD c; - for (y = 0; y < head.biHeight; ++y) { - for (x = 0; x < head.biWidth; ++x) { - if (head.biClrUsed==0){ - c = GetPixelColor(x,y); - jas_matrix_setv(cmpts[0], x, c.rgbRed); - jas_matrix_setv(cmpts[1], x, c.rgbGreen); - jas_matrix_setv(cmpts[2], x, c.rgbBlue); - } else { - jas_matrix_setv(cmpts[0], x, GetPixelIndex(x,y)); - } - } - yflip = head.biHeight - 1 - y; - for (cmptno = 0; cmptno < numcmpts; ++cmptno) { - if (jas_image_writecmpt(image, cmptno, 0, yflip, head.biWidth, 1, cmpts[cmptno])) { - cx_throw("error : jas_image_writecmpt"); - } - } - } - - char szfmt[4]; - *szfmt = '\0'; -#if CXIMAGE_SUPPORT_JP2 - if (imagetype == CXIMAGE_FORMAT_JP2) strcpy(szfmt,"jp2"); -#endif -#if CXIMAGE_SUPPORT_JPC - if (imagetype == CXIMAGE_FORMAT_JPC) strcpy(szfmt,"jpc"); -#endif -#if CXIMAGE_SUPPORT_RAS - if (imagetype == CXIMAGE_FORMAT_RAS) strcpy(szfmt,"ras"); -#endif -#if CXIMAGE_SUPPORT_PNM - if (imagetype == CXIMAGE_FORMAT_PNM) strcpy(szfmt,"pnm"); -#endif -#if CXIMAGE_SUPPORT_PGX - if (imagetype == CXIMAGE_FORMAT_PGX){ - strcpy(szfmt,"pgx"); - if (head.biClrUsed==0) cx_throw("PGX can save only GrayScale images"); - } -#endif - int outfmt = jas_image_strtofmt(szfmt); - - char szoutopts[32]; - sprintf(szoutopts,"rate=%.3f", info.fQuality/100.0f); - - if (jas_image_encode(image, out, outfmt, szoutopts)) { - cx_throw("error: cannot encode image"); - } - jas_stream_flush(out); - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - error = 1; - } - - for (x = 0; x < numcmpts; ++x) { if (cmpts[x]) { jas_matrix_destroy(cmpts[x]); } } - jas_cleanup(); - if (image) jas_image_destroy(image); - if (out) jas_stream_close(out); - - return (error==0); -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_JASPER - +/* + * File: ximajas.cpp + * Purpose: Platform Independent JasPer Image Class Loader and Writer + * 12/Apr/2003 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximajas.h" + +#if CXIMAGE_SUPPORT_JASPER + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageJAS::Decode(CxFile *hFile, DWORD imagetype) +{ + if (hFile == NULL) return false; + + jas_image_t *image=0; + jas_stream_t *in=0; + jas_matrix_t **bufs=0; + long i,error=0; + int fmt; + //jas_setdbglevel(0); + + cx_try + { + if (jas_init()) + cx_throw("cannot initialize jasper"); + + in = jas_stream_fdopen(0, "rb"); + if (!in) + cx_throw("error: cannot open standard input"); + + CxFileJas src(hFile,in); + + fmt = jas_image_getfmt(in); + if (fmt<0) + cx_throw("error: unknowm format"); + + image = jas_image_decode(in, fmt, 0); + if (!image){ + fmt = -1; + cx_throw("error: cannot load image data"); + } + + char szfmt[4]; + *szfmt = '\0'; + strncpy(szfmt,jas_image_fmttostr(fmt),3); + szfmt[3] = '\0'; + + fmt = -1; +#if CXIMAGE_SUPPORT_JP2 + if (strcmp(szfmt,"jp2")==0) fmt = CXIMAGE_FORMAT_JP2; +#endif +#if CXIMAGE_SUPPORT_JPC + if (strcmp(szfmt,"jpc")==0) fmt = CXIMAGE_FORMAT_JPC; +#endif +#if CXIMAGE_SUPPORT_RAS + if (strcmp(szfmt,"ras")==0) fmt = CXIMAGE_FORMAT_RAS; +#endif +#if CXIMAGE_SUPPORT_PNM + if (strcmp(szfmt,"pnm")==0) fmt = CXIMAGE_FORMAT_PNM; +#endif +#if CXIMAGE_SUPPORT_PGX + if (strcmp(szfmt,"pgx")==0) fmt = CXIMAGE_FORMAT_PGX; +#endif + + //if (fmt<0) + // cx_throw("error: unknowm format"); + + long x,y,w,h,depth,cmptno; + + w = jas_image_cmptwidth(image,0); + h = jas_image_cmptheight(image,0); + depth = jas_image_cmptprec(image,0); + + if (info.nEscape == -1){ + head.biWidth = w; + head.biHeight= h; + info.dwType = fmt<0 ? 0 : fmt; + cx_throw("output dimensions returned"); + } + + if (image->numcmpts_ > 64 || image->numcmpts_ < 0) + cx_throw("error: too many components"); + + // 01/Jan/2005: Always force conversion to sRGB. Seems to be required for many types of JPEG2000 file. + // if (depth!=1 && depth!=4 && depth!=8) + if (image->numcmpts_>=3 && depth <=8) + { + jas_image_t *newimage; + jas_cmprof_t *outprof; + //jas_eprintf("forcing conversion to sRGB\n"); + outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB); + if (!outprof) { + cx_throw("cannot create sRGB profile"); + } + newimage = jas_image_chclrspc(image, outprof, JAS_CMXFORM_INTENT_PER); + if (!newimage) { + jas_cmprof_destroy(outprof); // 01/Jan/2005: Destroy color profile on error. + cx_throw("cannot convert to sRGB"); + } + jas_image_destroy(image); + jas_cmprof_destroy(outprof); + image = newimage; + } + + bufs = (jas_matrix_t **)calloc(image->numcmpts_, sizeof(jas_matrix_t**)); + for (i = 0; i < image->numcmpts_; ++i) { + bufs[i] = jas_matrix_create(1, w); + if (!bufs[i]) { + cx_throw("error: cannot allocate memory"); + } + } + + int nshift = (depth>8) ? (depth-8) : 0; + + if (image->numcmpts_==3 && + image->cmpts_[0]->width_ == image->cmpts_[1]->width_ && + image->cmpts_[1]->width_ == image->cmpts_[2]->width_ && + image->cmpts_[0]->height_ == image->cmpts_[1]->height_ && + image->cmpts_[1]->height_ == image->cmpts_[2]->height_ && + image->cmpts_[0]->prec_ == image->cmpts_[1]->prec_ && + image->cmpts_[1]->prec_ == image->cmpts_[2]->prec_ ) + { + + if(!Create(w,h,24,fmt)) + cx_throw(""); + + RGBQUAD c; + for (y=0; ynumcmpts_; ++cmptno) { + jas_image_readcmpt(image, cmptno, 0, y, w, 1, bufs[cmptno]); + } + + for (x=0; x>nshift)); + c.rgbGreen = (BYTE)((jas_matrix_getv(bufs[1], x)>>nshift)); + c.rgbBlue = (BYTE)((jas_matrix_getv(bufs[2], x)>>nshift)); + SetPixelColor(x,h-1-y,c); + } + } + } else { + info.nNumFrames = image->numcmpts_; + if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)){ + cx_throw("wrong frame!"); + } + for (cmptno=0; cmptno<=info.nFrame; cmptno++) { + w = jas_image_cmptwidth(image,cmptno); + h = jas_image_cmptheight(image,cmptno); + depth = jas_image_cmptprec(image,cmptno); + if (depth>8) depth=8; + if(!Create(w,h,depth,imagetype)) + cx_throw(""); + SetGrayPalette(); + for (y=0; y>nshift))); + } + } + } + } + + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (info.nEscape == -1 && fmt>0){ + error = 0; + } else { + error = 1; + } + } + + if (bufs) { + for (i = 0; i < image->numcmpts_; ++i){ if (bufs[i]) jas_matrix_destroy(bufs[i]);} + free(bufs); + } + jas_cleanup(); + if (image) jas_image_destroy(image); + if (in) jas_stream_close(in); + return (error==0); +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageJAS::Encode(CxFile * hFile, DWORD imagetype) +{ + if (EncodeSafeCheck(hFile)) return false; + + if (head.biClrUsed!=0 && !IsGrayScale()){ + strcpy(info.szLastError,"JasPer can save only RGB or GrayScale images"); + return false; + } + + jas_image_t *image=0; + jas_stream_t *out=0; + jas_matrix_t *cmpts[3]; + long x,y,yflip,error=0; + uint_fast16_t cmptno, numcmpts=0; + jas_image_cmptparm_t cmptparms[3], *cmptparm; + + cx_try { + + if (jas_init()) + cx_throw("cannot initialize jasper"); + + out = jas_stream_fdopen(0, "wb"); + if (!out) + cx_throw("error: cannot open standard output"); + + CxFileJas src(hFile,out); + + numcmpts = head.biClrUsed==0 ? 3 : 1; + + for (cmptno = 0, cmptparm = cmptparms; cmptno < numcmpts; ++cmptno, ++cmptparm) { + cmptparm->tlx = 0; + cmptparm->tly = 0; + cmptparm->hstep = 1; + cmptparm->vstep = 1; + cmptparm->width = head.biWidth; + cmptparm->height = head.biHeight; + cmptparm->prec = 8; + cmptparm->sgnd = false; + } + + /* Create image object. */ + image = jas_image_create(numcmpts, cmptparms, JAS_CLRSPC_UNKNOWN); + if (!image) + cx_throw("error : jas_image_create"); + + if (numcmpts == 3) { + jas_image_setclrspc(image, JAS_CLRSPC_SRGB); + jas_image_setcmpttype(image, 0, + JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R)); + jas_image_setcmpttype(image, 1, + JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G)); + jas_image_setcmpttype(image, 2, + JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B)); + } else { + jas_image_setclrspc(image, JAS_CLRSPC_SGRAY); + jas_image_setcmpttype(image, 0, + JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y)); + } + + + for (x = 0; x < numcmpts; ++x) { cmpts[x] = 0; } + /* Create temporary matrices to hold component data. */ + for (x = 0; x < numcmpts; ++x) { + cmpts[x] = jas_matrix_create(1, head.biWidth); + if (!cmpts[x]) { + cx_throw("error : can't allocate memory"); + } + } + + RGBQUAD c; + for (y = 0; y < head.biHeight; ++y) { + for (x = 0; x < head.biWidth; ++x) { + if (head.biClrUsed==0){ + c = GetPixelColor(x,y); + jas_matrix_setv(cmpts[0], x, c.rgbRed); + jas_matrix_setv(cmpts[1], x, c.rgbGreen); + jas_matrix_setv(cmpts[2], x, c.rgbBlue); + } else { + jas_matrix_setv(cmpts[0], x, GetPixelIndex(x,y)); + } + } + yflip = head.biHeight - 1 - y; + for (cmptno = 0; cmptno < numcmpts; ++cmptno) { + if (jas_image_writecmpt(image, cmptno, 0, yflip, head.biWidth, 1, cmpts[cmptno])) { + cx_throw("error : jas_image_writecmpt"); + } + } + } + + char szfmt[4]; + *szfmt = '\0'; +#if CXIMAGE_SUPPORT_JP2 + if (imagetype == CXIMAGE_FORMAT_JP2) strcpy(szfmt,"jp2"); +#endif +#if CXIMAGE_SUPPORT_JPC + if (imagetype == CXIMAGE_FORMAT_JPC) strcpy(szfmt,"jpc"); +#endif +#if CXIMAGE_SUPPORT_RAS + if (imagetype == CXIMAGE_FORMAT_RAS) strcpy(szfmt,"ras"); +#endif +#if CXIMAGE_SUPPORT_PNM + if (imagetype == CXIMAGE_FORMAT_PNM) strcpy(szfmt,"pnm"); +#endif +#if CXIMAGE_SUPPORT_PGX + if (imagetype == CXIMAGE_FORMAT_PGX){ + strcpy(szfmt,"pgx"); + if (head.biClrUsed==0) cx_throw("PGX can save only GrayScale images"); + } +#endif + int outfmt = jas_image_strtofmt(szfmt); + + char szoutopts[32]; + sprintf(szoutopts,"rate=%.3f", info.fQuality/100.0f); + + if (jas_image_encode(image, out, outfmt, szoutopts)) { + cx_throw("error: cannot encode image"); + } + jas_stream_flush(out); + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + error = 1; + } + + for (x = 0; x < numcmpts; ++x) { if (cmpts[x]) { jas_matrix_destroy(cmpts[x]); } } + jas_cleanup(); + if (image) jas_image_destroy(image); + if (out) jas_stream_close(out); + + return (error==0); +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_JASPER + diff --git a/utilities/CxImage/ximajas.h b/utilities/CxImage/ximajas.h index 7225f01..c5874d1 100644 --- a/utilities/CxImage/ximajas.h +++ b/utilities/CxImage/ximajas.h @@ -1,84 +1,84 @@ -/* - * File: ximajas.h - * Purpose: Jasper Image Class Loader and Writer - */ -/* ========================================================== - * CxImageJAS (c) 12/Apr/2003 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * based on JasPer Copyright (c) 2001-2003 Michael David Adams - All rights reserved. - * ========================================================== - */ -#if !defined(__ximaJAS_h) -#define __ximaJAS_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_JASPER - -#include "../jasper/include/jasper/jasper.h" - -class CxImageJAS: public CxImage -{ -public: - CxImageJAS(): CxImage((DWORD)0) {} // cast to DWORD - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,0);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,0);} - bool Decode(CxFile * hFile, DWORD imagetype = 0); - bool Decode(FILE *hFile, DWORD imagetype = 0) { CxIOFile file(hFile); return Decode(&file,imagetype); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile, DWORD imagetype = 0); - bool Encode(FILE *hFile, DWORD imagetype = 0) { CxIOFile file(hFile); return Encode(&file,imagetype); } -#endif // CXIMAGE_SUPPORT_ENCODE -protected: - - class CxFileJas - { - public: - CxFileJas(CxFile* pFile,jas_stream_t *stream) - { - if (stream->obj_) jas_free(stream->obj_); - stream->obj_ = pFile; - - // - cannot set the stream->ops_->functions here, - // because this overwrites a static structure in the Jasper library. - // This structure is used by Jasper for internal operations too, e.g. tempfile. - // However the ops_ pointer in the stream can be overwritten. - - //stream->ops_->close_ = JasClose; - //stream->ops_->read_ = JasRead; - //stream->ops_->seek_ = JasSeek; - //stream->ops_->write_ = JasWrite; - - jas_stream_CxFile.close_ = JasClose; - jas_stream_CxFile.read_ = JasRead; - jas_stream_CxFile.seek_ = JasSeek; - jas_stream_CxFile.write_ = JasWrite; - - stream->ops_ = &jas_stream_CxFile; - - // - end - } - static int JasRead(jas_stream_obj_t *obj, char *buf, int cnt) - { return ((CxFile*)obj)->Read(buf,1,cnt); } - static int JasWrite(jas_stream_obj_t *obj, char *buf, int cnt) - { return ((CxFile*)obj)->Write(buf,1,cnt); } - static long JasSeek(jas_stream_obj_t *obj, long offset, int origin) - { return ((CxFile*)obj)->Seek(offset,origin); } - static int JasClose(jas_stream_obj_t * /*obj*/) - { return 1; } - - // -private: - jas_stream_ops_t jas_stream_CxFile; - // - end - - }; - -}; - -#endif - -#endif +/* + * File: ximajas.h + * Purpose: Jasper Image Class Loader and Writer + */ +/* ========================================================== + * CxImageJAS (c) 12/Apr/2003 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * based on JasPer Copyright (c) 2001-2003 Michael David Adams - All rights reserved. + * ========================================================== + */ +#if !defined(__ximaJAS_h) +#define __ximaJAS_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_JASPER + +#include "../jasper/include/jasper/jasper.h" + +class CxImageJAS: public CxImage +{ +public: + CxImageJAS(): CxImage((DWORD)0) {} // cast to DWORD + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,0);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,0);} + bool Decode(CxFile * hFile, DWORD imagetype = 0); + bool Decode(FILE *hFile, DWORD imagetype = 0) { CxIOFile file(hFile); return Decode(&file,imagetype); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile, DWORD imagetype = 0); + bool Encode(FILE *hFile, DWORD imagetype = 0) { CxIOFile file(hFile); return Encode(&file,imagetype); } +#endif // CXIMAGE_SUPPORT_ENCODE +protected: + + class CxFileJas + { + public: + CxFileJas(CxFile* pFile,jas_stream_t *stream) + { + if (stream->obj_) jas_free(stream->obj_); + stream->obj_ = pFile; + + // - cannot set the stream->ops_->functions here, + // because this overwrites a static structure in the Jasper library. + // This structure is used by Jasper for internal operations too, e.g. tempfile. + // However the ops_ pointer in the stream can be overwritten. + + //stream->ops_->close_ = JasClose; + //stream->ops_->read_ = JasRead; + //stream->ops_->seek_ = JasSeek; + //stream->ops_->write_ = JasWrite; + + jas_stream_CxFile.close_ = JasClose; + jas_stream_CxFile.read_ = JasRead; + jas_stream_CxFile.seek_ = JasSeek; + jas_stream_CxFile.write_ = JasWrite; + + stream->ops_ = &jas_stream_CxFile; + + // - end + } + static int JasRead(jas_stream_obj_t *obj, char *buf, int cnt) + { return ((CxFile*)obj)->Read(buf,1,cnt); } + static int JasWrite(jas_stream_obj_t *obj, char *buf, int cnt) + { return ((CxFile*)obj)->Write(buf,1,cnt); } + static long JasSeek(jas_stream_obj_t *obj, long offset, int origin) + { return ((CxFile*)obj)->Seek(offset,origin); } + static int JasClose(jas_stream_obj_t * /*obj*/) + { return 1; } + + // +private: + jas_stream_ops_t jas_stream_CxFile; + // - end + + }; + +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximajbg.cpp b/utilities/CxImage/ximajbg.cpp index 2533108..06fb9bf 100644 --- a/utilities/CxImage/ximajbg.cpp +++ b/utilities/CxImage/ximajbg.cpp @@ -1,174 +1,174 @@ -/* - * File: ximajbg.cpp - * Purpose: Platform Independent JBG Image Class Loader and Writer - * 18/Aug/2002 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximajbg.h" - -#if CXIMAGE_SUPPORT_JBG - -#include "ximaiter.h" - -#define JBIG_BUFSIZE 8192 - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageJBG::Decode(CxFile *hFile) -{ - if (hFile == NULL) return false; - - struct jbg_dec_state jbig_state; - unsigned long xmax = 4294967295UL, ymax = 4294967295UL; - unsigned int len, cnt; - BYTE *buffer,*p; - int result; - - cx_try - { - jbg_dec_init(&jbig_state); - jbg_dec_maxsize(&jbig_state, xmax, ymax); - - buffer = (BYTE*)malloc(JBIG_BUFSIZE); - if (!buffer) cx_throw("Sorry, not enough memory available!"); - - result = JBG_EAGAIN; - do { - len = hFile->Read(buffer, 1, JBIG_BUFSIZE); - if (!len) break; - cnt = 0; - p = buffer; - while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) { - result = jbg_dec_in(&jbig_state, p, len, &cnt); - p += cnt; - len -= cnt; - } - } while (result == JBG_EAGAIN || result == JBG_EOK); - - if (hFile->Error()) - cx_throw("Problem while reading input file"); - if (result != JBG_EOK && result != JBG_EOK_INTR) - cx_throw("Problem with input file"); - - int w, h, bpp, planes, ew; - - w = jbg_dec_getwidth(&jbig_state); - h = jbg_dec_getheight(&jbig_state); - planes = jbg_dec_getplanes(&jbig_state); - bpp = (planes+7)>>3; - ew = (w + 7)>>3; - - if (info.nEscape == -1){ - head.biWidth = w; - head.biHeight= h; - info.dwType = CXIMAGE_FORMAT_JBG; - cx_throw("output dimensions returned"); - } - - switch (planes){ - case 1: - { - BYTE* binary_image = jbg_dec_getimage(&jbig_state, 0); - - if (!Create(w,h,1,CXIMAGE_FORMAT_JBG)) - cx_throw(""); - - SetPaletteColor(0,255,255,255); - SetPaletteColor(1,0,0,0); - - CImageIterator iter(this); - iter.Upset(); - for (int i=0;i>3; - ew = (w + 7)>>3; - - BYTE mask; - RGBQUAD *rgb = GetPalette(); - if (CompareColors(&rgb[0],&rgb[1])<0) mask=255; else mask=0; - - BYTE *buffer = (BYTE*)malloc(ew*h*2); - if (!buffer) { - strcpy(info.szLastError,"Sorry, not enough memory available!"); - return false; - } - - for (y=0; yError()){ - strcpy(info.szLastError,"Problem while writing JBG file"); - return false; - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_JBG - +/* + * File: ximajbg.cpp + * Purpose: Platform Independent JBG Image Class Loader and Writer + * 18/Aug/2002 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximajbg.h" + +#if CXIMAGE_SUPPORT_JBG + +#include "ximaiter.h" + +#define JBIG_BUFSIZE 8192 + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageJBG::Decode(CxFile *hFile) +{ + if (hFile == NULL) return false; + + struct jbg_dec_state jbig_state; + unsigned long xmax = 4294967295UL, ymax = 4294967295UL; + unsigned int len, cnt; + BYTE *buffer,*p; + int result; + + cx_try + { + jbg_dec_init(&jbig_state); + jbg_dec_maxsize(&jbig_state, xmax, ymax); + + buffer = (BYTE*)malloc(JBIG_BUFSIZE); + if (!buffer) cx_throw("Sorry, not enough memory available!"); + + result = JBG_EAGAIN; + do { + len = hFile->Read(buffer, 1, JBIG_BUFSIZE); + if (!len) break; + cnt = 0; + p = buffer; + while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) { + result = jbg_dec_in(&jbig_state, p, len, &cnt); + p += cnt; + len -= cnt; + } + } while (result == JBG_EAGAIN || result == JBG_EOK); + + if (hFile->Error()) + cx_throw("Problem while reading input file"); + if (result != JBG_EOK && result != JBG_EOK_INTR) + cx_throw("Problem with input file"); + + int w, h, bpp, planes, ew; + + w = jbg_dec_getwidth(&jbig_state); + h = jbg_dec_getheight(&jbig_state); + planes = jbg_dec_getplanes(&jbig_state); + bpp = (planes+7)>>3; + ew = (w + 7)>>3; + + if (info.nEscape == -1){ + head.biWidth = w; + head.biHeight= h; + info.dwType = CXIMAGE_FORMAT_JBG; + cx_throw("output dimensions returned"); + } + + switch (planes){ + case 1: + { + BYTE* binary_image = jbg_dec_getimage(&jbig_state, 0); + + if (!Create(w,h,1,CXIMAGE_FORMAT_JBG)) + cx_throw(""); + + SetPaletteColor(0,255,255,255); + SetPaletteColor(1,0,0,0); + + CImageIterator iter(this); + iter.Upset(); + for (int i=0;i>3; + ew = (w + 7)>>3; + + BYTE mask; + RGBQUAD *rgb = GetPalette(); + if (CompareColors(&rgb[0],&rgb[1])<0) mask=255; else mask=0; + + BYTE *buffer = (BYTE*)malloc(ew*h*2); + if (!buffer) { + strcpy(info.szLastError,"Sorry, not enough memory available!"); + return false; + } + + for (y=0; yError()){ + strcpy(info.szLastError,"Problem while writing JBG file"); + return false; + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_JBG + diff --git a/utilities/CxImage/ximajbg.h b/utilities/CxImage/ximajbg.h index 137eedf..926b591 100644 --- a/utilities/CxImage/ximajbg.h +++ b/utilities/CxImage/ximajbg.h @@ -1,44 +1,44 @@ -/* - * File: ximajbg.h - * Purpose: JBG Image Class Loader and Writer - */ -/* ========================================================== - * CxImageJBG (c) 18/Aug/2002 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * based on LIBJBG Copyright (c) 2002, Markus Kuhn - All rights reserved. - * ========================================================== - */ -#if !defined(__ximaJBG_h) -#define __ximaJBG_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_JBG - -extern "C" { -#include "../jbig/jbig.h" -}; - -class CxImageJBG: public CxImage -{ -public: - CxImageJBG(): CxImage(CXIMAGE_FORMAT_JBG) {} - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JBG);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JBG);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE -protected: - static void jbig_data_out(BYTE *buffer, unsigned int len, void *file) - {((CxFile*)file)->Write(buffer,len,1);} -}; - -#endif - -#endif +/* + * File: ximajbg.h + * Purpose: JBG Image Class Loader and Writer + */ +/* ========================================================== + * CxImageJBG (c) 18/Aug/2002 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * based on LIBJBG Copyright (c) 2002, Markus Kuhn - All rights reserved. + * ========================================================== + */ +#if !defined(__ximaJBG_h) +#define __ximaJBG_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_JBG + +extern "C" { +#include "../jbig/jbig.h" +}; + +class CxImageJBG: public CxImage +{ +public: + CxImageJBG(): CxImage(CXIMAGE_FORMAT_JBG) {} + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JBG);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JBG);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE +protected: + static void jbig_data_out(BYTE *buffer, unsigned int len, void *file) + {((CxFile*)file)->Write(buffer,len,1);} +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximajpg.cpp b/utilities/CxImage/ximajpg.cpp index 30146aa..1cf5a00 100644 --- a/utilities/CxImage/ximajpg.cpp +++ b/utilities/CxImage/ximajpg.cpp @@ -1,496 +1,496 @@ -/* - * File: ximajpg.cpp - * Purpose: Platform Independent JPEG Image Class Loader and Writer - * 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximajpg.h" - -#if CXIMAGE_SUPPORT_JPG - -#include "../jpeg/jmorecfg.h" - -#include "ximaiter.h" - -#include - -struct jpg_error_mgr { - struct jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ - char* buffer; /* error message */ -}; -typedef jpg_error_mgr *jpg_error_ptr; - -//////////////////////////////////////////////////////////////////////////////// -// Here's the routine that will replace the standard error_exit method: -//////////////////////////////////////////////////////////////////////////////// -static void -ima_jpeg_error_exit (j_common_ptr cinfo) -{ - /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ - jpg_error_ptr myerr = (jpg_error_ptr) cinfo->err; - /* Create the message */ - myerr->pub.format_message (cinfo, myerr->buffer); - /* Send it to stderr, adding a newline */ - /* Return control to the setjmp point */ - longjmp(myerr->setjmp_buffer, 1); -} -//////////////////////////////////////////////////////////////////////////////// -CxImageJPG::CxImageJPG(): CxImage(CXIMAGE_FORMAT_JPG) -{ -#if CXIMAGEJPG_SUPPORT_EXIF - m_exif = NULL; - memset(&m_exifinfo, 0, sizeof(EXIFINFO)); -#endif -} -//////////////////////////////////////////////////////////////////////////////// -CxImageJPG::~CxImageJPG() -{ -#if CXIMAGEJPG_SUPPORT_EXIF - if (m_exif) delete m_exif; -#endif -} -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGEJPG_SUPPORT_EXIF -bool CxImageJPG::DecodeExif(CxFile * hFile) -{ - m_exif = new CxExifInfo(&m_exifinfo); - if (m_exif){ - long pos=hFile->Tell(); - m_exif->DecodeExif(hFile); - hFile->Seek(pos,SEEK_SET); - return m_exif->m_exifinfo->IsExif; - } else { - return false; - } -} -#endif //CXIMAGEJPG_SUPPORT_EXIF -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageJPG::Decode(CxFile * hFile) -{ - - bool is_exif = false; -#if CXIMAGEJPG_SUPPORT_EXIF - is_exif = DecodeExif(hFile); -#endif - - CImageIterator iter(this); - /* This struct contains the JPEG decompression parameters and pointers to - * working space (which is allocated as needed by the JPEG library). - */ - struct jpeg_decompress_struct cinfo; - /* We use our private extension JPEG error handler. */ - struct jpg_error_mgr jerr; - jerr.buffer=info.szLastError; - /* More stuff */ - JSAMPARRAY buffer; /* Output row buffer */ - int row_stride; /* physical row width in output buffer */ - - /* In this example we want to open the input file before doing anything else, - * so that the setjmp() error recovery below can assume the file is open. - * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that - * requires it in order to read binary files. - */ - - /* Step 1: allocate and initialize JPEG decompression object */ - /* We set up the normal JPEG error routines, then override error_exit. */ - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = ima_jpeg_error_exit; - - /* Establish the setjmp return context for my_error_exit to use. */ - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_decompress(&cinfo); - return 0; - } - /* Now we can initialize the JPEG decompression object. */ - jpeg_create_decompress(&cinfo); - - /* Step 2: specify data source (eg, a file) */ - //jpeg_stdio_src(&cinfo, infile); - CxFileJpg src(hFile); - cinfo.src = &src; - - /* Step 3: read file parameters with jpeg_read_header() */ - (void) jpeg_read_header(&cinfo, TRUE); - - /* Step 4 handle decoder options*/ - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_GRAYSCALE) != 0) - cinfo.out_color_space = JCS_GRAYSCALE; - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_QUANTIZE) != 0) { - cinfo.quantize_colors = TRUE; - cinfo.desired_number_of_colors = GetJpegQuality(); - } - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_DITHER) != 0) - cinfo.dither_mode = m_nDither; - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_ONEPASS) != 0) - cinfo.two_pass_quantize = FALSE; - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_NOSMOOTH) != 0) - cinfo.do_fancy_upsampling = FALSE; - -//: Load true color images as RGB (no quantize) -/* Step 4: set parameters for decompression */ -/* if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) { - * cinfo.quantize_colors = TRUE; - * cinfo.desired_number_of_colors = 128; - *} - */ // - - // Set the scale - cinfo.scale_denom = GetJpegScale(); - - // Borrowed the idea from GIF implementation - if (info.nEscape == -1) { - // Return output dimensions only - jpeg_calc_output_dimensions(&cinfo); - head.biWidth = cinfo.output_width; - head.biHeight = cinfo.output_height; - info.dwType = CXIMAGE_FORMAT_JPG; - jpeg_destroy_decompress(&cinfo); - return true; - } - - /* Step 5: Start decompressor */ - jpeg_start_decompress(&cinfo); - - /* We may need to do some setup of our own at this point before reading - * the data. After jpeg_start_decompress() we have the correct scaled - * output image dimensions available, as well as the output colormap - * if we asked for color quantization. - */ - //Create the image using output dimensions - //Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); - Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); - - if (!pDib) longjmp(jerr.setjmp_buffer, 1); // check if the image has been created - - if (is_exif){ -#if CXIMAGEJPG_SUPPORT_EXIF - if ((m_exifinfo.Xresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0)) - SetXDPI((long)(m_exifinfo.Xresolution/m_exifinfo.ResolutionUnit)); - if ((m_exifinfo.Yresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0)) - SetYDPI((long)(m_exifinfo.Yresolution/m_exifinfo.ResolutionUnit)); -#endif - } else { - switch (cinfo.density_unit) { - case 0: // [andy] fix for aspect ratio... - if((cinfo.Y_density > 0) && (cinfo.X_density > 0)){ - SetYDPI((long)(GetXDPI()*(float(cinfo.Y_density)/float(cinfo.X_density)))); - } - break; - case 2: // [andy] fix: cinfo.X/Y_density is pixels per centimeter - SetXDPI((long)floor(cinfo.X_density * 2.54 + 0.5)); - SetYDPI((long)floor(cinfo.Y_density * 2.54 + 0.5)); - break; - default: - SetXDPI(cinfo.X_density); - SetYDPI(cinfo.Y_density); - } - } - - if (cinfo.out_color_space==JCS_GRAYSCALE){ - SetGrayPalette(); - head.biClrUsed =256; - } else { - if (cinfo.quantize_colors){ - SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]); - head.biClrUsed=cinfo.actual_number_of_colors; - } else { - head.biClrUsed=0; - } - } - - /* JSAMPLEs per row in output buffer */ - row_stride = cinfo.output_width * cinfo.output_components; - - /* Make a one-row-high sample array that will go away when done with image */ - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - - /* Step 6: while (scan lines remain to be read) */ - /* jpeg_read_scanlines(...); */ - /* Here we use the library's state variable cinfo.output_scanline as the - * loop counter, so that we don't have to keep track ourselves. - */ - iter.Upset(); - while (cinfo.output_scanline < cinfo.output_height) { - - if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // - cancel decoding - - (void) jpeg_read_scanlines(&cinfo, buffer, 1); - // info.nProgress = (long)(100*cinfo.output_scanline/cinfo.output_height); - // Step 6a: CMYK->RGB */ - if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){ - BYTE k,*dst,*src; - dst=iter.GetRow(); - src=buffer[0]; - for(long x3=0,x4=0; x3<(long)info.dwEffWidth && x4 Step 7A: Swap red and blue components - // not necessary if swapped red and blue definition in jmorecfg.h;ln322 - if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){ - BYTE* r0=GetBits(); - for(long y=0;y - cancel decoding - RGBtoBGR(r0,3*head.biWidth); - r0+=info.dwEffWidth; - } - } - - /* Step 8: Release JPEG decompression object */ - /* This is an important step since it will release a good deal of memory. */ - jpeg_destroy_decompress(&cinfo); - - /* At this point you may want to check to see whether any corrupt-data - * warnings occurred (test whether jerr.pub.num_warnings is nonzero). - */ - - /* And we're done! */ - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageJPG::Encode(CxFile * hFile) -{ - if (EncodeSafeCheck(hFile)) return false; - - if (head.biClrUsed!=0 && !IsGrayScale()){ - strcpy(info.szLastError,"JPEG can save only RGB or GreyScale images"); - return false; - } - - // necessary for EXIF, and for roll backs - long pos=hFile->Tell(); - - /* This struct contains the JPEG compression parameters and pointers to - * working space (which is allocated as needed by the JPEG library). - * It is possible to have several such structures, representing multiple - * compression/decompression processes, in existence at once. We refer - * to any one struct (and its associated working data) as a "JPEG object". - */ - struct jpeg_compress_struct cinfo; - /* This struct represents a JPEG error handler. It is declared separately - * because applications often want to supply a specialized error handler - * (see the second half of this file for an example). But here we just - * take the easy way out and use the standard error handler, which will - * print a message on stderr and call exit() if compression fails. - * Note that this struct must live as long as the main JPEG parameter - * struct, to avoid dangling-pointer problems. - */ - //struct jpeg_error_mgr jerr; - /* We use our private extension JPEG error handler. */ - struct jpg_error_mgr jerr; - jerr.buffer=info.szLastError; - /* More stuff */ - int row_stride; /* physical row width in image buffer */ - JSAMPARRAY buffer; /* Output row buffer */ - - /* Step 1: allocate and initialize JPEG compression object */ - /* We have to set up the error handler first, in case the initialization - * step fails. (Unlikely, but it could happen if you are out of memory.) - * This routine fills in the contents of struct jerr, and returns jerr's - * address which we place into the link field in cinfo. - */ - //cinfo.err = jpeg_std_error(&jerr); - /* We set up the normal JPEG error routines, then override error_exit. */ - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = ima_jpeg_error_exit; - - /* Establish the setjmp return context for my_error_exit to use. */ - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - strcpy(info.szLastError, jerr.buffer); // - jpeg_destroy_compress(&cinfo); - return 0; - } - - /* Now we can initialize the JPEG compression object. */ - jpeg_create_compress(&cinfo); - /* Step 2: specify data destination (eg, a file) */ - /* Note: steps 2 and 3 can be done in either order. */ - /* Here we use the library-supplied code to send compressed data to a - * stdio stream. You can also write your own code to do something else. - * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that - * requires it in order to write binary files. - */ - - //jpeg_stdio_dest(&cinfo, outfile); - CxFileJpg dest(hFile); - cinfo.dest = &dest; - - /* Step 3: set parameters for compression */ - /* First we supply a description of the input image. - * Four fields of the cinfo struct must be filled in: - */ - cinfo.image_width = GetWidth(); // image width and height, in pixels - cinfo.image_height = GetHeight(); - - if (IsGrayScale()){ - cinfo.input_components = 1; // # of color components per pixel - cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ - } else { - cinfo.input_components = 3; // # of color components per pixel - cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ - } - - /* Now use the library's routine to set default compression parameters. - * (You must set at least cinfo.in_color_space before calling this, - * since the defaults depend on the source color space.) - */ - jpeg_set_defaults(&cinfo); - /* Now you can set any non-default parameters you wish to. - * Here we just illustrate the use of quality (quantization table) scaling: - */ - -//#ifdef C_ARITH_CODING_SUPPORTED - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_ARITHMETIC) != 0) - cinfo.arith_code = TRUE; -//#endif - -//#ifdef ENTROPY_OPT_SUPPORTED - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_OPTIMIZE) != 0) - cinfo.optimize_coding = TRUE; -//#endif - - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_GRAYSCALE) != 0) - jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE); - - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SMOOTHING) != 0) - cinfo.smoothing_factor = m_nSmoothing; - - jpeg_set_quality(&cinfo, GetJpegQuality(), (GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_BASELINE) != 0); - -//#ifdef C_PROGRESSIVE_SUPPORTED - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_PROGRESSIVE) != 0) - jpeg_simple_progression(&cinfo); -//#endif - -#ifdef C_LOSSLESS_SUPPORTED - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_LOSSLESS) != 0) - jpeg_simple_lossless(&cinfo, m_nPredictor, m_nPointTransform); -#endif - - //SetCodecOption(ENCODE_SUBSAMPLE_444 | GetCodecOption(CXIMAGE_FORMAT_JPG),CXIMAGE_FORMAT_JPG); - - // 2x2, 1x1, 1x1 (4:1:1) : High (default sub sampling) - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; - - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_422) != 0){ - // 2x1, 1x1, 1x1 (4:2:2) : Medium - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 1; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; - } - - if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_444) != 0){ - // 1x1 1x1 1x1 (4:4:4) : None - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; - } - - cinfo.density_unit=1; - cinfo.X_density=(unsigned short)GetXDPI(); - cinfo.Y_density=(unsigned short)GetYDPI(); - - /* Step 4: Start compressor */ - /* TRUE ensures that we will write a complete interchange-JPEG file. - * Pass TRUE unless you are very sure of what you're doing. - */ - jpeg_start_compress(&cinfo, TRUE); - - /* Step 5: while (scan lines remain to be written) */ - /* jpeg_write_scanlines(...); */ - /* Here we use the library's state variable cinfo.next_scanline as the - * loop counter, so that we don't have to keep track ourselves. - * To keep things simple, we pass one scanline per call; you can pass - * more if you wish, though. - */ - row_stride = info.dwEffWidth; /* JSAMPLEs per row in image_buffer */ - - // "8+row_stride" fix heap deallocation problem during debug??? - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, 8+row_stride, 1); - - CImageIterator iter(this); - - iter.Upset(); - while (cinfo.next_scanline < cinfo.image_height) { - // info.nProgress = (long)(100*cinfo.next_scanline/cinfo.image_height); - iter.GetRow(buffer[0], row_stride); - // not necessary if swapped red and blue definition in jmorecfg.h;ln322 - if (head.biClrUsed==0){ // swap R & B for RGB images - RGBtoBGR(buffer[0], row_stride); // Lance : 1998/09/01 : Bug ID: EXP-2.1.1-9 - } - iter.PrevRow(); - (void) jpeg_write_scanlines(&cinfo, buffer, 1); - } - - /* Step 6: Finish compression */ - jpeg_finish_compress(&cinfo); - - /* Step 7: release JPEG compression object */ - /* This is an important step since it will release a good deal of memory. */ - jpeg_destroy_compress(&cinfo); - - -#if CXIMAGEJPG_SUPPORT_EXIF - if (m_exif && m_exif->m_exifinfo->IsExif){ - // discard useless sections (if any) read from original image - m_exif->DiscardAllButExif(); - // read new created image, to split the sections - hFile->Seek(pos,SEEK_SET); - m_exif->DecodeExif(hFile,EXIF_READ_IMAGE); - // save back the image, adding EXIF section - hFile->Seek(pos,SEEK_SET); - m_exif->EncodeExif(hFile); - } -#endif - - - /* And we're done! */ - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_JPG - +/* + * File: ximajpg.cpp + * Purpose: Platform Independent JPEG Image Class Loader and Writer + * 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximajpg.h" + +#if CXIMAGE_SUPPORT_JPG + +#include "../jpeg/jmorecfg.h" + +#include "ximaiter.h" + +#include + +struct jpg_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ + char* buffer; /* error message */ +}; +typedef jpg_error_mgr *jpg_error_ptr; + +//////////////////////////////////////////////////////////////////////////////// +// Here's the routine that will replace the standard error_exit method: +//////////////////////////////////////////////////////////////////////////////// +static void +ima_jpeg_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + jpg_error_ptr myerr = (jpg_error_ptr) cinfo->err; + /* Create the message */ + myerr->pub.format_message (cinfo, myerr->buffer); + /* Send it to stderr, adding a newline */ + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} +//////////////////////////////////////////////////////////////////////////////// +CxImageJPG::CxImageJPG(): CxImage(CXIMAGE_FORMAT_JPG) +{ +#if CXIMAGEJPG_SUPPORT_EXIF + m_exif = NULL; + memset(&m_exifinfo, 0, sizeof(EXIFINFO)); +#endif +} +//////////////////////////////////////////////////////////////////////////////// +CxImageJPG::~CxImageJPG() +{ +#if CXIMAGEJPG_SUPPORT_EXIF + if (m_exif) delete m_exif; +#endif +} +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGEJPG_SUPPORT_EXIF +bool CxImageJPG::DecodeExif(CxFile * hFile) +{ + m_exif = new CxExifInfo(&m_exifinfo); + if (m_exif){ + long pos=hFile->Tell(); + m_exif->DecodeExif(hFile); + hFile->Seek(pos,SEEK_SET); + return m_exif->m_exifinfo->IsExif; + } else { + return false; + } +} +#endif //CXIMAGEJPG_SUPPORT_EXIF +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageJPG::Decode(CxFile * hFile) +{ + + bool is_exif = false; +#if CXIMAGEJPG_SUPPORT_EXIF + is_exif = DecodeExif(hFile); +#endif + + CImageIterator iter(this); + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. */ + struct jpg_error_mgr jerr; + jerr.buffer=info.szLastError; + /* More stuff */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + /* Step 1: allocate and initialize JPEG decompression object */ + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = ima_jpeg_error_exit; + + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + return 0; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + //jpeg_stdio_src(&cinfo, infile); + CxFileJpg src(hFile); + cinfo.src = &src; + + /* Step 3: read file parameters with jpeg_read_header() */ + (void) jpeg_read_header(&cinfo, TRUE); + + /* Step 4 handle decoder options*/ + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_GRAYSCALE) != 0) + cinfo.out_color_space = JCS_GRAYSCALE; + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_QUANTIZE) != 0) { + cinfo.quantize_colors = TRUE; + cinfo.desired_number_of_colors = GetJpegQuality(); + } + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_DITHER) != 0) + cinfo.dither_mode = m_nDither; + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_ONEPASS) != 0) + cinfo.two_pass_quantize = FALSE; + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_NOSMOOTH) != 0) + cinfo.do_fancy_upsampling = FALSE; + +//: Load true color images as RGB (no quantize) +/* Step 4: set parameters for decompression */ +/* if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) { + * cinfo.quantize_colors = TRUE; + * cinfo.desired_number_of_colors = 128; + *} + */ // + + // Set the scale + cinfo.scale_denom = GetJpegScale(); + + // Borrowed the idea from GIF implementation + if (info.nEscape == -1) { + // Return output dimensions only + jpeg_calc_output_dimensions(&cinfo); + head.biWidth = cinfo.output_width; + head.biHeight = cinfo.output_height; + info.dwType = CXIMAGE_FORMAT_JPG; + jpeg_destroy_decompress(&cinfo); + return true; + } + + /* Step 5: Start decompressor */ + jpeg_start_decompress(&cinfo); + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + */ + //Create the image using output dimensions + //Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); + Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); + + if (!pDib) longjmp(jerr.setjmp_buffer, 1); // check if the image has been created + + if (is_exif){ +#if CXIMAGEJPG_SUPPORT_EXIF + if ((m_exifinfo.Xresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0)) + SetXDPI((long)(m_exifinfo.Xresolution/m_exifinfo.ResolutionUnit)); + if ((m_exifinfo.Yresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0)) + SetYDPI((long)(m_exifinfo.Yresolution/m_exifinfo.ResolutionUnit)); +#endif + } else { + switch (cinfo.density_unit) { + case 0: // [andy] fix for aspect ratio... + if((cinfo.Y_density > 0) && (cinfo.X_density > 0)){ + SetYDPI((long)(GetXDPI()*(float(cinfo.Y_density)/float(cinfo.X_density)))); + } + break; + case 2: // [andy] fix: cinfo.X/Y_density is pixels per centimeter + SetXDPI((long)floor(cinfo.X_density * 2.54 + 0.5)); + SetYDPI((long)floor(cinfo.Y_density * 2.54 + 0.5)); + break; + default: + SetXDPI(cinfo.X_density); + SetYDPI(cinfo.Y_density); + } + } + + if (cinfo.out_color_space==JCS_GRAYSCALE){ + SetGrayPalette(); + head.biClrUsed =256; + } else { + if (cinfo.quantize_colors){ + SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]); + head.biClrUsed=cinfo.actual_number_of_colors; + } else { + head.biClrUsed=0; + } + } + + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + iter.Upset(); + while (cinfo.output_scanline < cinfo.output_height) { + + if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // - cancel decoding + + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + // info.nProgress = (long)(100*cinfo.output_scanline/cinfo.output_height); + // Step 6a: CMYK->RGB */ + if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){ + BYTE k,*dst,*src; + dst=iter.GetRow(); + src=buffer[0]; + for(long x3=0,x4=0; x3<(long)info.dwEffWidth && x4 Step 7A: Swap red and blue components + // not necessary if swapped red and blue definition in jmorecfg.h;ln322 + if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){ + BYTE* r0=GetBits(); + for(long y=0;y - cancel decoding + RGBtoBGR(r0,3*head.biWidth); + r0+=info.dwEffWidth; + } + } + + /* Step 8: Release JPEG decompression object */ + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageJPG::Encode(CxFile * hFile) +{ + if (EncodeSafeCheck(hFile)) return false; + + if (head.biClrUsed!=0 && !IsGrayScale()){ + strcpy(info.szLastError,"JPEG can save only RGB or GreyScale images"); + return false; + } + + // necessary for EXIF, and for roll backs + long pos=hFile->Tell(); + + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + //struct jpeg_error_mgr jerr; + /* We use our private extension JPEG error handler. */ + struct jpg_error_mgr jerr; + jerr.buffer=info.szLastError; + /* More stuff */ + int row_stride; /* physical row width in image buffer */ + JSAMPARRAY buffer; /* Output row buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + //cinfo.err = jpeg_std_error(&jerr); + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = ima_jpeg_error_exit; + + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + strcpy(info.szLastError, jerr.buffer); // + jpeg_destroy_compress(&cinfo); + return 0; + } + + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + + //jpeg_stdio_dest(&cinfo, outfile); + CxFileJpg dest(hFile); + cinfo.dest = &dest; + + /* Step 3: set parameters for compression */ + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = GetWidth(); // image width and height, in pixels + cinfo.image_height = GetHeight(); + + if (IsGrayScale()){ + cinfo.input_components = 1; // # of color components per pixel + cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */ + } else { + cinfo.input_components = 3; // # of color components per pixel + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + } + + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + +//#ifdef C_ARITH_CODING_SUPPORTED + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_ARITHMETIC) != 0) + cinfo.arith_code = TRUE; +//#endif + +//#ifdef ENTROPY_OPT_SUPPORTED + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_OPTIMIZE) != 0) + cinfo.optimize_coding = TRUE; +//#endif + + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_GRAYSCALE) != 0) + jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE); + + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SMOOTHING) != 0) + cinfo.smoothing_factor = m_nSmoothing; + + jpeg_set_quality(&cinfo, GetJpegQuality(), (GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_BASELINE) != 0); + +//#ifdef C_PROGRESSIVE_SUPPORTED + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_PROGRESSIVE) != 0) + jpeg_simple_progression(&cinfo); +//#endif + +#ifdef C_LOSSLESS_SUPPORTED + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_LOSSLESS) != 0) + jpeg_simple_lossless(&cinfo, m_nPredictor, m_nPointTransform); +#endif + + //SetCodecOption(ENCODE_SUBSAMPLE_444 | GetCodecOption(CXIMAGE_FORMAT_JPG),CXIMAGE_FORMAT_JPG); + + // 2x2, 1x1, 1x1 (4:1:1) : High (default sub sampling) + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_422) != 0){ + // 2x1, 1x1, 1x1 (4:2:2) : Medium + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } + + if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_444) != 0){ + // 1x1 1x1 1x1 (4:4:4) : None + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } + + cinfo.density_unit=1; + cinfo.X_density=(unsigned short)GetXDPI(); + cinfo.Y_density=(unsigned short)GetYDPI(); + + /* Step 4: Start compressor */ + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = info.dwEffWidth; /* JSAMPLEs per row in image_buffer */ + + // "8+row_stride" fix heap deallocation problem during debug??? + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, 8+row_stride, 1); + + CImageIterator iter(this); + + iter.Upset(); + while (cinfo.next_scanline < cinfo.image_height) { + // info.nProgress = (long)(100*cinfo.next_scanline/cinfo.image_height); + iter.GetRow(buffer[0], row_stride); + // not necessary if swapped red and blue definition in jmorecfg.h;ln322 + if (head.biClrUsed==0){ // swap R & B for RGB images + RGBtoBGR(buffer[0], row_stride); // Lance : 1998/09/01 : Bug ID: EXP-2.1.1-9 + } + iter.PrevRow(); + (void) jpeg_write_scanlines(&cinfo, buffer, 1); + } + + /* Step 6: Finish compression */ + jpeg_finish_compress(&cinfo); + + /* Step 7: release JPEG compression object */ + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + +#if CXIMAGEJPG_SUPPORT_EXIF + if (m_exif && m_exif->m_exifinfo->IsExif){ + // discard useless sections (if any) read from original image + m_exif->DiscardAllButExif(); + // read new created image, to split the sections + hFile->Seek(pos,SEEK_SET); + m_exif->DecodeExif(hFile,EXIF_READ_IMAGE); + // save back the image, adding EXIF section + hFile->Seek(pos,SEEK_SET); + m_exif->EncodeExif(hFile); + } +#endif + + + /* And we're done! */ + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_JPG + diff --git a/utilities/CxImage/ximajpg.h b/utilities/CxImage/ximajpg.h index 899c6bc..de7835a 100644 --- a/utilities/CxImage/ximajpg.h +++ b/utilities/CxImage/ximajpg.h @@ -1,317 +1,317 @@ -/* - * File: ximajpg.h - * Purpose: JPG Image Class Loader and Writer - */ -/* ========================================================== - * CxImageJPG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes - * - * Special thanks to Chris Shearer Cooper for CxFileJpg tips & code - * - * EXIF support based on jhead-1.8 by Matthias Wandel - * - * original CImageJPG and CImageIterator implementation are: - * Copyright: (c) 1995, Alejandro Aguilar Sierra - * - * This software is based in part on the work of the Independent JPEG Group. - * Copyright (C) 1991-1998, Thomas G. Lane. - * ========================================================== - */ -#if !defined(__ximaJPEG_h) -#define __ximaJPEG_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_JPG - -#define CXIMAGEJPG_SUPPORT_EXIF 1 - -extern "C" { - #include "../jpeg/jpeglib.h" - #include "../jpeg/jerror.h" -} - -class DLL_EXP CxImageJPG: public CxImage -{ -public: - CxImageJPG(); - ~CxImageJPG(); - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JPG);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JPG);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE - -/* - * EXIF support based on jhead-1.8 by Matthias Wandel - */ - -#if CXIMAGEJPG_SUPPORT_EXIF - -#define MAX_COMMENT 1000 -#define MAX_SECTIONS 20 - -typedef struct tag_ExifInfo { - char Version [5]; - char CameraMake [32]; - char CameraModel [40]; - char DateTime [20]; - int Height, Width; - int Orientation; - int IsColor; - int Process; - int FlashUsed; - float FocalLength; - float ExposureTime; - float ApertureFNumber; - float Distance; - float CCDWidth; - float ExposureBias; - int Whitebalance; - int MeteringMode; - int ExposureProgram; - int ISOequivalent; - int CompressionLevel; - float FocalplaneXRes; - float FocalplaneYRes; - float FocalplaneUnits; - float Xresolution; - float Yresolution; - float ResolutionUnit; - float Brightness; - char Comments[MAX_COMMENT]; - - unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */ - unsigned ThumbnailSize; /* Size of thumbnail. */ - - bool IsExif; -} EXIFINFO; - -//-------------------------------------------------------------------------- -// JPEG markers consist of one or more 0xFF bytes, followed by a marker -// code byte (which is not an FF). Here are the marker codes of interest -// in this program. (See jdmarker.c for a more complete list.) -//-------------------------------------------------------------------------- - -#define M_SOF0 0xC0 // Start Of Frame N -#define M_SOF1 0xC1 // N indicates which compression process -#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use -#define M_SOF3 0xC3 -#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers -#define M_SOF6 0xC6 -#define M_SOF7 0xC7 -#define M_SOF9 0xC9 -#define M_SOF10 0xCA -#define M_SOF11 0xCB -#define M_SOF13 0xCD -#define M_SOF14 0xCE -#define M_SOF15 0xCF -#define M_SOI 0xD8 // Start Of Image (beginning of datastream) -#define M_EOI 0xD9 // End Of Image (end of datastream) -#define M_SOS 0xDA // Start Of Scan (begins compressed data) -#define M_JFIF 0xE0 // Jfif marker -#define M_EXIF 0xE1 // Exif marker -#define M_COM 0xFE // COMment - -#define PSEUDO_IMAGE_MARKER 0x123; // Extra value. - -#define EXIF_READ_EXIF 0x01 -#define EXIF_READ_IMAGE 0x02 -#define EXIF_READ_ALL 0x03 - -class DLL_EXP CxExifInfo -{ - -typedef struct tag_Section_t{ - BYTE* Data; - int Type; - unsigned Size; -} Section_t; - -public: - EXIFINFO* m_exifinfo; - char m_szLastError[256]; - CxExifInfo(EXIFINFO* info = NULL); - ~CxExifInfo(); - bool DecodeExif(CxFile * hFile, int nReadMode = EXIF_READ_EXIF); - bool EncodeExif(CxFile * hFile); - void DiscardAllButExif(); -protected: - bool process_EXIF(unsigned char * CharBuf, unsigned int length); - void process_COM (const BYTE * Data, int length); - void process_SOFn (const BYTE * Data, int marker); - int Get16u(void * Short); - int Get16m(void * Short); - long Get32s(void * Long); - unsigned long Get32u(void * Long); - double ConvertAnyFormat(void * ValuePtr, int Format); - void* FindSection(int SectionType); - bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, - EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP, int NestingLevel=0); - int ExifImageWidth; - int MotorolaOrder; - Section_t Sections[MAX_SECTIONS]; - int SectionsRead; - bool freeinfo; -}; - - CxExifInfo* m_exif; - EXIFINFO m_exifinfo; - bool DecodeExif(CxFile * hFile); - bool DecodeExif(FILE * hFile) { CxIOFile file(hFile); return DecodeExif(&file); } - -#endif //CXIMAGEJPG_SUPPORT_EXIF - -//////////////////////////////////////////////////////////////////////////////////////// -////////////////////// C x F i l e J p g //////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////// - -// thanks to Chris Shearer Cooper -class CxFileJpg : public jpeg_destination_mgr, public jpeg_source_mgr - { -public: - enum { eBufSize = 4096 }; - - CxFileJpg(CxFile* pFile) - { - m_pFile = pFile; - - init_destination = InitDestination; - empty_output_buffer = EmptyOutputBuffer; - term_destination = TermDestination; - - init_source = InitSource; - fill_input_buffer = FillInputBuffer; - skip_input_data = SkipInputData; - resync_to_restart = jpeg_resync_to_restart; // use default method - term_source = TermSource; - next_input_byte = NULL; //* => next byte to read from buffer - bytes_in_buffer = 0; //* # of bytes remaining in buffer - - m_pBuffer = new unsigned char[eBufSize]; - } - ~CxFileJpg() - { - delete [] m_pBuffer; - } - - static void InitDestination(j_compress_ptr cinfo) - { - CxFileJpg* pDest = (CxFileJpg*)cinfo->dest; - pDest->next_output_byte = pDest->m_pBuffer; - pDest->free_in_buffer = eBufSize; - } - - static boolean EmptyOutputBuffer(j_compress_ptr cinfo) - { - CxFileJpg* pDest = (CxFileJpg*)cinfo->dest; - if (pDest->m_pFile->Write(pDest->m_pBuffer,1,eBufSize)!=(size_t)eBufSize) - ERREXIT(cinfo, JERR_FILE_WRITE); - pDest->next_output_byte = pDest->m_pBuffer; - pDest->free_in_buffer = eBufSize; - return TRUE; - } - - static void TermDestination(j_compress_ptr cinfo) - { - CxFileJpg* pDest = (CxFileJpg*)cinfo->dest; - size_t datacount = eBufSize - pDest->free_in_buffer; - /* Write any data remaining in the buffer */ - if (datacount > 0) { - if (!pDest->m_pFile->Write(pDest->m_pBuffer,1,datacount)) - ERREXIT(cinfo, JERR_FILE_WRITE); - } - pDest->m_pFile->Flush(); - /* Make sure we wrote the output file OK */ - if (pDest->m_pFile->Error()) ERREXIT(cinfo, JERR_FILE_WRITE); - return; - } - - static void InitSource(j_decompress_ptr cinfo) - { - CxFileJpg* pSource = (CxFileJpg*)cinfo->src; - pSource->m_bStartOfFile = TRUE; - } - - static boolean FillInputBuffer(j_decompress_ptr cinfo) - { - size_t nbytes; - CxFileJpg* pSource = (CxFileJpg*)cinfo->src; - nbytes = pSource->m_pFile->Read(pSource->m_pBuffer,1,eBufSize); - if (nbytes <= 0){ - if (pSource->m_bStartOfFile) //* Treat empty input file as fatal error - ERREXIT(cinfo, JERR_INPUT_EMPTY); - WARNMS(cinfo, JWRN_JPEG_EOF); - // Insert a fake EOI marker - pSource->m_pBuffer[0] = (JOCTET) 0xFF; - pSource->m_pBuffer[1] = (JOCTET) JPEG_EOI; - nbytes = 2; - } - pSource->next_input_byte = pSource->m_pBuffer; - pSource->bytes_in_buffer = nbytes; - pSource->m_bStartOfFile = FALSE; - return TRUE; - } - - static void SkipInputData(j_decompress_ptr cinfo, long num_bytes) - { - CxFileJpg* pSource = (CxFileJpg*)cinfo->src; - if (num_bytes > 0){ - while (num_bytes > (long)pSource->bytes_in_buffer){ - num_bytes -= (long)pSource->bytes_in_buffer; - FillInputBuffer(cinfo); - // note we assume that fill_input_buffer will never return FALSE, - // so suspension need not be handled. - } - pSource->next_input_byte += (size_t) num_bytes; - pSource->bytes_in_buffer -= (size_t) num_bytes; - } - } - - static void TermSource(j_decompress_ptr /*cinfo*/) - { - return; - } -protected: - CxFile *m_pFile; - unsigned char *m_pBuffer; - bool m_bStartOfFile; -}; - -public: - enum CODEC_OPTION - { - ENCODE_BASELINE = 0x1, - ENCODE_ARITHMETIC = 0x2, - ENCODE_GRAYSCALE = 0x4, - ENCODE_OPTIMIZE = 0x8, - ENCODE_PROGRESSIVE = 0x10, - ENCODE_LOSSLESS = 0x20, - ENCODE_SMOOTHING = 0x40, - DECODE_GRAYSCALE = 0x80, - DECODE_QUANTIZE = 0x100, - DECODE_DITHER = 0x200, - DECODE_ONEPASS = 0x400, - DECODE_NOSMOOTH = 0x800, - ENCODE_SUBSAMPLE_422 = 0x1000, - ENCODE_SUBSAMPLE_444 = 0x2000 - }; - - int m_nPredictor; - int m_nPointTransform; - int m_nSmoothing; - int m_nQuantize; - J_DITHER_MODE m_nDither; - -}; - -#endif - -#endif +/* + * File: ximajpg.h + * Purpose: JPG Image Class Loader and Writer + */ +/* ========================================================== + * CxImageJPG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes + * + * Special thanks to Chris Shearer Cooper for CxFileJpg tips & code + * + * EXIF support based on jhead-1.8 by Matthias Wandel + * + * original CImageJPG and CImageIterator implementation are: + * Copyright: (c) 1995, Alejandro Aguilar Sierra + * + * This software is based in part on the work of the Independent JPEG Group. + * Copyright (C) 1991-1998, Thomas G. Lane. + * ========================================================== + */ +#if !defined(__ximaJPEG_h) +#define __ximaJPEG_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_JPG + +#define CXIMAGEJPG_SUPPORT_EXIF 1 + +extern "C" { + #include "../jpeg/jpeglib.h" + #include "../jpeg/jerror.h" +} + +class DLL_EXP CxImageJPG: public CxImage +{ +public: + CxImageJPG(); + ~CxImageJPG(); + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JPG);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JPG);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE + +/* + * EXIF support based on jhead-1.8 by Matthias Wandel + */ + +#if CXIMAGEJPG_SUPPORT_EXIF + +#define MAX_COMMENT 1000 +#define MAX_SECTIONS 20 + +typedef struct tag_ExifInfo { + char Version [5]; + char CameraMake [32]; + char CameraModel [40]; + char DateTime [20]; + int Height, Width; + int Orientation; + int IsColor; + int Process; + int FlashUsed; + float FocalLength; + float ExposureTime; + float ApertureFNumber; + float Distance; + float CCDWidth; + float ExposureBias; + int Whitebalance; + int MeteringMode; + int ExposureProgram; + int ISOequivalent; + int CompressionLevel; + float FocalplaneXRes; + float FocalplaneYRes; + float FocalplaneUnits; + float Xresolution; + float Yresolution; + float ResolutionUnit; + float Brightness; + char Comments[MAX_COMMENT]; + + unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */ + unsigned ThumbnailSize; /* Size of thumbnail. */ + + bool IsExif; +} EXIFINFO; + +//-------------------------------------------------------------------------- +// JPEG markers consist of one or more 0xFF bytes, followed by a marker +// code byte (which is not an FF). Here are the marker codes of interest +// in this program. (See jdmarker.c for a more complete list.) +//-------------------------------------------------------------------------- + +#define M_SOF0 0xC0 // Start Of Frame N +#define M_SOF1 0xC1 // N indicates which compression process +#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 // Start Of Image (beginning of datastream) +#define M_EOI 0xD9 // End Of Image (end of datastream) +#define M_SOS 0xDA // Start Of Scan (begins compressed data) +#define M_JFIF 0xE0 // Jfif marker +#define M_EXIF 0xE1 // Exif marker +#define M_COM 0xFE // COMment + +#define PSEUDO_IMAGE_MARKER 0x123; // Extra value. + +#define EXIF_READ_EXIF 0x01 +#define EXIF_READ_IMAGE 0x02 +#define EXIF_READ_ALL 0x03 + +class DLL_EXP CxExifInfo +{ + +typedef struct tag_Section_t{ + BYTE* Data; + int Type; + unsigned Size; +} Section_t; + +public: + EXIFINFO* m_exifinfo; + char m_szLastError[256]; + CxExifInfo(EXIFINFO* info = NULL); + ~CxExifInfo(); + bool DecodeExif(CxFile * hFile, int nReadMode = EXIF_READ_EXIF); + bool EncodeExif(CxFile * hFile); + void DiscardAllButExif(); +protected: + bool process_EXIF(unsigned char * CharBuf, unsigned int length); + void process_COM (const BYTE * Data, int length); + void process_SOFn (const BYTE * Data, int marker); + int Get16u(void * Short); + int Get16m(void * Short); + long Get32s(void * Long); + unsigned long Get32u(void * Long); + double ConvertAnyFormat(void * ValuePtr, int Format); + void* FindSection(int SectionType); + bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, + EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP, int NestingLevel=0); + int ExifImageWidth; + int MotorolaOrder; + Section_t Sections[MAX_SECTIONS]; + int SectionsRead; + bool freeinfo; +}; + + CxExifInfo* m_exif; + EXIFINFO m_exifinfo; + bool DecodeExif(CxFile * hFile); + bool DecodeExif(FILE * hFile) { CxIOFile file(hFile); return DecodeExif(&file); } + +#endif //CXIMAGEJPG_SUPPORT_EXIF + +//////////////////////////////////////////////////////////////////////////////////////// +////////////////////// C x F i l e J p g //////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// + +// thanks to Chris Shearer Cooper +class CxFileJpg : public jpeg_destination_mgr, public jpeg_source_mgr + { +public: + enum { eBufSize = 4096 }; + + CxFileJpg(CxFile* pFile) + { + m_pFile = pFile; + + init_destination = InitDestination; + empty_output_buffer = EmptyOutputBuffer; + term_destination = TermDestination; + + init_source = InitSource; + fill_input_buffer = FillInputBuffer; + skip_input_data = SkipInputData; + resync_to_restart = jpeg_resync_to_restart; // use default method + term_source = TermSource; + next_input_byte = NULL; //* => next byte to read from buffer + bytes_in_buffer = 0; //* # of bytes remaining in buffer + + m_pBuffer = new unsigned char[eBufSize]; + } + ~CxFileJpg() + { + delete [] m_pBuffer; + } + + static void InitDestination(j_compress_ptr cinfo) + { + CxFileJpg* pDest = (CxFileJpg*)cinfo->dest; + pDest->next_output_byte = pDest->m_pBuffer; + pDest->free_in_buffer = eBufSize; + } + + static boolean EmptyOutputBuffer(j_compress_ptr cinfo) + { + CxFileJpg* pDest = (CxFileJpg*)cinfo->dest; + if (pDest->m_pFile->Write(pDest->m_pBuffer,1,eBufSize)!=(size_t)eBufSize) + ERREXIT(cinfo, JERR_FILE_WRITE); + pDest->next_output_byte = pDest->m_pBuffer; + pDest->free_in_buffer = eBufSize; + return TRUE; + } + + static void TermDestination(j_compress_ptr cinfo) + { + CxFileJpg* pDest = (CxFileJpg*)cinfo->dest; + size_t datacount = eBufSize - pDest->free_in_buffer; + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (!pDest->m_pFile->Write(pDest->m_pBuffer,1,datacount)) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + pDest->m_pFile->Flush(); + /* Make sure we wrote the output file OK */ + if (pDest->m_pFile->Error()) ERREXIT(cinfo, JERR_FILE_WRITE); + return; + } + + static void InitSource(j_decompress_ptr cinfo) + { + CxFileJpg* pSource = (CxFileJpg*)cinfo->src; + pSource->m_bStartOfFile = TRUE; + } + + static boolean FillInputBuffer(j_decompress_ptr cinfo) + { + size_t nbytes; + CxFileJpg* pSource = (CxFileJpg*)cinfo->src; + nbytes = pSource->m_pFile->Read(pSource->m_pBuffer,1,eBufSize); + if (nbytes <= 0){ + if (pSource->m_bStartOfFile) //* Treat empty input file as fatal error + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + // Insert a fake EOI marker + pSource->m_pBuffer[0] = (JOCTET) 0xFF; + pSource->m_pBuffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + pSource->next_input_byte = pSource->m_pBuffer; + pSource->bytes_in_buffer = nbytes; + pSource->m_bStartOfFile = FALSE; + return TRUE; + } + + static void SkipInputData(j_decompress_ptr cinfo, long num_bytes) + { + CxFileJpg* pSource = (CxFileJpg*)cinfo->src; + if (num_bytes > 0){ + while (num_bytes > (long)pSource->bytes_in_buffer){ + num_bytes -= (long)pSource->bytes_in_buffer; + FillInputBuffer(cinfo); + // note we assume that fill_input_buffer will never return FALSE, + // so suspension need not be handled. + } + pSource->next_input_byte += (size_t) num_bytes; + pSource->bytes_in_buffer -= (size_t) num_bytes; + } + } + + static void TermSource(j_decompress_ptr /*cinfo*/) + { + return; + } +protected: + CxFile *m_pFile; + unsigned char *m_pBuffer; + bool m_bStartOfFile; +}; + +public: + enum CODEC_OPTION + { + ENCODE_BASELINE = 0x1, + ENCODE_ARITHMETIC = 0x2, + ENCODE_GRAYSCALE = 0x4, + ENCODE_OPTIMIZE = 0x8, + ENCODE_PROGRESSIVE = 0x10, + ENCODE_LOSSLESS = 0x20, + ENCODE_SMOOTHING = 0x40, + DECODE_GRAYSCALE = 0x80, + DECODE_QUANTIZE = 0x100, + DECODE_DITHER = 0x200, + DECODE_ONEPASS = 0x400, + DECODE_NOSMOOTH = 0x800, + ENCODE_SUBSAMPLE_422 = 0x1000, + ENCODE_SUBSAMPLE_444 = 0x2000 + }; + + int m_nPredictor; + int m_nPointTransform; + int m_nSmoothing; + int m_nQuantize; + J_DITHER_MODE m_nDither; + +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximalpha.cpp b/utilities/CxImage/ximalpha.cpp index 8233dcb..823c3ce 100644 --- a/utilities/CxImage/ximalpha.cpp +++ b/utilities/CxImage/ximalpha.cpp @@ -1,365 +1,365 @@ -// xImalpha.cpp : Alpha channel functions -/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_ALPHA - -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa AlphaSetMax - */ -BYTE CxImage::AlphaGetMax() const -{ - return info.nAlphaMax; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets global Alpha (opacity) value applied to the whole image, - * valid only for painting functions. - * \param nAlphaMax: can be from 0 to 255 - */ -void CxImage::AlphaSetMax(BYTE nAlphaMax) -{ - info.nAlphaMax=nAlphaMax; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Checks if the image has a valid alpha channel. - */ -bool CxImage::AlphaIsValid() -{ - return pAlpha!=0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Enables the alpha palette, so the Draw() function changes its behavior. - */ -void CxImage::AlphaPaletteEnable(bool enable) -{ - info.bAlphaPaletteEnabled=enable; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * True if the alpha palette is enabled for painting. - */ -bool CxImage::AlphaPaletteIsEnabled() -{ - return info.bAlphaPaletteEnabled; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets the alpha channel to full transparent. AlphaSet(0) has the same effect - */ -void CxImage::AlphaClear() -{ - if (pAlpha) memset(pAlpha,0,head.biWidth * head.biHeight); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets the alpha level for the whole image. - * \param level : from 0 (transparent) to 255 (opaque) - */ -void CxImage::AlphaSet(BYTE level) -{ - if (pAlpha) memset(pAlpha,level,head.biWidth * head.biHeight); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Allocates an empty (opaque) alpha channel. - */ -bool CxImage::AlphaCreate() -{ - if (pAlpha==NULL) { - pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight); - if (pAlpha) memset(pAlpha,255,head.biWidth * head.biHeight); - } - return (pAlpha!=0); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::AlphaDelete() -{ - if (pAlpha) { free(pAlpha); pAlpha=0; } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::AlphaInvert() -{ - if (pAlpha) { - BYTE *iSrc=pAlpha; - long n=head.biHeight*head.biWidth; - for(long i=0; i < n; i++){ - *iSrc=(BYTE)~(*(iSrc)); - iSrc++; - } - } -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Imports an existing alpa channel from another image with the same width and height. - */ -bool CxImage::AlphaCopy(CxImage &from) -{ - if (from.pAlpha == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false; - if (pAlpha==NULL) pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight); - if (pAlpha==NULL) return false; - memcpy(pAlpha,from.pAlpha,head.biWidth * head.biHeight); - info.nAlphaMax=from.info.nAlphaMax; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Creates the alpha channel from a gray scale image. - */ -bool CxImage::AlphaSet(CxImage &from) -{ - if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false; - if (pAlpha==NULL) pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight); - BYTE* src = from.info.pImage; - BYTE* dst = pAlpha; - if (src==NULL || dst==NULL) return false; - for (long y=0; y>8); - c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8); - c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8); - BlindSetPixelColor(x,y,c); - } - } - AlphaDelete(); - } else { - CxImage tmp(head.biWidth,head.biHeight,24); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return; - } - - for(long y=0; y>8); - c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8); - c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8); - tmp.BlindSetPixelColor(x,y,c); - } - } - Transfer(tmp); - } - return; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::AlphaFlip() -{ - if (!pAlpha) return false; - - BYTE *buff = (BYTE*)malloc(head.biWidth); - if (!buff) return false; - - BYTE *iSrc,*iDst; - iSrc = pAlpha + (head.biHeight-1)*head.biWidth; - iDst = pAlpha; - for (long i=0; i<(head.biHeight/2); ++i) - { - memcpy(buff, iSrc, head.biWidth); - memcpy(iSrc, iDst, head.biWidth); - memcpy(iDst, buff, head.biWidth); - iSrc-=head.biWidth; - iDst+=head.biWidth; - } - - free(buff); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::AlphaMirror() -{ - if (!pAlpha) return false; - BYTE* pAlpha2 = (BYTE*)malloc(head.biWidth * head.biHeight); - if (!pAlpha2) return false; - BYTE *iSrc,*iDst; - long wdt=head.biWidth-1; - iSrc=pAlpha + wdt; - iDst=pAlpha2; - for(long y=0; y < head.biHeight; y++){ - for(long x=0; x <= wdt; x++) - *(iDst+x)=*(iSrc-x); - iSrc+=head.biWidth; - iDst+=head.biWidth; - } - free(pAlpha); - pAlpha=pAlpha2; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Exports the alpha channel in a 8bpp grayscale image. - */ -bool CxImage::AlphaSplit(CxImage *dest) -{ - if (!pAlpha || !dest) return false; - - CxImage tmp(head.biWidth,head.biHeight,8); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - for(long y=0; yTransfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Exports the alpha palette channel in a 8bpp grayscale image. - */ -bool CxImage::AlphaPaletteSplit(CxImage *dest) -{ - if (!AlphaPaletteIsValid() || !dest) return false; - - CxImage tmp(head.biWidth,head.biHeight,8); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - for(long y=0; yTransfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Merge in the alpha layer the transparent color mask - * (previously set with SetTransColor or SetTransIndex) - */ -bool CxImage::AlphaFromTransparency() -{ - if (!IsValid() || !IsTransparent()) - return false; - - AlphaCreate(); - - for(long y=0; y>8); + c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8); + c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8); + BlindSetPixelColor(x,y,c); + } + } + AlphaDelete(); + } else { + CxImage tmp(head.biWidth,head.biHeight,24); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return; + } + + for(long y=0; y>8); + c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8); + c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8); + tmp.BlindSetPixelColor(x,y,c); + } + } + Transfer(tmp); + } + return; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::AlphaFlip() +{ + if (!pAlpha) return false; + + BYTE *buff = (BYTE*)malloc(head.biWidth); + if (!buff) return false; + + BYTE *iSrc,*iDst; + iSrc = pAlpha + (head.biHeight-1)*head.biWidth; + iDst = pAlpha; + for (long i=0; i<(head.biHeight/2); ++i) + { + memcpy(buff, iSrc, head.biWidth); + memcpy(iSrc, iDst, head.biWidth); + memcpy(iDst, buff, head.biWidth); + iSrc-=head.biWidth; + iDst+=head.biWidth; + } + + free(buff); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::AlphaMirror() +{ + if (!pAlpha) return false; + BYTE* pAlpha2 = (BYTE*)malloc(head.biWidth * head.biHeight); + if (!pAlpha2) return false; + BYTE *iSrc,*iDst; + long wdt=head.biWidth-1; + iSrc=pAlpha + wdt; + iDst=pAlpha2; + for(long y=0; y < head.biHeight; y++){ + for(long x=0; x <= wdt; x++) + *(iDst+x)=*(iSrc-x); + iSrc+=head.biWidth; + iDst+=head.biWidth; + } + free(pAlpha); + pAlpha=pAlpha2; + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Exports the alpha channel in a 8bpp grayscale image. + */ +bool CxImage::AlphaSplit(CxImage *dest) +{ + if (!pAlpha || !dest) return false; + + CxImage tmp(head.biWidth,head.biHeight,8); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + for(long y=0; yTransfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Exports the alpha palette channel in a 8bpp grayscale image. + */ +bool CxImage::AlphaPaletteSplit(CxImage *dest) +{ + if (!AlphaPaletteIsValid() || !dest) return false; + + CxImage tmp(head.biWidth,head.biHeight,8); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + for(long y=0; yTransfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Merge in the alpha layer the transparent color mask + * (previously set with SetTransColor or SetTransIndex) + */ +bool CxImage::AlphaFromTransparency() +{ + if (!IsValid() || !IsTransparent()) + return false; + + AlphaCreate(); + + for(long y=0; y info.nNumLayers ) position = info.nNumLayers; - - CxImage** ptmp = new CxImage*[info.nNumLayers + 1]; - if (ptmp==0) return false; - - int i=0; - for (int n=0; ninfo.pParent = this; - } else { - free(ptmp); - return false; - } - - info.nNumLayers++; - delete [] ppLayers; - ppLayers = ptmp; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Deletes a layer. If position is less than 0, the last layer will be deleted - */ -bool CxImage::LayerDelete(long position) -{ - if ( position >= info.nNumLayers ) return false; - if ( position < 0) position = info.nNumLayers - 1; - if ( position < 0) return false; - - if (info.nNumLayers>1){ - - CxImage** ptmp = new CxImage*[info.nNumLayers - 1]; - if (ptmp==0) return false; - - int i=0; - for (int n=0; n= info.nNumLayers ) return NULL; - if ( position < 0) position = info.nNumLayers - 1; - return ppLayers[position]; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_LAYERS +// xImaLyr.cpp : Layers functions +/* 21/04/2003 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_LAYERS + +//////////////////////////////////////////////////////////////////////////////// +/** + * If the object is an internal layer, GetParent return its parent in the hierarchy. + */ +CxImage* CxImage::GetParent() const +{ + return info.pParent; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Number of layers allocated directly by the object. + */ +long CxImage::GetNumLayers() const +{ + return info.nNumLayers; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Creates an empty layer. If position is less than 0, the new layer will be placed in the last position + */ +bool CxImage::LayerCreate(long position) +{ + if ( position < 0 || position > info.nNumLayers ) position = info.nNumLayers; + + CxImage** ptmp = new CxImage*[info.nNumLayers + 1]; + if (ptmp==0) return false; + + int i=0; + for (int n=0; ninfo.pParent = this; + } else { + free(ptmp); + return false; + } + + info.nNumLayers++; + delete [] ppLayers; + ppLayers = ptmp; + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Deletes a layer. If position is less than 0, the last layer will be deleted + */ +bool CxImage::LayerDelete(long position) +{ + if ( position >= info.nNumLayers ) return false; + if ( position < 0) position = info.nNumLayers - 1; + if ( position < 0) return false; + + if (info.nNumLayers>1){ + + CxImage** ptmp = new CxImage*[info.nNumLayers - 1]; + if (ptmp==0) return false; + + int i=0; + for (int n=0; n= info.nNumLayers ) return NULL; + if ( position < 0) position = info.nNumLayers - 1; + return ppLayers[position]; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_LAYERS diff --git a/utilities/CxImage/ximamng.cpp b/utilities/CxImage/ximamng.cpp index cc86f4e..865c490 100644 --- a/utilities/CxImage/ximamng.cpp +++ b/utilities/CxImage/ximamng.cpp @@ -1,430 +1,430 @@ -/* - * File: ximamng.cpp - * Purpose: Platform Independent MNG Image Class Loader and Writer - * Author: 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximamng.h" - -#if CXIMAGE_SUPPORT_MNG - -//////////////////////////////////////////////////////////////////////////////// -// callbacks for the mng decoder: -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -// memory allocation; data must be zeroed -static mng_ptr -mymngalloc( mng_uint32 size ) -{ - return (mng_ptr)calloc(1, size); -} - -//////////////////////////////////////////////////////////////////////////////// -// memory deallocation -static void mymngfree(mng_ptr p, mng_uint32 size) -{ - free(p); -} - -//////////////////////////////////////////////////////////////////////////////// -// Stream open/close: -// since the user is responsible for opening and closing the file, -// we leave the default implementation open -static mng_bool mymngopenstream(mng_handle mng) { return MNG_TRUE; } -static mng_bool mymngopenstreamwrite(mng_handle mng) { return MNG_TRUE; } -static mng_bool mymngclosestream(mng_handle mng) { return MNG_TRUE; } - -//////////////////////////////////////////////////////////////////////////////// -// feed data to the decoder -static mng_bool mymngreadstream(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread) -{ - mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); - // read the requested amount of data from the file - *bytesread = mymng->file->Read( buffer, sizeof(BYTE), size); - return MNG_TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -static mng_bool mymngwritestream (mng_handle mng, mng_ptr pBuf, mng_uint32 iSize, mng_uint32 *iWritten) -{ - mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); - // write it - *iWritten = mymng->file->Write (pBuf, 1, iSize); - return MNG_TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// the header's been read. set up the display stuff -static mng_bool mymngprocessheader( mng_handle mng, mng_uint32 width, mng_uint32 height ) -{ - // normally the image buffer is allocated here, - // but in this module we don't know nothing about - // the final environment. - - mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); - - mymng->width = width; - mymng->height = height; - mymng->bpp = 24; - mymng->effwdt = ((((width * mymng->bpp) + 31) >> 5) << 2); - - if (mng->bUseBKGD){ - mymng->nBkgndIndex = 0; - mymng->nBkgndColor.rgbRed = mng->iBGred >> 8; - mymng->nBkgndColor.rgbGreen =mng->iBGgreen >> 8; - mymng->nBkgndColor.rgbBlue = mng->iBGblue >> 8; - } - - mymng->image = (BYTE*)malloc(height * mymng->effwdt); - - // tell the mng decoder about our bit-depth choice -#if CXIMAGE_SUPPORT_ALPHA - mng_set_canvasstyle( mng, MNG_CANVAS_RGB8_A8 ); - mymng->alpha = (BYTE*)malloc(height * width); -#else - mng_set_canvasstyle( mng, MNG_CANVAS_BGR8); - mymng->alpha = NULL; -#endif - return MNG_TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// return a row pointer for the decoder to fill -static mng_ptr mymnggetcanvasline( mng_handle mng, mng_uint32 line ) -{ - mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); - return (mng_ptr)(mymng->image + (mymng->effwdt * (mymng->height - 1 - line))); -} -//////////////////////////////////////////////////////////////////////////////// -// return a row pointer for the decoder to fill for alpha channel -static mng_ptr mymnggetalphaline( mng_handle mng, mng_uint32 line ) -{ - mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); - return (mng_ptr)(mymng->alpha + (mymng->width * (mymng->height - 1 - line))); -} - -//////////////////////////////////////////////////////////////////////////////// -// timer -static mng_uint32 mymnggetticks(mng_handle mng) -{ -#ifdef WIN32 - return (mng_uint32)GetTickCount(); -#else - return 0; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// Refresh: actual frame need to be updated (Invalidate) -static mng_bool mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h) -{ -// mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); - return MNG_TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -// interframe delay callback -static mng_bool mymngsettimer(mng_handle mng, mng_uint32 msecs) -{ - mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); - mymng->delay = msecs; // set the timer for when the decoder wants to be woken - return MNG_TRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -static mng_bool mymngerror(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text) -{ - return mng_cleanup(&mng); // -} - -//////////////////////////////////////////////////////////////////////////////// -// CxImage members -//////////////////////////////////////////////////////////////////////////////// -CxImageMNG::CxImageMNG(): CxImage(CXIMAGE_FORMAT_MNG) -{ - hmng = NULL; - memset(&mnginfo,0,sizeof(mngstuff)); - mnginfo.nBkgndIndex = -1; - mnginfo.speed = 1.0f; -} -//////////////////////////////////////////////////////////////////////////////// -CxImageMNG::~CxImageMNG() -{ - // cleanup and return - if (mnginfo.thread){ //close the animation thread - mnginfo.animation_enabled=0; - ResumeThread(mnginfo.thread); - WaitForSingleObject(mnginfo.thread,500); - CloseHandle(mnginfo.thread); - } - // free objects - if (mnginfo.image) free(mnginfo.image); - if (mnginfo.alpha) free(mnginfo.alpha); - if (hmng) mng_cleanup(&hmng); //be sure it's not needed any more. (active timers ?) -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageMNG::SetCallbacks(mng_handle mng) -{ - // set the callbacks - mng_setcb_errorproc(mng, mymngerror); - mng_setcb_openstream(mng, mymngopenstream); - mng_setcb_closestream(mng, mymngclosestream); - mng_setcb_readdata(mng, mymngreadstream); - mng_setcb_processheader(mng, mymngprocessheader); - mng_setcb_getcanvasline(mng, mymnggetcanvasline); - mng_setcb_refresh(mng, mymngrefresh); - mng_setcb_gettickcount(mng, mymnggetticks); - mng_setcb_settimer(mng, mymngsettimer); - mng_setcb_refresh(mng, mymngrefresh); - mng_setcb_getalphaline(mng, mymnggetalphaline); -} -//////////////////////////////////////////////////////////////////////////////// -// can't use the CxImage implementation because it looses mnginfo -bool CxImageMNG::Load(const TCHAR * imageFileName){ - FILE* hFile; //file handle to read the image -#ifdef WIN32 - if ((hFile=_tfopen(imageFileName,_T("rb")))==NULL) return false; // For UNICODE support -#else - if ((hFile=fopen(imageFileName,"rb"))==NULL) return false; -#endif - bool bOK = Decode(hFile); - fclose(hFile); - return bOK; -} -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageMNG::Decode(CxFile *hFile) -{ - if (hFile == NULL) return false; - - cx_try - { - // set up the mng decoder for our stream - hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL); - if (hmng == NULL) cx_throw("could not initialize libmng"); - - // set the file we want to play - mnginfo.file = hFile; - - // Set the colorprofile, lcms uses this: - mng_set_srgb(hmng, MNG_TRUE ); - // Set white as background color: - WORD Red,Green,Blue; - Red = Green = Blue = (255 << 8) + 255; - mng_set_bgcolor(hmng, Red, Green, Blue ); - // If PNG Background is available, use it: - mng_set_usebkgd(hmng, MNG_TRUE ); - - // No need to store chunks: - mng_set_storechunks(hmng, MNG_FALSE); - // No need to wait: straight reading - mng_set_suspensionmode(hmng, MNG_FALSE); - - SetCallbacks(hmng); - - mng_datap pData = (mng_datap)hmng; - - // read in the image - info.nNumFrames=0; - int retval=MNG_NOERROR; - - retval = mng_readdisplay(hmng); - - if (retval != MNG_NOERROR && retval != MNG_NEEDTIMERWAIT){ - mng_store_error(hmng,retval,0,0); - if (hmng->zErrortext){ - cx_throw(hmng->zErrortext); - } else { - cx_throw("Error in MNG file"); - } - } - - if (info.nEscape == -1) { - // Return output dimensions only - head.biWidth = hmng->iWidth; - head.biHeight = hmng->iHeight; - info.dwType = CXIMAGE_FORMAT_MNG; - return true; - } - - // read all - while(pData->bReading){ - retval = mng_display_resume(hmng); - info.nNumFrames++; - } - - // single frame check: - if (retval != MNG_NEEDTIMERWAIT){ - info.nNumFrames--; - } else { - mnginfo.animation=1; - } - - if (info.nNumFrames<=0) info.nNumFrames=1; - - if (mnginfo.animation_enabled==0){ - // select the frame - if (info.nFrame>=0 && info.nFrame= 0){ - info.nBkgndIndex = mnginfo.nBkgndIndex; - info.nBkgndColor.rgbRed = mnginfo.nBkgndColor.rgbRed; - info.nBkgndColor.rgbGreen = mnginfo.nBkgndColor.rgbGreen; - info.nBkgndColor.rgbBlue = mnginfo.nBkgndColor.rgbBlue; - } - - //store the newly created image - if (Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG)){ - memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight); -#if CXIMAGE_SUPPORT_ALPHA - SwapRGB2BGR(); - AlphaCreate(); - if(AlphaIsValid() && mnginfo.alpha){ - memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height); - } -#endif - } else cx_throw("CxImageMNG::Decode cannot create image"); - - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - return false; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageMNG::Encode(CxFile *hFile) -{ - if (EncodeSafeCheck(hFile)) return false; - - cx_try - { - if (head.biClrUsed != 0) cx_throw("MNG encoder can save only RGB images"); - // set the file we want to play - mnginfo.file = hFile; - mnginfo.bpp = head.biBitCount; - mnginfo.effwdt = info.dwEffWidth; - mnginfo.height = head.biHeight; - mnginfo.width = head.biWidth; - - mnginfo.image = (BYTE*)malloc(head.biSizeImage); - if (mnginfo.image == NULL) cx_throw("could not allocate memory for MNG"); - memcpy(mnginfo.image,info.pImage, head.biSizeImage); - - // set up the mng decoder for our stream - hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL); - if (hmng == NULL) cx_throw("could not initialize libmng"); - - mng_setcb_openstream(hmng, mymngopenstreamwrite ); - mng_setcb_closestream(hmng, mymngclosestream); - mng_setcb_writedata(hmng, mymngwritestream); - - // Write File: - mng_create(hmng); - // Just a single Frame (save a normal PNG): - WritePNG(hmng, 0, 1 ); - // Now write file: - mng_write(hmng); - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - return false; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -// Writes a single PNG datastream -void CxImageMNG::WritePNG( mng_handle hMNG, int Frame, int FrameCount ) -{ - mngstuff *mymng = (mngstuff *)mng_get_userdata(hMNG); - - int OffsetX=0,OffsetY=0,OffsetW=mymng->width,OffsetH=mymng->height; - - BYTE *tmpbuffer = new BYTE[ (mymng->effwdt+1) * mymng->height]; - if( tmpbuffer == 0 ) return; - - // Write DEFI chunk. - mng_putchunk_defi( hMNG, 0, 0, 0, MNG_TRUE, OffsetX, OffsetY, MNG_FALSE, 0, 0, 0, 0 ); - - // Write Header: - mng_putchunk_ihdr( - hMNG, - OffsetW, OffsetH, - MNG_BITDEPTH_8, - MNG_COLORTYPE_RGB, - MNG_COMPRESSION_DEFLATE, - MNG_FILTER_ADAPTIVE, - MNG_INTERLACE_NONE - ); - - // transfer data, add Filterbyte: - for( int Row=0; Row No Filter. - tmpbuffer[Row*(mymng->effwdt+1)]=0; - // Copy the scanline: (reverse order) - memcpy(tmpbuffer+Row*(mymng->effwdt+1)+1, - mymng->image+((OffsetH-1-(OffsetY+Row))*(mymng->effwdt))+OffsetX,mymng->effwdt); - // swap red and blue components - RGBtoBGR(tmpbuffer+Row*(mymng->effwdt+1)+1,mymng->effwdt); - } - - // Compress data with ZLib (Deflate): - BYTE *dstbuffer = new BYTE[(mymng->effwdt+1)*OffsetH]; - if( dstbuffer == 0 ) return; - DWORD dstbufferSize=(mymng->effwdt+1)*OffsetH; - - // Compress data: - if(Z_OK != compress2((Bytef *)dstbuffer,(ULONG *)&dstbufferSize,(const Bytef*)tmpbuffer, - (ULONG) (mymng->effwdt+1)*OffsetH,9 )) return; - - // Write Data into MNG File: - mng_putchunk_idat( hMNG, dstbufferSize, (mng_ptr*)dstbuffer); - mng_putchunk_iend(hMNG); - - // Free the stuff: - delete [] tmpbuffer; - delete [] dstbuffer; -} -//////////////////////////////////////////////////////////////////////////////// -long CxImageMNG::Resume() -{ - if (MNG_NEEDTIMERWAIT == mng_display_resume(hmng)){ - if (info.pImage==NULL){ - Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG); - } - if (IsValid()){ - memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight); -#if CXIMAGE_SUPPORT_ALPHA - SwapRGB2BGR(); - AlphaCreate(); - if(AlphaIsValid() && mnginfo.alpha){ - memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height); - } -#endif - } - } else { - mnginfo.animation_enabled = 0; - } - return mnginfo.animation_enabled; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageMNG::SetSpeed(float speed) -{ - if (speed>10.0) mnginfo.speed = 10.0f; - else if (speed<0.1) mnginfo.speed = 0.1f; - else mnginfo.speed=speed; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_MNG +/* + * File: ximamng.cpp + * Purpose: Platform Independent MNG Image Class Loader and Writer + * Author: 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximamng.h" + +#if CXIMAGE_SUPPORT_MNG + +//////////////////////////////////////////////////////////////////////////////// +// callbacks for the mng decoder: +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// memory allocation; data must be zeroed +static mng_ptr +mymngalloc( mng_uint32 size ) +{ + return (mng_ptr)calloc(1, size); +} + +//////////////////////////////////////////////////////////////////////////////// +// memory deallocation +static void mymngfree(mng_ptr p, mng_uint32 size) +{ + free(p); +} + +//////////////////////////////////////////////////////////////////////////////// +// Stream open/close: +// since the user is responsible for opening and closing the file, +// we leave the default implementation open +static mng_bool mymngopenstream(mng_handle mng) { return MNG_TRUE; } +static mng_bool mymngopenstreamwrite(mng_handle mng) { return MNG_TRUE; } +static mng_bool mymngclosestream(mng_handle mng) { return MNG_TRUE; } + +//////////////////////////////////////////////////////////////////////////////// +// feed data to the decoder +static mng_bool mymngreadstream(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread) +{ + mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + // read the requested amount of data from the file + *bytesread = mymng->file->Read( buffer, sizeof(BYTE), size); + return MNG_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +static mng_bool mymngwritestream (mng_handle mng, mng_ptr pBuf, mng_uint32 iSize, mng_uint32 *iWritten) +{ + mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + // write it + *iWritten = mymng->file->Write (pBuf, 1, iSize); + return MNG_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// the header's been read. set up the display stuff +static mng_bool mymngprocessheader( mng_handle mng, mng_uint32 width, mng_uint32 height ) +{ + // normally the image buffer is allocated here, + // but in this module we don't know nothing about + // the final environment. + + mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + + mymng->width = width; + mymng->height = height; + mymng->bpp = 24; + mymng->effwdt = ((((width * mymng->bpp) + 31) >> 5) << 2); + + if (mng->bUseBKGD){ + mymng->nBkgndIndex = 0; + mymng->nBkgndColor.rgbRed = mng->iBGred >> 8; + mymng->nBkgndColor.rgbGreen =mng->iBGgreen >> 8; + mymng->nBkgndColor.rgbBlue = mng->iBGblue >> 8; + } + + mymng->image = (BYTE*)malloc(height * mymng->effwdt); + + // tell the mng decoder about our bit-depth choice +#if CXIMAGE_SUPPORT_ALPHA + mng_set_canvasstyle( mng, MNG_CANVAS_RGB8_A8 ); + mymng->alpha = (BYTE*)malloc(height * width); +#else + mng_set_canvasstyle( mng, MNG_CANVAS_BGR8); + mymng->alpha = NULL; +#endif + return MNG_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// return a row pointer for the decoder to fill +static mng_ptr mymnggetcanvasline( mng_handle mng, mng_uint32 line ) +{ + mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + return (mng_ptr)(mymng->image + (mymng->effwdt * (mymng->height - 1 - line))); +} +//////////////////////////////////////////////////////////////////////////////// +// return a row pointer for the decoder to fill for alpha channel +static mng_ptr mymnggetalphaline( mng_handle mng, mng_uint32 line ) +{ + mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + return (mng_ptr)(mymng->alpha + (mymng->width * (mymng->height - 1 - line))); +} + +//////////////////////////////////////////////////////////////////////////////// +// timer +static mng_uint32 mymnggetticks(mng_handle mng) +{ +#ifdef WIN32 + return (mng_uint32)GetTickCount(); +#else + return 0; +#endif +} + +//////////////////////////////////////////////////////////////////////////////// +// Refresh: actual frame need to be updated (Invalidate) +static mng_bool mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h) +{ +// mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + return MNG_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// interframe delay callback +static mng_bool mymngsettimer(mng_handle mng, mng_uint32 msecs) +{ + mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + mymng->delay = msecs; // set the timer for when the decoder wants to be woken + return MNG_TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +static mng_bool mymngerror(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text) +{ + return mng_cleanup(&mng); // +} + +//////////////////////////////////////////////////////////////////////////////// +// CxImage members +//////////////////////////////////////////////////////////////////////////////// +CxImageMNG::CxImageMNG(): CxImage(CXIMAGE_FORMAT_MNG) +{ + hmng = NULL; + memset(&mnginfo,0,sizeof(mngstuff)); + mnginfo.nBkgndIndex = -1; + mnginfo.speed = 1.0f; +} +//////////////////////////////////////////////////////////////////////////////// +CxImageMNG::~CxImageMNG() +{ + // cleanup and return + if (mnginfo.thread){ //close the animation thread + mnginfo.animation_enabled=0; + ResumeThread(mnginfo.thread); + WaitForSingleObject(mnginfo.thread,500); + CloseHandle(mnginfo.thread); + } + // free objects + if (mnginfo.image) free(mnginfo.image); + if (mnginfo.alpha) free(mnginfo.alpha); + if (hmng) mng_cleanup(&hmng); //be sure it's not needed any more. (active timers ?) +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageMNG::SetCallbacks(mng_handle mng) +{ + // set the callbacks + mng_setcb_errorproc(mng, mymngerror); + mng_setcb_openstream(mng, mymngopenstream); + mng_setcb_closestream(mng, mymngclosestream); + mng_setcb_readdata(mng, mymngreadstream); + mng_setcb_processheader(mng, mymngprocessheader); + mng_setcb_getcanvasline(mng, mymnggetcanvasline); + mng_setcb_refresh(mng, mymngrefresh); + mng_setcb_gettickcount(mng, mymnggetticks); + mng_setcb_settimer(mng, mymngsettimer); + mng_setcb_refresh(mng, mymngrefresh); + mng_setcb_getalphaline(mng, mymnggetalphaline); +} +//////////////////////////////////////////////////////////////////////////////// +// can't use the CxImage implementation because it looses mnginfo +bool CxImageMNG::Load(const TCHAR * imageFileName){ + FILE* hFile; //file handle to read the image +#ifdef WIN32 + if ((hFile=_tfopen(imageFileName,_T("rb")))==NULL) return false; // For UNICODE support +#else + if ((hFile=fopen(imageFileName,"rb"))==NULL) return false; +#endif + bool bOK = Decode(hFile); + fclose(hFile); + return bOK; +} +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageMNG::Decode(CxFile *hFile) +{ + if (hFile == NULL) return false; + + cx_try + { + // set up the mng decoder for our stream + hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL); + if (hmng == NULL) cx_throw("could not initialize libmng"); + + // set the file we want to play + mnginfo.file = hFile; + + // Set the colorprofile, lcms uses this: + mng_set_srgb(hmng, MNG_TRUE ); + // Set white as background color: + WORD Red,Green,Blue; + Red = Green = Blue = (255 << 8) + 255; + mng_set_bgcolor(hmng, Red, Green, Blue ); + // If PNG Background is available, use it: + mng_set_usebkgd(hmng, MNG_TRUE ); + + // No need to store chunks: + mng_set_storechunks(hmng, MNG_FALSE); + // No need to wait: straight reading + mng_set_suspensionmode(hmng, MNG_FALSE); + + SetCallbacks(hmng); + + mng_datap pData = (mng_datap)hmng; + + // read in the image + info.nNumFrames=0; + int retval=MNG_NOERROR; + + retval = mng_readdisplay(hmng); + + if (retval != MNG_NOERROR && retval != MNG_NEEDTIMERWAIT){ + mng_store_error(hmng,retval,0,0); + if (hmng->zErrortext){ + cx_throw(hmng->zErrortext); + } else { + cx_throw("Error in MNG file"); + } + } + + if (info.nEscape == -1) { + // Return output dimensions only + head.biWidth = hmng->iWidth; + head.biHeight = hmng->iHeight; + info.dwType = CXIMAGE_FORMAT_MNG; + return true; + } + + // read all + while(pData->bReading){ + retval = mng_display_resume(hmng); + info.nNumFrames++; + } + + // single frame check: + if (retval != MNG_NEEDTIMERWAIT){ + info.nNumFrames--; + } else { + mnginfo.animation=1; + } + + if (info.nNumFrames<=0) info.nNumFrames=1; + + if (mnginfo.animation_enabled==0){ + // select the frame + if (info.nFrame>=0 && info.nFrame= 0){ + info.nBkgndIndex = mnginfo.nBkgndIndex; + info.nBkgndColor.rgbRed = mnginfo.nBkgndColor.rgbRed; + info.nBkgndColor.rgbGreen = mnginfo.nBkgndColor.rgbGreen; + info.nBkgndColor.rgbBlue = mnginfo.nBkgndColor.rgbBlue; + } + + //store the newly created image + if (Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG)){ + memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight); +#if CXIMAGE_SUPPORT_ALPHA + SwapRGB2BGR(); + AlphaCreate(); + if(AlphaIsValid() && mnginfo.alpha){ + memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height); + } +#endif + } else cx_throw("CxImageMNG::Decode cannot create image"); + + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + return false; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageMNG::Encode(CxFile *hFile) +{ + if (EncodeSafeCheck(hFile)) return false; + + cx_try + { + if (head.biClrUsed != 0) cx_throw("MNG encoder can save only RGB images"); + // set the file we want to play + mnginfo.file = hFile; + mnginfo.bpp = head.biBitCount; + mnginfo.effwdt = info.dwEffWidth; + mnginfo.height = head.biHeight; + mnginfo.width = head.biWidth; + + mnginfo.image = (BYTE*)malloc(head.biSizeImage); + if (mnginfo.image == NULL) cx_throw("could not allocate memory for MNG"); + memcpy(mnginfo.image,info.pImage, head.biSizeImage); + + // set up the mng decoder for our stream + hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL); + if (hmng == NULL) cx_throw("could not initialize libmng"); + + mng_setcb_openstream(hmng, mymngopenstreamwrite ); + mng_setcb_closestream(hmng, mymngclosestream); + mng_setcb_writedata(hmng, mymngwritestream); + + // Write File: + mng_create(hmng); + // Just a single Frame (save a normal PNG): + WritePNG(hmng, 0, 1 ); + // Now write file: + mng_write(hmng); + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + return false; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +// Writes a single PNG datastream +void CxImageMNG::WritePNG( mng_handle hMNG, int Frame, int FrameCount ) +{ + mngstuff *mymng = (mngstuff *)mng_get_userdata(hMNG); + + int OffsetX=0,OffsetY=0,OffsetW=mymng->width,OffsetH=mymng->height; + + BYTE *tmpbuffer = new BYTE[ (mymng->effwdt+1) * mymng->height]; + if( tmpbuffer == 0 ) return; + + // Write DEFI chunk. + mng_putchunk_defi( hMNG, 0, 0, 0, MNG_TRUE, OffsetX, OffsetY, MNG_FALSE, 0, 0, 0, 0 ); + + // Write Header: + mng_putchunk_ihdr( + hMNG, + OffsetW, OffsetH, + MNG_BITDEPTH_8, + MNG_COLORTYPE_RGB, + MNG_COMPRESSION_DEFLATE, + MNG_FILTER_ADAPTIVE, + MNG_INTERLACE_NONE + ); + + // transfer data, add Filterbyte: + for( int Row=0; Row No Filter. + tmpbuffer[Row*(mymng->effwdt+1)]=0; + // Copy the scanline: (reverse order) + memcpy(tmpbuffer+Row*(mymng->effwdt+1)+1, + mymng->image+((OffsetH-1-(OffsetY+Row))*(mymng->effwdt))+OffsetX,mymng->effwdt); + // swap red and blue components + RGBtoBGR(tmpbuffer+Row*(mymng->effwdt+1)+1,mymng->effwdt); + } + + // Compress data with ZLib (Deflate): + BYTE *dstbuffer = new BYTE[(mymng->effwdt+1)*OffsetH]; + if( dstbuffer == 0 ) return; + DWORD dstbufferSize=(mymng->effwdt+1)*OffsetH; + + // Compress data: + if(Z_OK != compress2((Bytef *)dstbuffer,(ULONG *)&dstbufferSize,(const Bytef*)tmpbuffer, + (ULONG) (mymng->effwdt+1)*OffsetH,9 )) return; + + // Write Data into MNG File: + mng_putchunk_idat( hMNG, dstbufferSize, (mng_ptr*)dstbuffer); + mng_putchunk_iend(hMNG); + + // Free the stuff: + delete [] tmpbuffer; + delete [] dstbuffer; +} +//////////////////////////////////////////////////////////////////////////////// +long CxImageMNG::Resume() +{ + if (MNG_NEEDTIMERWAIT == mng_display_resume(hmng)){ + if (info.pImage==NULL){ + Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG); + } + if (IsValid()){ + memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight); +#if CXIMAGE_SUPPORT_ALPHA + SwapRGB2BGR(); + AlphaCreate(); + if(AlphaIsValid() && mnginfo.alpha){ + memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height); + } +#endif + } + } else { + mnginfo.animation_enabled = 0; + } + return mnginfo.animation_enabled; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageMNG::SetSpeed(float speed) +{ + if (speed>10.0) mnginfo.speed = 10.0f; + else if (speed<0.1) mnginfo.speed = 0.1f; + else mnginfo.speed=speed; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_MNG diff --git a/utilities/CxImage/ximamng.h b/utilities/CxImage/ximamng.h index adc922c..86c05c3 100644 --- a/utilities/CxImage/ximamng.h +++ b/utilities/CxImage/ximamng.h @@ -1,88 +1,88 @@ -/* - * File: ximamng.h - * Purpose: Declaration of the MNG Image Class - * Author: Davide Pizzolato - www.xdp.it - * Created: 2001 - */ -/* ========================================================== - * CxImageMNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Special thanks to Frank Haug for suggestions and code. - * - * original mng.cpp code created by Nikolaus Brennig, November 14th, 2000. - * - * LIBMNG Copyright (c) 2000,2001 Gerard Juyn (gerard@libmng.com) - * ========================================================== - */ - -#if !defined(__ximaMNG_h) -#define __ximaMNG_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_MNG - -//#define MNG_NO_CMS -#define MNG_SUPPORT_DISPLAY -#define MNG_SUPPORT_READ -#define MNG_SUPPORT_WRITE -#define MNG_ACCESS_CHUNKS -#define MNG_STORE_CHUNKS - -extern "C" { -#include "../mng/libmng.h" -#include "../mng/libmng_data.h" -#include "../mng/libmng_error.h" -} - -//unsigned long _stdcall RunMNGThread(void *lpParam); - -typedef struct tagmngstuff -{ - CxFile *file; - BYTE *image; - BYTE *alpha; - HANDLE thread; - mng_uint32 delay; - mng_uint32 width; - mng_uint32 height; - mng_uint32 effwdt; - mng_int16 bpp; - mng_bool animation; - mng_bool animation_enabled; - float speed; - long nBkgndIndex; - RGBQUAD nBkgndColor; -} mngstuff; - -class CxImageMNG: public CxImage -{ -public: - CxImageMNG(); - ~CxImageMNG(); - - bool Load(const TCHAR * imageFileName); - - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } - bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_MNG);} -#endif // CXIMAGE_SUPPORT_ENCODE - - long Resume(); - void SetSpeed(float speed); - - mng_handle hmng; - mngstuff mnginfo; -protected: - void WritePNG(mng_handle hMNG, int Frame, int FrameCount ); - void SetCallbacks(mng_handle mng); -}; - -#endif - -#endif +/* + * File: ximamng.h + * Purpose: Declaration of the MNG Image Class + * Author: Davide Pizzolato - www.xdp.it + * Created: 2001 + */ +/* ========================================================== + * CxImageMNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Special thanks to Frank Haug for suggestions and code. + * + * original mng.cpp code created by Nikolaus Brennig, November 14th, 2000. + * + * LIBMNG Copyright (c) 2000,2001 Gerard Juyn (gerard@libmng.com) + * ========================================================== + */ + +#if !defined(__ximaMNG_h) +#define __ximaMNG_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_MNG + +//#define MNG_NO_CMS +#define MNG_SUPPORT_DISPLAY +#define MNG_SUPPORT_READ +#define MNG_SUPPORT_WRITE +#define MNG_ACCESS_CHUNKS +#define MNG_STORE_CHUNKS + +extern "C" { +#include "../mng/libmng.h" +#include "../mng/libmng_data.h" +#include "../mng/libmng_error.h" +} + +//unsigned long _stdcall RunMNGThread(void *lpParam); + +typedef struct tagmngstuff +{ + CxFile *file; + BYTE *image; + BYTE *alpha; + HANDLE thread; + mng_uint32 delay; + mng_uint32 width; + mng_uint32 height; + mng_uint32 effwdt; + mng_int16 bpp; + mng_bool animation; + mng_bool animation_enabled; + float speed; + long nBkgndIndex; + RGBQUAD nBkgndColor; +} mngstuff; + +class CxImageMNG: public CxImage +{ +public: + CxImageMNG(); + ~CxImageMNG(); + + bool Load(const TCHAR * imageFileName); + + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } + bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_MNG);} +#endif // CXIMAGE_SUPPORT_ENCODE + + long Resume(); + void SetSpeed(float speed); + + mng_handle hmng; + mngstuff mnginfo; +protected: + void WritePNG(mng_handle hMNG, int Frame, int FrameCount ); + void SetCallbacks(mng_handle mng); +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximapal.cpp b/utilities/CxImage/ximapal.cpp index f7de9eb..b3bd3da 100644 --- a/utilities/CxImage/ximapal.cpp +++ b/utilities/CxImage/ximapal.cpp @@ -1,834 +1,834 @@ -// xImaPal.cpp : Palette and Pixel functions -/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" - -//////////////////////////////////////////////////////////////////////////////// -/** - * returns the palette dimension in byte - */ -DWORD CxImage::GetPaletteSize() -{ - return (head.biClrUsed * sizeof(RGBQUAD)); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha) -{ - if ((pDib)&&(head.biClrUsed)){ - BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER); - if (idx=head.biWidth)||(y>=head.biHeight)) { - if (info.nBkgndIndex >= 0) return (BYTE)info.nBkgndIndex; - else return *info.pImage; - } - if (head.biBitCount==8){ - return info.pImage[y*info.dwEffWidth + x]; - } else { - BYTE pos; - BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)]; - if (head.biBitCount==4){ - pos = (BYTE)(4*(1-x%2)); - iDst &= (0x0F<> pos); - } else if (head.biBitCount==1){ - pos = (BYTE)(7-x%8); - iDst &= (0x01<> pos); - } - } - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -BYTE CxImage::BlindGetPixelIndex(const long x,const long y) -{ -#ifdef _DEBUG - if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y)) - #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - throw 0; - #else - return 0; - #endif -#endif - - if (head.biBitCount==8){ - return info.pImage[y*info.dwEffWidth + x]; - } else { - BYTE pos; - BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)]; - if (head.biBitCount==4){ - pos = (BYTE)(4*(1-x%2)); - iDst &= (0x0F<> pos); - } else if (head.biBitCount==1){ - pos = (BYTE)(7-x%8); - iDst &= (0x01<> pos); - } - } - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -RGBQUAD CxImage::GetPixelColor(long x,long y, bool bGetAlpha) -{ -// RGBQUAD rgb={0,0,0,0}; - RGBQUAD rgb=info.nBkgndColor; // - if ((pDib==NULL)||(x<0)||(y<0)|| - (x>=head.biWidth)||(y>=head.biHeight)){ - if (info.nBkgndIndex >= 0){ - if (head.biBitCount<24) return GetPaletteColor((BYTE)info.nBkgndIndex); - else return info.nBkgndColor; - } else if (pDib) return GetPixelColor(0,0); - return rgb; - } - - if (head.biClrUsed){ - rgb = GetPaletteColor(BlindGetPixelIndex(x,y)); - } else { - BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; - rgb.rgbBlue = *iDst++; - rgb.rgbGreen= *iDst++; - rgb.rgbRed = *iDst; - } -#if CXIMAGE_SUPPORT_ALPHA - if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y); -#else - rgb.rgbReserved = 0; -#endif //CXIMAGE_SUPPORT_ALPHA - return rgb; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * This is (a bit) faster version of GetPixelColor. - * It tests bounds only in debug mode (_DEBUG defined). - * - * It is an error to request out-of-borders pixel with this method. - * In DEBUG mode an exception will be thrown, and data will be violated in non-DEBUG mode. - * \author ***bd*** 2.2004 - */ -RGBQUAD CxImage::BlindGetPixelColor(const long x,const long y, bool bGetAlpha) -{ - RGBQUAD rgb; -#ifdef _DEBUG - if ((pDib==NULL) || !IsInside(x,y)) - #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - throw 0; - #else - {rgb.rgbReserved = 0; return rgb;} - #endif -#endif - - if (head.biClrUsed){ - rgb = GetPaletteColor(BlindGetPixelIndex(x,y)); - } else { - BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; - rgb.rgbBlue = *iDst++; - rgb.rgbGreen= *iDst++; - rgb.rgbRed = *iDst; - rgb.rgbReserved = 0; //needed for images without alpha layer - } -#if CXIMAGE_SUPPORT_ALPHA - if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y); -#else - rgb.rgbReserved = 0; -#endif //CXIMAGE_SUPPORT_ALPHA - return rgb; -} -//////////////////////////////////////////////////////////////////////////////// -BYTE CxImage::GetPixelGray(long x, long y) -{ - RGBQUAD color = GetPixelColor(x,y); - return (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::BlindSetPixelIndex(long x,long y,BYTE i) -{ -#ifdef _DEBUG - if ((pDib==NULL)||(head.biClrUsed==0)|| - (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) - #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - throw 0; - #else - return; - #endif -#endif - - if (head.biBitCount==8){ - info.pImage[y*info.dwEffWidth + x]=i; - return; - } else { - BYTE pos; - BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3); - if (head.biBitCount==4){ - pos = (BYTE)(4*(1-x%2)); - *iDst &= ~(0x0F<=head.biWidth)||(y>=head.biHeight)) return ; - - if (head.biBitCount==8){ - info.pImage[y*info.dwEffWidth + x]=i; - return; - } else { - BYTE pos; - BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3); - if (head.biBitCount==4){ - pos = (BYTE)(4*(1-x%2)); - *iDst &= ~(0x0F<=head.biWidth)||(y>=head.biHeight)) - #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - throw 0; - #else - return; - #endif -#endif - if (head.biClrUsed) - BlindSetPixelIndex(x,y,GetNearestIndex(c)); - else { - BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; - *iDst++ = c.rgbBlue; - *iDst++ = c.rgbGreen; - *iDst = c.rgbRed; - } -#if CXIMAGE_SUPPORT_ALPHA - if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); -#endif //CXIMAGE_SUPPORT_ALPHA -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha) -{ - if ((pDib==NULL)||(x<0)||(y<0)|| - (x>=head.biWidth)||(y>=head.biHeight)) return; - if (head.biClrUsed) - BlindSetPixelIndex(x,y,GetNearestIndex(c)); - else { - BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; - *iDst++ = c.rgbBlue; - *iDst++ = c.rgbGreen; - *iDst = c.rgbRed; - } -#if CXIMAGE_SUPPORT_ALPHA - if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); -#endif //CXIMAGE_SUPPORT_ALPHA -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Blends the current pixel color with a new color. - * \param x,y = pixel - * \param c = new color - * \param blend = can be from 0 (no effect) to 1 (full effect). - * \param bSetAlpha = if true, blends also the alpha component stored in c.rgbReserved - */ -void CxImage::BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha) -{ - if ((pDib==NULL)||(x<0)||(y<0)|| - (x>=head.biWidth)||(y>=head.biHeight)) return; - - int a0 = (int)(256*blend); - int a1 = 256 - a0; - - RGBQUAD c0 = BlindGetPixelColor(x,y); - c.rgbRed = (BYTE)((c.rgbRed * a0 + c0.rgbRed * a1)>>8); - c.rgbBlue = (BYTE)((c.rgbBlue * a0 + c0.rgbBlue * a1)>>8); - c.rgbGreen = (BYTE)((c.rgbGreen * a0 + c0.rgbGreen * a1)>>8); - - if (head.biClrUsed) - BlindSetPixelIndex(x,y,GetNearestIndex(c)); - else { - BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; - *iDst++ = c.rgbBlue; - *iDst++ = c.rgbGreen; - *iDst = c.rgbRed; -#if CXIMAGE_SUPPORT_ALPHA - if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); -#endif //CXIMAGE_SUPPORT_ALPHA - } -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Returns the best palette index that matches a specified color. - */ -BYTE CxImage::GetNearestIndex(RGBQUAD c) -{ - if ((pDib==NULL)||(head.biClrUsed==0)) return 0; - - // check matching with the previous result - if (info.last_c_isvalid && (*(long*)&info.last_c == *(long*)&c)) return info.last_c_index; - info.last_c = c; - info.last_c_isvalid = true; - - BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER); - long distance=200000; - int i,j = 0; - long k,l; - int m = (int)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant); - for(i=0,l=0;i100) perc=100; - for(i=0;i=0){ - if (head.biClrUsed){ - if (GetPixelIndex(x,y) == info.nBkgndIndex) return true; - } else { - RGBQUAD ct = info.nBkgndColor; - RGBQUAD c = GetPixelColor(x,y,false); - if (*(long*)&c==*(long*)&ct) return true; - } - } - -#if CXIMAGE_SUPPORT_ALPHA - if (pAlpha) return AlphaGet(x,y)==0; -#endif - - return false; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::GetTransparentMask(CxImage* iDst) -{ - if (!pDib) return false; - - CxImage tmp; - tmp.Create(head.biWidth, head.biHeight, 1, GetType()); - tmp.SetStdPalette(); - tmp.Clear(0); - - for(long y=0; yTransfer(tmp); - else Transfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Checks if image has the same palette, if any. - * \param img = image to compare. - * \param bCheckAlpha = check also the rgbReserved field. - */ -bool CxImage::IsSamePalette(CxImage &img, bool bCheckAlpha) -{ - if (head.biClrUsed != img.head.biClrUsed) - return false; - if (head.biClrUsed == 0) - return false; - - RGBQUAD c1,c2; - for (DWORD n=0; n256) { - head.biClrImportant = 0; - return; - } - - switch(head.biBitCount){ - case 1: - head.biClrImportant = min(ncolors,2); - break; - case 4: - head.biClrImportant = min(ncolors,16); - break; - case 8: - head.biClrImportant = ncolors; - break; - } - return; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Returns pointer to pixel. Currently implemented only for truecolor images. - * - * \param x,y - coordinates - * - * \return pointer to first byte of pixel data - * - * \author ***bd*** 2.2004 - */ -void* CxImage::BlindGetPixelPointer(const long x, const long y) -{ -#ifdef _DEBUG - if ((pDib==NULL) || !IsInside(x,y)) - #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - throw 0; - #else - return 0; - #endif -#endif - if (!IsIndexed()) - return info.pImage + y*info.dwEffWidth + x*3; - else - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr) -{ - DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr)); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha) -{ - if (!pDib) return; - ////////////////////////////////////////////////////// - // Draws a line using the Bresenham line algorithm - // Thanks to Jordan DeLozier - ////////////////////////////////////////////////////// - int x1 = StartX; - int y1 = StartY; - int x = x1; // Start x off at the first pixel - int y = y1; // Start y off at the first pixel - int x2 = EndX; - int y2 = EndY; - - int xinc1,xinc2,yinc1,yinc2; // Increasing values - int den, num, numadd,numpixels; - int deltax = abs(x2 - x1); // The difference between the x's - int deltay = abs(y2 - y1); // The difference between the y's - - // Get Increasing Values - if (x2 >= x1) { // The x-values are increasing - xinc1 = 1; - xinc2 = 1; - } else { // The x-values are decreasing - xinc1 = -1; - xinc2 = -1; - } - - if (y2 >= y1) { // The y-values are increasing - yinc1 = 1; - yinc2 = 1; - } else { // The y-values are decreasing - yinc1 = -1; - yinc2 = -1; - } - - // Actually draw the line - if (deltax >= deltay) // There is at least one x-value for every y-value - { - xinc1 = 0; // Don't change the x when numerator >= denominator - yinc2 = 0; // Don't change the y for every iteration - den = deltax; - num = deltax / 2; - numadd = deltay; - numpixels = deltax; // There are more x-values than y-values - } - else // There is at least one y-value for every x-value - { - xinc2 = 0; // Don't change the x for every iteration - yinc1 = 0; // Don't change the y when numerator >= denominator - den = deltay; - num = deltay / 2; - numadd = deltax; - numpixels = deltay; // There are more y-values than x-values - } - - for (int curpixel = 0; curpixel <= numpixels; curpixel++) - { - // Draw the current pixel - SetPixelColor(x,y,color,bSetAlpha); - - num += numadd; // Increase the numerator by the top of the fraction - if (num >= den) // Check if numerator >= denominator - { - num -= den; // Calculate the new numerator value - x += xinc1; // Change the x as appropriate - y += yinc1; // Change the y as appropriate - } - x += xinc2; // Change the x as appropriate - y += yinc2; // Change the y as appropriate - } -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Sets a palette with standard colors for 1, 4 and 8 bpp images. - */ -void CxImage::SetStdPalette() -{ - if (!pDib) return; - switch (head.biBitCount){ - case 8: - { - const BYTE pal256[1024] = {0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0, - 192,220,192,0,240,202,166,0,212,240,255,0,177,226,255,0,142,212,255,0,107,198,255,0, - 72,184,255,0,37,170,255,0,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0, - 50,80,0,212,227,255,0,177,199,255,0,142,171,255,0,107,143,255,0,72,115,255,0,37,87,255,0,0, - 85,255,0,0,73,220,0,0,61,185,0,0,49,150,0,0,37,115,0,0,25,80,0,212,212,255,0,177,177,255,0, - 142,142,255,0,107,107,255,0,72,72,255,0,37,37,255,0,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0, - 0,0,115,0,0,0,80,0,227,212,255,0,199,177,255,0,171,142,255,0,143,107,255,0,115,72,255,0, - 87,37,255,0,85,0,255,0,73,0,220,0,61,0,185,0,49,0,150,0,37,0,115,0,25,0,80,0,240,212,255,0, - 226,177,255,0,212,142,255,0,198,107,255,0,184,72,255,0,170,37,255,0,170,0,255,0,146,0,220,0, - 122,0,185,0,98,0,150,0,74,0,115,0,50,0,80,0,255,212,255,0,255,177,255,0,255,142,255,0,255,107,255,0, - 255,72,255,0,255,37,255,0,254,0,254,0,220,0,220,0,185,0,185,0,150,0,150,0,115,0,115,0,80,0,80,0, - 255,212,240,0,255,177,226,0,255,142,212,0,255,107,198,0,255,72,184,0,255,37,170,0,255,0,170,0, - 220,0,146,0,185,0,122,0,150,0,98,0,115,0,74,0,80,0,50,0,255,212,227,0,255,177,199,0,255,142,171,0, - 255,107,143,0,255,72,115,0,255,37,87,0,255,0,85,0,220,0,73,0,185,0,61,0,150,0,49,0,115,0,37,0, - 80,0,25,0,255,212,212,0,255,177,177,0,255,142,142,0,255,107,107,0,255,72,72,0,255,37,37,0,254,0, - 0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,0,255,227,212,0,255,199,177,0,255,171,142,0, - 255,143,107,0,255,115,72,0,255,87,37,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0,115,37,0, - 0,80,25,0,0,255,240,212,0,255,226,177,0,255,212,142,0,255,198,107,0,255,184,72,0,255,170,37,0, - 255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,0,255,255,212,0,255,255,177,0, - 255,255,142,0,255,255,107,0,255,255,72,0,255,255,37,0,254,254,0,0,220,220,0,0,185,185,0,0,150,150,0, - 0,115,115,0,0,80,80,0,0,240,255,212,0,226,255,177,0,212,255,142,0,198,255,107,0,184,255,72,0, - 170,255,37,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0,50,80,0,0,227,255,212,0, - 199,255,177,0,171,255,142,0,143,255,107,0,115,255,72,0,87,255,37,0,85,255,0,0,73,220,0,0,61,185,0, - 0,49,150,0,0,37,115,0,0,25,80,0,0,212,255,212,0,177,255,177,0,142,255,142,0,107,255,107,0,72,255,72,0, - 37,255,37,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,212,255,227,0,177,255,199,0, - 142,255,171,0,107,255,143,0,72,255,115,0,37,255,87,0,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0, - 115,37,0,0,80,25,0,212,255,240,0,177,255,226,0,142,255,212,0,107,255,198,0,72,255,184,0,37,255,170,0, - 0,255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,212,255,255,0,177,255,255,0, - 142,255,255,0,107,255,255,0,72,255,255,0,37,255,255,0,0,254,254,0,0,220,220,0,0,185,185,0,0, - 150,150,0,0,115,115,0,0,80,80,0,242,242,242,0,230,230,230,0,218,218,218,0,206,206,206,0,194,194,194,0, - 182,182,182,0,170,170,170,0,158,158,158,0,146,146,146,0,134,134,134,0,122,122,122,0,110,110,110,0, - 98,98,98,0,86,86,86,0,74,74,74,0,62,62,62,0,50,50,50,0,38,38,38,0,26,26,26,0,14,14,14,0,240,251,255,0, - 164,160,160,0,128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0}; - memcpy(GetPalette(),pal256,1024); - break; - } - case 4: - { - const BYTE pal16[64]={0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0, - 128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0}; - memcpy(GetPalette(),pal16,64); - break; - } - case 1: - { - const BYTE pal2[8]={0,0,0,0,255,255,255,0}; - memcpy(GetPalette(),pal2,8); - break; - } - } - info.last_c_isvalid = false; - return; -} -//////////////////////////////////////////////////////////////////////////////// +// xImaPal.cpp : Palette and Pixel functions +/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +//////////////////////////////////////////////////////////////////////////////// +/** + * returns the palette dimension in byte + */ +DWORD CxImage::GetPaletteSize() +{ + return (head.biClrUsed * sizeof(RGBQUAD)); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha) +{ + if ((pDib)&&(head.biClrUsed)){ + BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER); + if (idx=head.biWidth)||(y>=head.biHeight)) { + if (info.nBkgndIndex >= 0) return (BYTE)info.nBkgndIndex; + else return *info.pImage; + } + if (head.biBitCount==8){ + return info.pImage[y*info.dwEffWidth + x]; + } else { + BYTE pos; + BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)]; + if (head.biBitCount==4){ + pos = (BYTE)(4*(1-x%2)); + iDst &= (0x0F<> pos); + } else if (head.biBitCount==1){ + pos = (BYTE)(7-x%8); + iDst &= (0x01<> pos); + } + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +BYTE CxImage::BlindGetPixelIndex(const long x,const long y) +{ +#ifdef _DEBUG + if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return 0; + #endif +#endif + + if (head.biBitCount==8){ + return info.pImage[y*info.dwEffWidth + x]; + } else { + BYTE pos; + BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)]; + if (head.biBitCount==4){ + pos = (BYTE)(4*(1-x%2)); + iDst &= (0x0F<> pos); + } else if (head.biBitCount==1){ + pos = (BYTE)(7-x%8); + iDst &= (0x01<> pos); + } + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +RGBQUAD CxImage::GetPixelColor(long x,long y, bool bGetAlpha) +{ +// RGBQUAD rgb={0,0,0,0}; + RGBQUAD rgb=info.nBkgndColor; // + if ((pDib==NULL)||(x<0)||(y<0)|| + (x>=head.biWidth)||(y>=head.biHeight)){ + if (info.nBkgndIndex >= 0){ + if (head.biBitCount<24) return GetPaletteColor((BYTE)info.nBkgndIndex); + else return info.nBkgndColor; + } else if (pDib) return GetPixelColor(0,0); + return rgb; + } + + if (head.biClrUsed){ + rgb = GetPaletteColor(BlindGetPixelIndex(x,y)); + } else { + BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; + rgb.rgbBlue = *iDst++; + rgb.rgbGreen= *iDst++; + rgb.rgbRed = *iDst; + } +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y); +#else + rgb.rgbReserved = 0; +#endif //CXIMAGE_SUPPORT_ALPHA + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * This is (a bit) faster version of GetPixelColor. + * It tests bounds only in debug mode (_DEBUG defined). + * + * It is an error to request out-of-borders pixel with this method. + * In DEBUG mode an exception will be thrown, and data will be violated in non-DEBUG mode. + * \author ***bd*** 2.2004 + */ +RGBQUAD CxImage::BlindGetPixelColor(const long x,const long y, bool bGetAlpha) +{ + RGBQUAD rgb; +#ifdef _DEBUG + if ((pDib==NULL) || !IsInside(x,y)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + {rgb.rgbReserved = 0; return rgb;} + #endif +#endif + + if (head.biClrUsed){ + rgb = GetPaletteColor(BlindGetPixelIndex(x,y)); + } else { + BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; + rgb.rgbBlue = *iDst++; + rgb.rgbGreen= *iDst++; + rgb.rgbRed = *iDst; + rgb.rgbReserved = 0; //needed for images without alpha layer + } +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y); +#else + rgb.rgbReserved = 0; +#endif //CXIMAGE_SUPPORT_ALPHA + return rgb; +} +//////////////////////////////////////////////////////////////////////////////// +BYTE CxImage::GetPixelGray(long x, long y) +{ + RGBQUAD color = GetPixelColor(x,y); + return (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::BlindSetPixelIndex(long x,long y,BYTE i) +{ +#ifdef _DEBUG + if ((pDib==NULL)||(head.biClrUsed==0)|| + (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return; + #endif +#endif + + if (head.biBitCount==8){ + info.pImage[y*info.dwEffWidth + x]=i; + return; + } else { + BYTE pos; + BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3); + if (head.biBitCount==4){ + pos = (BYTE)(4*(1-x%2)); + *iDst &= ~(0x0F<=head.biWidth)||(y>=head.biHeight)) return ; + + if (head.biBitCount==8){ + info.pImage[y*info.dwEffWidth + x]=i; + return; + } else { + BYTE pos; + BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3); + if (head.biBitCount==4){ + pos = (BYTE)(4*(1-x%2)); + *iDst &= ~(0x0F<=head.biWidth)||(y>=head.biHeight)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return; + #endif +#endif + if (head.biClrUsed) + BlindSetPixelIndex(x,y,GetNearestIndex(c)); + else { + BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; + *iDst++ = c.rgbBlue; + *iDst++ = c.rgbGreen; + *iDst = c.rgbRed; + } +#if CXIMAGE_SUPPORT_ALPHA + if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); +#endif //CXIMAGE_SUPPORT_ALPHA +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha) +{ + if ((pDib==NULL)||(x<0)||(y<0)|| + (x>=head.biWidth)||(y>=head.biHeight)) return; + if (head.biClrUsed) + BlindSetPixelIndex(x,y,GetNearestIndex(c)); + else { + BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; + *iDst++ = c.rgbBlue; + *iDst++ = c.rgbGreen; + *iDst = c.rgbRed; + } +#if CXIMAGE_SUPPORT_ALPHA + if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); +#endif //CXIMAGE_SUPPORT_ALPHA +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Blends the current pixel color with a new color. + * \param x,y = pixel + * \param c = new color + * \param blend = can be from 0 (no effect) to 1 (full effect). + * \param bSetAlpha = if true, blends also the alpha component stored in c.rgbReserved + */ +void CxImage::BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha) +{ + if ((pDib==NULL)||(x<0)||(y<0)|| + (x>=head.biWidth)||(y>=head.biHeight)) return; + + int a0 = (int)(256*blend); + int a1 = 256 - a0; + + RGBQUAD c0 = BlindGetPixelColor(x,y); + c.rgbRed = (BYTE)((c.rgbRed * a0 + c0.rgbRed * a1)>>8); + c.rgbBlue = (BYTE)((c.rgbBlue * a0 + c0.rgbBlue * a1)>>8); + c.rgbGreen = (BYTE)((c.rgbGreen * a0 + c0.rgbGreen * a1)>>8); + + if (head.biClrUsed) + BlindSetPixelIndex(x,y,GetNearestIndex(c)); + else { + BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3; + *iDst++ = c.rgbBlue; + *iDst++ = c.rgbGreen; + *iDst = c.rgbRed; +#if CXIMAGE_SUPPORT_ALPHA + if (bSetAlpha) AlphaSet(x,y,c.rgbReserved); +#endif //CXIMAGE_SUPPORT_ALPHA + } +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Returns the best palette index that matches a specified color. + */ +BYTE CxImage::GetNearestIndex(RGBQUAD c) +{ + if ((pDib==NULL)||(head.biClrUsed==0)) return 0; + + // check matching with the previous result + if (info.last_c_isvalid && (*(long*)&info.last_c == *(long*)&c)) return info.last_c_index; + info.last_c = c; + info.last_c_isvalid = true; + + BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER); + long distance=200000; + int i,j = 0; + long k,l; + int m = (int)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant); + for(i=0,l=0;i100) perc=100; + for(i=0;i=0){ + if (head.biClrUsed){ + if (GetPixelIndex(x,y) == info.nBkgndIndex) return true; + } else { + RGBQUAD ct = info.nBkgndColor; + RGBQUAD c = GetPixelColor(x,y,false); + if (*(long*)&c==*(long*)&ct) return true; + } + } + +#if CXIMAGE_SUPPORT_ALPHA + if (pAlpha) return AlphaGet(x,y)==0; +#endif + + return false; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::GetTransparentMask(CxImage* iDst) +{ + if (!pDib) return false; + + CxImage tmp; + tmp.Create(head.biWidth, head.biHeight, 1, GetType()); + tmp.SetStdPalette(); + tmp.Clear(0); + + for(long y=0; yTransfer(tmp); + else Transfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Checks if image has the same palette, if any. + * \param img = image to compare. + * \param bCheckAlpha = check also the rgbReserved field. + */ +bool CxImage::IsSamePalette(CxImage &img, bool bCheckAlpha) +{ + if (head.biClrUsed != img.head.biClrUsed) + return false; + if (head.biClrUsed == 0) + return false; + + RGBQUAD c1,c2; + for (DWORD n=0; n256) { + head.biClrImportant = 0; + return; + } + + switch(head.biBitCount){ + case 1: + head.biClrImportant = min(ncolors,2); + break; + case 4: + head.biClrImportant = min(ncolors,16); + break; + case 8: + head.biClrImportant = ncolors; + break; + } + return; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Returns pointer to pixel. Currently implemented only for truecolor images. + * + * \param x,y - coordinates + * + * \return pointer to first byte of pixel data + * + * \author ***bd*** 2.2004 + */ +void* CxImage::BlindGetPixelPointer(const long x, const long y) +{ +#ifdef _DEBUG + if ((pDib==NULL) || !IsInside(x,y)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return 0; + #endif +#endif + if (!IsIndexed()) + return info.pImage + y*info.dwEffWidth + x*3; + else + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr) +{ + DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr)); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha) +{ + if (!pDib) return; + ////////////////////////////////////////////////////// + // Draws a line using the Bresenham line algorithm + // Thanks to Jordan DeLozier + ////////////////////////////////////////////////////// + int x1 = StartX; + int y1 = StartY; + int x = x1; // Start x off at the first pixel + int y = y1; // Start y off at the first pixel + int x2 = EndX; + int y2 = EndY; + + int xinc1,xinc2,yinc1,yinc2; // Increasing values + int den, num, numadd,numpixels; + int deltax = abs(x2 - x1); // The difference between the x's + int deltay = abs(y2 - y1); // The difference between the y's + + // Get Increasing Values + if (x2 >= x1) { // The x-values are increasing + xinc1 = 1; + xinc2 = 1; + } else { // The x-values are decreasing + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) { // The y-values are increasing + yinc1 = 1; + yinc2 = 1; + } else { // The y-values are decreasing + yinc1 = -1; + yinc2 = -1; + } + + // Actually draw the line + if (deltax >= deltay) // There is at least one x-value for every y-value + { + xinc1 = 0; // Don't change the x when numerator >= denominator + yinc2 = 0; // Don't change the y for every iteration + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; // There are more x-values than y-values + } + else // There is at least one y-value for every x-value + { + xinc2 = 0; // Don't change the x for every iteration + yinc1 = 0; // Don't change the y when numerator >= denominator + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; // There are more y-values than x-values + } + + for (int curpixel = 0; curpixel <= numpixels; curpixel++) + { + // Draw the current pixel + SetPixelColor(x,y,color,bSetAlpha); + + num += numadd; // Increase the numerator by the top of the fraction + if (num >= den) // Check if numerator >= denominator + { + num -= den; // Calculate the new numerator value + x += xinc1; // Change the x as appropriate + y += yinc1; // Change the y as appropriate + } + x += xinc2; // Change the x as appropriate + y += yinc2; // Change the y as appropriate + } +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Sets a palette with standard colors for 1, 4 and 8 bpp images. + */ +void CxImage::SetStdPalette() +{ + if (!pDib) return; + switch (head.biBitCount){ + case 8: + { + const BYTE pal256[1024] = {0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0, + 192,220,192,0,240,202,166,0,212,240,255,0,177,226,255,0,142,212,255,0,107,198,255,0, + 72,184,255,0,37,170,255,0,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0, + 50,80,0,212,227,255,0,177,199,255,0,142,171,255,0,107,143,255,0,72,115,255,0,37,87,255,0,0, + 85,255,0,0,73,220,0,0,61,185,0,0,49,150,0,0,37,115,0,0,25,80,0,212,212,255,0,177,177,255,0, + 142,142,255,0,107,107,255,0,72,72,255,0,37,37,255,0,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0, + 0,0,115,0,0,0,80,0,227,212,255,0,199,177,255,0,171,142,255,0,143,107,255,0,115,72,255,0, + 87,37,255,0,85,0,255,0,73,0,220,0,61,0,185,0,49,0,150,0,37,0,115,0,25,0,80,0,240,212,255,0, + 226,177,255,0,212,142,255,0,198,107,255,0,184,72,255,0,170,37,255,0,170,0,255,0,146,0,220,0, + 122,0,185,0,98,0,150,0,74,0,115,0,50,0,80,0,255,212,255,0,255,177,255,0,255,142,255,0,255,107,255,0, + 255,72,255,0,255,37,255,0,254,0,254,0,220,0,220,0,185,0,185,0,150,0,150,0,115,0,115,0,80,0,80,0, + 255,212,240,0,255,177,226,0,255,142,212,0,255,107,198,0,255,72,184,0,255,37,170,0,255,0,170,0, + 220,0,146,0,185,0,122,0,150,0,98,0,115,0,74,0,80,0,50,0,255,212,227,0,255,177,199,0,255,142,171,0, + 255,107,143,0,255,72,115,0,255,37,87,0,255,0,85,0,220,0,73,0,185,0,61,0,150,0,49,0,115,0,37,0, + 80,0,25,0,255,212,212,0,255,177,177,0,255,142,142,0,255,107,107,0,255,72,72,0,255,37,37,0,254,0, + 0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,0,255,227,212,0,255,199,177,0,255,171,142,0, + 255,143,107,0,255,115,72,0,255,87,37,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0,115,37,0, + 0,80,25,0,0,255,240,212,0,255,226,177,0,255,212,142,0,255,198,107,0,255,184,72,0,255,170,37,0, + 255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,0,255,255,212,0,255,255,177,0, + 255,255,142,0,255,255,107,0,255,255,72,0,255,255,37,0,254,254,0,0,220,220,0,0,185,185,0,0,150,150,0, + 0,115,115,0,0,80,80,0,0,240,255,212,0,226,255,177,0,212,255,142,0,198,255,107,0,184,255,72,0, + 170,255,37,0,170,255,0,0,146,220,0,0,122,185,0,0,98,150,0,0,74,115,0,0,50,80,0,0,227,255,212,0, + 199,255,177,0,171,255,142,0,143,255,107,0,115,255,72,0,87,255,37,0,85,255,0,0,73,220,0,0,61,185,0, + 0,49,150,0,0,37,115,0,0,25,80,0,0,212,255,212,0,177,255,177,0,142,255,142,0,107,255,107,0,72,255,72,0, + 37,255,37,0,0,254,0,0,0,220,0,0,0,185,0,0,0,150,0,0,0,115,0,0,0,80,0,0,212,255,227,0,177,255,199,0, + 142,255,171,0,107,255,143,0,72,255,115,0,37,255,87,0,0,255,85,0,0,220,73,0,0,185,61,0,0,150,49,0,0, + 115,37,0,0,80,25,0,212,255,240,0,177,255,226,0,142,255,212,0,107,255,198,0,72,255,184,0,37,255,170,0, + 0,255,170,0,0,220,146,0,0,185,122,0,0,150,98,0,0,115,74,0,0,80,50,0,212,255,255,0,177,255,255,0, + 142,255,255,0,107,255,255,0,72,255,255,0,37,255,255,0,0,254,254,0,0,220,220,0,0,185,185,0,0, + 150,150,0,0,115,115,0,0,80,80,0,242,242,242,0,230,230,230,0,218,218,218,0,206,206,206,0,194,194,194,0, + 182,182,182,0,170,170,170,0,158,158,158,0,146,146,146,0,134,134,134,0,122,122,122,0,110,110,110,0, + 98,98,98,0,86,86,86,0,74,74,74,0,62,62,62,0,50,50,50,0,38,38,38,0,26,26,26,0,14,14,14,0,240,251,255,0, + 164,160,160,0,128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0}; + memcpy(GetPalette(),pal256,1024); + break; + } + case 4: + { + const BYTE pal16[64]={0,0,0,0,0,0,128,0,0,128,0,0,0,128,128,0,128,0,0,0,128,0,128,0,128,128,0,0,192,192,192,0, + 128,128,128,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255,0,255,0,255,255,0,0,255,255,255,0}; + memcpy(GetPalette(),pal16,64); + break; + } + case 1: + { + const BYTE pal2[8]={0,0,0,0,255,255,255,0}; + memcpy(GetPalette(),pal2,8); + break; + } + } + info.last_c_isvalid = false; + return; +} +//////////////////////////////////////////////////////////////////////////////// diff --git a/utilities/CxImage/ximapcx.cpp b/utilities/CxImage/ximapcx.cpp index 0d7e0a8..f32ba33 100644 --- a/utilities/CxImage/ximapcx.cpp +++ b/utilities/CxImage/ximapcx.cpp @@ -1,479 +1,479 @@ -/* - * File: ximapcx.cpp - * Purpose: Platform Independent PCX Image Class Loader and Writer - * 05/Jan/2002 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - * - * based on ppmtopcx.c - convert a portable pixmap to PCX - * Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) - * based on ppmtopcx.c by Michael Davidson - */ - -#include "ximapcx.h" - -#if CXIMAGE_SUPPORT_PCX - -#include "xmemfile.h" - -#define PCX_MAGIC 0X0A // PCX magic number -#define PCX_256_COLORS 0X0C // magic number for 256 colors -#define PCX_HDR_SIZE 128 // size of PCX header -#define PCX_MAXCOLORS 256 -#define PCX_MAXPLANES 4 -#define PCX_MAXVAL 255 - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImagePCX::Decode(CxFile *hFile) -{ - if (hFile == NULL) return false; - - PCXHEADER pcxHeader; - int i, x, y, y2, nbytes, count, Height, Width; - BYTE c, ColorMap[PCX_MAXCOLORS][3]; - BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL; - BYTE *pcxplanes, *pcxpixels; - - cx_try - { - if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) cx_throw("Can't read PCX image"); - - PCX_toh(&pcxHeader); - - if (pcxHeader.Manufacturer != PCX_MAGIC) cx_throw("Error: Not a PCX file"); - // Check for PCX run length encoding - if (pcxHeader.Encoding != 1) cx_throw("PCX file has unknown encoding scheme"); - - Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1; - Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1; - info.xDPI = pcxHeader.Hres; - info.yDPI = pcxHeader.Vres; - - if (info.nEscape == -1){ - head.biWidth = Width; - head.biHeight= Height; - info.dwType = CXIMAGE_FORMAT_PCX; - return true; - } - - // Check that we can handle this image format - if (pcxHeader.ColorPlanes > 4) - cx_throw("Can't handle image with more than 4 planes"); - - // Create the image - if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){ - Create (Width, Height, 24, CXIMAGE_FORMAT_PCX); -#if CXIMAGE_SUPPORT_ALPHA - if (pcxHeader.ColorPlanes==4) AlphaCreate(); -#endif //CXIMAGE_SUPPORT_ALPHA - } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1) - Create (Width, Height, 4, CXIMAGE_FORMAT_PCX); - else - Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX); - - if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding - - //Read the image and check if it's ok - nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height; - lpHead1 = pcximage = (BYTE*)malloc(nbytes); - while (nbytes > 0){ - if (hFile == NULL || hFile->Eof()) cx_throw("corrupted PCX"); - - hFile->Read(&c,1,1); - if ((c & 0XC0) != 0XC0){ // Repeated group - *pcximage++ = c; - --nbytes; - continue; - } - count = c & 0X3F; // extract count - hFile->Read(&c,1,1); - if (count > nbytes) cx_throw("repeat count spans end of image"); - - nbytes -= count; - while (--count >=0) *pcximage++ = c; - } - pcximage = lpHead1; - - //store the palette - for (i = 0; i < 16; i++){ - ColorMap[i][0] = pcxHeader.ColorMap[i][0]; - ColorMap[i][1] = pcxHeader.ColorMap[i][1]; - ColorMap[i][2] = pcxHeader.ColorMap[i][2]; - } - if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){ - hFile->Read(&c,1,1); - if (c != PCX_256_COLORS) cx_throw("bad color map signature"); - - for (i = 0; i < PCX_MAXCOLORS; i++){ - hFile->Read(&ColorMap[i][0],1,1); - hFile->Read(&ColorMap[i][1],1,1); - hFile->Read(&ColorMap[i][2],1,1); - } - } - if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){ - ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0; - ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255; - } - - for (DWORD idx=0; idx - cancel decoding - - y2=Height-1-y; - pcxpixels = lpHead2; - pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes); - - if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){ - // Deal with 24 bit color image - for (x = 0; x < Width; x++){ - SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); - } - continue; -#if CXIMAGE_SUPPORT_ALPHA - } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){ - for (x = 0; x < Width; x++){ - SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); - AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]); - } - continue; -#endif //CXIMAGE_SUPPORT_ALPHA - } else if (pcxHeader.ColorPlanes == 1) { - if (!PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){ - cx_throw("PCX_UnpackPixels: Can't handle packed pixels with more than 1 plane"); - } - } else { - if (!PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){ - cx_throw("PCX_PlanesToPixels: more than 4 planes or more than 1 bit per pixel"); - } - } - for (x = 0; x < Width; x++) SetPixelIndex(x,y2,pcxpixels[x]); - } - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (lpHead1){ free(lpHead1); lpHead1 = NULL; } - if (lpHead2){ free(lpHead2); lpHead2 = NULL; } - return false; - } - if (lpHead1){ free(lpHead1); lpHead1 = NULL; } - if (lpHead2){ free(lpHead2); lpHead2 = NULL; } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImagePCX::Encode(CxFile * hFile) -{ - if (EncodeSafeCheck(hFile)) return false; - - cx_try - { - PCXHEADER pcxHeader; - memset(&pcxHeader,0,sizeof(pcxHeader)); - pcxHeader.Manufacturer = PCX_MAGIC; - pcxHeader.Version = 5; - pcxHeader.Encoding = 1; - pcxHeader.Xmin = 0; - pcxHeader.Ymin = 0; - pcxHeader.Xmax = (WORD)head.biWidth-1; - pcxHeader.Ymax = (WORD)head.biHeight-1; - pcxHeader.Hres = (WORD)info.xDPI; - pcxHeader.Vres = (WORD)info.yDPI; - pcxHeader.Reserved = 0; - pcxHeader.PaletteType = head.biClrUsed==0; - - switch(head.biBitCount){ - case 24: - case 8: - { - pcxHeader.BitsPerPixel = 8; - pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1; -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4; -#endif //CXIMAGE_SUPPORT_ALPHA - pcxHeader.BytesPerLine = (WORD)head.biWidth; - break; - } - default: //(4 1) - pcxHeader.BitsPerPixel = 1; - pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1; - pcxHeader.BytesPerLine = (WORD)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3); - } - - if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){ - pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0; - pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255; - } - if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){ - RGBQUAD c; - for (int i = 0; i < 16; i++){ - c=GetPaletteColor(i); - pcxHeader.ColorMap[i][0] = c.rgbRed; - pcxHeader.ColorMap[i][1] = c.rgbGreen; - pcxHeader.ColorMap[i][2] = c.rgbBlue; - } - } - - pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1); - - PCX_toh(&pcxHeader); - if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 ) - cx_throw("cannot write PCX header"); - PCX_toh(&pcxHeader); - - CxMemFile buffer; - buffer.Open(); - - BYTE c,n; - long x,y; - if (head.biClrUsed==0){ - for (y = head.biHeight-1; y >=0 ; y--){ - for (int p=0; pWrite(buffer.GetBuffer(false),buffer.Tell(),1); - - } else if (head.biBitCount==8) { - - for (y = head.biHeight-1; y >=0 ; y--){ - c=n=0; - for (x = 0; xWrite(buffer.GetBuffer(false),buffer.Tell(),1); - - if (head.biBitCount == 8){ - hFile->PutC(0x0C); - BYTE* pal = (BYTE*)malloc(768); - RGBQUAD c; - for (int i=0;i<256;i++){ - c=GetPaletteColor(i); - pal[3*i+0] = c.rgbRed; - pal[3*i+1] = c.rgbGreen; - pal[3*i+2] = c.rgbBlue; - } - hFile->Write(pal,768,1); - free(pal); - } - } else { //(head.biBitCount==4) || (head.biBitCount==1) - - RGBQUAD *rgb = GetPalette(); - bool binvert = false; - if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1); - - BYTE* plane = (BYTE*)malloc(pcxHeader.BytesPerLine); - BYTE* raw = (BYTE*)malloc(head.biWidth); - - for(y = head.biHeight-1; y >=0 ; y--) { - - for( x = 0; x < head.biWidth; x++) raw[x] = (BYTE)GetPixelIndex(x,y); - - if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x]; - - for( x = 0; x < pcxHeader.ColorPlanes; x++ ) { - PCX_PixelsToPlanes(raw, head.biWidth, plane, x); - PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer); - } - } - - free(plane); - free(raw); - - hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1); - - } - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - return false; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -// Convert multi-plane format into 1 pixel per byte -// from unpacked file data bitplanes[] into pixel row pixels[] -// image Height rows, with each row having planes image planes each -// bytesperline bytes -bool CxImagePCX::PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel) -{ - int i, j, npixels; - BYTE * p; - if (planes > 4) return false; - if (bitsperpixel != 1) return false; - - // Clear the pixel buffer - npixels = (bytesperline * 8) / bitsperpixel; - p = pixels; - while (--npixels >= 0) *p++ = 0; - - // Do the format conversion - for (i = 0; i < planes; i++){ - int pixbit, bits, mask; - p = pixels; - pixbit = (1 << i); // pixel bit for this plane - for (j = 0; j < bytesperline; j++){ - bits = *bitplanes++; - for (mask = 0X80; mask != 0; mask >>= 1, p++) - if (bits & mask) *p |= pixbit; - } - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -// convert packed pixel format into 1 pixel per byte -// from unpacked file data bitplanes[] into pixel row pixels[] -// image Height rows, with each row having planes image planes each -// bytesperline bytes -bool CxImagePCX::PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel) -{ - register int bits; - if (planes != 1) return false; - - if (bitsperpixel == 8){ // 8 bits/pixels, no unpacking needed - while (bytesperline-- > 0) *pixels++ = *bitplanes++; - } else if (bitsperpixel == 4){ // 4 bits/pixel, two pixels per byte - while (bytesperline-- > 0){ - bits = *bitplanes++; - *pixels++ = (BYTE)((bits >> 4) & 0X0F); - *pixels++ = (BYTE)((bits) & 0X0F); - } - } else if (bitsperpixel == 2){ // 2 bits/pixel, four pixels per byte - while (bytesperline-- > 0){ - bits = *bitplanes++; - *pixels++ = (BYTE)((bits >> 6) & 0X03); - *pixels++ = (BYTE)((bits >> 4) & 0X03); - *pixels++ = (BYTE)((bits >> 2) & 0X03); - *pixels++ = (BYTE)((bits) & 0X03); - } - } else if (bitsperpixel == 1){ // 1 bits/pixel, 8 pixels per byte - while (bytesperline-- > 0){ - bits = *bitplanes++; - *pixels++ = ((bits & 0X80) != 0); - *pixels++ = ((bits & 0X40) != 0); - *pixels++ = ((bits & 0X20) != 0); - *pixels++ = ((bits & 0X10) != 0); - *pixels++ = ((bits & 0X08) != 0); - *pixels++ = ((bits & 0X04) != 0); - *pixels++ = ((bits & 0X02) != 0); - *pixels++ = ((bits & 0X01) != 0); - } - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/* PCX_PackPixels(const long p,BYTE &c, BYTE &n, long &l, CxFile &f) - * p = current pixel (-1 ends the line -2 ends odd line) - * c = previous pixel - * n = number of consecutive pixels - */ -void CxImagePCX::PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f) -{ - if (p!=c && n){ - if (n==1 && c<0xC0){ - f.PutC(c); - } else { - f.PutC(0xC0|n); - f.PutC(c); - } - n=0; - } - if (n==0x3F) { - f.PutC(0xFF); - f.PutC(c); - n=0; - } - if (p==-2) f.PutC(0); - c=(BYTE)p; - n++; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImagePCX::PCX_PackPlanes(BYTE* buff, const long size, CxFile &f) -{ - BYTE *start,*end; - BYTE c, previous, count; - - start = buff; - end = buff + size; - previous = *start++; - count = 1; - - while (start < end) { - c = *start++; - if (c == previous && count < 63) { - ++count; - continue; - } - - if (count > 1 || (previous & 0xc0) == 0xc0) { - f.PutC( count | 0xc0 ); - } - f.PutC(previous); - previous = c; - count = 1; - } - - if (count > 1 || (previous & 0xc0) == 0xc0) { - count |= 0xc0; - f.PutC(count); - } - f.PutC(previous); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImagePCX::PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane) -{ - int cbit, x, mask; - unsigned char *cp = buf-1; - - mask = 1 << plane; - cbit = -1; - for( x = 0; x < width; x++ ) { - if( cbit < 0 ) { - cbit = 7; - *++cp = 0; - } - if( raw[x] & mask ) - *cp |= (1<Xmin = ntohs(p->Xmin); - p->Ymin = ntohs(p->Ymin); - p->Xmax = ntohs(p->Xmax); - p->Ymax = ntohs(p->Ymax); - p->Hres = ntohs(p->Hres); - p->Vres = ntohs(p->Vres); - p->BytesPerLine = ntohs(p->BytesPerLine); - p->PaletteType = ntohs(p->PaletteType); -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_PCX +/* + * File: ximapcx.cpp + * Purpose: Platform Independent PCX Image Class Loader and Writer + * 05/Jan/2002 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + * + * based on ppmtopcx.c - convert a portable pixmap to PCX + * Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) + * based on ppmtopcx.c by Michael Davidson + */ + +#include "ximapcx.h" + +#if CXIMAGE_SUPPORT_PCX + +#include "xmemfile.h" + +#define PCX_MAGIC 0X0A // PCX magic number +#define PCX_256_COLORS 0X0C // magic number for 256 colors +#define PCX_HDR_SIZE 128 // size of PCX header +#define PCX_MAXCOLORS 256 +#define PCX_MAXPLANES 4 +#define PCX_MAXVAL 255 + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImagePCX::Decode(CxFile *hFile) +{ + if (hFile == NULL) return false; + + PCXHEADER pcxHeader; + int i, x, y, y2, nbytes, count, Height, Width; + BYTE c, ColorMap[PCX_MAXCOLORS][3]; + BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL; + BYTE *pcxplanes, *pcxpixels; + + cx_try + { + if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) cx_throw("Can't read PCX image"); + + PCX_toh(&pcxHeader); + + if (pcxHeader.Manufacturer != PCX_MAGIC) cx_throw("Error: Not a PCX file"); + // Check for PCX run length encoding + if (pcxHeader.Encoding != 1) cx_throw("PCX file has unknown encoding scheme"); + + Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1; + Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1; + info.xDPI = pcxHeader.Hres; + info.yDPI = pcxHeader.Vres; + + if (info.nEscape == -1){ + head.biWidth = Width; + head.biHeight= Height; + info.dwType = CXIMAGE_FORMAT_PCX; + return true; + } + + // Check that we can handle this image format + if (pcxHeader.ColorPlanes > 4) + cx_throw("Can't handle image with more than 4 planes"); + + // Create the image + if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){ + Create (Width, Height, 24, CXIMAGE_FORMAT_PCX); +#if CXIMAGE_SUPPORT_ALPHA + if (pcxHeader.ColorPlanes==4) AlphaCreate(); +#endif //CXIMAGE_SUPPORT_ALPHA + } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1) + Create (Width, Height, 4, CXIMAGE_FORMAT_PCX); + else + Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX); + + if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding + + //Read the image and check if it's ok + nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height; + lpHead1 = pcximage = (BYTE*)malloc(nbytes); + while (nbytes > 0){ + if (hFile == NULL || hFile->Eof()) cx_throw("corrupted PCX"); + + hFile->Read(&c,1,1); + if ((c & 0XC0) != 0XC0){ // Repeated group + *pcximage++ = c; + --nbytes; + continue; + } + count = c & 0X3F; // extract count + hFile->Read(&c,1,1); + if (count > nbytes) cx_throw("repeat count spans end of image"); + + nbytes -= count; + while (--count >=0) *pcximage++ = c; + } + pcximage = lpHead1; + + //store the palette + for (i = 0; i < 16; i++){ + ColorMap[i][0] = pcxHeader.ColorMap[i][0]; + ColorMap[i][1] = pcxHeader.ColorMap[i][1]; + ColorMap[i][2] = pcxHeader.ColorMap[i][2]; + } + if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){ + hFile->Read(&c,1,1); + if (c != PCX_256_COLORS) cx_throw("bad color map signature"); + + for (i = 0; i < PCX_MAXCOLORS; i++){ + hFile->Read(&ColorMap[i][0],1,1); + hFile->Read(&ColorMap[i][1],1,1); + hFile->Read(&ColorMap[i][2],1,1); + } + } + if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){ + ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0; + ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255; + } + + for (DWORD idx=0; idx - cancel decoding + + y2=Height-1-y; + pcxpixels = lpHead2; + pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes); + + if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){ + // Deal with 24 bit color image + for (x = 0; x < Width; x++){ + SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); + } + continue; +#if CXIMAGE_SUPPORT_ALPHA + } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){ + for (x = 0; x < Width; x++){ + SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x])); + AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]); + } + continue; +#endif //CXIMAGE_SUPPORT_ALPHA + } else if (pcxHeader.ColorPlanes == 1) { + if (!PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){ + cx_throw("PCX_UnpackPixels: Can't handle packed pixels with more than 1 plane"); + } + } else { + if (!PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){ + cx_throw("PCX_PlanesToPixels: more than 4 planes or more than 1 bit per pixel"); + } + } + for (x = 0; x < Width; x++) SetPixelIndex(x,y2,pcxpixels[x]); + } + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (lpHead1){ free(lpHead1); lpHead1 = NULL; } + if (lpHead2){ free(lpHead2); lpHead2 = NULL; } + return false; + } + if (lpHead1){ free(lpHead1); lpHead1 = NULL; } + if (lpHead2){ free(lpHead2); lpHead2 = NULL; } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImagePCX::Encode(CxFile * hFile) +{ + if (EncodeSafeCheck(hFile)) return false; + + cx_try + { + PCXHEADER pcxHeader; + memset(&pcxHeader,0,sizeof(pcxHeader)); + pcxHeader.Manufacturer = PCX_MAGIC; + pcxHeader.Version = 5; + pcxHeader.Encoding = 1; + pcxHeader.Xmin = 0; + pcxHeader.Ymin = 0; + pcxHeader.Xmax = (WORD)head.biWidth-1; + pcxHeader.Ymax = (WORD)head.biHeight-1; + pcxHeader.Hres = (WORD)info.xDPI; + pcxHeader.Vres = (WORD)info.yDPI; + pcxHeader.Reserved = 0; + pcxHeader.PaletteType = head.biClrUsed==0; + + switch(head.biBitCount){ + case 24: + case 8: + { + pcxHeader.BitsPerPixel = 8; + pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1; +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4; +#endif //CXIMAGE_SUPPORT_ALPHA + pcxHeader.BytesPerLine = (WORD)head.biWidth; + break; + } + default: //(4 1) + pcxHeader.BitsPerPixel = 1; + pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1; + pcxHeader.BytesPerLine = (WORD)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3); + } + + if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){ + pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0; + pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255; + } + if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){ + RGBQUAD c; + for (int i = 0; i < 16; i++){ + c=GetPaletteColor(i); + pcxHeader.ColorMap[i][0] = c.rgbRed; + pcxHeader.ColorMap[i][1] = c.rgbGreen; + pcxHeader.ColorMap[i][2] = c.rgbBlue; + } + } + + pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1); + + PCX_toh(&pcxHeader); + if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 ) + cx_throw("cannot write PCX header"); + PCX_toh(&pcxHeader); + + CxMemFile buffer; + buffer.Open(); + + BYTE c,n; + long x,y; + if (head.biClrUsed==0){ + for (y = head.biHeight-1; y >=0 ; y--){ + for (int p=0; pWrite(buffer.GetBuffer(false),buffer.Tell(),1); + + } else if (head.biBitCount==8) { + + for (y = head.biHeight-1; y >=0 ; y--){ + c=n=0; + for (x = 0; xWrite(buffer.GetBuffer(false),buffer.Tell(),1); + + if (head.biBitCount == 8){ + hFile->PutC(0x0C); + BYTE* pal = (BYTE*)malloc(768); + RGBQUAD c; + for (int i=0;i<256;i++){ + c=GetPaletteColor(i); + pal[3*i+0] = c.rgbRed; + pal[3*i+1] = c.rgbGreen; + pal[3*i+2] = c.rgbBlue; + } + hFile->Write(pal,768,1); + free(pal); + } + } else { //(head.biBitCount==4) || (head.biBitCount==1) + + RGBQUAD *rgb = GetPalette(); + bool binvert = false; + if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1); + + BYTE* plane = (BYTE*)malloc(pcxHeader.BytesPerLine); + BYTE* raw = (BYTE*)malloc(head.biWidth); + + for(y = head.biHeight-1; y >=0 ; y--) { + + for( x = 0; x < head.biWidth; x++) raw[x] = (BYTE)GetPixelIndex(x,y); + + if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x]; + + for( x = 0; x < pcxHeader.ColorPlanes; x++ ) { + PCX_PixelsToPlanes(raw, head.biWidth, plane, x); + PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer); + } + } + + free(plane); + free(raw); + + hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1); + + } + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + return false; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +// Convert multi-plane format into 1 pixel per byte +// from unpacked file data bitplanes[] into pixel row pixels[] +// image Height rows, with each row having planes image planes each +// bytesperline bytes +bool CxImagePCX::PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel) +{ + int i, j, npixels; + BYTE * p; + if (planes > 4) return false; + if (bitsperpixel != 1) return false; + + // Clear the pixel buffer + npixels = (bytesperline * 8) / bitsperpixel; + p = pixels; + while (--npixels >= 0) *p++ = 0; + + // Do the format conversion + for (i = 0; i < planes; i++){ + int pixbit, bits, mask; + p = pixels; + pixbit = (1 << i); // pixel bit for this plane + for (j = 0; j < bytesperline; j++){ + bits = *bitplanes++; + for (mask = 0X80; mask != 0; mask >>= 1, p++) + if (bits & mask) *p |= pixbit; + } + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +// convert packed pixel format into 1 pixel per byte +// from unpacked file data bitplanes[] into pixel row pixels[] +// image Height rows, with each row having planes image planes each +// bytesperline bytes +bool CxImagePCX::PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel) +{ + register int bits; + if (planes != 1) return false; + + if (bitsperpixel == 8){ // 8 bits/pixels, no unpacking needed + while (bytesperline-- > 0) *pixels++ = *bitplanes++; + } else if (bitsperpixel == 4){ // 4 bits/pixel, two pixels per byte + while (bytesperline-- > 0){ + bits = *bitplanes++; + *pixels++ = (BYTE)((bits >> 4) & 0X0F); + *pixels++ = (BYTE)((bits) & 0X0F); + } + } else if (bitsperpixel == 2){ // 2 bits/pixel, four pixels per byte + while (bytesperline-- > 0){ + bits = *bitplanes++; + *pixels++ = (BYTE)((bits >> 6) & 0X03); + *pixels++ = (BYTE)((bits >> 4) & 0X03); + *pixels++ = (BYTE)((bits >> 2) & 0X03); + *pixels++ = (BYTE)((bits) & 0X03); + } + } else if (bitsperpixel == 1){ // 1 bits/pixel, 8 pixels per byte + while (bytesperline-- > 0){ + bits = *bitplanes++; + *pixels++ = ((bits & 0X80) != 0); + *pixels++ = ((bits & 0X40) != 0); + *pixels++ = ((bits & 0X20) != 0); + *pixels++ = ((bits & 0X10) != 0); + *pixels++ = ((bits & 0X08) != 0); + *pixels++ = ((bits & 0X04) != 0); + *pixels++ = ((bits & 0X02) != 0); + *pixels++ = ((bits & 0X01) != 0); + } + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/* PCX_PackPixels(const long p,BYTE &c, BYTE &n, long &l, CxFile &f) + * p = current pixel (-1 ends the line -2 ends odd line) + * c = previous pixel + * n = number of consecutive pixels + */ +void CxImagePCX::PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f) +{ + if (p!=c && n){ + if (n==1 && c<0xC0){ + f.PutC(c); + } else { + f.PutC(0xC0|n); + f.PutC(c); + } + n=0; + } + if (n==0x3F) { + f.PutC(0xFF); + f.PutC(c); + n=0; + } + if (p==-2) f.PutC(0); + c=(BYTE)p; + n++; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImagePCX::PCX_PackPlanes(BYTE* buff, const long size, CxFile &f) +{ + BYTE *start,*end; + BYTE c, previous, count; + + start = buff; + end = buff + size; + previous = *start++; + count = 1; + + while (start < end) { + c = *start++; + if (c == previous && count < 63) { + ++count; + continue; + } + + if (count > 1 || (previous & 0xc0) == 0xc0) { + f.PutC( count | 0xc0 ); + } + f.PutC(previous); + previous = c; + count = 1; + } + + if (count > 1 || (previous & 0xc0) == 0xc0) { + count |= 0xc0; + f.PutC(count); + } + f.PutC(previous); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImagePCX::PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane) +{ + int cbit, x, mask; + unsigned char *cp = buf-1; + + mask = 1 << plane; + cbit = -1; + for( x = 0; x < width; x++ ) { + if( cbit < 0 ) { + cbit = 7; + *++cp = 0; + } + if( raw[x] & mask ) + *cp |= (1<Xmin = ntohs(p->Xmin); + p->Ymin = ntohs(p->Ymin); + p->Xmax = ntohs(p->Xmax); + p->Ymax = ntohs(p->Ymax); + p->Hres = ntohs(p->Hres); + p->Vres = ntohs(p->Vres); + p->BytesPerLine = ntohs(p->BytesPerLine); + p->PaletteType = ntohs(p->PaletteType); +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_PCX diff --git a/utilities/CxImage/ximapcx.h b/utilities/CxImage/ximapcx.h index 6e18f15..271992c 100644 --- a/utilities/CxImage/ximapcx.h +++ b/utilities/CxImage/ximapcx.h @@ -1,64 +1,64 @@ -/* - * File: ximapcx.h - * Purpose: PCX Image Class Loader and Writer - */ -/* ========================================================== - * CxImagePCX (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Parts of the code come from Paintlib: Copyright (c) 1996-1998 Ulrich von Zadow - * ========================================================== - */ -#if !defined(__ximaPCX_h) -#define __ximaPCX_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_PCX - -class CxImagePCX: public CxImage -{ -// PCX Image File -#pragma pack(1) -typedef struct tagPCXHEADER -{ - char Manufacturer; // always 0X0A - char Version; // version number - char Encoding; // always 1 - char BitsPerPixel; // color bits - WORD Xmin, Ymin; // image origin - WORD Xmax, Ymax; // image dimensions - WORD Hres, Vres; // resolution values - BYTE ColorMap[16][3]; // color palette - char Reserved; - char ColorPlanes; // color planes - WORD BytesPerLine; // line buffer size - WORD PaletteType; // grey or color palette - char Filter[58]; -} PCXHEADER; -#pragma pack() - -public: - CxImagePCX(): CxImage(CXIMAGE_FORMAT_PCX) {} - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PCX);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PCX);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE -protected: - bool PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel); - bool PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel); - void PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f); - void PCX_PackPlanes(BYTE* buff, const long size, CxFile &f); - void PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane); - void PCX_toh(PCXHEADER* p); -}; - -#endif - -#endif +/* + * File: ximapcx.h + * Purpose: PCX Image Class Loader and Writer + */ +/* ========================================================== + * CxImagePCX (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Parts of the code come from Paintlib: Copyright (c) 1996-1998 Ulrich von Zadow + * ========================================================== + */ +#if !defined(__ximaPCX_h) +#define __ximaPCX_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_PCX + +class CxImagePCX: public CxImage +{ +// PCX Image File +#pragma pack(1) +typedef struct tagPCXHEADER +{ + char Manufacturer; // always 0X0A + char Version; // version number + char Encoding; // always 1 + char BitsPerPixel; // color bits + WORD Xmin, Ymin; // image origin + WORD Xmax, Ymax; // image dimensions + WORD Hres, Vres; // resolution values + BYTE ColorMap[16][3]; // color palette + char Reserved; + char ColorPlanes; // color planes + WORD BytesPerLine; // line buffer size + WORD PaletteType; // grey or color palette + char Filter[58]; +} PCXHEADER; +#pragma pack() + +public: + CxImagePCX(): CxImage(CXIMAGE_FORMAT_PCX) {} + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PCX);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PCX);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE +protected: + bool PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel); + bool PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel); + void PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f); + void PCX_PackPlanes(BYTE* buff, const long size, CxFile &f); + void PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane); + void PCX_toh(PCXHEADER* p); +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximapng.cpp b/utilities/CxImage/ximapng.cpp index f91bf27..96b9257 100644 --- a/utilities/CxImage/ximapng.cpp +++ b/utilities/CxImage/ximapng.cpp @@ -1,536 +1,536 @@ -/* - * File: ximapng.cpp - * Purpose: Platform Independent PNG Image Class Loader and Writer - * 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximapng.h" - -#if CXIMAGE_SUPPORT_PNG - -#include "ximaiter.h" - -//////////////////////////////////////////////////////////////////////////////// -void CxImagePNG::ima_png_error(png_struct *png_ptr, char *message) -{ - strcpy(info.szLastError,message); - longjmp(png_ptr->jmpbuf, 1); -} -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -void CxImagePNG::expand2to4bpp(BYTE* prow) -{ - BYTE *psrc,*pdst; - BYTE pos,idx; - for(long x=head.biWidth-1;x>=0;x--){ - psrc = prow + ((2*x)>>3); - pdst = prow + ((4*x)>>3); - pos = (BYTE)(2*(3-x%4)); - idx = (BYTE)((*psrc & (0x03<>pos); - pos = (BYTE)(4*(1-x%2)); - *pdst &= ~(0x0F<jmpbuf)) { - /* Free all of the memory associated with the png_ptr and info_ptr */ - delete [] row_pointers; - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - cx_throw(""); - } - - // use custom I/O functions - png_set_read_fn(png_ptr, hFile, /*(png_rw_ptr)*/user_read_data); - png_set_error_fn(png_ptr,info.szLastError,/*(png_error_ptr)*/user_error_fn,NULL); - - /* read the file information */ - png_read_info(png_ptr, info_ptr); - - if (info.nEscape == -1){ - head.biWidth = info_ptr->width; - head.biHeight= info_ptr->height; - info.dwType = CXIMAGE_FORMAT_PNG; - longjmp(png_ptr->jmpbuf, 1); - } - - /* calculate new number of channels */ - int channels=0; - switch(info_ptr->color_type){ - case PNG_COLOR_TYPE_GRAY: - case PNG_COLOR_TYPE_PALETTE: - channels = 1; - break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - channels = 2; - break; - case PNG_COLOR_TYPE_RGB: - channels = 3; - break; - case PNG_COLOR_TYPE_RGB_ALPHA: - channels = 4; - break; - default: - strcpy(info.szLastError,"unknown PNG color type"); - longjmp(png_ptr->jmpbuf, 1); - } - - //find the right pixel depth used for cximage - int pixel_depth = info_ptr->pixel_depth; - if (channels == 1 && pixel_depth>8) pixel_depth=8; - if (channels == 2) pixel_depth=8; - if (channels >= 3) pixel_depth=24; - - if (!Create(info_ptr->width, info_ptr->height, pixel_depth, CXIMAGE_FORMAT_PNG)){ - longjmp(png_ptr->jmpbuf, 1); - } - - /* get metrics */ - switch (info_ptr->phys_unit_type) - { - case PNG_RESOLUTION_UNKNOWN: - SetXDPI(info_ptr->x_pixels_per_unit); - SetYDPI(info_ptr->y_pixels_per_unit); - break; - case PNG_RESOLUTION_METER: - SetXDPI((long)floor(info_ptr->x_pixels_per_unit * 254.0 / 10000.0 + 0.5)); - SetYDPI((long)floor(info_ptr->y_pixels_per_unit * 254.0 / 10000.0 + 0.5)); - break; - } - - if (info_ptr->num_palette>0){ - SetPalette((rgb_color*)info_ptr->palette,info_ptr->num_palette); - SetClrImportant(info_ptr->num_palette); - } else if (info_ptr->bit_depth ==2) { // needed for 2 bpp grayscale PNGs - SetPaletteColor(0,0,0,0); - SetPaletteColor(1,85,85,85); - SetPaletteColor(2,170,170,170); - SetPaletteColor(3,255,255,255); - } else SetGrayPalette(); // needed for grayscale PNGs - - int nshift = max(0,(info_ptr->bit_depth>>3)-1)<<3; - - if (info_ptr->num_trans!=0){ //palette transparency - if (info_ptr->num_trans==1){ - if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE){ - info.nBkgndIndex = info_ptr->trans_values.index; - } else{ - info.nBkgndIndex = info_ptr->trans_values.gray>>nshift; - } - } - if (info_ptr->num_trans>1){ - RGBQUAD* pal=GetPalette(); - if (pal){ - DWORD ip; - for (ip=0;ipnum_trans);ip++) - pal[ip].rgbReserved=info_ptr->trans[ip]; - for (ip=info_ptr->num_trans;iptrans_values.red>>nshift); - info.nBkgndColor.rgbGreen = (BYTE)(info_ptr->trans_values.green>>nshift); - info.nBkgndColor.rgbBlue = (BYTE)(info_ptr->trans_values.blue>>nshift); - info.nBkgndColor.rgbReserved = 0; - info.nBkgndIndex = 0; - } - } - - int alpha_present = (channels - 1) % 2; - if (alpha_present){ -#if CXIMAGE_SUPPORT_ALPHA // - AlphaCreate(); -#else - png_set_strip_alpha(png_ptr); -#endif //CXIMAGE_SUPPORT_ALPHA - } - - // - flip the RGB pixels to BGR (or RGBA to BGRA) - if (info_ptr->color_type & PNG_COLOR_MASK_COLOR){ - png_set_bgr(png_ptr); - } - - // - handle cancel - if (info.nEscape) longjmp(png_ptr->jmpbuf, 1); - - // row_bytes is the width x number of channels x (bit-depth / 8) - row_pointers = new BYTE[info_ptr->rowbytes + 8]; - - // turn on interlace handling - int number_passes = png_set_interlace_handling(png_ptr); - - if (number_passes>1){ - SetCodecOption(1); - } else { - SetCodecOption(0); - } - - int chan_offset = info_ptr->bit_depth >> 3; - int pixel_offset = info_ptr->pixel_depth >> 3; - - for (int pass=0; pass < number_passes; pass++) { - iter.Upset(); - int y=0; - do { - - // - handle cancel - if (info.nEscape) longjmp(png_ptr->jmpbuf, 1); - -#if CXIMAGE_SUPPORT_ALPHA // - if (AlphaIsValid()) { - - //compute the correct position of the line - long ax,ay; - ay = head.biHeight-1-y; - BYTE* prow= iter.GetRow(ay); - - //recover data from previous scan - if (info_ptr->interlace_type && pass>0 && pass!=7){ - for(ax=0;ax RGB + A - for(ax=0;axinterlace_type && pass>0){ - iter.GetRow(row_pointers, info_ptr->rowbytes); - //re-expand buffer for images with bit depth > 8 - if (info_ptr->bit_depth > 8){ - for(long ax=(head.biWidth*channels-1);ax>=0;ax--) - row_pointers[ax*chan_offset] = row_pointers[ax]; - } - } - - //read next row - png_read_row(png_ptr, row_pointers, NULL); - - //shrink 16 bit depth images down to 8 bits - if (info_ptr->bit_depth > 8){ - for(long ax=0;ax<(head.biWidth*channels);ax++) - row_pointers[ax] = row_pointers[ax*chan_offset]; - } - - //copy the pixels - iter.SetRow(row_pointers, info_ptr->rowbytes); - // expand 2 bpp images only in the last pass - if (info_ptr->bit_depth==2 && pass==(number_passes-1)) - expand2to4bpp(iter.GetRow()); - - //go on - iter.PrevRow(); - } - - y++; - } while(yjmpbuf)){ - /* If we get here, we had a problem reading the file */ - if (info_ptr->palette) free(info_ptr->palette); - png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr); - cx_throw("Error saving PNG file"); - } - - /* set up the output control */ - //png_init_io(png_ptr, hFile); - - // use custom I/O functions - png_set_write_fn(png_ptr,hFile,/*(png_rw_ptr)*/user_write_data,/*(png_flush_ptr)*/user_flush_data); - - /* set the file information here */ - info_ptr->width = GetWidth(); - info_ptr->height = GetHeight(); - info_ptr->pixel_depth = (BYTE)GetBpp(); - info_ptr->channels = (GetBpp()>8) ? (BYTE)3: (BYTE)1; - info_ptr->bit_depth = (BYTE)(GetBpp()/info_ptr->channels); - info_ptr->compression_type = info_ptr->filter_type = 0; - info_ptr->valid = 0; - - switch(GetCodecOption(CXIMAGE_FORMAT_PNG)){ - case 1: - info_ptr->interlace_type = PNG_INTERLACE_ADAM7; - break; - default: - info_ptr->interlace_type = PNG_INTERLACE_NONE; - } - - /* set compression level */ - //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); - - bool bGrayScale = IsGrayScale(); - - if (GetNumColors()){ - if (bGrayScale){ - info_ptr->color_type = PNG_COLOR_TYPE_GRAY; - } else { - info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; - } - } else { - info_ptr->color_type = PNG_COLOR_TYPE_RGB; - } -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()){ - info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; - info_ptr->channels++; - info_ptr->bit_depth = 8; - info_ptr->pixel_depth += 8; - } -#endif - - /* set background */ - png_color_16 image_background={ 0, 255, 255, 255, 0 }; - RGBQUAD tc = GetTransColor(); - if (info.nBkgndIndex>=0) { - image_background.blue = tc.rgbBlue; - image_background.green = tc.rgbGreen; - image_background.red = tc.rgbRed; - } - png_set_bKGD(png_ptr, info_ptr, &image_background); - - /* set metrics */ - png_set_pHYs(png_ptr, info_ptr, head.biXPelsPerMeter, head.biYPelsPerMeter, PNG_RESOLUTION_METER); - - png_set_IHDR(png_ptr, info_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, - info_ptr->color_type, info_ptr->interlace_type, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - // simple transparency - if (info.nBkgndIndex >= 0){ - info_ptr->num_trans = 1; - info_ptr->valid |= PNG_INFO_tRNS; - info_ptr->trans = trans; - info_ptr->trans_values.index = (BYTE)info.nBkgndIndex; - info_ptr->trans_values.red = tc.rgbRed; - info_ptr->trans_values.green = tc.rgbGreen; - info_ptr->trans_values.blue = tc.rgbBlue; - info_ptr->trans_values.gray = info_ptr->trans_values.index; - - // the transparency indexes start from 0 for non grayscale palette - if (!bGrayScale && head.biClrUsed && info.nBkgndIndex) - SwapIndex(0,(BYTE)info.nBkgndIndex); - } - - /* set the palette if there is one */ - if (GetPalette()){ - if (!bGrayScale){ - info_ptr->valid |= PNG_INFO_PLTE; - } - - int nc = GetClrImportant(); - if (nc==0) nc = GetNumColors(); - - if (info.bAlphaPaletteEnabled){ - for(WORD ip=0; ipnum_trans = (WORD)nc; - info_ptr->valid |= PNG_INFO_tRNS; - info_ptr->trans = trans; - } - - // copy the palette colors - info_ptr->palette = new png_color[nc]; - info_ptr->num_palette = (png_uint_16) nc; - for (int i=0; ipalette[i].red, &info_ptr->palette[i].green, &info_ptr->palette[i].blue); - } - -#if CXIMAGE_SUPPORT_ALPHA // - //Merge the transparent color with the alpha channel - if (AlphaIsValid() && head.biBitCount==24 && info.nBkgndIndex>=0){ - for(long y=0; y < head.biHeight; y++){ - for(long x=0; x < head.biWidth ; x++){ - RGBQUAD c=GetPixelColor(x,y,false); - if (*(long*)&c==*(long*)&tc) - AlphaSet(x,y,0); - } } } -#endif // CXIMAGE_SUPPORT_ALPHA // - - int row_size = max(info.dwEffWidth, info_ptr->width*info_ptr->channels*(info_ptr->bit_depth/8)); - info_ptr->rowbytes = row_size; - BYTE *row_pointers = new BYTE[row_size]; - - /* write the file information */ - png_write_info(png_ptr, info_ptr); - - //interlace handling - int num_pass = png_set_interlace_handling(png_ptr); - for (int pass = 0; pass < num_pass; pass++){ - //write image - iter.Upset(); - long ay=head.biHeight-1; - RGBQUAD c; - do { -#if CXIMAGE_SUPPORT_ALPHA // - if (AlphaIsValid()){ - for (long ax=head.biWidth-1; ax>=0;ax--){ - c = BlindGetPixelColor(ax,ay); - int px = ax * info_ptr->channels; - if (!bGrayScale){ - row_pointers[px++]=c.rgbRed; - row_pointers[px++]=c.rgbGreen; - } - row_pointers[px++]=c.rgbBlue; - row_pointers[px] = AlphaGet(ax,ay); - } - png_write_row(png_ptr, row_pointers); - ay--; - } - else -#endif //CXIMAGE_SUPPORT_ALPHA // - { - iter.GetRow(row_pointers, row_size); - if (info_ptr->color_type == PNG_COLOR_TYPE_RGB) //HACK BY OP - RGBtoBGR(row_pointers, row_size); - png_write_row(png_ptr, row_pointers); - } - } while(iter.PrevRow()); - } - - delete [] row_pointers; - - //if necessary, restore the original palette - if (!bGrayScale && head.biClrUsed && info.nBkgndIndex>0) - SwapIndex((BYTE)info.nBkgndIndex,0); - - /* It is REQUIRED to call this to finish writing the rest of the file */ - png_write_end(png_ptr, info_ptr); - - /* if you malloced the palette, free it here */ - if (info_ptr->palette){ - delete [] (info_ptr->palette); - info_ptr->palette = NULL; - } - - /* clean up after the write, and free any memory allocated */ - png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr); - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - return FALSE; - } - /* that's it */ - return TRUE; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_PNG +/* + * File: ximapng.cpp + * Purpose: Platform Independent PNG Image Class Loader and Writer + * 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximapng.h" + +#if CXIMAGE_SUPPORT_PNG + +#include "ximaiter.h" + +//////////////////////////////////////////////////////////////////////////////// +void CxImagePNG::ima_png_error(png_struct *png_ptr, char *message) +{ + strcpy(info.szLastError,message); + longjmp(png_ptr->jmpbuf, 1); +} +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +void CxImagePNG::expand2to4bpp(BYTE* prow) +{ + BYTE *psrc,*pdst; + BYTE pos,idx; + for(long x=head.biWidth-1;x>=0;x--){ + psrc = prow + ((2*x)>>3); + pdst = prow + ((4*x)>>3); + pos = (BYTE)(2*(3-x%4)); + idx = (BYTE)((*psrc & (0x03<>pos); + pos = (BYTE)(4*(1-x%2)); + *pdst &= ~(0x0F<jmpbuf)) { + /* Free all of the memory associated with the png_ptr and info_ptr */ + delete [] row_pointers; + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + cx_throw(""); + } + + // use custom I/O functions + png_set_read_fn(png_ptr, hFile, /*(png_rw_ptr)*/user_read_data); + png_set_error_fn(png_ptr,info.szLastError,/*(png_error_ptr)*/user_error_fn,NULL); + + /* read the file information */ + png_read_info(png_ptr, info_ptr); + + if (info.nEscape == -1){ + head.biWidth = info_ptr->width; + head.biHeight= info_ptr->height; + info.dwType = CXIMAGE_FORMAT_PNG; + longjmp(png_ptr->jmpbuf, 1); + } + + /* calculate new number of channels */ + int channels=0; + switch(info_ptr->color_type){ + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + channels = 1; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + channels = 2; + break; + case PNG_COLOR_TYPE_RGB: + channels = 3; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + channels = 4; + break; + default: + strcpy(info.szLastError,"unknown PNG color type"); + longjmp(png_ptr->jmpbuf, 1); + } + + //find the right pixel depth used for cximage + int pixel_depth = info_ptr->pixel_depth; + if (channels == 1 && pixel_depth>8) pixel_depth=8; + if (channels == 2) pixel_depth=8; + if (channels >= 3) pixel_depth=24; + + if (!Create(info_ptr->width, info_ptr->height, pixel_depth, CXIMAGE_FORMAT_PNG)){ + longjmp(png_ptr->jmpbuf, 1); + } + + /* get metrics */ + switch (info_ptr->phys_unit_type) + { + case PNG_RESOLUTION_UNKNOWN: + SetXDPI(info_ptr->x_pixels_per_unit); + SetYDPI(info_ptr->y_pixels_per_unit); + break; + case PNG_RESOLUTION_METER: + SetXDPI((long)floor(info_ptr->x_pixels_per_unit * 254.0 / 10000.0 + 0.5)); + SetYDPI((long)floor(info_ptr->y_pixels_per_unit * 254.0 / 10000.0 + 0.5)); + break; + } + + if (info_ptr->num_palette>0){ + SetPalette((rgb_color*)info_ptr->palette,info_ptr->num_palette); + SetClrImportant(info_ptr->num_palette); + } else if (info_ptr->bit_depth ==2) { // needed for 2 bpp grayscale PNGs + SetPaletteColor(0,0,0,0); + SetPaletteColor(1,85,85,85); + SetPaletteColor(2,170,170,170); + SetPaletteColor(3,255,255,255); + } else SetGrayPalette(); // needed for grayscale PNGs + + int nshift = max(0,(info_ptr->bit_depth>>3)-1)<<3; + + if (info_ptr->num_trans!=0){ //palette transparency + if (info_ptr->num_trans==1){ + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE){ + info.nBkgndIndex = info_ptr->trans_values.index; + } else{ + info.nBkgndIndex = info_ptr->trans_values.gray>>nshift; + } + } + if (info_ptr->num_trans>1){ + RGBQUAD* pal=GetPalette(); + if (pal){ + DWORD ip; + for (ip=0;ipnum_trans);ip++) + pal[ip].rgbReserved=info_ptr->trans[ip]; + for (ip=info_ptr->num_trans;iptrans_values.red>>nshift); + info.nBkgndColor.rgbGreen = (BYTE)(info_ptr->trans_values.green>>nshift); + info.nBkgndColor.rgbBlue = (BYTE)(info_ptr->trans_values.blue>>nshift); + info.nBkgndColor.rgbReserved = 0; + info.nBkgndIndex = 0; + } + } + + int alpha_present = (channels - 1) % 2; + if (alpha_present){ +#if CXIMAGE_SUPPORT_ALPHA // + AlphaCreate(); +#else + png_set_strip_alpha(png_ptr); +#endif //CXIMAGE_SUPPORT_ALPHA + } + + // - flip the RGB pixels to BGR (or RGBA to BGRA) + if (info_ptr->color_type & PNG_COLOR_MASK_COLOR){ + png_set_bgr(png_ptr); + } + + // - handle cancel + if (info.nEscape) longjmp(png_ptr->jmpbuf, 1); + + // row_bytes is the width x number of channels x (bit-depth / 8) + row_pointers = new BYTE[info_ptr->rowbytes + 8]; + + // turn on interlace handling + int number_passes = png_set_interlace_handling(png_ptr); + + if (number_passes>1){ + SetCodecOption(1); + } else { + SetCodecOption(0); + } + + int chan_offset = info_ptr->bit_depth >> 3; + int pixel_offset = info_ptr->pixel_depth >> 3; + + for (int pass=0; pass < number_passes; pass++) { + iter.Upset(); + int y=0; + do { + + // - handle cancel + if (info.nEscape) longjmp(png_ptr->jmpbuf, 1); + +#if CXIMAGE_SUPPORT_ALPHA // + if (AlphaIsValid()) { + + //compute the correct position of the line + long ax,ay; + ay = head.biHeight-1-y; + BYTE* prow= iter.GetRow(ay); + + //recover data from previous scan + if (info_ptr->interlace_type && pass>0 && pass!=7){ + for(ax=0;ax RGB + A + for(ax=0;axinterlace_type && pass>0){ + iter.GetRow(row_pointers, info_ptr->rowbytes); + //re-expand buffer for images with bit depth > 8 + if (info_ptr->bit_depth > 8){ + for(long ax=(head.biWidth*channels-1);ax>=0;ax--) + row_pointers[ax*chan_offset] = row_pointers[ax]; + } + } + + //read next row + png_read_row(png_ptr, row_pointers, NULL); + + //shrink 16 bit depth images down to 8 bits + if (info_ptr->bit_depth > 8){ + for(long ax=0;ax<(head.biWidth*channels);ax++) + row_pointers[ax] = row_pointers[ax*chan_offset]; + } + + //copy the pixels + iter.SetRow(row_pointers, info_ptr->rowbytes); + // expand 2 bpp images only in the last pass + if (info_ptr->bit_depth==2 && pass==(number_passes-1)) + expand2to4bpp(iter.GetRow()); + + //go on + iter.PrevRow(); + } + + y++; + } while(yjmpbuf)){ + /* If we get here, we had a problem reading the file */ + if (info_ptr->palette) free(info_ptr->palette); + png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr); + cx_throw("Error saving PNG file"); + } + + /* set up the output control */ + //png_init_io(png_ptr, hFile); + + // use custom I/O functions + png_set_write_fn(png_ptr,hFile,/*(png_rw_ptr)*/user_write_data,/*(png_flush_ptr)*/user_flush_data); + + /* set the file information here */ + info_ptr->width = GetWidth(); + info_ptr->height = GetHeight(); + info_ptr->pixel_depth = (BYTE)GetBpp(); + info_ptr->channels = (GetBpp()>8) ? (BYTE)3: (BYTE)1; + info_ptr->bit_depth = (BYTE)(GetBpp()/info_ptr->channels); + info_ptr->compression_type = info_ptr->filter_type = 0; + info_ptr->valid = 0; + + switch(GetCodecOption(CXIMAGE_FORMAT_PNG)){ + case 1: + info_ptr->interlace_type = PNG_INTERLACE_ADAM7; + break; + default: + info_ptr->interlace_type = PNG_INTERLACE_NONE; + } + + /* set compression level */ + //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); + + bool bGrayScale = IsGrayScale(); + + if (GetNumColors()){ + if (bGrayScale){ + info_ptr->color_type = PNG_COLOR_TYPE_GRAY; + } else { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } else { + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + } +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()){ + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + info_ptr->channels++; + info_ptr->bit_depth = 8; + info_ptr->pixel_depth += 8; + } +#endif + + /* set background */ + png_color_16 image_background={ 0, 255, 255, 255, 0 }; + RGBQUAD tc = GetTransColor(); + if (info.nBkgndIndex>=0) { + image_background.blue = tc.rgbBlue; + image_background.green = tc.rgbGreen; + image_background.red = tc.rgbRed; + } + png_set_bKGD(png_ptr, info_ptr, &image_background); + + /* set metrics */ + png_set_pHYs(png_ptr, info_ptr, head.biXPelsPerMeter, head.biYPelsPerMeter, PNG_RESOLUTION_METER); + + png_set_IHDR(png_ptr, info_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, + info_ptr->color_type, info_ptr->interlace_type, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + // simple transparency + if (info.nBkgndIndex >= 0){ + info_ptr->num_trans = 1; + info_ptr->valid |= PNG_INFO_tRNS; + info_ptr->trans = trans; + info_ptr->trans_values.index = (BYTE)info.nBkgndIndex; + info_ptr->trans_values.red = tc.rgbRed; + info_ptr->trans_values.green = tc.rgbGreen; + info_ptr->trans_values.blue = tc.rgbBlue; + info_ptr->trans_values.gray = info_ptr->trans_values.index; + + // the transparency indexes start from 0 for non grayscale palette + if (!bGrayScale && head.biClrUsed && info.nBkgndIndex) + SwapIndex(0,(BYTE)info.nBkgndIndex); + } + + /* set the palette if there is one */ + if (GetPalette()){ + if (!bGrayScale){ + info_ptr->valid |= PNG_INFO_PLTE; + } + + int nc = GetClrImportant(); + if (nc==0) nc = GetNumColors(); + + if (info.bAlphaPaletteEnabled){ + for(WORD ip=0; ipnum_trans = (WORD)nc; + info_ptr->valid |= PNG_INFO_tRNS; + info_ptr->trans = trans; + } + + // copy the palette colors + info_ptr->palette = new png_color[nc]; + info_ptr->num_palette = (png_uint_16) nc; + for (int i=0; ipalette[i].red, &info_ptr->palette[i].green, &info_ptr->palette[i].blue); + } + +#if CXIMAGE_SUPPORT_ALPHA // + //Merge the transparent color with the alpha channel + if (AlphaIsValid() && head.biBitCount==24 && info.nBkgndIndex>=0){ + for(long y=0; y < head.biHeight; y++){ + for(long x=0; x < head.biWidth ; x++){ + RGBQUAD c=GetPixelColor(x,y,false); + if (*(long*)&c==*(long*)&tc) + AlphaSet(x,y,0); + } } } +#endif // CXIMAGE_SUPPORT_ALPHA // + + int row_size = max(info.dwEffWidth, info_ptr->width*info_ptr->channels*(info_ptr->bit_depth/8)); + info_ptr->rowbytes = row_size; + BYTE *row_pointers = new BYTE[row_size]; + + /* write the file information */ + png_write_info(png_ptr, info_ptr); + + //interlace handling + int num_pass = png_set_interlace_handling(png_ptr); + for (int pass = 0; pass < num_pass; pass++){ + //write image + iter.Upset(); + long ay=head.biHeight-1; + RGBQUAD c; + do { +#if CXIMAGE_SUPPORT_ALPHA // + if (AlphaIsValid()){ + for (long ax=head.biWidth-1; ax>=0;ax--){ + c = BlindGetPixelColor(ax,ay); + int px = ax * info_ptr->channels; + if (!bGrayScale){ + row_pointers[px++]=c.rgbRed; + row_pointers[px++]=c.rgbGreen; + } + row_pointers[px++]=c.rgbBlue; + row_pointers[px] = AlphaGet(ax,ay); + } + png_write_row(png_ptr, row_pointers); + ay--; + } + else +#endif //CXIMAGE_SUPPORT_ALPHA // + { + iter.GetRow(row_pointers, row_size); + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB) //HACK BY OP + RGBtoBGR(row_pointers, row_size); + png_write_row(png_ptr, row_pointers); + } + } while(iter.PrevRow()); + } + + delete [] row_pointers; + + //if necessary, restore the original palette + if (!bGrayScale && head.biClrUsed && info.nBkgndIndex>0) + SwapIndex((BYTE)info.nBkgndIndex,0); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + /* if you malloced the palette, free it here */ + if (info_ptr->palette){ + delete [] (info_ptr->palette); + info_ptr->palette = NULL; + } + + /* clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr); + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + return FALSE; + } + /* that's it */ + return TRUE; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_PNG diff --git a/utilities/CxImage/ximapng.h b/utilities/CxImage/ximapng.h index 3fddf5b..abfd80b 100644 --- a/utilities/CxImage/ximapng.h +++ b/utilities/CxImage/ximapng.h @@ -1,74 +1,74 @@ -/* - * File: ximapng.h - * Purpose: PNG Image Class Loader and Writer - */ -/* ========================================================== - * CxImagePNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes - * - * original CImagePNG and CImageIterator implementation are: - * Copyright: (c) 1995, Alejandro Aguilar Sierra - * - * libpng Copyright (c) 1998-2003 Glenn Randers-Pehrson - * ========================================================== - */ -#if !defined(__ximaPNG_h) -#define __ximaPNG_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_PNG - -extern "C" { -#include "../png/png.h" -} - -class CxImagePNG: public CxImage -{ -public: - CxImagePNG(): CxImage(CXIMAGE_FORMAT_PNG) {} - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PNG);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PNG);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE - -protected: - void ima_png_error(png_struct *png_ptr, char *message); - void expand2to4bpp(BYTE* prow); - - static void PNGAPI user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) - { - CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr); - if (hFile == NULL || hFile->Read(data,1,length) != length) png_error(png_ptr, "Read Error"); - } - - static void PNGAPI user_write_data(png_structp png_ptr, png_bytep data, png_size_t length) - { - CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr); - if (hFile == NULL || hFile->Write(data,1,length) != length) png_error(png_ptr, "Write Error"); - } - - static void PNGAPI user_flush_data(png_structp png_ptr) - { - CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr); - if (hFile == NULL || !hFile->Flush()) png_error(png_ptr, "Flush Error"); - } - - static void PNGAPI user_error_fn(png_structp png_ptr,png_const_charp error_msg) - { - strncpy((char*)png_ptr->error_ptr,error_msg,255); - longjmp(png_ptr->jmpbuf, 1); - } -}; - -#endif - -#endif +/* + * File: ximapng.h + * Purpose: PNG Image Class Loader and Writer + */ +/* ========================================================== + * CxImagePNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes + * + * original CImagePNG and CImageIterator implementation are: + * Copyright: (c) 1995, Alejandro Aguilar Sierra + * + * libpng Copyright (c) 1998-2003 Glenn Randers-Pehrson + * ========================================================== + */ +#if !defined(__ximaPNG_h) +#define __ximaPNG_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_PNG + +extern "C" { +#include "../png/png.h" +} + +class CxImagePNG: public CxImage +{ +public: + CxImagePNG(): CxImage(CXIMAGE_FORMAT_PNG) {} + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PNG);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PNG);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE + +protected: + void ima_png_error(png_struct *png_ptr, char *message); + void expand2to4bpp(BYTE* prow); + + static void PNGAPI user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) + { + CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr); + if (hFile == NULL || hFile->Read(data,1,length) != length) png_error(png_ptr, "Read Error"); + } + + static void PNGAPI user_write_data(png_structp png_ptr, png_bytep data, png_size_t length) + { + CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr); + if (hFile == NULL || hFile->Write(data,1,length) != length) png_error(png_ptr, "Write Error"); + } + + static void PNGAPI user_flush_data(png_structp png_ptr) + { + CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr); + if (hFile == NULL || !hFile->Flush()) png_error(png_ptr, "Flush Error"); + } + + static void PNGAPI user_error_fn(png_structp png_ptr,png_const_charp error_msg) + { + strncpy((char*)png_ptr->error_ptr,error_msg,255); + longjmp(png_ptr->jmpbuf, 1); + } +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximaraw.cpp b/utilities/CxImage/ximaraw.cpp index ca50750..71dc772 100644 --- a/utilities/CxImage/ximaraw.cpp +++ b/utilities/CxImage/ximaraw.cpp @@ -1,228 +1,228 @@ -/* - * File: ximaraw.cpp - * Purpose: Platform Independent RAW Image Class Loader - * 16/Dec/2007 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - * - * CxImageRAW (c) May/2006 pdw63 - * - * based on dcraw.c -- Dave Coffin's raw photo decoder - * Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net - */ - -#include "ximaraw.h" - -#if CXIMAGE_SUPPORT_RAW - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageRAW::Decode(CxFile *hFile) -{ - if (hFile==NULL) - return false; - - DCRAW dcr; - - cx_try - { - // initialization - dcr_init_dcraw(&dcr); - - dcr.opt.user_qual = GetCodecOption(CXIMAGE_FORMAT_RAW) & 0x03; - - // setup variables for debugging - char szClass[] = "CxImageRAW"; - dcr.ifname = szClass; - dcr.sz_error = info.szLastError; - - // setup library options, see dcr_print_manual for the available switches - // call dcr_parse_command_line_options(&dcr,0,0,0) to set default options - // if (dcr_parse_command_line_options(&dcr,argc,argv,&arg)) - if (dcr_parse_command_line_options(&dcr,0,0,0)){ - cx_throw("CxImageRAW: unknown option"); - } - - // set return point for error handling - if (setjmp (dcr.failure)) { - cx_throw(""); - } - - // install file manager - CxFileRaw src(hFile,&dcr); - - // check file header - dcr_identify(&dcr); - - if(!dcr.is_raw){ - cx_throw("CxImageRAW: not a raw image"); - } - - if (dcr.load_raw == NULL) { - cx_throw("CxImageRAW: missing raw decoder"); - } - - // verify special case - if (dcr.load_raw == dcr_kodak_ycbcr_load_raw) { - dcr.height += dcr.height & 1; - dcr.width += dcr.width & 1; - } - - if (info.nEscape == -1){ - head.biWidth = dcr.width; - head.biHeight= dcr.height; - info.dwType = CXIMAGE_FORMAT_RAW; - cx_throw("output dimensions returned"); - } - - // shrinked decoding available and requested? - dcr.shrink = dcr.filters && (dcr.opt.half_size || dcr.opt.threshold || dcr.opt.aber[0] != 1 || dcr.opt.aber[2] != 1); - dcr.iheight = (dcr.height + dcr.shrink) >> dcr.shrink; - dcr.iwidth = (dcr.width + dcr.shrink) >> dcr.shrink; - - // install custom camera matrix - if (dcr.opt.use_camera_matrix && dcr.cmatrix[0][0] > 0.25) { - memcpy (dcr.rgb_cam, dcr.cmatrix, sizeof dcr.cmatrix); - dcr.raw_color = 0; - } - - // allocate memory for the image - dcr.image = (ushort (*)[4]) calloc (dcr.iheight*dcr.iwidth, sizeof *dcr.image); - dcr_merror (&dcr, dcr.image, szClass); - - if (dcr.meta_length) { - dcr.meta_data = (char *) malloc (dcr.meta_length); - dcr_merror (&dcr, dcr.meta_data, szClass); - } - - // start image decoder - hFile->Seek(dcr.data_offset, SEEK_SET); - (*dcr.load_raw)(&dcr); - - // post processing - if (dcr.zero_is_bad) dcr_remove_zeroes(&dcr); - - dcr_bad_pixels(&dcr); - - if (dcr.opt.dark_frame) dcr_subtract (&dcr,dcr.opt.dark_frame); - - dcr.quality = 2 + !dcr.fuji_width; - - if (dcr.opt.user_qual >= 0) dcr.quality = dcr.opt.user_qual; - - if (dcr.opt.user_black >= 0) dcr.black = dcr.opt.user_black; - -#ifdef COLORCHECK - dcr_colorcheck(&dcr); -#endif - -#if RESTRICTED - if (dcr.is_foveon && !dcr.opt.document_mode) dcr_foveon_interpolate(&dcr); -#endif - - if (!dcr.is_foveon && dcr.opt.document_mode < 2) dcr_scale_colors(&dcr); - - // pixel interpolation and filters - dcr_pre_interpolate(&dcr); - - if (dcr.filters && !dcr.opt.document_mode) { - if (dcr.quality == 0) - dcr_lin_interpolate(&dcr); - else if (dcr.quality == 1 || dcr.colors > 3) - dcr_vng_interpolate(&dcr); - else if (dcr.quality == 2) - dcr_ppg_interpolate(&dcr); - else - dcr_ahd_interpolate(&dcr); - } - - if (dcr.mix_green) { - long i; - for (dcr.colors=3, i=0; i < dcr.height*dcr.width; i++) { - dcr.image[i][1] = (dcr.image[i][1] + dcr.image[i][3]) >> 1; - } - } - - if (!dcr.is_foveon && dcr.colors == 3) dcr_median_filter(&dcr); - - if (!dcr.is_foveon && dcr.opt.highlight == 2) dcr_blend_highlights(&dcr); - - if (!dcr.is_foveon && dcr.opt.highlight > 2) dcr_recover_highlights(&dcr); - - if (dcr.opt.use_fuji_rotate) dcr_fuji_rotate(&dcr); - -#ifndef NO_LCMS - if (dcr.opt.cam_profile) dcr_apply_profile (dcr.opt.cam_profile, dcr.opt.out_profile); -#endif - - // final conversion - dcr_convert_to_rgb(&dcr); - - if (dcr.opt.use_fuji_rotate) dcr_stretch(&dcr); - - dcr.iheight = dcr.height; - dcr.iwidth = dcr.width; - if (dcr.flip & 4) SWAP(dcr.height,dcr.width); - - // ready to transfer data from dcr.image - if (!Create(dcr.width,dcr.height,24,CXIMAGE_FORMAT_RAW)){ - cx_throw(""); - } - - uchar *ppm = (uchar *) calloc (dcr.width, dcr.colors*dcr.opt.output_bps/8); - ushort *ppm2 = (ushort *) ppm; - dcr_merror (&dcr, ppm, szClass); - - uchar lut[0x10000]; - if (dcr.opt.output_bps == 8) dcr_gamma_lut (&dcr, lut); - - long c, row, col, soff, rstep, cstep; - soff = dcr_flip_index (&dcr, 0, 0); - cstep = dcr_flip_index (&dcr, 0, 1) - soff; - rstep = dcr_flip_index (&dcr, 1, 0) - dcr_flip_index (&dcr, 0, dcr.width); - for (row=0; row < dcr.height; row++, soff += rstep) { - for (col=0; col < dcr.width; col++, soff += cstep) { - if (dcr.opt.output_bps == 8) - for (c=0; c < dcr.colors; c++) ppm [col*dcr.colors+c] = lut[dcr.image[soff][c]]; - else - for (c=0; c < dcr.colors; c++) ppm2[col*dcr.colors+c] = dcr.image[soff][c]; - } - if (dcr.opt.output_bps == 16 && !dcr.opt.output_tiff && htons(0x55aa) != 0x55aa) - _swab ((char*)ppm2, (char*)ppm2, dcr.width*dcr.colors*2); - - DWORD size = dcr.width * (dcr.colors*dcr.opt.output_bps/8); - RGBtoBGR(ppm,size); - memcpy(GetBits(dcr.height - 1 - row), ppm, min(size,GetEffWidth())); - } - free (ppm); - - - dcr_cleanup_dcraw(&dcr); - - } cx_catch { - - dcr_cleanup_dcraw(&dcr); - - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_RAW) return true; - return false; - } - /* that's it */ - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageRAW::Encode(CxFile * hFile) -{ - if (hFile == NULL) return false; - strcpy(info.szLastError, "Save RAW not supported"); - return false; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_RAW - +/* + * File: ximaraw.cpp + * Purpose: Platform Independent RAW Image Class Loader + * 16/Dec/2007 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + * + * CxImageRAW (c) May/2006 pdw63 + * + * based on dcraw.c -- Dave Coffin's raw photo decoder + * Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net + */ + +#include "ximaraw.h" + +#if CXIMAGE_SUPPORT_RAW + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageRAW::Decode(CxFile *hFile) +{ + if (hFile==NULL) + return false; + + DCRAW dcr; + + cx_try + { + // initialization + dcr_init_dcraw(&dcr); + + dcr.opt.user_qual = GetCodecOption(CXIMAGE_FORMAT_RAW) & 0x03; + + // setup variables for debugging + char szClass[] = "CxImageRAW"; + dcr.ifname = szClass; + dcr.sz_error = info.szLastError; + + // setup library options, see dcr_print_manual for the available switches + // call dcr_parse_command_line_options(&dcr,0,0,0) to set default options + // if (dcr_parse_command_line_options(&dcr,argc,argv,&arg)) + if (dcr_parse_command_line_options(&dcr,0,0,0)){ + cx_throw("CxImageRAW: unknown option"); + } + + // set return point for error handling + if (setjmp (dcr.failure)) { + cx_throw(""); + } + + // install file manager + CxFileRaw src(hFile,&dcr); + + // check file header + dcr_identify(&dcr); + + if(!dcr.is_raw){ + cx_throw("CxImageRAW: not a raw image"); + } + + if (dcr.load_raw == NULL) { + cx_throw("CxImageRAW: missing raw decoder"); + } + + // verify special case + if (dcr.load_raw == dcr_kodak_ycbcr_load_raw) { + dcr.height += dcr.height & 1; + dcr.width += dcr.width & 1; + } + + if (info.nEscape == -1){ + head.biWidth = dcr.width; + head.biHeight= dcr.height; + info.dwType = CXIMAGE_FORMAT_RAW; + cx_throw("output dimensions returned"); + } + + // shrinked decoding available and requested? + dcr.shrink = dcr.filters && (dcr.opt.half_size || dcr.opt.threshold || dcr.opt.aber[0] != 1 || dcr.opt.aber[2] != 1); + dcr.iheight = (dcr.height + dcr.shrink) >> dcr.shrink; + dcr.iwidth = (dcr.width + dcr.shrink) >> dcr.shrink; + + // install custom camera matrix + if (dcr.opt.use_camera_matrix && dcr.cmatrix[0][0] > 0.25) { + memcpy (dcr.rgb_cam, dcr.cmatrix, sizeof dcr.cmatrix); + dcr.raw_color = 0; + } + + // allocate memory for the image + dcr.image = (ushort (*)[4]) calloc (dcr.iheight*dcr.iwidth, sizeof *dcr.image); + dcr_merror (&dcr, dcr.image, szClass); + + if (dcr.meta_length) { + dcr.meta_data = (char *) malloc (dcr.meta_length); + dcr_merror (&dcr, dcr.meta_data, szClass); + } + + // start image decoder + hFile->Seek(dcr.data_offset, SEEK_SET); + (*dcr.load_raw)(&dcr); + + // post processing + if (dcr.zero_is_bad) dcr_remove_zeroes(&dcr); + + dcr_bad_pixels(&dcr); + + if (dcr.opt.dark_frame) dcr_subtract (&dcr,dcr.opt.dark_frame); + + dcr.quality = 2 + !dcr.fuji_width; + + if (dcr.opt.user_qual >= 0) dcr.quality = dcr.opt.user_qual; + + if (dcr.opt.user_black >= 0) dcr.black = dcr.opt.user_black; + +#ifdef COLORCHECK + dcr_colorcheck(&dcr); +#endif + +#if RESTRICTED + if (dcr.is_foveon && !dcr.opt.document_mode) dcr_foveon_interpolate(&dcr); +#endif + + if (!dcr.is_foveon && dcr.opt.document_mode < 2) dcr_scale_colors(&dcr); + + // pixel interpolation and filters + dcr_pre_interpolate(&dcr); + + if (dcr.filters && !dcr.opt.document_mode) { + if (dcr.quality == 0) + dcr_lin_interpolate(&dcr); + else if (dcr.quality == 1 || dcr.colors > 3) + dcr_vng_interpolate(&dcr); + else if (dcr.quality == 2) + dcr_ppg_interpolate(&dcr); + else + dcr_ahd_interpolate(&dcr); + } + + if (dcr.mix_green) { + long i; + for (dcr.colors=3, i=0; i < dcr.height*dcr.width; i++) { + dcr.image[i][1] = (dcr.image[i][1] + dcr.image[i][3]) >> 1; + } + } + + if (!dcr.is_foveon && dcr.colors == 3) dcr_median_filter(&dcr); + + if (!dcr.is_foveon && dcr.opt.highlight == 2) dcr_blend_highlights(&dcr); + + if (!dcr.is_foveon && dcr.opt.highlight > 2) dcr_recover_highlights(&dcr); + + if (dcr.opt.use_fuji_rotate) dcr_fuji_rotate(&dcr); + +#ifndef NO_LCMS + if (dcr.opt.cam_profile) dcr_apply_profile (dcr.opt.cam_profile, dcr.opt.out_profile); +#endif + + // final conversion + dcr_convert_to_rgb(&dcr); + + if (dcr.opt.use_fuji_rotate) dcr_stretch(&dcr); + + dcr.iheight = dcr.height; + dcr.iwidth = dcr.width; + if (dcr.flip & 4) SWAP(dcr.height,dcr.width); + + // ready to transfer data from dcr.image + if (!Create(dcr.width,dcr.height,24,CXIMAGE_FORMAT_RAW)){ + cx_throw(""); + } + + uchar *ppm = (uchar *) calloc (dcr.width, dcr.colors*dcr.opt.output_bps/8); + ushort *ppm2 = (ushort *) ppm; + dcr_merror (&dcr, ppm, szClass); + + uchar lut[0x10000]; + if (dcr.opt.output_bps == 8) dcr_gamma_lut (&dcr, lut); + + long c, row, col, soff, rstep, cstep; + soff = dcr_flip_index (&dcr, 0, 0); + cstep = dcr_flip_index (&dcr, 0, 1) - soff; + rstep = dcr_flip_index (&dcr, 1, 0) - dcr_flip_index (&dcr, 0, dcr.width); + for (row=0; row < dcr.height; row++, soff += rstep) { + for (col=0; col < dcr.width; col++, soff += cstep) { + if (dcr.opt.output_bps == 8) + for (c=0; c < dcr.colors; c++) ppm [col*dcr.colors+c] = lut[dcr.image[soff][c]]; + else + for (c=0; c < dcr.colors; c++) ppm2[col*dcr.colors+c] = dcr.image[soff][c]; + } + if (dcr.opt.output_bps == 16 && !dcr.opt.output_tiff && htons(0x55aa) != 0x55aa) + _swab ((char*)ppm2, (char*)ppm2, dcr.width*dcr.colors*2); + + DWORD size = dcr.width * (dcr.colors*dcr.opt.output_bps/8); + RGBtoBGR(ppm,size); + memcpy(GetBits(dcr.height - 1 - row), ppm, min(size,GetEffWidth())); + } + free (ppm); + + + dcr_cleanup_dcraw(&dcr); + + } cx_catch { + + dcr_cleanup_dcraw(&dcr); + + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_RAW) return true; + return false; + } + /* that's it */ + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageRAW::Encode(CxFile * hFile) +{ + if (hFile == NULL) return false; + strcpy(info.szLastError, "Save RAW not supported"); + return false; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_RAW + diff --git a/utilities/CxImage/ximaraw.h b/utilities/CxImage/ximaraw.h index 15b938d..c99d1c4 100644 --- a/utilities/CxImage/ximaraw.h +++ b/utilities/CxImage/ximaraw.h @@ -1,108 +1,108 @@ -/* - * File: ximaraw.h - * Purpose: RAW Image Class Loader and Writer - */ -/* ========================================================== - * CxImageRAW (c) May/2006 pdw63 - * For conditions of distribution and use, see copyright notice in ximage.h - * Special thanks to David Coffin for dcraw without which this class would not exist - * - * libdcr (c) Dec/2007 Davide Pizzolato - www.xdp.it - * - * based on dcraw.c -- Dave Coffin's raw photo decoder - * Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net - * ========================================================== - */ -#if !defined(__ximaRAW_h) -#define __ximaRAW_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_RAW - -extern "C" { - #include "../raw/libdcr.h" -} - -class CxImageRAW: public CxImage -{ - -public: - CxImageRAW(): CxImage(CXIMAGE_FORMAT_RAW) {} - -// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);} -// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE - - enum CODEC_OPTION - { - DECODE_QUALITY_LIN = 0x00, - DECODE_QUALITY_VNG = 0x01, - DECODE_QUALITY_PPG = 0x02, - DECODE_QUALITY_AHD = 0x03, - }; - -protected: - - class CxFileRaw - { - public: - CxFileRaw(CxFile* pFile,DCRAW *stream) - { - stream->obj_ = pFile; - - ras_stream_CxFile.read_ = raw_sfile_read; - ras_stream_CxFile.write_ = raw_sfile_write; - ras_stream_CxFile.seek_ = raw_sfile_seek; - ras_stream_CxFile.close_ = raw_sfile_close; - ras_stream_CxFile.gets_ = raw_sfile_gets; - ras_stream_CxFile.eof_ = raw_sfile_eof; - ras_stream_CxFile.tell_ = raw_sfile_tell; - ras_stream_CxFile.getc_ = raw_sfile_getc; - ras_stream_CxFile.scanf_ = raw_sfile_scanf; - - stream->ops_ = &ras_stream_CxFile; - - } - - static int raw_sfile_read(dcr_stream_obj *obj, void *buf, int size, int cnt) - { return ((CxFile*)obj)->Read(buf,size,cnt); } - - static int raw_sfile_write(dcr_stream_obj *obj, void *buf, int size, int cnt) - { return ((CxFile*)obj)->Write(buf,size,cnt); } - - static long raw_sfile_seek(dcr_stream_obj *obj, long offset, int origin) - { return ((CxFile*)obj)->Seek(offset,origin); } - - static int raw_sfile_close(dcr_stream_obj *obj) - { return 1; /*((CxFile*)obj)->Close();*/ } - - static char* raw_sfile_gets(dcr_stream_obj *obj, char *string, int n) - { return ((CxFile*)obj)->GetS(string,n); } - - static int raw_sfile_eof(dcr_stream_obj *obj) - { return ((CxFile*)obj)->Eof(); } - - static long raw_sfile_tell(dcr_stream_obj *obj) - { return ((CxFile*)obj)->Tell(); } - - static int raw_sfile_getc(dcr_stream_obj *obj) - { return ((CxFile*)obj)->GetC(); } - - static int raw_sfile_scanf(dcr_stream_obj *obj,const char *format, void* output) - { return ((CxFile*)obj)->Scanf(format, output); } - - private: - dcr_stream_ops ras_stream_CxFile; - }; -}; - -#endif - -#endif +/* + * File: ximaraw.h + * Purpose: RAW Image Class Loader and Writer + */ +/* ========================================================== + * CxImageRAW (c) May/2006 pdw63 + * For conditions of distribution and use, see copyright notice in ximage.h + * Special thanks to David Coffin for dcraw without which this class would not exist + * + * libdcr (c) Dec/2007 Davide Pizzolato - www.xdp.it + * + * based on dcraw.c -- Dave Coffin's raw photo decoder + * Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net + * ========================================================== + */ +#if !defined(__ximaRAW_h) +#define __ximaRAW_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_RAW + +extern "C" { + #include "../raw/libdcr.h" +} + +class CxImageRAW: public CxImage +{ + +public: + CxImageRAW(): CxImage(CXIMAGE_FORMAT_RAW) {} + +// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);} +// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE + + enum CODEC_OPTION + { + DECODE_QUALITY_LIN = 0x00, + DECODE_QUALITY_VNG = 0x01, + DECODE_QUALITY_PPG = 0x02, + DECODE_QUALITY_AHD = 0x03, + }; + +protected: + + class CxFileRaw + { + public: + CxFileRaw(CxFile* pFile,DCRAW *stream) + { + stream->obj_ = pFile; + + ras_stream_CxFile.read_ = raw_sfile_read; + ras_stream_CxFile.write_ = raw_sfile_write; + ras_stream_CxFile.seek_ = raw_sfile_seek; + ras_stream_CxFile.close_ = raw_sfile_close; + ras_stream_CxFile.gets_ = raw_sfile_gets; + ras_stream_CxFile.eof_ = raw_sfile_eof; + ras_stream_CxFile.tell_ = raw_sfile_tell; + ras_stream_CxFile.getc_ = raw_sfile_getc; + ras_stream_CxFile.scanf_ = raw_sfile_scanf; + + stream->ops_ = &ras_stream_CxFile; + + } + + static int raw_sfile_read(dcr_stream_obj *obj, void *buf, int size, int cnt) + { return ((CxFile*)obj)->Read(buf,size,cnt); } + + static int raw_sfile_write(dcr_stream_obj *obj, void *buf, int size, int cnt) + { return ((CxFile*)obj)->Write(buf,size,cnt); } + + static long raw_sfile_seek(dcr_stream_obj *obj, long offset, int origin) + { return ((CxFile*)obj)->Seek(offset,origin); } + + static int raw_sfile_close(dcr_stream_obj *obj) + { return 1; /*((CxFile*)obj)->Close();*/ } + + static char* raw_sfile_gets(dcr_stream_obj *obj, char *string, int n) + { return ((CxFile*)obj)->GetS(string,n); } + + static int raw_sfile_eof(dcr_stream_obj *obj) + { return ((CxFile*)obj)->Eof(); } + + static long raw_sfile_tell(dcr_stream_obj *obj) + { return ((CxFile*)obj)->Tell(); } + + static int raw_sfile_getc(dcr_stream_obj *obj) + { return ((CxFile*)obj)->GetC(); } + + static int raw_sfile_scanf(dcr_stream_obj *obj,const char *format, void* output) + { return ((CxFile*)obj)->Scanf(format, output); } + + private: + dcr_stream_ops ras_stream_CxFile; + }; +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximasel.cpp b/utilities/CxImage/ximasel.cpp index bf61078..3a7c9a1 100644 --- a/utilities/CxImage/ximasel.cpp +++ b/utilities/CxImage/ximasel.cpp @@ -1,697 +1,697 @@ -// xImaSel.cpp : Selection functions -/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_SELECTION - -//////////////////////////////////////////////////////////////////////////////// -/** - * Checks if the image has a valid selection. - */ -bool CxImage::SelectionIsValid() -{ - return pSelection!=0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Gets the smallest rectangle that contains the selection - */ -void CxImage::SelectionGetBox(RECT& r) -{ - memcpy(&r,&info.rSelectionBox,sizeof(RECT)); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Empties the selection. - */ -bool CxImage::SelectionClear(BYTE level) -{ - if (pSelection){ - if (level==0){ - memset(pSelection,0,head.biWidth * head.biHeight); - info.rSelectionBox.left = head.biWidth; - info.rSelectionBox.bottom = head.biHeight; - info.rSelectionBox.right = info.rSelectionBox.top = 0; - } else { - memset(pSelection,level,head.biWidth * head.biHeight); - info.rSelectionBox.right = head.biWidth; - info.rSelectionBox.top = head.biHeight; - info.rSelectionBox.left = info.rSelectionBox.bottom = 0; - } - return true; - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Allocates an empty selection. - */ -bool CxImage::SelectionCreate() -{ - SelectionDelete(); - pSelection = (BYTE*)calloc(head.biWidth * head.biHeight, 1); - return (pSelection!=0); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Deallocates the selction. - */ -bool CxImage::SelectionDelete() -{ - if (pSelection){ - free(pSelection); - pSelection=NULL; - } - info.rSelectionBox.left = head.biWidth; - info.rSelectionBox.bottom = head.biHeight; - info.rSelectionBox.right = info.rSelectionBox.top = 0; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Checks if the coordinates are inside the selection. - */ -bool CxImage::SelectionIsInside(long x, long y) -{ - if (IsInside(x,y)){ - if (pSelection==NULL) return true; - return pSelection[x+y*head.biWidth]!=0; - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Checks if the coordinates are inside the selection. - * "blind" version assumes that (x,y) is inside to the image. - */ -bool CxImage::BlindSelectionIsInside(long x, long y) -{ -#ifdef _DEBUG - if (!IsInside(x,y)) - #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - throw 0; - #else - return 0; - #endif -#endif - if (pSelection==NULL) return true; - return pSelection[x+y*head.biWidth]!=0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Adds a rectangle to the existing selection. - */ -bool CxImage::SelectionAddRect(RECT r, BYTE level) -{ - if (pSelection==NULL) SelectionCreate(); - if (pSelection==NULL) return false; - - RECT r2; - if (r.left r2.left) info.rSelectionBox.left = max(0L,min(head.biWidth,r2.left)); - if (info.rSelectionBox.right <= r2.right) info.rSelectionBox.right = max(0L,min(head.biWidth,r2.right+1)); - if (info.rSelectionBox.bottom > r2.bottom) info.rSelectionBox.bottom = max(0L,min(head.biHeight,r2.bottom)); - - long ymin = max(0L,min(head.biHeight,r2.bottom)); - long ymax = max(0L,min(head.biHeight,r2.top+1)); - long xmin = max(0L,min(head.biWidth,r2.left)); - long xmax = max(0L,min(head.biWidth,r2.right+1)); - - for (long y=ymin; y (xcenter - xradius)) info.rSelectionBox.left = max(0L,min(head.biWidth,(xcenter - xradius))); - if (info.rSelectionBox.right <= (xcenter + xradius)) info.rSelectionBox.right = max(0L,min(head.biWidth,(xcenter + xradius + 1))); - if (info.rSelectionBox.bottom > (ycenter - yradius)) info.rSelectionBox.bottom = max(0L,min(head.biHeight,(ycenter - yradius))); - if (info.rSelectionBox.top <= (ycenter + yradius)) info.rSelectionBox.top = max(0L,min(head.biHeight,(ycenter + yradius + 1))); - - long xmin = max(0L,min(head.biWidth,xcenter - xradius)); - long xmax = max(0L,min(head.biWidth,xcenter + xradius + 1)); - long ymin = max(0L,min(head.biHeight,ycenter - yradius)); - long ymax = max(0L,min(head.biHeight,ycenter + yradius + 1)); - - long y,yo; - for (y=ymin; yy) pSelection[x + y * head.biWidth] = level; - } - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Inverts the selection. - * Note: the SelectionBox is set to "full image", call SelectionGetBox before (if necessary) - */ -bool CxImage::SelectionInvert() -{ - if (pSelection) { - BYTE *iSrc=pSelection; - long n=head.biHeight*head.biWidth; - for(long i=0; i < n; i++){ - *iSrc=(BYTE)~(*(iSrc)); - iSrc++; - } - - SelectionRebuildBox(); - - return true; - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Imports an existing region from another image with the same width and height. - */ -bool CxImage::SelectionCopy(CxImage &from) -{ - if (from.pSelection == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false; - if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight); - if (pSelection==NULL) return false; - memcpy(pSelection,from.pSelection,head.biWidth * head.biHeight); - memcpy(&info.rSelectionBox,&from.info.rSelectionBox,sizeof(RECT)); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Adds a polygonal region to the existing selection. points points to an array of POINT structures. - * Each structure specifies the x-coordinate and y-coordinate of one vertex of the polygon. - * npoints specifies the number of POINT structures in the array pointed to by points. - */ -bool CxImage::SelectionAddPolygon(POINT *points, long npoints, BYTE level) -{ - if (points==NULL || npoints<3) return false; - - if (pSelection==NULL) SelectionCreate(); - if (pSelection==NULL) return false; - - BYTE* plocal = (BYTE*)calloc(head.biWidth*head.biHeight, 1); - RECT localbox = {head.biWidth,0,0,head.biHeight}; - - long x,y,i=0; - POINT *current; - POINT *next = NULL; - POINT *start = NULL; - //trace contour - while (i < npoints){ - current = &points[i]; - if (current->x!=-1){ - if (i==0 || (i>0 && points[i-1].x==-1)) start = &points[i]; - - if ((i+1)==npoints || points[i+1].x==-1) - next = start; - else - next = &points[i+1]; - - float beta; - if (current->x != next->x){ - beta = (float)(next->y - current->y)/(float)(next->x - current->x); - if (current->x < next->x){ - for (x=current->x; x<=next->x; x++){ - y = (long)(current->y + (x - current->x) * beta); - if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; - } - } else { - for (x=current->x; x>=next->x; x--){ - y = (long)(current->y + (x - current->x) * beta); - if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; - } - } - } - if (current->y != next->y){ - beta = (float)(next->x - current->x)/(float)(next->y - current->y); - if (current->y < next->y){ - for (y=current->y; y<=next->y; y++){ - x = (long)(current->x + (y - current->y) * beta); - if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; - } - } else { - for (y=current->y; y>=next->y; y--){ - x = (long)(current->x + (y - current->y) * beta); - if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; - } - } - } - } - - RECT r2; - if (current->x < next->x) {r2.left=current->x; r2.right=next->x; } else {r2.left=next->x ; r2.right=current->x; } - if (current->y < next->y) {r2.bottom=current->y; r2.top=next->y; } else {r2.bottom=next->y ; r2.top=current->y; } - if (localbox.top < r2.top) localbox.top = max(0L,min(head.biHeight-1,r2.top+1)); - if (localbox.left > r2.left) localbox.left = max(0L,min(head.biWidth-1,r2.left-1)); - if (localbox.right < r2.right) localbox.right = max(0L,min(head.biWidth-1,r2.right+1)); - if (localbox.bottom > r2.bottom) localbox.bottom = max(0L,min(head.biHeight-1,r2.bottom-1)); - - i++; - } - - //fill the outer region - long npix=(localbox.right - localbox.left)*(localbox.top - localbox.bottom); - POINT* pix = (POINT*)calloc(npix,sizeof(POINT)); - BYTE back=0, mark=1; - long fx, fy, fxx, fyy, first, last; - long xmin = 0; - long xmax = 0; - long ymin = 0; - long ymax = 0; - - for (int side=0; side<4; side++){ - switch(side){ - case 0: - xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.bottom+1; - break; - case 1: - xmin=localbox.right; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.top+1; - break; - case 2: - xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.top; ymax=localbox.top+1; - break; - case 3: - xmin=localbox.left; xmax=localbox.left+1; ymin=localbox.bottom; ymax=localbox.top+1; - break; - } - //fill from the border points - for(y=ymin;y=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top ) - { - plocal[fxx + fyy*head.biWidth] = mark; - if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){ - pix[last].x = fx; - pix[last].y = fy - 1; - last++; - if (last == npix) last = 0; - } - if ((fyy + 1)=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top ) - { - plocal[fxx + (y + fy)*head.biWidth] = mark; - if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){ - pix[last].x = fx; - pix[last].y = fy - 1; - last++; - if (last == npix) last = 0; - } - if ((fyy + 1) localbox.left) info.rSelectionBox.left = min(head.biWidth,localbox.left); - if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = min(head.biWidth,localbox.right + 1); - if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = min(head.biHeight,localbox.bottom); - - free(plocal); - free(pix); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Adds to the selection all the pixels matching the specified color. - */ -bool CxImage::SelectionAddColor(RGBQUAD c, BYTE level) -{ - if (pSelection==NULL) SelectionCreate(); - if (pSelection==NULL) return false; - - RECT localbox = {head.biWidth,0,0,head.biHeight}; - - for (long y = 0; y < head.biHeight; y++){ - for (long x = 0; x < head.biWidth; x++){ - RGBQUAD color = BlindGetPixelColor(x, y); - if (color.rgbRed == c.rgbRed && - color.rgbGreen == c.rgbGreen && - color.rgbBlue == c.rgbBlue) - { - pSelection[x + y * head.biWidth] = level; - - if (localbox.top < y) localbox.top = y; - if (localbox.left > x) localbox.left = x; - if (localbox.right < x) localbox.right = x; - if (localbox.bottom > y) localbox.bottom = y; - } - } - } - - if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = localbox.top + 1; - if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = localbox.left; - if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = localbox.right + 1; - if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = localbox.bottom; - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Adds a single pixel to the existing selection. - */ -bool CxImage::SelectionAddPixel(long x, long y, BYTE level) -{ - if (pSelection==NULL) SelectionCreate(); - if (pSelection==NULL) return false; - - if (IsInside(x,y)) { - pSelection[x + y * head.biWidth] = level; // set the correct mask bit - - if (info.rSelectionBox.top <= y) info.rSelectionBox.top = y+1; - if (info.rSelectionBox.left > x) info.rSelectionBox.left = x; - if (info.rSelectionBox.right <= x) info.rSelectionBox.right = x+1; - if (info.rSelectionBox.bottom > y) info.rSelectionBox.bottom = y; - - return true; - } - - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Exports the selection channel in a 8bpp grayscale image. - */ -bool CxImage::SelectionSplit(CxImage *dest) -{ - if (!pSelection || !dest) return false; - - CxImage tmp(head.biWidth,head.biHeight,8); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - for(long y=0; yTransfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Creates the selection channel from a gray scale image. - * black = unselected - */ -bool CxImage::SelectionSet(CxImage &from) -{ - if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight){ - strcpy(info.szLastError,"CxImage::SelectionSet: wrong width or height, or image is not gray scale"); - return false; - } - - if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight); - - BYTE* src = from.info.pImage; - BYTE* dst = pSelection; - if (src==NULL || dst==NULL){ - strcpy(info.szLastError,"CxImage::SelectionSet: null pointer"); - return false; - } - - for (long y=0; y=info.rSelectionBox.right; x--){ - if (pSelection[x+y*head.biWidth]){ - info.rSelectionBox.right = x+1; - continue; - } - } - } - - for (x=0; x=info.rSelectionBox.top; y--){ - if (pSelection[x+y*head.biWidth]){ - info.rSelectionBox.top = y+1; - continue; - } - } - } - -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Gets the Selection level for a single pixel - * "blind" version assumes that (x,y) is inside to the image. - */ -BYTE CxImage::BlindSelectionGet(const long x,const long y) -{ -#ifdef _DEBUG - if (!IsInside(x,y) || (pSelection==0)) - #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING - throw 0; - #else - return 0; - #endif -#endif - return pSelection[x+y*head.biWidth]; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Returns pointer to selection data for pixel (x,y). - */ -BYTE* CxImage::SelectionGetPointer(const long x,const long y) -{ - if (pSelection && IsInside(x,y)) return pSelection+x+y*head.biWidth; - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::SelectionFlip() -{ - if (!pSelection) return false; - - BYTE *buff = (BYTE*)malloc(head.biWidth); - if (!buff) return false; - - BYTE *iSrc,*iDst; - iSrc = pSelection + (head.biHeight-1)*head.biWidth; - iDst = pSelection; - for (long i=0; i<(head.biHeight/2); ++i) - { - memcpy(buff, iSrc, head.biWidth); - memcpy(iSrc, iDst, head.biWidth); - memcpy(iDst, buff, head.biWidth); - iSrc-=head.biWidth; - iDst+=head.biWidth; - } - - free(buff); - - long top = info.rSelectionBox.top; - info.rSelectionBox.top = head.biHeight - info.rSelectionBox.bottom; - info.rSelectionBox.bottom = head.biHeight - top; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::SelectionMirror() -{ - if (!pSelection) return false; - BYTE* pSelection2 = (BYTE*)malloc(head.biWidth * head.biHeight); - if (!pSelection2) return false; - - BYTE *iSrc,*iDst; - long wdt=head.biWidth-1; - iSrc=pSelection + wdt; - iDst=pSelection2; - for(long y=0; y < head.biHeight; y++){ - for(long x=0; x <= wdt; x++) - *(iDst+x)=*(iSrc-x); - iSrc+=head.biWidth; - iDst+=head.biWidth; - } - free(pSelection); - pSelection=pSelection2; - - long left = info.rSelectionBox.left; - info.rSelectionBox.left = head.biWidth - info.rSelectionBox.right; - info.rSelectionBox.right = head.biWidth - left; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_WINDOWS -/** - * Converts the selection in a HRGN object. - */ -bool CxImage::SelectionToHRGN(HRGN& region) -{ - if (pSelection && region){ - for(int y = 0; y < head.biHeight; y++){ - HRGN hTemp = NULL; - int iStart = -1; - int x = 0; - for(; x < head.biWidth; x++){ - if (pSelection[x + y * head.biWidth] != 0){ - if (iStart == -1) iStart = x; - continue; - }else{ - if (iStart >= 0){ - hTemp = CreateRectRgn(iStart, y, x, y + 1); - CombineRgn(region, hTemp, region, RGN_OR); - DeleteObject(hTemp); - iStart = -1; - } - } - } - if (iStart >= 0){ - hTemp = CreateRectRgn(iStart, y, x, y + 1); - CombineRgn(region, hTemp, region, RGN_OR); - DeleteObject(hTemp); - iStart = -1; - } - } - return true; - } - return false; -} -#endif //CXIMAGE_SUPPORT_WINDOWS -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_SELECTION +// xImaSel.cpp : Selection functions +/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_SELECTION + +//////////////////////////////////////////////////////////////////////////////// +/** + * Checks if the image has a valid selection. + */ +bool CxImage::SelectionIsValid() +{ + return pSelection!=0; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Gets the smallest rectangle that contains the selection + */ +void CxImage::SelectionGetBox(RECT& r) +{ + memcpy(&r,&info.rSelectionBox,sizeof(RECT)); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Empties the selection. + */ +bool CxImage::SelectionClear(BYTE level) +{ + if (pSelection){ + if (level==0){ + memset(pSelection,0,head.biWidth * head.biHeight); + info.rSelectionBox.left = head.biWidth; + info.rSelectionBox.bottom = head.biHeight; + info.rSelectionBox.right = info.rSelectionBox.top = 0; + } else { + memset(pSelection,level,head.biWidth * head.biHeight); + info.rSelectionBox.right = head.biWidth; + info.rSelectionBox.top = head.biHeight; + info.rSelectionBox.left = info.rSelectionBox.bottom = 0; + } + return true; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Allocates an empty selection. + */ +bool CxImage::SelectionCreate() +{ + SelectionDelete(); + pSelection = (BYTE*)calloc(head.biWidth * head.biHeight, 1); + return (pSelection!=0); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Deallocates the selction. + */ +bool CxImage::SelectionDelete() +{ + if (pSelection){ + free(pSelection); + pSelection=NULL; + } + info.rSelectionBox.left = head.biWidth; + info.rSelectionBox.bottom = head.biHeight; + info.rSelectionBox.right = info.rSelectionBox.top = 0; + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Checks if the coordinates are inside the selection. + */ +bool CxImage::SelectionIsInside(long x, long y) +{ + if (IsInside(x,y)){ + if (pSelection==NULL) return true; + return pSelection[x+y*head.biWidth]!=0; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Checks if the coordinates are inside the selection. + * "blind" version assumes that (x,y) is inside to the image. + */ +bool CxImage::BlindSelectionIsInside(long x, long y) +{ +#ifdef _DEBUG + if (!IsInside(x,y)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return 0; + #endif +#endif + if (pSelection==NULL) return true; + return pSelection[x+y*head.biWidth]!=0; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Adds a rectangle to the existing selection. + */ +bool CxImage::SelectionAddRect(RECT r, BYTE level) +{ + if (pSelection==NULL) SelectionCreate(); + if (pSelection==NULL) return false; + + RECT r2; + if (r.left r2.left) info.rSelectionBox.left = max(0L,min(head.biWidth,r2.left)); + if (info.rSelectionBox.right <= r2.right) info.rSelectionBox.right = max(0L,min(head.biWidth,r2.right+1)); + if (info.rSelectionBox.bottom > r2.bottom) info.rSelectionBox.bottom = max(0L,min(head.biHeight,r2.bottom)); + + long ymin = max(0L,min(head.biHeight,r2.bottom)); + long ymax = max(0L,min(head.biHeight,r2.top+1)); + long xmin = max(0L,min(head.biWidth,r2.left)); + long xmax = max(0L,min(head.biWidth,r2.right+1)); + + for (long y=ymin; y (xcenter - xradius)) info.rSelectionBox.left = max(0L,min(head.biWidth,(xcenter - xradius))); + if (info.rSelectionBox.right <= (xcenter + xradius)) info.rSelectionBox.right = max(0L,min(head.biWidth,(xcenter + xradius + 1))); + if (info.rSelectionBox.bottom > (ycenter - yradius)) info.rSelectionBox.bottom = max(0L,min(head.biHeight,(ycenter - yradius))); + if (info.rSelectionBox.top <= (ycenter + yradius)) info.rSelectionBox.top = max(0L,min(head.biHeight,(ycenter + yradius + 1))); + + long xmin = max(0L,min(head.biWidth,xcenter - xradius)); + long xmax = max(0L,min(head.biWidth,xcenter + xradius + 1)); + long ymin = max(0L,min(head.biHeight,ycenter - yradius)); + long ymax = max(0L,min(head.biHeight,ycenter + yradius + 1)); + + long y,yo; + for (y=ymin; yy) pSelection[x + y * head.biWidth] = level; + } + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Inverts the selection. + * Note: the SelectionBox is set to "full image", call SelectionGetBox before (if necessary) + */ +bool CxImage::SelectionInvert() +{ + if (pSelection) { + BYTE *iSrc=pSelection; + long n=head.biHeight*head.biWidth; + for(long i=0; i < n; i++){ + *iSrc=(BYTE)~(*(iSrc)); + iSrc++; + } + + SelectionRebuildBox(); + + return true; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Imports an existing region from another image with the same width and height. + */ +bool CxImage::SelectionCopy(CxImage &from) +{ + if (from.pSelection == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false; + if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight); + if (pSelection==NULL) return false; + memcpy(pSelection,from.pSelection,head.biWidth * head.biHeight); + memcpy(&info.rSelectionBox,&from.info.rSelectionBox,sizeof(RECT)); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Adds a polygonal region to the existing selection. points points to an array of POINT structures. + * Each structure specifies the x-coordinate and y-coordinate of one vertex of the polygon. + * npoints specifies the number of POINT structures in the array pointed to by points. + */ +bool CxImage::SelectionAddPolygon(POINT *points, long npoints, BYTE level) +{ + if (points==NULL || npoints<3) return false; + + if (pSelection==NULL) SelectionCreate(); + if (pSelection==NULL) return false; + + BYTE* plocal = (BYTE*)calloc(head.biWidth*head.biHeight, 1); + RECT localbox = {head.biWidth,0,0,head.biHeight}; + + long x,y,i=0; + POINT *current; + POINT *next = NULL; + POINT *start = NULL; + //trace contour + while (i < npoints){ + current = &points[i]; + if (current->x!=-1){ + if (i==0 || (i>0 && points[i-1].x==-1)) start = &points[i]; + + if ((i+1)==npoints || points[i+1].x==-1) + next = start; + else + next = &points[i+1]; + + float beta; + if (current->x != next->x){ + beta = (float)(next->y - current->y)/(float)(next->x - current->x); + if (current->x < next->x){ + for (x=current->x; x<=next->x; x++){ + y = (long)(current->y + (x - current->x) * beta); + if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; + } + } else { + for (x=current->x; x>=next->x; x--){ + y = (long)(current->y + (x - current->x) * beta); + if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; + } + } + } + if (current->y != next->y){ + beta = (float)(next->x - current->x)/(float)(next->y - current->y); + if (current->y < next->y){ + for (y=current->y; y<=next->y; y++){ + x = (long)(current->x + (y - current->y) * beta); + if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; + } + } else { + for (y=current->y; y>=next->y; y--){ + x = (long)(current->x + (y - current->y) * beta); + if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255; + } + } + } + } + + RECT r2; + if (current->x < next->x) {r2.left=current->x; r2.right=next->x; } else {r2.left=next->x ; r2.right=current->x; } + if (current->y < next->y) {r2.bottom=current->y; r2.top=next->y; } else {r2.bottom=next->y ; r2.top=current->y; } + if (localbox.top < r2.top) localbox.top = max(0L,min(head.biHeight-1,r2.top+1)); + if (localbox.left > r2.left) localbox.left = max(0L,min(head.biWidth-1,r2.left-1)); + if (localbox.right < r2.right) localbox.right = max(0L,min(head.biWidth-1,r2.right+1)); + if (localbox.bottom > r2.bottom) localbox.bottom = max(0L,min(head.biHeight-1,r2.bottom-1)); + + i++; + } + + //fill the outer region + long npix=(localbox.right - localbox.left)*(localbox.top - localbox.bottom); + POINT* pix = (POINT*)calloc(npix,sizeof(POINT)); + BYTE back=0, mark=1; + long fx, fy, fxx, fyy, first, last; + long xmin = 0; + long xmax = 0; + long ymin = 0; + long ymax = 0; + + for (int side=0; side<4; side++){ + switch(side){ + case 0: + xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.bottom+1; + break; + case 1: + xmin=localbox.right; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.top+1; + break; + case 2: + xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.top; ymax=localbox.top+1; + break; + case 3: + xmin=localbox.left; xmax=localbox.left+1; ymin=localbox.bottom; ymax=localbox.top+1; + break; + } + //fill from the border points + for(y=ymin;y=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top ) + { + plocal[fxx + fyy*head.biWidth] = mark; + if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){ + pix[last].x = fx; + pix[last].y = fy - 1; + last++; + if (last == npix) last = 0; + } + if ((fyy + 1)=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top ) + { + plocal[fxx + (y + fy)*head.biWidth] = mark; + if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){ + pix[last].x = fx; + pix[last].y = fy - 1; + last++; + if (last == npix) last = 0; + } + if ((fyy + 1) localbox.left) info.rSelectionBox.left = min(head.biWidth,localbox.left); + if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = min(head.biWidth,localbox.right + 1); + if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = min(head.biHeight,localbox.bottom); + + free(plocal); + free(pix); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Adds to the selection all the pixels matching the specified color. + */ +bool CxImage::SelectionAddColor(RGBQUAD c, BYTE level) +{ + if (pSelection==NULL) SelectionCreate(); + if (pSelection==NULL) return false; + + RECT localbox = {head.biWidth,0,0,head.biHeight}; + + for (long y = 0; y < head.biHeight; y++){ + for (long x = 0; x < head.biWidth; x++){ + RGBQUAD color = BlindGetPixelColor(x, y); + if (color.rgbRed == c.rgbRed && + color.rgbGreen == c.rgbGreen && + color.rgbBlue == c.rgbBlue) + { + pSelection[x + y * head.biWidth] = level; + + if (localbox.top < y) localbox.top = y; + if (localbox.left > x) localbox.left = x; + if (localbox.right < x) localbox.right = x; + if (localbox.bottom > y) localbox.bottom = y; + } + } + } + + if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = localbox.top + 1; + if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = localbox.left; + if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = localbox.right + 1; + if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = localbox.bottom; + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Adds a single pixel to the existing selection. + */ +bool CxImage::SelectionAddPixel(long x, long y, BYTE level) +{ + if (pSelection==NULL) SelectionCreate(); + if (pSelection==NULL) return false; + + if (IsInside(x,y)) { + pSelection[x + y * head.biWidth] = level; // set the correct mask bit + + if (info.rSelectionBox.top <= y) info.rSelectionBox.top = y+1; + if (info.rSelectionBox.left > x) info.rSelectionBox.left = x; + if (info.rSelectionBox.right <= x) info.rSelectionBox.right = x+1; + if (info.rSelectionBox.bottom > y) info.rSelectionBox.bottom = y; + + return true; + } + + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Exports the selection channel in a 8bpp grayscale image. + */ +bool CxImage::SelectionSplit(CxImage *dest) +{ + if (!pSelection || !dest) return false; + + CxImage tmp(head.biWidth,head.biHeight,8); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + for(long y=0; yTransfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Creates the selection channel from a gray scale image. + * black = unselected + */ +bool CxImage::SelectionSet(CxImage &from) +{ + if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight){ + strcpy(info.szLastError,"CxImage::SelectionSet: wrong width or height, or image is not gray scale"); + return false; + } + + if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight); + + BYTE* src = from.info.pImage; + BYTE* dst = pSelection; + if (src==NULL || dst==NULL){ + strcpy(info.szLastError,"CxImage::SelectionSet: null pointer"); + return false; + } + + for (long y=0; y=info.rSelectionBox.right; x--){ + if (pSelection[x+y*head.biWidth]){ + info.rSelectionBox.right = x+1; + continue; + } + } + } + + for (x=0; x=info.rSelectionBox.top; y--){ + if (pSelection[x+y*head.biWidth]){ + info.rSelectionBox.top = y+1; + continue; + } + } + } + +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Gets the Selection level for a single pixel + * "blind" version assumes that (x,y) is inside to the image. + */ +BYTE CxImage::BlindSelectionGet(const long x,const long y) +{ +#ifdef _DEBUG + if (!IsInside(x,y) || (pSelection==0)) + #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING + throw 0; + #else + return 0; + #endif +#endif + return pSelection[x+y*head.biWidth]; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Returns pointer to selection data for pixel (x,y). + */ +BYTE* CxImage::SelectionGetPointer(const long x,const long y) +{ + if (pSelection && IsInside(x,y)) return pSelection+x+y*head.biWidth; + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::SelectionFlip() +{ + if (!pSelection) return false; + + BYTE *buff = (BYTE*)malloc(head.biWidth); + if (!buff) return false; + + BYTE *iSrc,*iDst; + iSrc = pSelection + (head.biHeight-1)*head.biWidth; + iDst = pSelection; + for (long i=0; i<(head.biHeight/2); ++i) + { + memcpy(buff, iSrc, head.biWidth); + memcpy(iSrc, iDst, head.biWidth); + memcpy(iDst, buff, head.biWidth); + iSrc-=head.biWidth; + iDst+=head.biWidth; + } + + free(buff); + + long top = info.rSelectionBox.top; + info.rSelectionBox.top = head.biHeight - info.rSelectionBox.bottom; + info.rSelectionBox.bottom = head.biHeight - top; + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::SelectionMirror() +{ + if (!pSelection) return false; + BYTE* pSelection2 = (BYTE*)malloc(head.biWidth * head.biHeight); + if (!pSelection2) return false; + + BYTE *iSrc,*iDst; + long wdt=head.biWidth-1; + iSrc=pSelection + wdt; + iDst=pSelection2; + for(long y=0; y < head.biHeight; y++){ + for(long x=0; x <= wdt; x++) + *(iDst+x)=*(iSrc-x); + iSrc+=head.biWidth; + iDst+=head.biWidth; + } + free(pSelection); + pSelection=pSelection2; + + long left = info.rSelectionBox.left; + info.rSelectionBox.left = head.biWidth - info.rSelectionBox.right; + info.rSelectionBox.right = head.biWidth - left; + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_WINDOWS +/** + * Converts the selection in a HRGN object. + */ +bool CxImage::SelectionToHRGN(HRGN& region) +{ + if (pSelection && region){ + for(int y = 0; y < head.biHeight; y++){ + HRGN hTemp = NULL; + int iStart = -1; + int x = 0; + for(; x < head.biWidth; x++){ + if (pSelection[x + y * head.biWidth] != 0){ + if (iStart == -1) iStart = x; + continue; + }else{ + if (iStart >= 0){ + hTemp = CreateRectRgn(iStart, y, x, y + 1); + CombineRgn(region, hTemp, region, RGN_OR); + DeleteObject(hTemp); + iStart = -1; + } + } + } + if (iStart >= 0){ + hTemp = CreateRectRgn(iStart, y, x, y + 1); + CombineRgn(region, hTemp, region, RGN_OR); + DeleteObject(hTemp); + iStart = -1; + } + } + return true; + } + return false; +} +#endif //CXIMAGE_SUPPORT_WINDOWS +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_SELECTION diff --git a/utilities/CxImage/ximaska.cpp b/utilities/CxImage/ximaska.cpp index 1ecdf7f..3248716 100644 --- a/utilities/CxImage/ximaska.cpp +++ b/utilities/CxImage/ximaska.cpp @@ -1,126 +1,126 @@ -/* - * File: ximaska.cpp - * Purpose: Platform Independent SKA Image Class Loader and Writer - * 25/Sep/2007 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximaska.h" - -#if CXIMAGE_SUPPORT_SKA - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageSKA::Decode(CxFile *hFile) -{ - if (hFile==NULL) - return false; - - // read the header - SKAHEADER ska_header; - hFile->Read(&ska_header,sizeof(SKAHEADER),1); - - ska_header.Width = ntohs(ska_header.Width); - ska_header.Height = ntohs(ska_header.Height); - ska_header.dwUnknown = ntohl(ska_header.dwUnknown); - - // check header - if (ska_header.dwUnknown != 0x01000000 || - ska_header.Width > 0x7FFF || ska_header.Height > 0x7FFF || - ska_header.BppExp != 3) - return false; - - if (info.nEscape == -1){ - head.biWidth = ska_header.Width ; - head.biHeight= ska_header.Height; - info.dwType = CXIMAGE_FORMAT_SKA; - return true; - } - - int bpp = 1<Read(ppal,nColors*sizeof(rgb_color),1); - SetPalette(ppal,nColors); - free(ppal); - - //read the image - hFile->Read(GetBits(),ska_header.Width*ska_header.Height,1); - - //reorder rows - if (GetEffWidth() != ska_header.Width){ - BYTE *src,*dst; - src = GetBits() + ska_header.Width*(ska_header.Height-1); - dst = GetBits(ska_header.Height-1); - for(int y=0;y 8) { - strcpy(info.szLastError,"SKA Images must be 8 bit or less"); - return false; - } - - SKAHEADER ska_header; - - ska_header.Width = (unsigned short)GetWidth(); - ska_header.Height = (unsigned short)GetHeight(); - ska_header.BppExp = 3; - ska_header.dwUnknown = 0x01000000; - - ska_header.Width = ntohs(ska_header.Width); - ska_header.Height = ntohs(ska_header.Height); - ska_header.dwUnknown = ntohl(ska_header.dwUnknown); - - hFile->Write(&ska_header,sizeof(SKAHEADER),1); - - ska_header.Width = ntohs(ska_header.Width); - ska_header.Height = ntohs(ska_header.Height); - ska_header.dwUnknown = ntohl(ska_header.dwUnknown); - - if (head.biBitCount<8) IncreaseBpp(8); - - rgb_color pal[256]; - for(int idx=0; idx<256; idx++){ - GetPaletteColor(idx,&(pal[idx].r),&(pal[idx].g),&(pal[idx].b)); - } - - hFile->Write(pal,256*sizeof(rgb_color),1); - - BYTE* src = GetBits(ska_header.Height-1); - for(int y=0;yWrite(src,ska_header.Width,1); - src -= GetEffWidth(); - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_SKA - +/* + * File: ximaska.cpp + * Purpose: Platform Independent SKA Image Class Loader and Writer + * 25/Sep/2007 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximaska.h" + +#if CXIMAGE_SUPPORT_SKA + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageSKA::Decode(CxFile *hFile) +{ + if (hFile==NULL) + return false; + + // read the header + SKAHEADER ska_header; + hFile->Read(&ska_header,sizeof(SKAHEADER),1); + + ska_header.Width = ntohs(ska_header.Width); + ska_header.Height = ntohs(ska_header.Height); + ska_header.dwUnknown = ntohl(ska_header.dwUnknown); + + // check header + if (ska_header.dwUnknown != 0x01000000 || + ska_header.Width > 0x7FFF || ska_header.Height > 0x7FFF || + ska_header.BppExp != 3) + return false; + + if (info.nEscape == -1){ + head.biWidth = ska_header.Width ; + head.biHeight= ska_header.Height; + info.dwType = CXIMAGE_FORMAT_SKA; + return true; + } + + int bpp = 1<Read(ppal,nColors*sizeof(rgb_color),1); + SetPalette(ppal,nColors); + free(ppal); + + //read the image + hFile->Read(GetBits(),ska_header.Width*ska_header.Height,1); + + //reorder rows + if (GetEffWidth() != ska_header.Width){ + BYTE *src,*dst; + src = GetBits() + ska_header.Width*(ska_header.Height-1); + dst = GetBits(ska_header.Height-1); + for(int y=0;y 8) { + strcpy(info.szLastError,"SKA Images must be 8 bit or less"); + return false; + } + + SKAHEADER ska_header; + + ska_header.Width = (unsigned short)GetWidth(); + ska_header.Height = (unsigned short)GetHeight(); + ska_header.BppExp = 3; + ska_header.dwUnknown = 0x01000000; + + ska_header.Width = ntohs(ska_header.Width); + ska_header.Height = ntohs(ska_header.Height); + ska_header.dwUnknown = ntohl(ska_header.dwUnknown); + + hFile->Write(&ska_header,sizeof(SKAHEADER),1); + + ska_header.Width = ntohs(ska_header.Width); + ska_header.Height = ntohs(ska_header.Height); + ska_header.dwUnknown = ntohl(ska_header.dwUnknown); + + if (head.biBitCount<8) IncreaseBpp(8); + + rgb_color pal[256]; + for(int idx=0; idx<256; idx++){ + GetPaletteColor(idx,&(pal[idx].r),&(pal[idx].g),&(pal[idx].b)); + } + + hFile->Write(pal,256*sizeof(rgb_color),1); + + BYTE* src = GetBits(ska_header.Height-1); + for(int y=0;yWrite(src,ska_header.Width,1); + src -= GetEffWidth(); + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_SKA + diff --git a/utilities/CxImage/ximaska.h b/utilities/CxImage/ximaska.h index f2facc9..381acf5 100644 --- a/utilities/CxImage/ximaska.h +++ b/utilities/CxImage/ximaska.h @@ -1,44 +1,44 @@ -/* - * File: ximaska.h - * Purpose: SKA Image Class Loader and Writer - */ -/* ========================================================== - * CxImageSKA (c) 25/Sep/2007 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * ========================================================== - */ -#if !defined(__ximaSKA_h) -#define __ximaSKA_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_SKA - -class CxImageSKA: public CxImage -{ -#pragma pack(1) - typedef struct tagSkaHeader { - unsigned short Width; - unsigned short Height; - BYTE BppExp; - DWORD dwUnknown; -} SKAHEADER; -#pragma pack() - -public: - CxImageSKA(): CxImage(CXIMAGE_FORMAT_SKA) {} - -// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);} -// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE -}; - -#endif - -#endif +/* + * File: ximaska.h + * Purpose: SKA Image Class Loader and Writer + */ +/* ========================================================== + * CxImageSKA (c) 25/Sep/2007 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * ========================================================== + */ +#if !defined(__ximaSKA_h) +#define __ximaSKA_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_SKA + +class CxImageSKA: public CxImage +{ +#pragma pack(1) + typedef struct tagSkaHeader { + unsigned short Width; + unsigned short Height; + BYTE BppExp; + DWORD dwUnknown; +} SKAHEADER; +#pragma pack() + +public: + CxImageSKA(): CxImage(CXIMAGE_FORMAT_SKA) {} + +// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);} +// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximatga.cpp b/utilities/CxImage/ximatga.cpp index b137126..d084254 100644 --- a/utilities/CxImage/ximatga.cpp +++ b/utilities/CxImage/ximatga.cpp @@ -1,321 +1,321 @@ -/* - * File: ximatga.cpp - * Purpose: Platform Independent TGA Image Class Loader and Writer - * 05/Jan/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximatga.h" - -#if CXIMAGE_SUPPORT_TGA - -#include "ximaiter.h" - -// Definitions for image types. -#define TGA_Null 0 -#define TGA_Map 1 -#define TGA_RGB 2 -#define TGA_Mono 3 -#define TGA_RLEMap 9 -#define TGA_RLERGB 10 -#define TGA_RLEMono 11 -#define TGA_CompMap 32 -#define TGA_CompMap4 33 - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageTGA::Decode(CxFile *hFile) -{ - if (hFile == NULL) return false; - - TGAHEADER tgaHead; - - cx_try - { - if (hFile->Read(&tgaHead,sizeof(tgaHead),1)==0) - cx_throw("Not a TGA"); - - tga_toh(&tgaHead); - - bool bCompressed; - switch (tgaHead.ImageType){ - case TGA_Map: - case TGA_RGB: - case TGA_Mono: - bCompressed = false; - break; - case TGA_RLEMap: - case TGA_RLERGB: - case TGA_RLEMono: - bCompressed = true; - break; - default: - cx_throw("Unknown TGA image type"); - } - - if (tgaHead.ImageWidth==0 || tgaHead.ImageHeight==0 || tgaHead.PixelDepth==0 || tgaHead.CmapLength>256) - cx_throw("bad TGA header"); - - if (tgaHead.PixelDepth!=8 && tgaHead.PixelDepth!=15 && tgaHead.PixelDepth!=16 && tgaHead.PixelDepth!=24 && tgaHead.PixelDepth!=32) - cx_throw("bad TGA header"); - - if (info.nEscape == -1){ - head.biWidth = tgaHead.ImageWidth ; - head.biHeight= tgaHead.ImageHeight; - info.dwType = CXIMAGE_FORMAT_TGA; - return true; - } - - if (tgaHead.IdLength>0) hFile->Seek(tgaHead.IdLength,SEEK_CUR); //skip descriptor - - Create(tgaHead.ImageWidth, tgaHead.ImageHeight, tgaHead.PixelDepth, CXIMAGE_FORMAT_TGA); -#if CXIMAGE_SUPPORT_ALPHA // - if (tgaHead.PixelDepth==32) AlphaCreate(); // Image has alpha channel -#endif //CXIMAGE_SUPPORT_ALPHA - - if (!IsValid()) cx_throw("TGA Create failed"); - - if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding - - if (tgaHead.CmapType != 0){ // read the palette - rgb_color pal[256]; - hFile->Read(pal,tgaHead.CmapLength*sizeof(rgb_color), 1); - for (int i=0;i - cancel decoding - - if (hFile == NULL || hFile->Eof()) cx_throw("corrupted TGA"); - - if (bYReversed) pDest = iter.GetRow(tgaHead.ImageHeight-y-1); - else pDest = iter.GetRow(y); - - if (bCompressed) rleLeftover = ExpandCompressedLine(pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,rleLeftover); - else ExpandUncompressedLine (pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,0); - } - - if (bXReversed) Mirror(); - -#if CXIMAGE_SUPPORT_ALPHA - if (bYReversed && tgaHead.PixelDepth==32) AlphaFlip(); // -#endif //CXIMAGE_SUPPORT_ALPHA - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - return false; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageTGA::Encode(CxFile * hFile) -{ - if (EncodeSafeCheck(hFile)) return false; - - if (head.biBitCount<8){ - strcpy(info.szLastError,"Bit depth must be 8 or 24"); - return false; - } - - TGAHEADER tgaHead; - - tgaHead.IdLength = 0; // Image ID Field Length - tgaHead.CmapType = GetPalette()!=0; // Color Map Type - tgaHead.ImageType = (head.biBitCount == 8) ? (BYTE)TGA_Map : (BYTE)TGA_RGB; // Image Type - - tgaHead.CmapIndex=0; // First Entry Index - tgaHead.CmapLength=(head.biBitCount == 8) ? 256 : 0; // Color Map Length - tgaHead.CmapEntrySize=(head.biBitCount == 8) ? (BYTE)24 : (BYTE)0; // Color Map Entry Size - - tgaHead.X_Origin=0; // X-origin of Image - tgaHead.Y_Origin=0; // Y-origin of Image - tgaHead.ImageWidth=(WORD)head.biWidth; // Image Width - tgaHead.ImageHeight=(WORD)head.biHeight; // Image Height - tgaHead.PixelDepth=(BYTE)head.biBitCount; // Pixel Depth - tgaHead.ImagDesc=0; // Image Descriptor - - if (pAlpha && head.biBitCount==24) tgaHead.PixelDepth=32; - - tga_toh(&tgaHead); - hFile->Write(&tgaHead,sizeof(TGAHEADER),1); - tga_toh(&tgaHead); - - if (head.biBitCount==8){ - rgb_color pal[256]; - RGBQUAD* ppal = GetPalette(); - for (int i=0;i<256; i++){ - pal[i].r = ppal[i].rgbBlue; - pal[i].g = ppal[i].rgbGreen; - pal[i].b = ppal[i].rgbRed; - } - hFile->Write(&pal,256*sizeof(rgb_color),1); - } - - CImageIterator iter(this); - BYTE* pDest; - if (pAlpha==0 || head.biBitCount==8){ - for (int y=0; y < tgaHead.ImageHeight; y++){ - pDest = iter.GetRow(y); - hFile->Write(pDest,tgaHead.ImageWidth * (head.biBitCount >> 3),1); - } - } else { - pDest = (BYTE*)malloc(4*tgaHead.ImageWidth); - RGBQUAD c; - for (int y=0; y < tgaHead.ImageHeight; y++){ - for(int x=0, x4=0;x - pDest[x4+3]=AlphaGet(x,y); -#else - pDest[x4+3]=0; -#endif //CXIMAGE_SUPPORT_ALPHA - } - hFile->Write(pDest,4*tgaHead.ImageWidth,1); - } - free(pDest); - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -BYTE CxImageTGA::ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover) -{ - BYTE rle; - long filePos=0; - for (int x=0; xRead(&rle,1,1); - } - if (rle & 128) { // RLE-Encoded packet - rle -= 127; // Calculate real repeat count. - if ((x+rle)>width){ - rleLeftover = (BYTE)(128 + (rle - (width - x) - 1)); - filePos = hFile->Tell(); - rle = (BYTE)(width - x); - } - switch (ptgaHead->PixelDepth) - { - case 32: { - RGBQUAD color; - hFile->Read(&color,4,1); - for (int ix = 0; ix < rle; ix++){ - memcpy(&pDest[3*ix],&color,3); -#if CXIMAGE_SUPPORT_ALPHA // - AlphaSet(ix+x,y,color.rgbReserved); -#endif //CXIMAGE_SUPPORT_ALPHA - } - break; - } - case 24: { - rgb_color triple; - hFile->Read(&triple,3,1); - for (int ix = 0; ix < rle; ix++) memcpy(&pDest[3*ix],&triple,3); - break; - } - case 15: - case 16: { - WORD pixel; - hFile->Read(&pixel,2,1); - rgb_color triple; - triple.r = (BYTE)(( pixel & 0x1F ) * 8); // red - triple.g = (BYTE)(( pixel >> 2 ) & 0x0F8); // green - triple.b = (BYTE)(( pixel >> 7 ) & 0x0F8); // blue - for (int ix = 0; ix < rle; ix++){ - memcpy(&pDest[3*ix],&triple,3); - } - break; - } - case 8: { - BYTE pixel; - hFile->Read(&pixel,1,1); - for (int ix = 0; ix < rle; ix++) pDest[ix] = pixel; - } - } - if (rleLeftover!=255) hFile->Seek(filePos, SEEK_SET); - } else { // Raw packet - rle += 1; // Calculate real repeat count. - if ((x+rle)>width){ - rleLeftover = (BYTE)(rle - (width - x) - 1); - rle = (BYTE)(width - x); - } - ExpandUncompressedLine(pDest,ptgaHead,hFile,rle,y,x); - } - if (head.biBitCount == 24) pDest += rle*3; else pDest += rle; - x += rle; - } - return rleLeftover; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTGA::ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset) -{ - switch (ptgaHead->PixelDepth){ - case 8: - hFile->Read(pDest,width,1); - break; - case 15: - case 16:{ - BYTE* dst=pDest; - WORD pixel; - for (int x=0; xRead(&pixel,2,1); - *dst++ = (BYTE)(( pixel & 0x1F ) * 8); // blue - *dst++ = (BYTE)(( pixel >> 2 ) & 0x0F8); // green - *dst++ = (BYTE)(( pixel >> 7 ) & 0x0F8); // red - } - break; - } - case 24: - hFile->Read(pDest,3*width,1); - break; - case 32:{ - BYTE* dst=pDest; - for (int x=0; xRead(&pixel,4,1); - *dst++ = pixel.rgbBlue; - *dst++ = pixel.rgbGreen; - *dst++ = pixel.rgbRed; -#if CXIMAGE_SUPPORT_ALPHA // - AlphaSet(x+xoffset,y,pixel.rgbReserved); //alpha -#endif //CXIMAGE_SUPPORT_ALPHA - } - break; - } - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTGA::tga_toh(TGAHEADER* p) -{ - p->CmapIndex = ntohs(p->CmapIndex); - p->CmapLength = ntohs(p->CmapLength); - p->X_Origin = ntohs(p->X_Origin); - p->Y_Origin = ntohs(p->Y_Origin); - p->ImageWidth = ntohs(p->ImageWidth); - p->ImageHeight = ntohs(p->ImageHeight); -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_TGA - +/* + * File: ximatga.cpp + * Purpose: Platform Independent TGA Image Class Loader and Writer + * 05/Jan/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximatga.h" + +#if CXIMAGE_SUPPORT_TGA + +#include "ximaiter.h" + +// Definitions for image types. +#define TGA_Null 0 +#define TGA_Map 1 +#define TGA_RGB 2 +#define TGA_Mono 3 +#define TGA_RLEMap 9 +#define TGA_RLERGB 10 +#define TGA_RLEMono 11 +#define TGA_CompMap 32 +#define TGA_CompMap4 33 + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageTGA::Decode(CxFile *hFile) +{ + if (hFile == NULL) return false; + + TGAHEADER tgaHead; + + cx_try + { + if (hFile->Read(&tgaHead,sizeof(tgaHead),1)==0) + cx_throw("Not a TGA"); + + tga_toh(&tgaHead); + + bool bCompressed; + switch (tgaHead.ImageType){ + case TGA_Map: + case TGA_RGB: + case TGA_Mono: + bCompressed = false; + break; + case TGA_RLEMap: + case TGA_RLERGB: + case TGA_RLEMono: + bCompressed = true; + break; + default: + cx_throw("Unknown TGA image type"); + } + + if (tgaHead.ImageWidth==0 || tgaHead.ImageHeight==0 || tgaHead.PixelDepth==0 || tgaHead.CmapLength>256) + cx_throw("bad TGA header"); + + if (tgaHead.PixelDepth!=8 && tgaHead.PixelDepth!=15 && tgaHead.PixelDepth!=16 && tgaHead.PixelDepth!=24 && tgaHead.PixelDepth!=32) + cx_throw("bad TGA header"); + + if (info.nEscape == -1){ + head.biWidth = tgaHead.ImageWidth ; + head.biHeight= tgaHead.ImageHeight; + info.dwType = CXIMAGE_FORMAT_TGA; + return true; + } + + if (tgaHead.IdLength>0) hFile->Seek(tgaHead.IdLength,SEEK_CUR); //skip descriptor + + Create(tgaHead.ImageWidth, tgaHead.ImageHeight, tgaHead.PixelDepth, CXIMAGE_FORMAT_TGA); +#if CXIMAGE_SUPPORT_ALPHA // + if (tgaHead.PixelDepth==32) AlphaCreate(); // Image has alpha channel +#endif //CXIMAGE_SUPPORT_ALPHA + + if (!IsValid()) cx_throw("TGA Create failed"); + + if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding + + if (tgaHead.CmapType != 0){ // read the palette + rgb_color pal[256]; + hFile->Read(pal,tgaHead.CmapLength*sizeof(rgb_color), 1); + for (int i=0;i - cancel decoding + + if (hFile == NULL || hFile->Eof()) cx_throw("corrupted TGA"); + + if (bYReversed) pDest = iter.GetRow(tgaHead.ImageHeight-y-1); + else pDest = iter.GetRow(y); + + if (bCompressed) rleLeftover = ExpandCompressedLine(pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,rleLeftover); + else ExpandUncompressedLine (pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,0); + } + + if (bXReversed) Mirror(); + +#if CXIMAGE_SUPPORT_ALPHA + if (bYReversed && tgaHead.PixelDepth==32) AlphaFlip(); // +#endif //CXIMAGE_SUPPORT_ALPHA + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + return false; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageTGA::Encode(CxFile * hFile) +{ + if (EncodeSafeCheck(hFile)) return false; + + if (head.biBitCount<8){ + strcpy(info.szLastError,"Bit depth must be 8 or 24"); + return false; + } + + TGAHEADER tgaHead; + + tgaHead.IdLength = 0; // Image ID Field Length + tgaHead.CmapType = GetPalette()!=0; // Color Map Type + tgaHead.ImageType = (head.biBitCount == 8) ? (BYTE)TGA_Map : (BYTE)TGA_RGB; // Image Type + + tgaHead.CmapIndex=0; // First Entry Index + tgaHead.CmapLength=(head.biBitCount == 8) ? 256 : 0; // Color Map Length + tgaHead.CmapEntrySize=(head.biBitCount == 8) ? (BYTE)24 : (BYTE)0; // Color Map Entry Size + + tgaHead.X_Origin=0; // X-origin of Image + tgaHead.Y_Origin=0; // Y-origin of Image + tgaHead.ImageWidth=(WORD)head.biWidth; // Image Width + tgaHead.ImageHeight=(WORD)head.biHeight; // Image Height + tgaHead.PixelDepth=(BYTE)head.biBitCount; // Pixel Depth + tgaHead.ImagDesc=0; // Image Descriptor + + if (pAlpha && head.biBitCount==24) tgaHead.PixelDepth=32; + + tga_toh(&tgaHead); + hFile->Write(&tgaHead,sizeof(TGAHEADER),1); + tga_toh(&tgaHead); + + if (head.biBitCount==8){ + rgb_color pal[256]; + RGBQUAD* ppal = GetPalette(); + for (int i=0;i<256; i++){ + pal[i].r = ppal[i].rgbBlue; + pal[i].g = ppal[i].rgbGreen; + pal[i].b = ppal[i].rgbRed; + } + hFile->Write(&pal,256*sizeof(rgb_color),1); + } + + CImageIterator iter(this); + BYTE* pDest; + if (pAlpha==0 || head.biBitCount==8){ + for (int y=0; y < tgaHead.ImageHeight; y++){ + pDest = iter.GetRow(y); + hFile->Write(pDest,tgaHead.ImageWidth * (head.biBitCount >> 3),1); + } + } else { + pDest = (BYTE*)malloc(4*tgaHead.ImageWidth); + RGBQUAD c; + for (int y=0; y < tgaHead.ImageHeight; y++){ + for(int x=0, x4=0;x + pDest[x4+3]=AlphaGet(x,y); +#else + pDest[x4+3]=0; +#endif //CXIMAGE_SUPPORT_ALPHA + } + hFile->Write(pDest,4*tgaHead.ImageWidth,1); + } + free(pDest); + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +BYTE CxImageTGA::ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover) +{ + BYTE rle; + long filePos=0; + for (int x=0; xRead(&rle,1,1); + } + if (rle & 128) { // RLE-Encoded packet + rle -= 127; // Calculate real repeat count. + if ((x+rle)>width){ + rleLeftover = (BYTE)(128 + (rle - (width - x) - 1)); + filePos = hFile->Tell(); + rle = (BYTE)(width - x); + } + switch (ptgaHead->PixelDepth) + { + case 32: { + RGBQUAD color; + hFile->Read(&color,4,1); + for (int ix = 0; ix < rle; ix++){ + memcpy(&pDest[3*ix],&color,3); +#if CXIMAGE_SUPPORT_ALPHA // + AlphaSet(ix+x,y,color.rgbReserved); +#endif //CXIMAGE_SUPPORT_ALPHA + } + break; + } + case 24: { + rgb_color triple; + hFile->Read(&triple,3,1); + for (int ix = 0; ix < rle; ix++) memcpy(&pDest[3*ix],&triple,3); + break; + } + case 15: + case 16: { + WORD pixel; + hFile->Read(&pixel,2,1); + rgb_color triple; + triple.r = (BYTE)(( pixel & 0x1F ) * 8); // red + triple.g = (BYTE)(( pixel >> 2 ) & 0x0F8); // green + triple.b = (BYTE)(( pixel >> 7 ) & 0x0F8); // blue + for (int ix = 0; ix < rle; ix++){ + memcpy(&pDest[3*ix],&triple,3); + } + break; + } + case 8: { + BYTE pixel; + hFile->Read(&pixel,1,1); + for (int ix = 0; ix < rle; ix++) pDest[ix] = pixel; + } + } + if (rleLeftover!=255) hFile->Seek(filePos, SEEK_SET); + } else { // Raw packet + rle += 1; // Calculate real repeat count. + if ((x+rle)>width){ + rleLeftover = (BYTE)(rle - (width - x) - 1); + rle = (BYTE)(width - x); + } + ExpandUncompressedLine(pDest,ptgaHead,hFile,rle,y,x); + } + if (head.biBitCount == 24) pDest += rle*3; else pDest += rle; + x += rle; + } + return rleLeftover; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTGA::ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset) +{ + switch (ptgaHead->PixelDepth){ + case 8: + hFile->Read(pDest,width,1); + break; + case 15: + case 16:{ + BYTE* dst=pDest; + WORD pixel; + for (int x=0; xRead(&pixel,2,1); + *dst++ = (BYTE)(( pixel & 0x1F ) * 8); // blue + *dst++ = (BYTE)(( pixel >> 2 ) & 0x0F8); // green + *dst++ = (BYTE)(( pixel >> 7 ) & 0x0F8); // red + } + break; + } + case 24: + hFile->Read(pDest,3*width,1); + break; + case 32:{ + BYTE* dst=pDest; + for (int x=0; xRead(&pixel,4,1); + *dst++ = pixel.rgbBlue; + *dst++ = pixel.rgbGreen; + *dst++ = pixel.rgbRed; +#if CXIMAGE_SUPPORT_ALPHA // + AlphaSet(x+xoffset,y,pixel.rgbReserved); //alpha +#endif //CXIMAGE_SUPPORT_ALPHA + } + break; + } + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTGA::tga_toh(TGAHEADER* p) +{ + p->CmapIndex = ntohs(p->CmapIndex); + p->CmapLength = ntohs(p->CmapLength); + p->X_Origin = ntohs(p->X_Origin); + p->Y_Origin = ntohs(p->Y_Origin); + p->ImageWidth = ntohs(p->ImageWidth); + p->ImageHeight = ntohs(p->ImageHeight); +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_TGA + diff --git a/utilities/CxImage/ximatga.h b/utilities/CxImage/ximatga.h index da572e6..300eb72 100644 --- a/utilities/CxImage/ximatga.h +++ b/utilities/CxImage/ximatga.h @@ -1,61 +1,61 @@ -/* - * File: ximatga.h - * Purpose: TARGA Image Class Loader and Writer - */ -/* ========================================================== - * CxImageTGA (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Parts of the code come from Paintlib : Copyright (c) 1996-1998 Ulrich von Zadow - * ========================================================== - */ -#if !defined(__ximaTGA_h) -#define __ximaTGA_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_TGA - -class CxImageTGA: public CxImage -{ -#pragma pack(1) -typedef struct tagTgaHeader -{ - BYTE IdLength; // Image ID Field Length - BYTE CmapType; // Color Map Type - BYTE ImageType; // Image Type - - WORD CmapIndex; // First Entry Index - WORD CmapLength; // Color Map Length - BYTE CmapEntrySize; // Color Map Entry Size - - WORD X_Origin; // X-origin of Image - WORD Y_Origin; // Y-origin of Image - WORD ImageWidth; // Image Width - WORD ImageHeight; // Image Height - BYTE PixelDepth; // Pixel Depth - BYTE ImagDesc; // Image Descriptor -} TGAHEADER; -#pragma pack() - -public: - CxImageTGA(): CxImage(CXIMAGE_FORMAT_TGA) {} - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TGA);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TGA);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE -protected: - BYTE ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover); - void ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset); - void tga_toh(TGAHEADER* p); -}; - -#endif - -#endif +/* + * File: ximatga.h + * Purpose: TARGA Image Class Loader and Writer + */ +/* ========================================================== + * CxImageTGA (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Parts of the code come from Paintlib : Copyright (c) 1996-1998 Ulrich von Zadow + * ========================================================== + */ +#if !defined(__ximaTGA_h) +#define __ximaTGA_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_TGA + +class CxImageTGA: public CxImage +{ +#pragma pack(1) +typedef struct tagTgaHeader +{ + BYTE IdLength; // Image ID Field Length + BYTE CmapType; // Color Map Type + BYTE ImageType; // Image Type + + WORD CmapIndex; // First Entry Index + WORD CmapLength; // Color Map Length + BYTE CmapEntrySize; // Color Map Entry Size + + WORD X_Origin; // X-origin of Image + WORD Y_Origin; // Y-origin of Image + WORD ImageWidth; // Image Width + WORD ImageHeight; // Image Height + BYTE PixelDepth; // Pixel Depth + BYTE ImagDesc; // Image Descriptor +} TGAHEADER; +#pragma pack() + +public: + CxImageTGA(): CxImage(CXIMAGE_FORMAT_TGA) {} + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TGA);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TGA);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE +protected: + BYTE ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover); + void ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset); + void tga_toh(TGAHEADER* p); +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximath.cpp b/utilities/CxImage/ximath.cpp index 0175184..37533e2 100644 --- a/utilities/CxImage/ximath.cpp +++ b/utilities/CxImage/ximath.cpp @@ -1,97 +1,97 @@ -#include "ximage.h" -#include "ximath.h" -#include - -//this module should contain some classes for geometrical transformations -//usable with selections, etc... once it's done, that is. :) - -CxPoint2::CxPoint2() -{ - x=y=0.0f; -} - -CxPoint2::CxPoint2(float const x_, float const y_) -{ - x=x_; - y=y_; -} - -CxPoint2::CxPoint2(CxPoint2 const &p) -{ - x=p.x; - y=p.y; -} - -float CxPoint2::Distance(CxPoint2 const p2) -{ - return (float)sqrt((x-p2.x)*(x-p2.x)+(y-p2.y)*(y-p2.y)); -} - -float CxPoint2::Distance(float const x_, float const y_) -{ - return (float)sqrt((x-x_)*(x-x_)+(y-y_)*(y-y_)); -} - -CxRect2::CxRect2() -{ -} - -CxRect2::CxRect2(float const x1_, float const y1_, float const x2_, float const y2_) -{ - botLeft.x=x1_; - botLeft.y=y1_; - topRight.x=x2_; - topRight.y=y2_; -} - -CxRect2::CxRect2(CxRect2 const &p) -{ - botLeft=p.botLeft; - topRight=p.topRight; -} - -float CxRect2::Surface() const -/* - * Returns the surface of rectangle. - */ -{ - return (topRight.x-botLeft.x)*(topRight.y-botLeft.y); -} - -CxRect2 CxRect2::CrossSection(CxRect2 const &r2) const -/* - * Returns crossection with another rectangle. - */ -{ - CxRect2 cs; - cs.botLeft.x=max(botLeft.x, r2.botLeft.x); - cs.botLeft.y=max(botLeft.y, r2.botLeft.y); - cs.topRight.x=min(topRight.x, r2.topRight.x); - cs.topRight.y=min(topRight.y, r2.topRight.y); - if (cs.botLeft.x<=cs.topRight.x && cs.botLeft.y<=cs.topRight.y) { - return cs; - } else { - return CxRect2(0,0,0,0); - }//if -} - -CxPoint2 CxRect2::Center() const -/* - * Returns the center point of rectangle. - */ -{ - return CxPoint2((topRight.x+botLeft.x)/2.0f, (topRight.y+botLeft.y)/2.0f); -} - -float CxRect2::Width() const -//returns rectangle width -{ - return topRight.x-botLeft.x; -} - -float CxRect2::Height() const -//returns rectangle height -{ - return topRight.y-botLeft.y; -} - +#include "ximage.h" +#include "ximath.h" +#include + +//this module should contain some classes for geometrical transformations +//usable with selections, etc... once it's done, that is. :) + +CxPoint2::CxPoint2() +{ + x=y=0.0f; +} + +CxPoint2::CxPoint2(float const x_, float const y_) +{ + x=x_; + y=y_; +} + +CxPoint2::CxPoint2(CxPoint2 const &p) +{ + x=p.x; + y=p.y; +} + +float CxPoint2::Distance(CxPoint2 const p2) +{ + return (float)sqrt((x-p2.x)*(x-p2.x)+(y-p2.y)*(y-p2.y)); +} + +float CxPoint2::Distance(float const x_, float const y_) +{ + return (float)sqrt((x-x_)*(x-x_)+(y-y_)*(y-y_)); +} + +CxRect2::CxRect2() +{ +} + +CxRect2::CxRect2(float const x1_, float const y1_, float const x2_, float const y2_) +{ + botLeft.x=x1_; + botLeft.y=y1_; + topRight.x=x2_; + topRight.y=y2_; +} + +CxRect2::CxRect2(CxRect2 const &p) +{ + botLeft=p.botLeft; + topRight=p.topRight; +} + +float CxRect2::Surface() const +/* + * Returns the surface of rectangle. + */ +{ + return (topRight.x-botLeft.x)*(topRight.y-botLeft.y); +} + +CxRect2 CxRect2::CrossSection(CxRect2 const &r2) const +/* + * Returns crossection with another rectangle. + */ +{ + CxRect2 cs; + cs.botLeft.x=max(botLeft.x, r2.botLeft.x); + cs.botLeft.y=max(botLeft.y, r2.botLeft.y); + cs.topRight.x=min(topRight.x, r2.topRight.x); + cs.topRight.y=min(topRight.y, r2.topRight.y); + if (cs.botLeft.x<=cs.topRight.x && cs.botLeft.y<=cs.topRight.y) { + return cs; + } else { + return CxRect2(0,0,0,0); + }//if +} + +CxPoint2 CxRect2::Center() const +/* + * Returns the center point of rectangle. + */ +{ + return CxPoint2((topRight.x+botLeft.x)/2.0f, (topRight.y+botLeft.y)/2.0f); +} + +float CxRect2::Width() const +//returns rectangle width +{ + return topRight.x-botLeft.x; +} + +float CxRect2::Height() const +//returns rectangle height +{ + return topRight.y-botLeft.y; +} + diff --git a/utilities/CxImage/ximath.h b/utilities/CxImage/ximath.h index 014c14b..10b9898 100644 --- a/utilities/CxImage/ximath.h +++ b/utilities/CxImage/ximath.h @@ -1,39 +1,39 @@ -#if !defined(__ximath_h) -#define __ximath_h - -#include "ximadef.h" - -//***bd*** simple floating point point -class DLL_EXP CxPoint2 -{ -public: - CxPoint2(); - CxPoint2(float const x_, float const y_); - CxPoint2(CxPoint2 const &p); - - float Distance(CxPoint2 const p2); - float Distance(float const x_, float const y_); - - float x,y; -}; - -//and simple rectangle -class DLL_EXP CxRect2 -{ -public: - CxRect2(); - CxRect2(float const x1_, float const y1_, float const x2_, float const y2_); - CxRect2(CxPoint2 const &bl, CxPoint2 const &tr); - CxRect2(CxRect2 const &p); - - float Surface() const; - CxRect2 CrossSection(CxRect2 const &r2) const; - CxPoint2 Center() const; - float Width() const; - float Height() const; - - CxPoint2 botLeft; - CxPoint2 topRight; -}; - -#endif +#if !defined(__ximath_h) +#define __ximath_h + +#include "ximadef.h" + +//***bd*** simple floating point point +class DLL_EXP CxPoint2 +{ +public: + CxPoint2(); + CxPoint2(float const x_, float const y_); + CxPoint2(CxPoint2 const &p); + + float Distance(CxPoint2 const p2); + float Distance(float const x_, float const y_); + + float x,y; +}; + +//and simple rectangle +class DLL_EXP CxRect2 +{ +public: + CxRect2(); + CxRect2(float const x1_, float const y1_, float const x2_, float const y2_); + CxRect2(CxPoint2 const &bl, CxPoint2 const &tr); + CxRect2(CxRect2 const &p); + + float Surface() const; + CxRect2 CrossSection(CxRect2 const &r2) const; + CxPoint2 Center() const; + float Width() const; + float Height() const; + + CxPoint2 botLeft; + CxPoint2 topRight; +}; + +#endif diff --git a/utilities/CxImage/ximatif.cpp b/utilities/CxImage/ximatif.cpp index b7415ed..6b4e7ad 100644 --- a/utilities/CxImage/ximatif.cpp +++ b/utilities/CxImage/ximatif.cpp @@ -1,980 +1,980 @@ -/* - * File: ximatif.cpp - * Purpose: Platform Independent TIFF Image Class Loader and Writer - * 07/Aug/2001 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximatif.h" - -#if CXIMAGE_SUPPORT_TIF - -#define FIX_16BPP_DARKIMG // + VK: if uncomment, dark 16bpp images are fixed - -#include "../tiff/tiffio.h" - -#define CVT(x) (((x) * 255L) / ((1L<<16)-1)) -#define SCALE(x) (((x)*((1L<<16)-1))/255) -#define CalculateLine(width,bitdepth) (((width * bitdepth) + 7) / 8) -#define CalculatePitch(line) (line + 3 & ~3) - -extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode); - -//////////////////////////////////////////////////////////////////////////////// -CxImageTIF::~CxImageTIF() -{ - if (m_tif2) TIFFClose(m_tif2); -} -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageTIF::Decode(CxFile * hFile) -{ - //Comment this line if you need more information on errors - // TIFFSetErrorHandler(NULL); // - - //Open file and fill the TIFF structure - // m_tif = TIFFOpen(imageFileName,"rb"); - TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); - - uint32 height=0; - uint32 width=0; - uint16 bitspersample=1; - uint16 samplesperpixel=1; - uint32 rowsperstrip=(DWORD)-1; - uint16 photometric=0; - uint16 compression=1; - uint16 orientation=ORIENTATION_TOPLEFT; // - uint16 res_unit; // - uint32 x, y; - float resolution, offset; - BOOL isRGB; - BYTE *bits; //pointer to source data - BYTE *bits2; //pointer to destination data - - cx_try - { - //check if it's a tiff file - if (!m_tif) - cx_throw("Error encountered while opening TIFF file"); - - // - 12/2002 : get NumFrames directly, instead of looping - // info.nNumFrames=0; - // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; - info.nNumFrames = TIFFNumberOfDirectories(m_tif); - - if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) - cx_throw("Error: page not present in TIFF file"); - - //get image info - TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); - TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); - TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); - TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); - TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); - TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); - - if (info.nEscape == -1) { - // Return output dimensions only - head.biWidth = width; - head.biHeight = height; - info.dwType = CXIMAGE_FORMAT_TIF; - cx_throw("output dimensions returned"); - } - - TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); - if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) - { - if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); - SetXDPI((long)resolution); - } - if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) - { - if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); - SetYDPI((long)resolution); - } - - if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; - if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; - - head.biClrUsed=0; - info.nBkgndIndex =-1; - - if (rowsperstrip>height){ - rowsperstrip=height; - TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); - } - - isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/ - (photometric == PHOTOMETRIC_RGB) || - (photometric == PHOTOMETRIC_YCBCR) || - (photometric == PHOTOMETRIC_SEPARATED) || - (photometric == PHOTOMETRIC_LOGL) || - (photometric == PHOTOMETRIC_LOGLUV); - - if (isRGB){ - head.biBitCount=24; - }else{ - if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){ - if (bitspersample == 1){ - head.biBitCount=1; //B&W image - head.biClrUsed =2; - } else if (bitspersample == 4) { - head.biBitCount=4; //16 colors gray scale - head.biClrUsed =16; - } else { - head.biBitCount=8; //gray scale - head.biClrUsed =256; - } - } else if (bitspersample == 4) { - head.biBitCount=4; // 16 colors - head.biClrUsed=16; - } else { - head.biBitCount=8; //256 colors - head.biClrUsed=256; - } - - if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB) - { head.biBitCount=24; - head.biClrUsed =0; - } - } - - if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding - - Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation - if (!pDib) cx_throw("CxImageTIF can't create image"); - -#if CXIMAGE_SUPPORT_ALPHA - if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs - if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha -#endif //CXIMAGE_SUPPORT_ALPHA - - TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); - SetCodecOption(compression); // save original compression type - - if (isRGB) { - // Read the whole image into one big RGBA buffer using - // the traditional TIFFReadRGBAImage() API that we trust. - uint32* raster; // retrieve RGBA image - uint32 *row; - - raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); - if (raster == NULL) cx_throw("No space for raster buffer"); - - // Read the image in one chunk into an RGBA array - if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { - _TIFFfree(raster); - cx_throw("Corrupted TIFF file!"); - } - - // read the raster lines and save them in the DIB - // with RGB mode, we have to change the order of the 3 samples RGB - row = &raster[0]; - bits2 = info.pImage; - for (y = 0; y < height; y++) { - - if (info.nEscape){ // - cancel decoding - _TIFFfree(raster); - cx_throw("Cancelled"); - } - - bits = bits2; - for (x = 0; x < width; x++) { - *bits++ = (BYTE)TIFFGetB(row[x]); - *bits++ = (BYTE)TIFFGetG(row[x]); - *bits++ = (BYTE)TIFFGetR(row[x]); -#if CXIMAGE_SUPPORT_ALPHA - if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); -#endif //CXIMAGE_SUPPORT_ALPHA - } - row += width; - bits2 += info.dwEffWidth; - } - _TIFFfree(raster); - } else { - int BIG_palette = (bitspersample > 8) && // + VK - (photometric==PHOTOMETRIC_PALETTE); - if (BIG_palette && (bitspersample > 24)) // + VK - cx_throw("Too big palette to handle"); // + VK - - RGBQUAD *pal; - pal=(RGBQUAD*)calloc(BIG_palette ? 1< 8) - - // set up the colormap based on photometric - switch(photometric) { - case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types - case PHOTOMETRIC_MINISWHITE: - if (bitspersample == 1) { // Monochrome image - if (photometric == PHOTOMETRIC_MINISBLACK) { - pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; - } else { - pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; - } - } else { // need to build the scale for greyscale images - if (photometric == PHOTOMETRIC_MINISBLACK) { - for (int i=0; i<(1< 0) { - if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { - Palette16Bits=TRUE; - break; - } - } - } - - // load the palette in the DIB - for (int i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) { - if (Palette16Bits) { - pal[i].rgbRed =(BYTE) CVT(red[i]); - pal[i].rgbGreen = (BYTE) CVT(green[i]); - pal[i].rgbBlue = (BYTE) CVT(blue[i]); - } else { - pal[i].rgbRed = (BYTE) red[i]; - pal[i].rgbGreen = (BYTE) green[i]; - pal[i].rgbBlue = (BYTE) blue[i]; - } - } - break; - } - if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) - SetPalette(pal,/*head.biClrUsed*/ 1< 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 - bitsize *= (bitspersample + 7)/8; - - int tiled_image = TIFFIsTiled(m_tif); - uint32 tw=0, tl=0; - BYTE* tilebuf=NULL; - if (tiled_image){ - TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); - TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); - rowsperstrip = tl; - bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw); - tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif)); - } - - bits = (BYTE*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK - BYTE * bits16 = NULL; // + VK - int line16 = 0; // + VK - - if (!tiled_image && bitspersample==16) { // + VK + - line16 = line; - line = CalculateLine(width, 8 * samplesperpixel); - bits16 = bits; - bits = (BYTE*)malloc(bitsize); - } - - if (bits==NULL){ - if (bits16) free(bits16); // + VK - if (pal) free(pal); // + VK - if (tilebuf)free(tilebuf); // + VK - cx_throw("CxImageTIF can't allocate memory"); - } - -#ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it - BYTE* row_shifts = NULL; - if (bits16) row_shifts = (BYTE*)malloc(height); -#endif - - for (ys = 0; ys < height; ys += rowsperstrip) { - - if (info.nEscape){ // - cancel decoding - free(bits); - cx_throw("Cancelled"); - } - - nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); - - if (tiled_image){ - uint32 imagew = TIFFScanlineSize(m_tif); - uint32 tilew = TIFFTileRowSize(m_tif); - int iskew = imagew - tilew; - uint8* bufp = (uint8*) bits; - - uint32 colb = 0; - for (uint32 col = 0; col < width; col += tw) { - if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ - free(tilebuf); - free(bits); - cx_throw("Corrupted tiled TIFF file!"); - } - - if (colb + tw > imagew) { - uint32 owidth = imagew - colb; - uint32 oskew = tilew - owidth; - TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); - } else { - TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); - } - colb += tilew; - } - - } else { - if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), - (bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK - -#ifdef NOT_IGNORE_CORRUPTED - free(bits); - if (bits16) free(bits16); // + VK - cx_throw("Corrupted TIFF file!"); -#else - break; -#endif - } - } - - for (y = 0; y < nrow; y++) { - long offset=(nrow-y-1)*line; - if ((bitspersample==16) && !BIG_palette) { // * VK - long offset16 = (nrow-y-1)*line16; // + VK - if (bits16) { // + VK + -#ifdef FIX_16BPP_DARKIMG - int the_shift; - BYTE hi_byte, hi_max=0; - DWORD xi; - for (xi=0;xi<(uint32)line;xi++) { - hi_byte = bits16[xi*2+offset16+1]; - if(hi_byte>hi_max) - hi_max = hi_byte; - } - the_shift = (hi_max == 0) ? 8 : 0; - if (!the_shift) - while( ! (hi_max & 0x80) ) { - the_shift++; - hi_max <<= 1; - } - row_shifts[height-ys-nrow+y] = the_shift; - the_shift = 8 - the_shift; - for (xi=0;xi<(uint32)line;xi++) - bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift; -#else - for (DWORD xi=0;xi<(uint32)line;xi++) - bits[xi+offset]=bits16[xi*2+offset16+1]; -#endif - } else { - for (DWORD xi=0;xi=(int)width){ - yi--; - xi=0; - } - } - } else { //photometric==PHOTOMETRIC_CIELAB - if (head.biBitCount!=24){ //fix image - Create(width,height,24,CXIMAGE_FORMAT_TIF); -#if CXIMAGE_SUPPORT_ALPHA - if (samplesperpixel==4) AlphaCreate(); -#endif //CXIMAGE_SUPPORT_ALPHA - } - - int xi=0; - uint32 ii=0; - int yi=height-ys-nrow+y; - RGBQUAD c; - int l,a,b,bitsoffset; - double p,cx,cy,cz,cr,cg,cb; - while (ii127) a-=256; - if (b>127) b-=256; - // lab to xyz - p = (l/2.55 + 16) / 116.0; - cx = pow( p + a * 0.002, 3); - cy = pow( p, 3); - cz = pow( p - b * 0.005, 3); - // white point - cx*=0.95047; - //cy*=1.000; - cz*=1.0883; - // xyz to rgb - cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; - cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; - cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; - - if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; - else cr = 12.92 * cr; - if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; - else cg = 12.92 * cg; - if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; - else cb = 12.92 * cb; - - c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255))); - c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255))); - c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255))); - - SetPixelColor(xi,yi,c); -#if CXIMAGE_SUPPORT_ALPHA - if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); -#endif //CXIMAGE_SUPPORT_ALPHA - ii++; - xi++; - if (xi>=(int)width){ - yi--; - xi=0; - } - } - } - } - } - free(bits); - if (bits16) free(bits16); - -#ifdef FIX_16BPP_DARKIMG - if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { - // 1. calculate maximum necessary shift - int min_row_shift = 8; - for( y=0; y row_shifts[y]) min_row_shift = row_shifts[y]; - } - // 2. for rows having less shift value, correct such rows: - for( y=0; y>= need_shift; - } - } - } - if (row_shifts) free( row_shifts ); -#endif - - if (tiled_image) free(tilebuf); - if (pal) free(pal); - - switch(orientation){ - case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ - Mirror(); - break; - case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ - Flip(); - Mirror(); - break; - case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ - Flip(); - break; - case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ - RotateRight(); - Mirror(); - break; - case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ - RotateLeft(); - break; - case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ - RotateLeft(); - Mirror(); - break; - case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ - RotateRight(); - break; - } - - } - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (m_tif) TIFFClose(m_tif); - if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_TIF) return true; - return false; - } - TIFFClose(m_tif); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageTIF::Encode(CxFile * hFile, bool bAppend) -{ - cx_try - { - if (hFile==NULL) cx_throw(CXIMAGE_ERR_NOFILE); - if (pDib==NULL) cx_throw(CXIMAGE_ERR_NOIMAGE); - - // replaced "w+b" with "a", to append an image directly on an existing file - if (m_tif2==NULL) m_tif2=_TIFFOpenEx(hFile, "a"); - if (m_tif2==NULL) cx_throw("initialization fail"); - - if (bAppend || m_pages) m_multipage=true; - m_pages++; - - if (!EncodeBody(m_tif2,m_multipage,m_pages,m_pages)) cx_throw("Error saving TIFF file"); - if (bAppend) { - if (!TIFFWriteDirectory(m_tif2)) cx_throw("Error saving TIFF directory"); - } - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - if (m_tif2){ - TIFFClose(m_tif2); - m_tif2=NULL; - m_multipage=false; - m_pages=0; - } - return false; - } - if (!bAppend){ - TIFFClose(m_tif2); - m_tif2=NULL; - m_multipage=false; - m_pages=0; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -// Thanks to Abe -bool CxImageTIF::Encode(CxFile * hFile, CxImage ** pImages, int pagecount) -{ - cx_try - { - if (hFile==NULL) cx_throw("invalid file pointer"); - if (pImages==NULL || pagecount<=0) cx_throw("multipage TIFF, no images!"); - - int i; - for (i=0; iIsValid())) - cx_throw("Empty image"); - } - - CxImageTIF ghost; - for (i=0; i some viewers do not handle PHOTOMETRIC_MINISBLACK: - * let's transform the image in PHOTOMETRIC_MINISWHITE - */ - //invert the colors - RGBQUAD tempRGB=GetPaletteColor(0); - SetPaletteColor(0,GetPaletteColor(1)); - SetPaletteColor(1,tempRGB); - //invert the pixels - BYTE *iSrc=info.pImage; - for (unsigned long i=0;irgbRed != x)||(rgb->rgbRed != rgb->rgbGreen)||(rgb->rgbRed != rgb->rgbBlue)){ - photometric = PHOTOMETRIC_PALETTE; - break; - } - rgb++; - } - break; - case 24: - case 32: - photometric = PHOTOMETRIC_RGB; - break; - } - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid() && bitcount==8) samplesperpixel=2; //8bpp + alpha layer -#endif //CXIMAGE_SUPPORT_ALPHA - -// line = CalculateLine(width, bitspersample * samplesperpixel); -// pitch = (uint16)CalculatePitch(line); - - //prepare the palette struct - RGBQUAD pal[256]; - if (GetPalette()){ - BYTE b; - memcpy(pal,GetPalette(),GetPaletteSize()); - for(WORD a=0;a gives better compression - TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); - - // handle metrics - TIFFSetField(m_tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(m_tif, TIFFTAG_XRESOLUTION, (float)info.xDPI); - TIFFSetField(m_tif, TIFFTAG_YRESOLUTION, (float)info.yDPI); -// TIFFSetField(m_tif, TIFFTAG_XPOSITION, (float)info.xOffset); -// TIFFSetField(m_tif, TIFFTAG_YPOSITION, (float)info.yOffset); - - // multi-paging - Thanks to Abe - if (multipage) - { - char page_number[20]; - sprintf(page_number, "Page %d", page); - - TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); - TIFFSetField(m_tif, TIFFTAG_PAGENUMBER, page,pagecount); - TIFFSetField(m_tif, TIFFTAG_PAGENAME, page_number); - } else { - TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, 0); - } - - // palettes (image colormaps are automatically scaled to 16-bits) - if (photometric == PHOTOMETRIC_PALETTE) { - uint16 *r, *g, *b; - r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * 256); - g = r + 256; - b = g + 256; - - for (int i = 255; i >= 0; i--) { - b[i] = (uint16)SCALE((uint16)pal[i].rgbRed); - g[i] = (uint16)SCALE((uint16)pal[i].rgbGreen); - r[i] = (uint16)SCALE((uint16)pal[i].rgbBlue); - } - - TIFFSetField(m_tif, TIFFTAG_COLORMAP, r, g, b); - _TIFFfree(r); - } - - // compression - if (GetCodecOption(CXIMAGE_FORMAT_TIF)) { - compression = (WORD)GetCodecOption(CXIMAGE_FORMAT_TIF); - } else { - switch (bitcount) { - case 1 : - compression = COMPRESSION_CCITTFAX4; - break; - case 4 : - case 8 : - compression = COMPRESSION_LZW; - break; - case 24 : - case 32 : - compression = COMPRESSION_JPEG; - break; - default : - compression = COMPRESSION_NONE; - break; - } - } - TIFFSetField(m_tif, TIFFTAG_COMPRESSION, compression); - - switch (compression) { - case COMPRESSION_JPEG: - TIFFSetField(m_tif, TIFFTAG_JPEGQUALITY, GetJpegQuality()); - TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, ((7+rowsperstrip)>>3)<<3); - break; - case COMPRESSION_LZW: - if (bitcount>=8) TIFFSetField(m_tif, TIFFTAG_PREDICTOR, 2); - break; - } - - // read the DIB lines from bottom to top and save them in the TIF - - BYTE *bits; - switch(bitcount) { - case 1 : - case 4 : - case 8 : - { - if (samplesperpixel==1){ - bits = (BYTE*)malloc(info.dwEffWidth); - if (!bits) return false; - for (y = 0; y < height; y++) { - memcpy(bits,info.pImage + (height - y - 1)*info.dwEffWidth,info.dwEffWidth); - if (TIFFWriteScanline(m_tif,bits, y, 0)==-1){ - free(bits); - return false; - } - } - free(bits); - } -#if CXIMAGE_SUPPORT_ALPHA - else { //8bpp + alpha layer - bits = (BYTE*)malloc(2*width); - if (!bits) return false; - for (y = 0; y < height; y++) { - for (x=0;x 0) { - uint32 j = cols; - while (j-- > 0) - *out++ = *in++; - out += outskew; - in += inskew; - } -} -//////////////////////////////////////////////////////////////////////////////// -TIFF* CxImageTIF::TIFFOpenEx(CxFile * hFile) -{ - if (hFile) return _TIFFOpenEx(hFile, "rb"); - return NULL; -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTIF::TIFFCloseEx(TIFF* tif) -{ - if (tif) TIFFClose(tif); -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTIF::MoveBits( BYTE* dest, BYTE* from, int count, int bpp ) -{ int offbits = 0; - uint16 w; - uint32 d; - if (bpp <= 8) { - while (count-- > 0) { - if (offbits + bpp <= 8) - w = *from >> (8 - offbits - bpp); - else { - w = *from++ << (offbits + bpp - 8); - w |= *from >> (16 - offbits - bpp); - } - offbits += bpp; - if (offbits >= 8) { - offbits -= 8; - if (offbits == 0) from++; - } - *dest++ = (BYTE)w & ((1 << bpp)-1); - } - } else if (bpp < 16) { - while (count-- > 0) { - d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; - d >>= (24 - offbits); - *dest++ = (BYTE) ( d ); - offbits += bpp; - while (offbits >= 8) { - from++; - offbits -= 8; - } - } - } else if (bpp < 32) { - while (count-- > 0) { - d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; - //d = *(uint32*)from; - *dest++ = (BYTE) ( d >> (offbits + bpp - 8) ); - offbits += bpp; - while (offbits >= 8) { - from++; - offbits -= 8; - } - } - } else { - while (count-- > 0) { - d = *(uint32*)from; - *dest++ = (BYTE) (d >> 24); - from += 4; - } - } -} -//////////////////////////////////////////////////////////////////////////////// -void CxImageTIF::MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal ) -{ int offbits = 0; - uint32 d; - uint16 palidx; - while (count-- > 0) { - d = (*from << 24) | ( *( from + 1 ) << 16 ) - | ( *( from + 2 ) << 8 ) - | ( *( from + 3 ) ); - palidx = (uint16) (d >> (32 - offbits - bpp)); - if (bpp < 16) { - palidx <<= 16-bpp; - palidx = (palidx >> 8) | (palidx <<8); - palidx >>= 16-bpp; - } else palidx = (palidx >> 8) | (palidx << 8); - *dest++ = pal[palidx].rgbBlue; - *dest++ = pal[palidx].rgbGreen; - *dest++ = pal[palidx].rgbRed; - offbits += bpp; - while (offbits >= 8) { - from++; - offbits -= 8; - } - } -} -//////////////////////////////////////////////////////////////////////////////// - -#endif // CXIMAGE_SUPPORT_TIF +/* + * File: ximatif.cpp + * Purpose: Platform Independent TIFF Image Class Loader and Writer + * 07/Aug/2001 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximatif.h" + +#if CXIMAGE_SUPPORT_TIF + +#define FIX_16BPP_DARKIMG // + VK: if uncomment, dark 16bpp images are fixed + +#include "../tiff/tiffio.h" + +#define CVT(x) (((x) * 255L) / ((1L<<16)-1)) +#define SCALE(x) (((x)*((1L<<16)-1))/255) +#define CalculateLine(width,bitdepth) (((width * bitdepth) + 7) / 8) +#define CalculatePitch(line) (line + 3 & ~3) + +extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode); + +//////////////////////////////////////////////////////////////////////////////// +CxImageTIF::~CxImageTIF() +{ + if (m_tif2) TIFFClose(m_tif2); +} +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageTIF::Decode(CxFile * hFile) +{ + //Comment this line if you need more information on errors + // TIFFSetErrorHandler(NULL); // + + //Open file and fill the TIFF structure + // m_tif = TIFFOpen(imageFileName,"rb"); + TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); + + uint32 height=0; + uint32 width=0; + uint16 bitspersample=1; + uint16 samplesperpixel=1; + uint32 rowsperstrip=(DWORD)-1; + uint16 photometric=0; + uint16 compression=1; + uint16 orientation=ORIENTATION_TOPLEFT; // + uint16 res_unit; // + uint32 x, y; + float resolution, offset; + BOOL isRGB; + BYTE *bits; //pointer to source data + BYTE *bits2; //pointer to destination data + + cx_try + { + //check if it's a tiff file + if (!m_tif) + cx_throw("Error encountered while opening TIFF file"); + + // - 12/2002 : get NumFrames directly, instead of looping + // info.nNumFrames=0; + // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; + info.nNumFrames = TIFFNumberOfDirectories(m_tif); + + if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) + cx_throw("Error: page not present in TIFF file"); + + //get image info + TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); + TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); + TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); + TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); + + if (info.nEscape == -1) { + // Return output dimensions only + head.biWidth = width; + head.biHeight = height; + info.dwType = CXIMAGE_FORMAT_TIF; + cx_throw("output dimensions returned"); + } + + TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); + if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) + { + if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); + SetXDPI((long)resolution); + } + if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) + { + if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); + SetYDPI((long)resolution); + } + + if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; + if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; + + head.biClrUsed=0; + info.nBkgndIndex =-1; + + if (rowsperstrip>height){ + rowsperstrip=height; + TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + } + + isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/ + (photometric == PHOTOMETRIC_RGB) || + (photometric == PHOTOMETRIC_YCBCR) || + (photometric == PHOTOMETRIC_SEPARATED) || + (photometric == PHOTOMETRIC_LOGL) || + (photometric == PHOTOMETRIC_LOGLUV); + + if (isRGB){ + head.biBitCount=24; + }else{ + if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){ + if (bitspersample == 1){ + head.biBitCount=1; //B&W image + head.biClrUsed =2; + } else if (bitspersample == 4) { + head.biBitCount=4; //16 colors gray scale + head.biClrUsed =16; + } else { + head.biBitCount=8; //gray scale + head.biClrUsed =256; + } + } else if (bitspersample == 4) { + head.biBitCount=4; // 16 colors + head.biClrUsed=16; + } else { + head.biBitCount=8; //256 colors + head.biClrUsed=256; + } + + if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB) + { head.biBitCount=24; + head.biClrUsed =0; + } + } + + if (info.nEscape) cx_throw("Cancelled"); // - cancel decoding + + Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation + if (!pDib) cx_throw("CxImageTIF can't create image"); + +#if CXIMAGE_SUPPORT_ALPHA + if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs + if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha +#endif //CXIMAGE_SUPPORT_ALPHA + + TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); + SetCodecOption(compression); // save original compression type + + if (isRGB) { + // Read the whole image into one big RGBA buffer using + // the traditional TIFFReadRGBAImage() API that we trust. + uint32* raster; // retrieve RGBA image + uint32 *row; + + raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); + if (raster == NULL) cx_throw("No space for raster buffer"); + + // Read the image in one chunk into an RGBA array + if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { + _TIFFfree(raster); + cx_throw("Corrupted TIFF file!"); + } + + // read the raster lines and save them in the DIB + // with RGB mode, we have to change the order of the 3 samples RGB + row = &raster[0]; + bits2 = info.pImage; + for (y = 0; y < height; y++) { + + if (info.nEscape){ // - cancel decoding + _TIFFfree(raster); + cx_throw("Cancelled"); + } + + bits = bits2; + for (x = 0; x < width; x++) { + *bits++ = (BYTE)TIFFGetB(row[x]); + *bits++ = (BYTE)TIFFGetG(row[x]); + *bits++ = (BYTE)TIFFGetR(row[x]); +#if CXIMAGE_SUPPORT_ALPHA + if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); +#endif //CXIMAGE_SUPPORT_ALPHA + } + row += width; + bits2 += info.dwEffWidth; + } + _TIFFfree(raster); + } else { + int BIG_palette = (bitspersample > 8) && // + VK + (photometric==PHOTOMETRIC_PALETTE); + if (BIG_palette && (bitspersample > 24)) // + VK + cx_throw("Too big palette to handle"); // + VK + + RGBQUAD *pal; + pal=(RGBQUAD*)calloc(BIG_palette ? 1< 8) + + // set up the colormap based on photometric + switch(photometric) { + case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types + case PHOTOMETRIC_MINISWHITE: + if (bitspersample == 1) { // Monochrome image + if (photometric == PHOTOMETRIC_MINISBLACK) { + pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; + } else { + pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; + } + } else { // need to build the scale for greyscale images + if (photometric == PHOTOMETRIC_MINISBLACK) { + for (int i=0; i<(1< 0) { + if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { + Palette16Bits=TRUE; + break; + } + } + } + + // load the palette in the DIB + for (int i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) { + if (Palette16Bits) { + pal[i].rgbRed =(BYTE) CVT(red[i]); + pal[i].rgbGreen = (BYTE) CVT(green[i]); + pal[i].rgbBlue = (BYTE) CVT(blue[i]); + } else { + pal[i].rgbRed = (BYTE) red[i]; + pal[i].rgbGreen = (BYTE) green[i]; + pal[i].rgbBlue = (BYTE) blue[i]; + } + } + break; + } + if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) + SetPalette(pal,/*head.biClrUsed*/ 1< 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 + bitsize *= (bitspersample + 7)/8; + + int tiled_image = TIFFIsTiled(m_tif); + uint32 tw=0, tl=0; + BYTE* tilebuf=NULL; + if (tiled_image){ + TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); + rowsperstrip = tl; + bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw); + tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif)); + } + + bits = (BYTE*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK + BYTE * bits16 = NULL; // + VK + int line16 = 0; // + VK + + if (!tiled_image && bitspersample==16) { // + VK + + line16 = line; + line = CalculateLine(width, 8 * samplesperpixel); + bits16 = bits; + bits = (BYTE*)malloc(bitsize); + } + + if (bits==NULL){ + if (bits16) free(bits16); // + VK + if (pal) free(pal); // + VK + if (tilebuf)free(tilebuf); // + VK + cx_throw("CxImageTIF can't allocate memory"); + } + +#ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it + BYTE* row_shifts = NULL; + if (bits16) row_shifts = (BYTE*)malloc(height); +#endif + + for (ys = 0; ys < height; ys += rowsperstrip) { + + if (info.nEscape){ // - cancel decoding + free(bits); + cx_throw("Cancelled"); + } + + nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); + + if (tiled_image){ + uint32 imagew = TIFFScanlineSize(m_tif); + uint32 tilew = TIFFTileRowSize(m_tif); + int iskew = imagew - tilew; + uint8* bufp = (uint8*) bits; + + uint32 colb = 0; + for (uint32 col = 0; col < width; col += tw) { + if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ + free(tilebuf); + free(bits); + cx_throw("Corrupted tiled TIFF file!"); + } + + if (colb + tw > imagew) { + uint32 owidth = imagew - colb; + uint32 oskew = tilew - owidth; + TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); + } else { + TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); + } + colb += tilew; + } + + } else { + if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), + (bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK + +#ifdef NOT_IGNORE_CORRUPTED + free(bits); + if (bits16) free(bits16); // + VK + cx_throw("Corrupted TIFF file!"); +#else + break; +#endif + } + } + + for (y = 0; y < nrow; y++) { + long offset=(nrow-y-1)*line; + if ((bitspersample==16) && !BIG_palette) { // * VK + long offset16 = (nrow-y-1)*line16; // + VK + if (bits16) { // + VK + +#ifdef FIX_16BPP_DARKIMG + int the_shift; + BYTE hi_byte, hi_max=0; + DWORD xi; + for (xi=0;xi<(uint32)line;xi++) { + hi_byte = bits16[xi*2+offset16+1]; + if(hi_byte>hi_max) + hi_max = hi_byte; + } + the_shift = (hi_max == 0) ? 8 : 0; + if (!the_shift) + while( ! (hi_max & 0x80) ) { + the_shift++; + hi_max <<= 1; + } + row_shifts[height-ys-nrow+y] = the_shift; + the_shift = 8 - the_shift; + for (xi=0;xi<(uint32)line;xi++) + bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift; +#else + for (DWORD xi=0;xi<(uint32)line;xi++) + bits[xi+offset]=bits16[xi*2+offset16+1]; +#endif + } else { + for (DWORD xi=0;xi=(int)width){ + yi--; + xi=0; + } + } + } else { //photometric==PHOTOMETRIC_CIELAB + if (head.biBitCount!=24){ //fix image + Create(width,height,24,CXIMAGE_FORMAT_TIF); +#if CXIMAGE_SUPPORT_ALPHA + if (samplesperpixel==4) AlphaCreate(); +#endif //CXIMAGE_SUPPORT_ALPHA + } + + int xi=0; + uint32 ii=0; + int yi=height-ys-nrow+y; + RGBQUAD c; + int l,a,b,bitsoffset; + double p,cx,cy,cz,cr,cg,cb; + while (ii127) a-=256; + if (b>127) b-=256; + // lab to xyz + p = (l/2.55 + 16) / 116.0; + cx = pow( p + a * 0.002, 3); + cy = pow( p, 3); + cz = pow( p - b * 0.005, 3); + // white point + cx*=0.95047; + //cy*=1.000; + cz*=1.0883; + // xyz to rgb + cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; + cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; + cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; + + if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; + else cr = 12.92 * cr; + if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; + else cg = 12.92 * cg; + if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; + else cb = 12.92 * cb; + + c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255))); + c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255))); + c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255))); + + SetPixelColor(xi,yi,c); +#if CXIMAGE_SUPPORT_ALPHA + if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); +#endif //CXIMAGE_SUPPORT_ALPHA + ii++; + xi++; + if (xi>=(int)width){ + yi--; + xi=0; + } + } + } + } + } + free(bits); + if (bits16) free(bits16); + +#ifdef FIX_16BPP_DARKIMG + if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { + // 1. calculate maximum necessary shift + int min_row_shift = 8; + for( y=0; y row_shifts[y]) min_row_shift = row_shifts[y]; + } + // 2. for rows having less shift value, correct such rows: + for( y=0; y>= need_shift; + } + } + } + if (row_shifts) free( row_shifts ); +#endif + + if (tiled_image) free(tilebuf); + if (pal) free(pal); + + switch(orientation){ + case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ + Mirror(); + break; + case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ + Flip(); + Mirror(); + break; + case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ + Flip(); + break; + case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ + RotateRight(); + Mirror(); + break; + case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ + RotateLeft(); + break; + case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ + RotateLeft(); + Mirror(); + break; + case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ + RotateRight(); + break; + } + + } + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (m_tif) TIFFClose(m_tif); + if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_TIF) return true; + return false; + } + TIFFClose(m_tif); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageTIF::Encode(CxFile * hFile, bool bAppend) +{ + cx_try + { + if (hFile==NULL) cx_throw(CXIMAGE_ERR_NOFILE); + if (pDib==NULL) cx_throw(CXIMAGE_ERR_NOIMAGE); + + // replaced "w+b" with "a", to append an image directly on an existing file + if (m_tif2==NULL) m_tif2=_TIFFOpenEx(hFile, "a"); + if (m_tif2==NULL) cx_throw("initialization fail"); + + if (bAppend || m_pages) m_multipage=true; + m_pages++; + + if (!EncodeBody(m_tif2,m_multipage,m_pages,m_pages)) cx_throw("Error saving TIFF file"); + if (bAppend) { + if (!TIFFWriteDirectory(m_tif2)) cx_throw("Error saving TIFF directory"); + } + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + if (m_tif2){ + TIFFClose(m_tif2); + m_tif2=NULL; + m_multipage=false; + m_pages=0; + } + return false; + } + if (!bAppend){ + TIFFClose(m_tif2); + m_tif2=NULL; + m_multipage=false; + m_pages=0; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +// Thanks to Abe +bool CxImageTIF::Encode(CxFile * hFile, CxImage ** pImages, int pagecount) +{ + cx_try + { + if (hFile==NULL) cx_throw("invalid file pointer"); + if (pImages==NULL || pagecount<=0) cx_throw("multipage TIFF, no images!"); + + int i; + for (i=0; iIsValid())) + cx_throw("Empty image"); + } + + CxImageTIF ghost; + for (i=0; i some viewers do not handle PHOTOMETRIC_MINISBLACK: + * let's transform the image in PHOTOMETRIC_MINISWHITE + */ + //invert the colors + RGBQUAD tempRGB=GetPaletteColor(0); + SetPaletteColor(0,GetPaletteColor(1)); + SetPaletteColor(1,tempRGB); + //invert the pixels + BYTE *iSrc=info.pImage; + for (unsigned long i=0;irgbRed != x)||(rgb->rgbRed != rgb->rgbGreen)||(rgb->rgbRed != rgb->rgbBlue)){ + photometric = PHOTOMETRIC_PALETTE; + break; + } + rgb++; + } + break; + case 24: + case 32: + photometric = PHOTOMETRIC_RGB; + break; + } + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid() && bitcount==8) samplesperpixel=2; //8bpp + alpha layer +#endif //CXIMAGE_SUPPORT_ALPHA + +// line = CalculateLine(width, bitspersample * samplesperpixel); +// pitch = (uint16)CalculatePitch(line); + + //prepare the palette struct + RGBQUAD pal[256]; + if (GetPalette()){ + BYTE b; + memcpy(pal,GetPalette(),GetPaletteSize()); + for(WORD a=0;a gives better compression + TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + + // handle metrics + TIFFSetField(m_tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); + TIFFSetField(m_tif, TIFFTAG_XRESOLUTION, (float)info.xDPI); + TIFFSetField(m_tif, TIFFTAG_YRESOLUTION, (float)info.yDPI); +// TIFFSetField(m_tif, TIFFTAG_XPOSITION, (float)info.xOffset); +// TIFFSetField(m_tif, TIFFTAG_YPOSITION, (float)info.yOffset); + + // multi-paging - Thanks to Abe + if (multipage) + { + char page_number[20]; + sprintf(page_number, "Page %d", page); + + TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + TIFFSetField(m_tif, TIFFTAG_PAGENUMBER, page,pagecount); + TIFFSetField(m_tif, TIFFTAG_PAGENAME, page_number); + } else { + TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, 0); + } + + // palettes (image colormaps are automatically scaled to 16-bits) + if (photometric == PHOTOMETRIC_PALETTE) { + uint16 *r, *g, *b; + r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * 256); + g = r + 256; + b = g + 256; + + for (int i = 255; i >= 0; i--) { + b[i] = (uint16)SCALE((uint16)pal[i].rgbRed); + g[i] = (uint16)SCALE((uint16)pal[i].rgbGreen); + r[i] = (uint16)SCALE((uint16)pal[i].rgbBlue); + } + + TIFFSetField(m_tif, TIFFTAG_COLORMAP, r, g, b); + _TIFFfree(r); + } + + // compression + if (GetCodecOption(CXIMAGE_FORMAT_TIF)) { + compression = (WORD)GetCodecOption(CXIMAGE_FORMAT_TIF); + } else { + switch (bitcount) { + case 1 : + compression = COMPRESSION_CCITTFAX4; + break; + case 4 : + case 8 : + compression = COMPRESSION_LZW; + break; + case 24 : + case 32 : + compression = COMPRESSION_JPEG; + break; + default : + compression = COMPRESSION_NONE; + break; + } + } + TIFFSetField(m_tif, TIFFTAG_COMPRESSION, compression); + + switch (compression) { + case COMPRESSION_JPEG: + TIFFSetField(m_tif, TIFFTAG_JPEGQUALITY, GetJpegQuality()); + TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, ((7+rowsperstrip)>>3)<<3); + break; + case COMPRESSION_LZW: + if (bitcount>=8) TIFFSetField(m_tif, TIFFTAG_PREDICTOR, 2); + break; + } + + // read the DIB lines from bottom to top and save them in the TIF + + BYTE *bits; + switch(bitcount) { + case 1 : + case 4 : + case 8 : + { + if (samplesperpixel==1){ + bits = (BYTE*)malloc(info.dwEffWidth); + if (!bits) return false; + for (y = 0; y < height; y++) { + memcpy(bits,info.pImage + (height - y - 1)*info.dwEffWidth,info.dwEffWidth); + if (TIFFWriteScanline(m_tif,bits, y, 0)==-1){ + free(bits); + return false; + } + } + free(bits); + } +#if CXIMAGE_SUPPORT_ALPHA + else { //8bpp + alpha layer + bits = (BYTE*)malloc(2*width); + if (!bits) return false; + for (y = 0; y < height; y++) { + for (x=0;x 0) { + uint32 j = cols; + while (j-- > 0) + *out++ = *in++; + out += outskew; + in += inskew; + } +} +//////////////////////////////////////////////////////////////////////////////// +TIFF* CxImageTIF::TIFFOpenEx(CxFile * hFile) +{ + if (hFile) return _TIFFOpenEx(hFile, "rb"); + return NULL; +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTIF::TIFFCloseEx(TIFF* tif) +{ + if (tif) TIFFClose(tif); +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTIF::MoveBits( BYTE* dest, BYTE* from, int count, int bpp ) +{ int offbits = 0; + uint16 w; + uint32 d; + if (bpp <= 8) { + while (count-- > 0) { + if (offbits + bpp <= 8) + w = *from >> (8 - offbits - bpp); + else { + w = *from++ << (offbits + bpp - 8); + w |= *from >> (16 - offbits - bpp); + } + offbits += bpp; + if (offbits >= 8) { + offbits -= 8; + if (offbits == 0) from++; + } + *dest++ = (BYTE)w & ((1 << bpp)-1); + } + } else if (bpp < 16) { + while (count-- > 0) { + d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; + d >>= (24 - offbits); + *dest++ = (BYTE) ( d ); + offbits += bpp; + while (offbits >= 8) { + from++; + offbits -= 8; + } + } + } else if (bpp < 32) { + while (count-- > 0) { + d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3]; + //d = *(uint32*)from; + *dest++ = (BYTE) ( d >> (offbits + bpp - 8) ); + offbits += bpp; + while (offbits >= 8) { + from++; + offbits -= 8; + } + } + } else { + while (count-- > 0) { + d = *(uint32*)from; + *dest++ = (BYTE) (d >> 24); + from += 4; + } + } +} +//////////////////////////////////////////////////////////////////////////////// +void CxImageTIF::MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal ) +{ int offbits = 0; + uint32 d; + uint16 palidx; + while (count-- > 0) { + d = (*from << 24) | ( *( from + 1 ) << 16 ) + | ( *( from + 2 ) << 8 ) + | ( *( from + 3 ) ); + palidx = (uint16) (d >> (32 - offbits - bpp)); + if (bpp < 16) { + palidx <<= 16-bpp; + palidx = (palidx >> 8) | (palidx <<8); + palidx >>= 16-bpp; + } else palidx = (palidx >> 8) | (palidx << 8); + *dest++ = pal[palidx].rgbBlue; + *dest++ = pal[palidx].rgbGreen; + *dest++ = pal[palidx].rgbRed; + offbits += bpp; + while (offbits >= 8) { + from++; + offbits -= 8; + } + } +} +//////////////////////////////////////////////////////////////////////////////// + +#endif // CXIMAGE_SUPPORT_TIF diff --git a/utilities/CxImage/ximatif.h b/utilities/CxImage/ximatif.h index e124430..8886316 100644 --- a/utilities/CxImage/ximatif.h +++ b/utilities/CxImage/ximatif.h @@ -1,62 +1,62 @@ -/* - * File: ximatif.h - * Purpose: TIFF Image Class Loader and Writer - */ -/* ========================================================== - * CxImageTIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * - * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes - * - * Special thanks to Abe for MultiPageTIFF code. - * - * LibTIFF is: - * Copyright (c) 1988-1997 Sam Leffler - * Copyright (c) 1991-1997 Silicon Graphics, Inc. - * ========================================================== - */ - -#if !defined(__ximatif_h) -#define __ximatif_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_TIF - -#include "../tiff/tiffio.h" - -class DLL_EXP CxImageTIF: public CxImage -{ -public: - CxImageTIF(): CxImage(CXIMAGE_FORMAT_TIF) {m_tif2=NULL; m_multipage=false; m_pages=0;} - ~CxImageTIF(); - - TIFF* TIFFOpenEx(CxFile * hFile); - void TIFFCloseEx(TIFF* tif); - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TIF);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TIF);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile, bool bAppend=false); - bool Encode(CxFile * hFile, CxImage ** pImages, int pagecount); - bool Encode(FILE *hFile, bool bAppend=false) { CxIOFile file(hFile); return Encode(&file,bAppend); } - bool Encode(FILE *hFile, CxImage ** pImages, int pagecount) - { CxIOFile file(hFile); return Encode(&file, pImages, pagecount); } -#endif // CXIMAGE_SUPPORT_ENCODE - -protected: - void TileToStrip(uint8* out, uint8* in, uint32 rows, uint32 cols, int outskew, int inskew); - bool EncodeBody(TIFF *m_tif, bool multipage=false, int page=0, int pagecount=0); - TIFF *m_tif2; - bool m_multipage; - int m_pages; - void MoveBits( BYTE* dest, BYTE* from, int count, int bpp ); - void MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal ); -}; - -#endif - -#endif +/* + * File: ximatif.h + * Purpose: TIFF Image Class Loader and Writer + */ +/* ========================================================== + * CxImageTIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * + * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes + * + * Special thanks to Abe for MultiPageTIFF code. + * + * LibTIFF is: + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * ========================================================== + */ + +#if !defined(__ximatif_h) +#define __ximatif_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_TIF + +#include "../tiff/tiffio.h" + +class DLL_EXP CxImageTIF: public CxImage +{ +public: + CxImageTIF(): CxImage(CXIMAGE_FORMAT_TIF) {m_tif2=NULL; m_multipage=false; m_pages=0;} + ~CxImageTIF(); + + TIFF* TIFFOpenEx(CxFile * hFile); + void TIFFCloseEx(TIFF* tif); + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TIF);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TIF);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile, bool bAppend=false); + bool Encode(CxFile * hFile, CxImage ** pImages, int pagecount); + bool Encode(FILE *hFile, bool bAppend=false) { CxIOFile file(hFile); return Encode(&file,bAppend); } + bool Encode(FILE *hFile, CxImage ** pImages, int pagecount) + { CxIOFile file(hFile); return Encode(&file, pImages, pagecount); } +#endif // CXIMAGE_SUPPORT_ENCODE + +protected: + void TileToStrip(uint8* out, uint8* in, uint32 rows, uint32 cols, int outskew, int inskew); + bool EncodeBody(TIFF *m_tif, bool multipage=false, int page=0, int pagecount=0); + TIFF *m_tif2; + bool m_multipage; + int m_pages; + void MoveBits( BYTE* dest, BYTE* from, int count, int bpp ); + void MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal ); +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximatran.cpp b/utilities/CxImage/ximatran.cpp index 9f136a0..d3aac01 100644 --- a/utilities/CxImage/ximatran.cpp +++ b/utilities/CxImage/ximatran.cpp @@ -1,2624 +1,2624 @@ -// xImaTran.cpp : Transformation functions -/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" -#include "ximath.h" - -#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::GrayScale() -{ - if (!pDib) return false; - if (head.biBitCount<=8){ - RGBQUAD* ppal=GetPalette(); - int gray; - //converts the colors to gray, use the blue channel only - for(DWORD i=0;i= 0) info.nBkgndIndex = ppal[info.nBkgndIndex].rgbBlue; - //create a "real" 8 bit gray scale image - if (head.biBitCount==8){ - BYTE *img=info.pImage; - for(DWORD i=0;i> 1]&((BYTE)0x0F<> pos)].rgbBlue; - } else { - BYTE pos = (BYTE)(7-x%8); - iDst[x]= ppal[(BYTE)((iSrc[x >> 3]&((BYTE)0x01<> pos)].rgbBlue; - } - } - } - Transfer(ima); - } - } else { //from RGB to 8 bit gray scale - BYTE *iSrc=info.pImage; - CxImage ima; - ima.CopyInfo(*this); - if (!ima.Create(head.biWidth,head.biHeight,8,info.dwType)) return false; - ima.SetGrayPalette(); -#if CXIMAGE_SUPPORT_SELECTION - ima.SelectionCopy(*this); -#endif //CXIMAGE_SUPPORT_SELECTION -#if CXIMAGE_SUPPORT_ALPHA - ima.AlphaCopy(*this); -#endif //CXIMAGE_SUPPORT_ALPHA - BYTE *img=ima.GetBits(); - long l8=ima.GetEffWidth(); - long l=head.biWidth * 3; - for(long y=0; y < head.biHeight; y++) { - for(long x=0,x8=0; x < l; x+=3,x8++) { - img[x8+y*l8]=(BYTE)RGB2GRAY(*(iSrc+x+2),*(iSrc+x+1),*(iSrc+x+0)); - } - iSrc+=info.dwEffWidth; - } - Transfer(ima); - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa Mirror - * \author [qhbo] - */ -bool CxImage::Flip(bool bFlipSelection, bool bFlipAlpha) -{ - if (!pDib) return false; - - BYTE *buff = (BYTE*)malloc(info.dwEffWidth); - if (!buff) return false; - - BYTE *iSrc,*iDst; - iSrc = GetBits(head.biHeight-1); - iDst = GetBits(0); - for (long i=0; i<(head.biHeight/2); ++i) - { - memcpy(buff, iSrc, info.dwEffWidth); - memcpy(iSrc, iDst, info.dwEffWidth); - memcpy(iDst, buff, info.dwEffWidth); - iSrc-=info.dwEffWidth; - iDst+=info.dwEffWidth; - } - - free(buff); - - if (bFlipSelection){ -#if CXIMAGE_SUPPORT_SELECTION - SelectionFlip(); -#endif //CXIMAGE_SUPPORT_SELECTION - } - - if (bFlipAlpha){ -#if CXIMAGE_SUPPORT_ALPHA - AlphaFlip(); -#endif //CXIMAGE_SUPPORT_ALPHA - } - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \sa Flip - */ -bool CxImage::Mirror(bool bMirrorSelection, bool bMirrorAlpha) -{ - if (!pDib) return false; - - CxImage* imatmp = new CxImage(*this,false,true,true); - if (!imatmp) return false; - if (!imatmp->IsValid()){ - delete imatmp; - return false; - } - - BYTE *iSrc,*iDst; - long wdt=(head.biWidth-1) * (head.biBitCount==24 ? 3:1); - iSrc=info.pImage + wdt; - iDst=imatmp->info.pImage; - long x,y; - switch (head.biBitCount){ - case 24: - for(y=0; y < head.biHeight; y++){ - for(x=0; x <= wdt; x+=3){ - *(iDst+x)=*(iSrc-x); - *(iDst+x+1)=*(iSrc-x+1); - *(iDst+x+2)=*(iSrc-x+2); - } - iSrc+=info.dwEffWidth; - iDst+=info.dwEffWidth; - } - break; - case 8: - for(y=0; y < head.biHeight; y++){ - for(x=0; x <= wdt; x++) - *(iDst+x)=*(iSrc-x); - iSrc+=info.dwEffWidth; - iDst+=info.dwEffWidth; - } - break; - default: - for(y=0; y < head.biHeight; y++){ - for(x=0; x <= wdt; x++) - imatmp->SetPixelIndex(x,y,GetPixelIndex(wdt-x,y)); - } - } - - if (bMirrorSelection){ -#if CXIMAGE_SUPPORT_SELECTION - imatmp->SelectionMirror(); -#endif //CXIMAGE_SUPPORT_SELECTION - } - - if (bMirrorAlpha){ -#if CXIMAGE_SUPPORT_ALPHA - imatmp->AlphaMirror(); -#endif //CXIMAGE_SUPPORT_ALPHA - } - - Transfer(*imatmp); - delete imatmp; - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -#define RBLOCK 64 - -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::RotateLeft(CxImage* iDst) -{ - if (!pDib) return false; - - long newWidth = GetHeight(); - long newHeight = GetWidth(); - - CxImage imgDest; - imgDest.CopyInfo(*this); - imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); - imgDest.SetPalette(GetPalette()); - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) imgDest.AlphaCreate(); -#endif - -#if CXIMAGE_SUPPORT_SELECTION - if (SelectionIsValid()) imgDest.SelectionCreate(); -#endif - - long x,x2,y,dlineup; - - // Speedy rotate for BW images - if (head.biBitCount == 1) { - - BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp; - ldiv_t div_r; - - BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits(); - dbitsmax = bdest + imgDest.head.biSizeImage - 1; - dlineup = 8 * imgDest.info.dwEffWidth - imgDest.head.biWidth; - - imgDest.Clear(0); - for (y = 0; y < head.biHeight; y++) { - // Figure out the Column we are going to be copying to - div_r = ldiv(y + dlineup, (long)8); - // set bit pos of src column byte - bitpos = (BYTE)(1 << div_r.rem); - srcdisp = bsrc + y * info.dwEffWidth; - for (x = 0; x < (long)info.dwEffWidth; x++) { - // Get Source Bits - sbits = srcdisp + x; - // Get destination column - nrow = bdest + (x * 8) * imgDest.info.dwEffWidth + imgDest.info.dwEffWidth - 1 - div_r.quot; - for (long z = 0; z < 8; z++) { - // Get Destination Byte - dbits = nrow + z * imgDest.info.dwEffWidth; - if ((dbits < bdest) || (dbits > dbitsmax)) break; - if (*sbits & (128 >> z)) *dbits |= bitpos; - } - } - }//for y - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) { - for (x = 0; x < newWidth; x++){ - x2=newWidth-x-1; - for (y = 0; y < newHeight; y++){ - imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2)); - }//for y - }//for x - } -#endif //CXIMAGE_SUPPORT_ALPHA - -#if CXIMAGE_SUPPORT_SELECTION - if (SelectionIsValid()) { - imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top; - imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom; - imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left; - imgDest.info.rSelectionBox.top = info.rSelectionBox.right; - for (x = 0; x < newWidth; x++){ - x2=newWidth-x-1; - for (y = 0; y < newHeight; y++){ - imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2)); - }//for y - }//for x - } -#endif //CXIMAGE_SUPPORT_SELECTION - - } else { - //anything other than BW: - //bd, 10. 2004: This optimized version of rotation rotates image by smaller blocks. It is quite - //a bit faster than obvious algorithm, because it produces much less CPU cache misses. - //This optimization can be tuned by changing block size (RBLOCK). 96 is good value for current - //CPUs (tested on Athlon XP and Celeron D). Larger value (if CPU has enough cache) will increase - //speed somehow, but once you drop out of CPU's cache, things will slow down drastically. - //For older CPUs with less cache, lower value would yield better results. - - BYTE *srcPtr, *dstPtr; //source and destionation for 24-bit version - int xs, ys; //x-segment and y-segment - for (xs = 0; xs < newWidth; xs+=RBLOCK) { //for all image blocks of RBLOCK*RBLOCK pixels - for (ys = 0; ys < newHeight; ys+=RBLOCK) { - if (head.biBitCount==24) { - //RGB24 optimized pixel access: - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ //do rotation - info.nProgress = (long)(100*x/newWidth); - x2=newWidth-x-1; - dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(x,ys); - srcPtr = (BYTE*) BlindGetPixelPointer(ys, x2); - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - //imgDest.SetPixelColor(x, y, GetPixelColor(y, x2)); - *(dstPtr) = *(srcPtr); - *(dstPtr+1) = *(srcPtr+1); - *(dstPtr+2) = *(srcPtr+2); - srcPtr += 3; - dstPtr += imgDest.info.dwEffWidth; - }//for y - }//for x - } else { - //anything else than 24bpp (and 1bpp): palette - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ - info.nProgress = (long)(100*x/newWidth); // - x2=newWidth-x-1; - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y, x2)); - }//for y - }//for x - }//if (version selection) -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) { - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ - x2=newWidth-x-1; - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2)); - }//for y - }//for x - }//if (alpha channel) -#endif //CXIMAGE_SUPPORT_ALPHA - -#if CXIMAGE_SUPPORT_SELECTION - if (SelectionIsValid()) { - imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top; - imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom; - imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left; - imgDest.info.rSelectionBox.top = info.rSelectionBox.right; - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ - x2=newWidth-x-1; - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2)); - }//for y - }//for x - }//if (selection) -#endif //CXIMAGE_SUPPORT_SELECTION - }//for ys - }//for xs - }//if - - //select the destination - if (iDst) iDst->Transfer(imgDest); - else Transfer(imgDest); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::RotateRight(CxImage* iDst) -{ - if (!pDib) return false; - - long newWidth = GetHeight(); - long newHeight = GetWidth(); - - CxImage imgDest; - imgDest.CopyInfo(*this); - imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); - imgDest.SetPalette(GetPalette()); - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) imgDest.AlphaCreate(); -#endif - -#if CXIMAGE_SUPPORT_SELECTION - if (SelectionIsValid()) imgDest.SelectionCreate(); -#endif - - long x,y,y2; - // Speedy rotate for BW images - if (head.biBitCount == 1) { - - BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp; - ldiv_t div_r; - - BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits(); - dbitsmax = bdest + imgDest.head.biSizeImage - 1; - - imgDest.Clear(0); - for (y = 0; y < head.biHeight; y++) { - // Figure out the Column we are going to be copying to - div_r = ldiv(y, (long)8); - // set bit pos of src column byte - bitpos = (BYTE)(128 >> div_r.rem); - srcdisp = bsrc + y * info.dwEffWidth; - for (x = 0; x < (long)info.dwEffWidth; x++) { - // Get Source Bits - sbits = srcdisp + x; - // Get destination column - nrow = bdest + (imgDest.head.biHeight-1-(x*8)) * imgDest.info.dwEffWidth + div_r.quot; - for (long z = 0; z < 8; z++) { - // Get Destination Byte - dbits = nrow - z * imgDest.info.dwEffWidth; - if ((dbits < bdest) || (dbits > dbitsmax)) break; - if (*sbits & (128 >> z)) *dbits |= bitpos; - } - } - } - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()){ - for (y = 0; y < newHeight; y++){ - y2=newHeight-y-1; - for (x = 0; x < newWidth; x++){ - imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x)); - } - } - } -#endif //CXIMAGE_SUPPORT_ALPHA - -#if CXIMAGE_SUPPORT_SELECTION - if (SelectionIsValid()){ - imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom; - imgDest.info.rSelectionBox.right = info.rSelectionBox.top; - imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right; - imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left; - for (y = 0; y < newHeight; y++){ - y2=newHeight-y-1; - for (x = 0; x < newWidth; x++){ - imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x)); - } - } - } -#endif //CXIMAGE_SUPPORT_SELECTION - - } else { - //anything else but BW - BYTE *srcPtr, *dstPtr; //source and destionation for 24-bit version - int xs, ys; //x-segment and y-segment - for (xs = 0; xs < newWidth; xs+=RBLOCK) { - for (ys = 0; ys < newHeight; ys+=RBLOCK) { - if (head.biBitCount==24) { - //RGB24 optimized pixel access: - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - info.nProgress = (long)(100*y/newHeight); // - y2=newHeight-y-1; - dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(xs,y); - srcPtr = (BYTE*) BlindGetPixelPointer(y2, xs); - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ - //imgDest.SetPixelColor(x, y, GetPixelColor(y2, x)); - *(dstPtr) = *(srcPtr); - *(dstPtr+1) = *(srcPtr+1); - *(dstPtr+2) = *(srcPtr+2); - dstPtr += 3; - srcPtr += info.dwEffWidth; - }//for x - }//for y - } else { - //anything else than BW & RGB24: palette - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - info.nProgress = (long)(100*y/newHeight); // - y2=newHeight-y-1; - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ - imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y2, x)); - }//for x - }//for y - }//if -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()){ - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - y2=newHeight-y-1; - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ - imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x)); - }//for x - }//for y - }//if (has alpha) -#endif //CXIMAGE_SUPPORT_ALPHA - -#if CXIMAGE_SUPPORT_SELECTION - if (SelectionIsValid()){ - imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom; - imgDest.info.rSelectionBox.right = info.rSelectionBox.top; - imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right; - imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left; - for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ - y2=newHeight-y-1; - for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ - imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x)); - }//for x - }//for y - }//if (has alpha) -#endif //CXIMAGE_SUPPORT_SELECTION - }//for ys - }//for xs - }//if - - //select the destination - if (iDst) iDst->Transfer(imgDest); - else Transfer(imgDest); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::Negative() -{ - if (!pDib) return false; - - if (head.biBitCount<=8){ - if (IsGrayScale()){ //GRAYSCALE, selection - if (pSelection){ - for(long y=info.rSelectionBox.bottom; y invert transparent color too - info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); - info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); - info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); - } - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_TRANSFORMATION -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::Rotate(float angle, CxImage* iDst) -{ - if (!pDib) return false; - - // Copyright (c) 1996-1998 Ulrich von Zadow - - // Negative the angle, because the y-axis is negative. - double ang = -angle*acos((float)0)/90; - int newWidth, newHeight; - int nWidth = GetWidth(); - int nHeight= GetHeight(); - double cos_angle = cos(ang); - double sin_angle = sin(ang); - - // Calculate the size of the new bitmap - POINT p1={0,0}; - POINT p2={nWidth,0}; - POINT p3={0,nHeight}; - POINT p4={nWidth,nHeight}; - CxPoint2 newP1,newP2,newP3,newP4, leftTop, rightTop, leftBottom, rightBottom; - - newP1.x = (float)p1.x; - newP1.y = (float)p1.y; - newP2.x = (float)(p2.x*cos_angle - p2.y*sin_angle); - newP2.y = (float)(p2.x*sin_angle + p2.y*cos_angle); - newP3.x = (float)(p3.x*cos_angle - p3.y*sin_angle); - newP3.y = (float)(p3.x*sin_angle + p3.y*cos_angle); - newP4.x = (float)(p4.x*cos_angle - p4.y*sin_angle); - newP4.y = (float)(p4.x*sin_angle + p4.y*cos_angle); - - leftTop.x = min(min(newP1.x,newP2.x),min(newP3.x,newP4.x)); - leftTop.y = min(min(newP1.y,newP2.y),min(newP3.y,newP4.y)); - rightBottom.x = max(max(newP1.x,newP2.x),max(newP3.x,newP4.x)); - rightBottom.y = max(max(newP1.y,newP2.y),max(newP3.y,newP4.y)); - leftBottom.x = leftTop.x; - leftBottom.y = rightBottom.y; - rightTop.x = rightBottom.x; - rightTop.y = leftTop.y; - - newWidth = (int) floor(0.5f + rightTop.x - leftTop.x); - newHeight= (int) floor(0.5f + leftBottom.y - leftTop.y); - CxImage imgDest; - imgDest.CopyInfo(*this); - imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); - imgDest.SetPalette(GetPalette()); - -#if CXIMAGE_SUPPORT_ALPHA - if(AlphaIsValid()) //MTA: Fix for rotation problem when the image has an alpha channel - { - imgDest.AlphaCreate(); - imgDest.AlphaClear(); - } -#endif //CXIMAGE_SUPPORT_ALPHA - - int x,y,newX,newY,oldX,oldY; - - if (head.biClrUsed==0){ //RGB - for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){ - info.nProgress = (long)(100*newY/newHeight); - if (info.nEscape) break; - for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){ - oldX = (long)(x*cos_angle + y*sin_angle + 0.5); - oldY = (long)(y*cos_angle - x*sin_angle + 0.5); - imgDest.SetPixelColor(newX,newY,GetPixelColor(oldX,oldY)); -#if CXIMAGE_SUPPORT_ALPHA - imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value -#endif //CXIMAGE_SUPPORT_ALPHA - } - } - } else { //PALETTE - for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){ - info.nProgress = (long)(100*newY/newHeight); - if (info.nEscape) break; - for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){ - oldX = (long)(x*cos_angle + y*sin_angle + 0.5); - oldY = (long)(y*cos_angle - x*sin_angle + 0.5); - imgDest.SetPixelIndex(newX,newY,GetPixelIndex(oldX,oldY)); -#if CXIMAGE_SUPPORT_ALPHA - imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value -#endif //CXIMAGE_SUPPORT_ALPHA - } - } - } - //select the destination - if (iDst) iDst->Transfer(imgDest); - else Transfer(imgDest); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Rotates image around it's center. - * Method can use interpolation with paletted images, but does not change pallete, so results vary. - * (If you have only four colours in a palette, there's not much room for interpolation.) - * - * \param angle - angle in degrees (positive values rotate clockwise) - * \param *iDst - destination image (if null, this image is changed) - * \param inMethod - interpolation method used - * (IM_NEAREST_NEIGHBOUR produces aliasing (fast), IM_BILINEAR softens picture a bit (slower) - * IM_SHARPBICUBIC is slower and produces some halos...) - * \param ofMethod - overflow method (how to choose colour of pixels that have no source) - * \param replColor - replacement colour to use (OM_COLOR, OM_BACKGROUND with no background colour...) - * \param optimizeRightAngles - call faster methods for 90, 180, and 270 degree rotations. Faster methods - * are called for angles, where error (in location of corner pixels) is less - * than 0.25 pixels. - * \param bKeepOriginalSize - rotates the image without resizing. - * - * \author ***bd*** 2.2004 - */ -bool CxImage::Rotate2(float angle, - CxImage *iDst, - InterpolationMethod inMethod, - OverflowMethod ofMethod, - RGBQUAD *replColor, - bool const optimizeRightAngles, - bool const bKeepOriginalSize) -{ - if (!pDib) return false; //no dib no go - - double ang = -angle*acos(0.0f)/90.0f; //convert angle to radians and invert (positive angle performs clockwise rotation) - float cos_angle = (float) cos(ang); //these two are needed later (to rotate) - float sin_angle = (float) sin(ang); - - //Calculate the size of the new bitmap (rotate corners of image) - CxPoint2 p[4]; //original corners of the image - p[0]=CxPoint2(-0.5f,-0.5f); - p[1]=CxPoint2(GetWidth()-0.5f,-0.5f); - p[2]=CxPoint2(-0.5f,GetHeight()-0.5f); - p[3]=CxPoint2(GetWidth()-0.5f,GetHeight()-0.5f); - CxPoint2 newp[4]; //rotated positions of corners - //(rotate corners) - if (bKeepOriginalSize){ - for (int i=0; i<4; i++) { - newp[i].x = p[i].x; - newp[i].y = p[i].y; - }//for - } else { - for (int i=0; i<4; i++) { - newp[i].x = (p[i].x*cos_angle - p[i].y*sin_angle); - newp[i].y = (p[i].x*sin_angle + p[i].y*cos_angle); - }//for i - - if (optimizeRightAngles) { - //For rotations of 90, -90 or 180 or 0 degrees, call faster routines - if (newp[3].Distance(CxPoint2(GetHeight()-0.5f, 0.5f-GetWidth())) < 0.25) - //rotation right for circa 90 degrees (diagonal pixels less than 0.25 pixel away from 90 degree rotation destination) - return RotateRight(iDst); - if (newp[3].Distance(CxPoint2(0.5f-GetHeight(), -0.5f+GetWidth())) < 0.25) - //rotation left for ~90 degrees - return RotateLeft(iDst); - if (newp[3].Distance(CxPoint2(0.5f-GetWidth(), 0.5f-GetHeight())) < 0.25) - //rotation left for ~180 degrees - return Rotate180(iDst); - if (newp[3].Distance(p[3]) < 0.25) { - //rotation not significant - if (iDst) iDst->Copy(*this); //copy image to iDst, if required - return true; //and we're done - }//if - }//if - }//if - - //(read new dimensions from location of corners) - float minx = (float) min(min(newp[0].x,newp[1].x),min(newp[2].x,newp[3].x)); - float miny = (float) min(min(newp[0].y,newp[1].y),min(newp[2].y,newp[3].y)); - float maxx = (float) max(max(newp[0].x,newp[1].x),max(newp[2].x,newp[3].x)); - float maxy = (float) max(max(newp[0].y,newp[1].y),max(newp[2].y,newp[3].y)); - int newWidth = (int) floor(maxx-minx+0.5f); - int newHeight= (int) floor(maxy-miny+0.5f); - float ssx=((maxx+minx)- ((float) newWidth-1))/2.0f; //start for x - float ssy=((maxy+miny)- ((float) newHeight-1))/2.0f; //start for y - - float newxcenteroffset = 0.5f * newWidth; - float newycenteroffset = 0.5f * newHeight; - if (bKeepOriginalSize){ - ssx -= 0.5f * GetWidth(); - ssy -= 0.5f * GetHeight(); - } - - //create destination image - CxImage imgDest; - imgDest.CopyInfo(*this); - imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); - imgDest.SetPalette(GetPalette()); -#if CXIMAGE_SUPPORT_ALPHA - if(AlphaIsValid()) imgDest.AlphaCreate(); //MTA: Fix for rotation problem when the image has an alpha channel -#endif //CXIMAGE_SUPPORT_ALPHA - - RGBQUAD rgb; //pixel colour - RGBQUAD rc; - if (replColor!=0) - rc=*replColor; - else { - rc.rgbRed=255; rc.rgbGreen=255; rc.rgbBlue=255; rc.rgbReserved=0; - }//if - float x,y; //destination location (float, with proper offset) - float origx, origy; //origin location - int destx, desty; //destination location - - y=ssy; //initialize y - if (!IsIndexed()){ //RGB24 - //optimized RGB24 implementation (direct write to destination): - BYTE *pxptr; -#if CXIMAGE_SUPPORT_ALPHA - BYTE *pxptra=0; -#endif //CXIMAGE_SUPPORT_ALPHA - for (desty=0; destyTransfer(imgDest); - else Transfer(imgDest); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::Rotate180(CxImage* iDst) -{ - if (!pDib) return false; - - long wid = GetWidth(); - long ht = GetHeight(); - - CxImage imgDest; - imgDest.CopyInfo(*this); - imgDest.Create(wid,ht,GetBpp(),GetType()); - imgDest.SetPalette(GetPalette()); - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) imgDest.AlphaCreate(); -#endif //CXIMAGE_SUPPORT_ALPHA - - long x,y,y2; - for (y = 0; y < ht; y++){ - info.nProgress = (long)(100*y/ht); // - y2=ht-y-1; - for (x = 0; x < wid; x++){ - if(head.biClrUsed==0)//RGB - imgDest.SetPixelColor(wid-x-1, y2, BlindGetPixelColor(x, y)); - else //PALETTE - imgDest.SetPixelIndex(wid-x-1, y2, BlindGetPixelIndex(x, y)); - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) imgDest.AlphaSet(wid-x-1, y2,BlindAlphaGet(x, y)); -#endif //CXIMAGE_SUPPORT_ALPHA - - } - } - - //select the destination - if (iDst) iDst->Transfer(imgDest); - else Transfer(imgDest); - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Resizes the image. mode can be 0 for slow (bilinear) method , - * 1 for fast (nearest pixel) method, or 2 for accurate (bicubic spline interpolation) method. - * The function is faster with 24 and 1 bpp images, slow for 4 bpp images and slowest for 8 bpp images. - */ -bool CxImage::Resample(long newx, long newy, int mode, CxImage* iDst) -{ - if (newx==0 || newy==0) return false; - - if (head.biWidth==newx && head.biHeight==newy){ - if (iDst) iDst->Copy(*this); - return true; - } - - float xScale, yScale, fX, fY; - xScale = (float)head.biWidth / (float)newx; - yScale = (float)head.biHeight / (float)newy; - - CxImage newImage; - newImage.CopyInfo(*this); - newImage.Create(newx,newy,head.biBitCount,GetType()); - newImage.SetPalette(GetPalette()); - if (!newImage.IsValid()){ - strcpy(info.szLastError,newImage.GetLastError()); - return false; - } - - switch (mode) { - case 1: // nearest pixel - { - for(long y=0; y=head.biHeight) yy = head.biHeight-1; - for(int n=-1; n<3; n++) { - r2 = r1 * KernelBSpline(b - (float)n); - xx = i_x+n; - if (xx<0) xx=0; - if (xx>=head.biWidth) xx=head.biWidth-1; - - if (head.biClrUsed){ - rgb = GetPixelColor(xx,yy); - } else { - iDst = info.pImage + yy*info.dwEffWidth + xx*3; - rgb.rgbBlue = *iDst++; - rgb.rgbGreen= *iDst++; - rgb.rgbRed = *iDst; - } - - rr += rgb.rgbRed * r2; - gg += rgb.rgbGreen * r2; - bb += rgb.rgbBlue * r2; - } - } - - if (head.biClrUsed) - newImage.SetPixelColor(x,y,RGB(rr,gg,bb)); - else { - iDst = newImage.info.pImage + y*newImage.info.dwEffWidth + x*3; - *iDst++ = (BYTE)bb; - *iDst++ = (BYTE)gg; - *iDst = (BYTE)rr; - } - - } - } - break; - } - default: // bilinear interpolation - if (!(head.biWidth>newx && head.biHeight>newy && head.biBitCount==24)) { - // (c) 1999 Steve McMahon (steve@dogma.demon.co.uk) - long ifX, ifY, ifX1, ifY1, xmax, ymax; - float ir1, ir2, ig1, ig2, ib1, ib2, dx, dy; - BYTE r,g,b; - RGBQUAD rgb1, rgb2, rgb3, rgb4; - xmax = head.biWidth-1; - ymax = head.biHeight-1; - for(long y=0; y - const long ACCURACY = 1000; - long i,j; // index for faValue - long x,y; // coordinates in source image - BYTE* pSource; - BYTE* pDest = newImage.info.pImage; - long* naAccu = new long[3 * newx + 3]; - long* naCarry = new long[3 * newx + 3]; - long* naTemp; - long nWeightX,nWeightY; - float fEndX; - long nScale = (long)(ACCURACY * xScale * yScale); - - memset(naAccu, 0, sizeof(long) * 3 * newx); - memset(naCarry, 0, sizeof(long) * 3 * newx); - - int u, v = 0; // coordinates in dest image - float fEndY = yScale - 1.0f; - for (y = 0; y < head.biHeight; y++){ - info.nProgress = (long)(100*y/head.biHeight); // - if (info.nEscape) break; - pSource = info.pImage + y * info.dwEffWidth; - u = i = 0; - fEndX = xScale - 1.0f; - if ((float)y < fEndY) { // complete source row goes into dest row - for (x = 0; x < head.biWidth; x++){ - if ((float)x < fEndX){ // complete source pixel goes into dest pixel - for (j = 0; j < 3; j++) naAccu[i + j] += (*pSource++) * ACCURACY; - } else { // source pixel is splitted for 2 dest pixels - nWeightX = (long)(((float)x - fEndX) * ACCURACY); - for (j = 0; j < 3; j++){ - naAccu[i] += (ACCURACY - nWeightX) * (*pSource); - naAccu[3 + i++] += nWeightX * (*pSource++); - } - fEndX += xScale; - u++; - } - } - } else { // source row is splitted for 2 dest rows - nWeightY = (long)(((float)y - fEndY) * ACCURACY); - for (x = 0; x < head.biWidth; x++){ - if ((float)x < fEndX){ // complete source pixel goes into 2 pixel - for (j = 0; j < 3; j++){ - naAccu[i + j] += ((ACCURACY - nWeightY) * (*pSource)); - naCarry[i + j] += nWeightY * (*pSource++); - } - } else { // source pixel is splitted for 4 dest pixels - nWeightX = (int)(((float)x - fEndX) * ACCURACY); - for (j = 0; j < 3; j++) { - naAccu[i] += ((ACCURACY - nWeightY) * (ACCURACY - nWeightX)) * (*pSource) / ACCURACY; - *pDest++ = (BYTE)(naAccu[i] / nScale); - naCarry[i] += (nWeightY * (ACCURACY - nWeightX) * (*pSource)) / ACCURACY; - naAccu[i + 3] += ((ACCURACY - nWeightY) * nWeightX * (*pSource)) / ACCURACY; - naCarry[i + 3] = (nWeightY * nWeightX * (*pSource)) / ACCURACY; - i++; - pSource++; - } - fEndX += xScale; - u++; - } - } - if (u < newx){ // possibly not completed due to rounding errors - for (j = 0; j < 3; j++) *pDest++ = (BYTE)(naAccu[i++] / nScale); - } - naTemp = naCarry; - naCarry = naAccu; - naAccu = naTemp; - memset(naCarry, 0, sizeof(int) * 3); // need only to set first pixel zero - pDest = newImage.info.pImage + (++v * newImage.info.dwEffWidth); - fEndY += yScale; - } - } - if (v < newy){ // possibly not completed due to rounding errors - for (i = 0; i < 3 * newx; i++) *pDest++ = (BYTE)(naAccu[i] / nScale); - } - delete [] naAccu; - delete [] naCarry; - } - } - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()){ - newImage.AlphaCreate(); - for(long y=0; yTransfer(newImage); - else Transfer(newImage); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * New simpler resample. Adds new interpolation methods and simplifies code (using GetPixelColorInterpolated - * and GetAreaColorInterpolated). It also (unlike old method) interpolates alpha layer. - * - * \param newx, newy - size of resampled image - * \param inMethod - interpolation method to use (see comments at GetPixelColorInterpolated) - * If image size is being reduced, averaging is used instead (or simultaneously with) inMethod. - * \param ofMethod - what to replace outside pixels by (only significant for bordering pixels of enlarged image) - * \param iDst - pointer to destination CxImage or NULL. - * \param disableAveraging - force no averaging when shrinking images (Produces aliasing. - * You probably just want to leave this off...) - * - * \author ***bd*** 2.2004 - */ -bool CxImage::Resample2( - long newx, long newy, - InterpolationMethod const inMethod, - OverflowMethod const ofMethod, - CxImage* const iDst, - bool const disableAveraging) -{ - if (newx<=0 || newy<=0 || !pDib) return false; - - if (head.biWidth==newx && head.biHeight==newy) { - //image already correct size (just copy and return) - if (iDst) iDst->Copy(*this); - return true; - }//if - - //calculate scale of new image (less than 1 for enlarge) - float xScale, yScale; - xScale = (float)head.biWidth / (float)newx; - yScale = (float)head.biHeight / (float)newy; - - //create temporary destination image - CxImage newImage; - newImage.CopyInfo(*this); - newImage.Create(newx,newy,head.biBitCount,GetType()); - newImage.SetPalette(GetPalette()); - if (!newImage.IsValid()){ - strcpy(info.szLastError,newImage.GetLastError()); - return false; - } - - //and alpha channel if required -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) newImage.AlphaCreate(); - BYTE *pxptra = 0; // destination alpha data -#endif - - float sX, sY; //source location - long dX,dY; //destination pixel (int value) - if ((xScale<=1 && yScale<=1) || disableAveraging) { - //image is being enlarged (or interpolation on demand) - if (!IsIndexed()) { - //RGB24 image (optimized version with direct writes) - RGBQUAD q; //pixel colour - BYTE *pxptr; //pointer to destination pixel - for(dY=0; dYTransfer(newImage); - else - Transfer(newImage); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Reduces the number of bits per pixel to nbit (1, 4 or 8). - * ppal points to a valid palette for the final image; if not supplied the function will use a standard palette. - * ppal is not necessary for reduction to 1 bpp. - */ -bool CxImage::DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal, DWORD clrimportant) -{ - if (!pDib) return false; - if (head.biBitCount < nbit){ - strcpy(info.szLastError,"DecreaseBpp: target BPP greater than source BPP"); - return false; - } - if (head.biBitCount == nbit){ - if (clrimportant==0) return true; - if (head.biClrImportant && (head.biClrImportant4) return false; - - CxImage tmp; - tmp.CopyInfo(*this); - tmp.Create(head.biWidth,head.biHeight,4,info.dwType); - tmp.SetPalette(GetPalette(),GetNumColors()); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - -#if CXIMAGE_SUPPORT_SELECTION - tmp.SelectionCopy(*this); -#endif //CXIMAGE_SUPPORT_SELECTION - -#if CXIMAGE_SUPPORT_ALPHA - tmp.AlphaCopy(*this); -#endif //CXIMAGE_SUPPORT_ALPHA - - for (long y=0;y8) return false; - - CxImage tmp; - tmp.CopyInfo(*this); - tmp.Create(head.biWidth,head.biHeight,8,info.dwType); - tmp.SetPalette(GetPalette(),GetNumColors()); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - -#if CXIMAGE_SUPPORT_SELECTION - tmp.SelectionCopy(*this); -#endif //CXIMAGE_SUPPORT_SELECTION - -#if CXIMAGE_SUPPORT_ALPHA - tmp.AlphaCopy(*this); -#endif //CXIMAGE_SUPPORT_ALPHA - - for (long y=0;y24) return false; - - CxImage tmp; - tmp.CopyInfo(*this); - tmp.Create(head.biWidth,head.biHeight,24,info.dwType); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - if (info.nBkgndIndex>=0) //translate transparency - tmp.info.nBkgndColor=GetPaletteColor((BYTE)info.nBkgndIndex); - -#if CXIMAGE_SUPPORT_SELECTION - tmp.SelectionCopy(*this); -#endif //CXIMAGE_SUPPORT_SELECTION - -#if CXIMAGE_SUPPORT_ALPHA - tmp.AlphaCopy(*this); - if (AlphaPaletteIsValid() && !AlphaIsValid()) tmp.AlphaCreate(); -#endif //CXIMAGE_SUPPORT_ALPHA - - for (long y=0;y 128) { - tmp.SetPixelIndex(x, y, 1); - error = level - 255; - } else { - tmp.SetPixelIndex(x, y, 0); - error = level; - } - - nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 1, y, level); - nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 2, y, level); - int i; - for (i = -2; i < 3; i++) { - switch (i) { - case -2: - coeff = 2; - break; - case -1: - coeff = 4; - break; - case 0: - coeff = 8; - break; - case 1: - coeff = 4; - break; - case 2: - coeff = 2; - break; - } - nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + i, y + 1, level); - } - } - } - break; - } - case 3: - { - //Stucki error diffusion (Thanks to Franco Gerevini) - int TotalCoeffSum = 42; - long error, nlevel, coeff=1; - BYTE level; - - for (long y = 0; y < head.biHeight; y++) { - info.nProgress = (long)(100 * y / head.biHeight); - if (info.nEscape) - break; - for (long x = 0; x < head.biWidth; x++) { - level = BlindGetPixelIndex(x, y); - if (level > 128) { - tmp.SetPixelIndex(x, y, 1); - error = level - 255; - } else { - tmp.SetPixelIndex(x, y, 0); - error = level; - } - - nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 1, y, level); - nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 2, y, level); - int i; - for (i = -2; i < 3; i++) { - switch (i) { - case -2: - coeff = 2; - break; - case -1: - coeff = 4; - break; - case 0: - coeff = 8; - break; - case 1: - coeff = 4; - break; - case 2: - coeff = 2; - break; - } - nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + i, y + 1, level); - } - for (i = -2; i < 3; i++) { - switch (i) { - case -2: - coeff = 1; - break; - case -1: - coeff = 2; - break; - case 0: - coeff = 4; - break; - case 1: - coeff = 2; - break; - case 2: - coeff = 1; - break; - } - nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + i, y + 2, level); - } - } - } - break; - } - case 4: - { - //Jarvis, Judice and Ninke error diffusion (Thanks to Franco Gerevini) - int TotalCoeffSum = 48; - long error, nlevel, coeff=1; - BYTE level; - - for (long y = 0; y < head.biHeight; y++) { - info.nProgress = (long)(100 * y / head.biHeight); - if (info.nEscape) - break; - for (long x = 0; x < head.biWidth; x++) { - level = BlindGetPixelIndex(x, y); - if (level > 128) { - tmp.SetPixelIndex(x, y, 1); - error = level - 255; - } else { - tmp.SetPixelIndex(x, y, 0); - error = level; - } - - nlevel = GetPixelIndex(x + 1, y) + (error * 7) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 1, y, level); - nlevel = GetPixelIndex(x + 2, y) + (error * 5) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 2, y, level); - int i; - for (i = -2; i < 3; i++) { - switch (i) { - case -2: - coeff = 3; - break; - case -1: - coeff = 5; - break; - case 0: - coeff = 7; - break; - case 1: - coeff = 5; - break; - case 2: - coeff = 3; - break; - } - nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + i, y + 1, level); - } - for (i = -2; i < 3; i++) { - switch (i) { - case -2: - coeff = 1; - break; - case -1: - coeff = 3; - break; - case 0: - coeff = 5; - break; - case 1: - coeff = 3; - break; - case 2: - coeff = 1; - break; - } - nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + i, y + 2, level); - } - } - } - break; - } - case 5: - { - //Sierra error diffusion (Thanks to Franco Gerevini) - int TotalCoeffSum = 32; - long error, nlevel, coeff=1; - BYTE level; - - for (long y = 0; y < head.biHeight; y++) { - info.nProgress = (long)(100 * y / head.biHeight); - if (info.nEscape) - break; - for (long x = 0; x < head.biWidth; x++) { - level = BlindGetPixelIndex(x, y); - if (level > 128) { - tmp.SetPixelIndex(x, y, 1); - error = level - 255; - } else { - tmp.SetPixelIndex(x, y, 0); - error = level; - } - - nlevel = GetPixelIndex(x + 1, y) + (error * 5) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 1, y, level); - nlevel = GetPixelIndex(x + 2, y) + (error * 3) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + 2, y, level); - int i; - for (i = -2; i < 3; i++) { - switch (i) { - case -2: - coeff = 2; - break; - case -1: - coeff = 4; - break; - case 0: - coeff = 5; - break; - case 1: - coeff = 4; - break; - case 2: - coeff = 2; - break; - } - nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + i, y + 1, level); - } - for (i = -1; i < 2; i++) { - switch (i) { - case -1: - coeff = 2; - break; - case 0: - coeff = 3; - break; - case 1: - coeff = 2; - break; - } - nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(x + i, y + 2, level); - } - } - } - break; - } - case 6: - { - //Stevenson and Arce error diffusion (Thanks to Franco Gerevini) - int TotalCoeffSum = 200; - long error, nlevel; - BYTE level; - - for (long y = 0; y < head.biHeight; y++) { - info.nProgress = (long)(100 * y / head.biHeight); - if (info.nEscape) - break; - for (long x = 0; x < head.biWidth; x++) { - level = BlindGetPixelIndex(x, y); - if (level > 128) { - tmp.SetPixelIndex(x, y, 1); - error = level - 255; - } else { - tmp.SetPixelIndex(x, y, 0); - error = level; - } - - int tmp_index_x = x + 2; - int tmp_index_y = y; - int tmp_coeff = 32; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x - 3; - tmp_index_y = y + 1; - tmp_coeff = 12; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x - 1; - tmp_coeff = 26; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x + 1; - tmp_coeff = 30; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x + 3; - tmp_coeff = 16; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x - 2; - tmp_index_y = y + 2; - tmp_coeff = 12; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x; - tmp_coeff = 26; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x + 2; - tmp_coeff = 12; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x - 3; - tmp_index_y = y + 3; - tmp_coeff = 5; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x - 1; - tmp_coeff = 12; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x + 1; - tmp_coeff = 12; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - - tmp_index_x = x + 3; - tmp_coeff = 5; - nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; - level = (BYTE)min(255, max(0, (int)nlevel)); - SetPixelIndex(tmp_index_x, tmp_index_y, level); - } - } - break; - } - case 7: - { - // Bayer ordered dither - int order = 4; - //create Bayer matrix - if (order>4) order = 4; - int size = (1 << (2*order)); - BYTE* Bmatrix = (BYTE*) malloc(size * sizeof(BYTE)); - for(int i = 0; i < size; i++) { - int n = order; - int x = i / n; - int y = i % n; - int dither = 0; - while (n-- > 0){ - dither = (((dither<<1)|((x&1) ^ (y&1)))<<1) | (y&1); - x >>= 1; - y >>= 1; - } - Bmatrix[i] = (BYTE)(dither); - } - - int scale = max(0,(8-2*order)); - int level; - for (long y=0;y> scale; - if(level > Bmatrix[ (x % order) + order * (y % order) ]){ - tmp.SetPixelIndex(x,y,1); - } else { - tmp.SetPixelIndex(x,y,0); - } - } - } - - free(Bmatrix); - - break; - } - default: - { - // Floyd-Steinberg error diffusion (Thanks to Steve McMahon) - long error,nlevel,coeff=1; - BYTE level; - - for (long y=0;y 128){ - tmp.SetPixelIndex(x,y,1); - error = level-255; - } else { - tmp.SetPixelIndex(x,y,0); - error = level; - } - - nlevel = GetPixelIndex(x+1,y) + (error * 7)/16; - level = (BYTE)min(255,max(0,(int)nlevel)); - SetPixelIndex(x+1,y,level); - for(int i=-1; i<2; i++){ - switch(i){ - case -1: - coeff=3; break; - case 0: - coeff=5; break; - case 1: - coeff=1; break; - } - nlevel = GetPixelIndex(x+i,y+1) + (error * coeff)/16; - level = (BYTE)min(255,max(0,(int)nlevel)); - SetPixelIndex(x+i,y+1,level); - } - } - } - } - } - - tmp.SetPaletteColor(0,0,0,0); - tmp.SetPaletteColor(1,255,255,255); - Transfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * CropRotatedRectangle - * \param topx,topy : topmost and leftmost point of the rectangle - (topmost, and if there are 2 topmost points, the left one) - * \param width : size of the right hand side of rect, from (topx,topy) roundwalking clockwise - * \param height : size of the left hand side of rect, from (topx,topy) roundwalking clockwise - * \param angle : angle of the right hand side of rect, from (topx,topy) - * \param iDst : pointer to destination image (if 0, this image is modified) - * \author [VATI] - */ -bool CxImage::CropRotatedRectangle( long topx, long topy, long width, long height, float angle, CxImage* iDst) -{ - if (!pDib) return false; - - - long startx,starty,endx,endy; - double cos_angle = cos(angle/*/57.295779513082320877*/); - double sin_angle = sin(angle/*/57.295779513082320877*/); - - // if there is nothing special, call the original Crop(): - if ( fabs(angle)<0.0002 ) - return Crop( topx, topy, topx+width, topy+height, iDst); - - startx = min(topx, topx - (long)(sin_angle*(double)height)); - endx = topx + (long)(cos_angle*(double)width); - endy = topy + (long)(cos_angle*(double)height + sin_angle*(double)width); - // check: corners of the rectangle must be inside - if ( IsInside( startx, topy )==false || - IsInside( endx, endy ) == false ) - return false; - - // first crop to bounding rectangle - CxImage tmp(*this, true, false, true); - // tmp.Copy(*this, true, false, true); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - if (!tmp.Crop( startx, topy, endx, endy)){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - // the midpoint of the image now became the same as the midpoint of the rectangle - // rotate new image with minus angle amount - if ( false == tmp.Rotate( (float)(-angle*57.295779513082320877) ) ) // Rotate expects angle in degrees - return false; - - // crop rotated image to the original selection rectangle - endx = (tmp.head.biWidth+width)/2; - startx = (tmp.head.biWidth-width)/2; - starty = (tmp.head.biHeight+height)/2; - endy = (tmp.head.biHeight-height)/2; - if ( false == tmp.Crop( startx, starty, endx, endy ) ) - return false; - - if (iDst) iDst->Transfer(tmp); - else Transfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::Crop(const RECT& rect, CxImage* iDst) -{ - return Crop(rect.left, rect.top, rect.right, rect.bottom, iDst); -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::Crop(long left, long top, long right, long bottom, CxImage* iDst) -{ - if (!pDib) return false; - - long startx = max(0L,min(left,head.biWidth)); - long endx = max(0L,min(right,head.biWidth)); - long starty = head.biHeight - max(0L,min(top,head.biHeight)); - long endy = head.biHeight - max(0L,min(bottom,head.biHeight)); - - if (startx==endx || starty==endy) return false; - - if (startx>endx) {long tmp=startx; startx=endx; endx=tmp;} - if (starty>endy) {long tmp=starty; starty=endy; endy=tmp;} - - CxImage tmp(endx-startx,endy-starty,head.biBitCount,info.dwType); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - tmp.SetPalette(GetPalette(),head.biClrUsed); - tmp.info.nBkgndIndex = info.nBkgndIndex; - tmp.info.nBkgndColor = info.nBkgndColor; - - switch (head.biBitCount) { - case 1: - case 4: - { - for(long y=starty, yd=0; y - for(long x=startx, xd=0; x> 3; - BYTE* pDest = tmp.info.pImage; - BYTE* pSrc = info.pImage + starty * info.dwEffWidth + (startx*head.biBitCount >> 3); - for(long y=starty; y - memcpy(pDest,pSrc,linelen); - pDest+=tmp.info.dwEffWidth; - pSrc+=info.dwEffWidth; - } - } - } - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()){ // - tmp.AlphaCreate(); - if (!tmp.AlphaIsValid()) return false; - BYTE* pDest = tmp.pAlpha; - BYTE* pSrc = pAlpha + startx + starty*head.biWidth; - for (long y=starty; yTransfer(tmp); - else Transfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * \param xgain, ygain : can be from 0 to 1. - * \param xpivot, ypivot : is the center of the transformation. - * \param bEnableInterpolation : if true, enables bilinear interpolation. - * \return true if everything is ok - */ -bool CxImage::Skew(float xgain, float ygain, long xpivot, long ypivot, bool bEnableInterpolation) -{ - if (!pDib) return false; - float nx,ny; - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - long xmin,xmax,ymin,ymax; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - for(long y=ymin; y top) || (x < left) || (x > right)) { - tmp.SetPixelIndex(x,y, pixel); - } else { - tmp.SetPixelIndex(x,y,GetPixelIndex(x-left,y-bottom)); - } - } - } - break; - } - case 8: - case 24: - { - if (head.biBitCount == 8) { - BYTE pixel = tmp.GetNearestIndex( canvascolor); - memset(tmp.info.pImage, pixel, + (tmp.info.dwEffWidth * newHeight)); - } else { - for (long y = 0; y < newHeight; ++y) { - BYTE *pDest = tmp.info.pImage + (y * tmp.info.dwEffWidth); - for (long x = 0; x < newWidth; ++x) { - *pDest++ = canvascolor.rgbBlue; - *pDest++ = canvascolor.rgbGreen; - *pDest++ = canvascolor.rgbRed; - } - } - } - - BYTE* pDest = tmp.info.pImage + (tmp.info.dwEffWidth * bottom) + (left*(head.biBitCount >> 3)); - BYTE* pSrc = info.pImage; - for(long y=bottom; y <= top; y++){ - info.nProgress = (long)(100*y/(1 + top - bottom)); - memcpy(pDest,pSrc,(head.biBitCount >> 3) * (right - left + 1)); - pDest+=tmp.info.dwEffWidth; - pSrc+=info.dwEffWidth; - } - } - } - -#if CXIMAGE_SUPPORT_SELECTION - if (SelectionIsValid()){ - if (!tmp.SelectionCreate()) - return false; - BYTE* pSrc = SelectionGetPointer(); - BYTE* pDst = tmp.SelectionGetPointer(left,bottom); - for(long y=bottom; y <= top; y++){ - memcpy(pDst,pSrc, (right - left + 1)); - pSrc+=head.biWidth; - pDst+=tmp.head.biWidth; - } - tmp.info.rSelectionBox.left = info.rSelectionBox.left + left; - tmp.info.rSelectionBox.right = info.rSelectionBox.right + left; - tmp.info.rSelectionBox.top = info.rSelectionBox.top + bottom; - tmp.info.rSelectionBox.bottom = info.rSelectionBox.bottom + bottom; - } -#endif //CXIMAGE_SUPPORT_SELECTION - -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()){ - if (!tmp.AlphaCreate()) - return false; - tmp.AlphaSet(canvascolor.rgbReserved); - BYTE* pSrc = AlphaGetPointer(); - BYTE* pDst = tmp.AlphaGetPointer(left,bottom); - for(long y=bottom; y <= top; y++){ - memcpy(pDst,pSrc, (right - left + 1)); - pSrc+=head.biWidth; - pDst+=tmp.head.biWidth; - } - } -#endif //CXIMAGE_SUPPORT_ALPHA - - //select the destination - if (iDst) iDst->Transfer(tmp); - else Transfer(tmp); - - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImage::Expand(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst) -{ - //thanks to - - if (!pDib) return false; - - if ((newx < head.biWidth) || (newy < head.biHeight)) return false; - - int nAddLeft = (newx - head.biWidth) / 2; - int nAddTop = (newy - head.biHeight) / 2; - - return Expand(nAddLeft, nAddTop, newx - (head.biWidth + nAddLeft), newy - (head.biHeight + nAddTop), canvascolor, iDst); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Resamples the image with the correct aspect ratio, and fills the borders. - * \param newx, newy = thumbnail size. - * \param canvascolor = border color. - * \param iDst = pointer to destination image (if it's 0, this image is modified). - * \return true if everything is ok. - * \author [Colin Urquhart] - */ -bool CxImage::Thumbnail(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst) -{ - if (!pDib) return false; - - if ((newx <= 0) || (newy <= 0)) return false; - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - // determine whether we need to shrink the image - if ((head.biWidth > newx) || (head.biHeight > newy)) { - float fScale; - float fAspect = (float) newx / (float) newy; - if (fAspect * head.biHeight > head.biWidth) { - fScale = (float) newy / head.biHeight; - } else { - fScale = (float) newx / head.biWidth; - } - tmp.Resample((long) (fScale * head.biWidth), (long) (fScale * head.biHeight), 0); - } - - // expand the frame - tmp.Expand(newx, newy, canvascolor, iDst); - - //select the destination - if (iDst) iDst->Transfer(tmp); - else Transfer(tmp); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Perform circle_based transformations. - * \param type - for different transformations - * - 0 for normal (proturberant) FishEye - * - 1 for reverse (concave) FishEye - * - 2 for Swirle - * - 3 for Cilinder mirror - * - 4 for bathroom - * - * \param rmax - effect radius. If 0, the whole image is processed - * \param Koeff - only for swirle - * \author Arkadiy Olovyannikov ark(at)msun(dot)ru - */ -bool CxImage::CircleTransform(int type,long rmax,float Koeff) -{ - if (!pDib) return false; - - long nx,ny; - double angle,radius,rnew; - - CxImage tmp(*this); - if (!tmp.IsValid()){ - strcpy(info.szLastError,tmp.GetLastError()); - return false; - } - - long xmin,xmax,ymin,ymax,xmid,ymid; - if (pSelection){ - xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; - ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; - } else { - xmin = ymin = 0; - xmax = head.biWidth; ymax=head.biHeight; - } - - xmid = (long) (tmp.GetWidth()/2); - ymid = (long) (tmp.GetHeight()/2); - - if (!rmax) rmax=(long)sqrt((float)((xmid-xmin)*(xmid-xmin)+(ymid-ymin)*(ymid-ymin))); - if (Koeff==0.0f) Koeff=1.0f; - - for(long y=ymin; yhead.biWidth || newy>head.biHeight) { - //let me repeat... this method can't enlarge image - strcpy(info.szLastError,"QIShrink can't enlarge image"); - return false; - } - - if (newx==head.biWidth && newy==head.biHeight) { - //image already correct size (just copy and return) - if (iDst) iDst->Copy(*this); - return true; - }//if - - //create temporary destination image - CxImage newImage; - newImage.CopyInfo(*this); - newImage.Create(newx,newy,(bChangeBpp)?24:head.biBitCount,GetType()); - newImage.SetPalette(GetPalette()); - if (!newImage.IsValid()){ - strcpy(info.szLastError,newImage.GetLastError()); - return false; - } - - //and alpha channel if required -#if CXIMAGE_SUPPORT_ALPHA - if (AlphaIsValid()) newImage.AlphaCreate(); -#endif - - const int oldx = head.biWidth; - const int oldy = head.biHeight; - - int accuCellSize = 4; -#if CXIMAGE_SUPPORT_ALPHA - BYTE *alphaPtr; - if (AlphaIsValid()) accuCellSize=5; -#endif - - unsigned int *accu = new unsigned int[newx*accuCellSize]; //array for suming pixels... one pixel for every destination column - unsigned int *accuPtr; //pointer for walking through accu - //each cell consists of blue, red, green component and count of pixels summed in this cell - memset(accu, 0, newx * accuCellSize * sizeof(unsigned int)); //clear accu - - if (!IsIndexed()) { - //RGB24 version with pointers - BYTE *destPtr, *srcPtr, *destPtrS, *srcPtrS; //destination and source pixel, and beginnings of current row - srcPtrS=(BYTE*)BlindGetPixelPointer(0,0); - destPtrS=(BYTE*)newImage.BlindGetPixelPointer(0,0); - int ex=0, ey=0; //ex and ey replace division... - int dy=0; - //(we just add pixels, until by adding newx or newy we get a number greater than old size... then - // it's time to move to next pixel) - - for(int y=0; yoldx) { //when we reach oldx, it's time to move to new slot - accuPtr += accuCellSize; - ex -= oldx; //(substract oldx from ex and resume from there on) - }//if (ex overflow) - }//for x - - if (ey>=oldy) { //now when this happens - ey -= oldy; //it's time to move to new destination row - destPtr = destPtrS; //reset pointers to proper initial values - accuPtr = accu; -#if CXIMAGE_SUPPORT_ALPHA - alphaPtr = newImage.AlphaGetPointer(0, dy++); -#endif - for (int k=0; koldx) { //when we reach oldx, it's time to move to new slot - accuPtr += accuCellSize; - ex -= oldx; //(substract oldx from ex and resume from there on) - }//if (ex overflow) - }//for x - - if (ey>=oldy) { //now when this happens - ey -= oldy; //it's time to move to new destination row - accuPtr = accu; - for (int dx=0; dxTransfer(newImage); - else - Transfer(newImage); - return true; - -} - -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_TRANSFORMATION +// xImaTran.cpp : Transformation functions +/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" +#include "ximath.h" + +#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::GrayScale() +{ + if (!pDib) return false; + if (head.biBitCount<=8){ + RGBQUAD* ppal=GetPalette(); + int gray; + //converts the colors to gray, use the blue channel only + for(DWORD i=0;i= 0) info.nBkgndIndex = ppal[info.nBkgndIndex].rgbBlue; + //create a "real" 8 bit gray scale image + if (head.biBitCount==8){ + BYTE *img=info.pImage; + for(DWORD i=0;i> 1]&((BYTE)0x0F<> pos)].rgbBlue; + } else { + BYTE pos = (BYTE)(7-x%8); + iDst[x]= ppal[(BYTE)((iSrc[x >> 3]&((BYTE)0x01<> pos)].rgbBlue; + } + } + } + Transfer(ima); + } + } else { //from RGB to 8 bit gray scale + BYTE *iSrc=info.pImage; + CxImage ima; + ima.CopyInfo(*this); + if (!ima.Create(head.biWidth,head.biHeight,8,info.dwType)) return false; + ima.SetGrayPalette(); +#if CXIMAGE_SUPPORT_SELECTION + ima.SelectionCopy(*this); +#endif //CXIMAGE_SUPPORT_SELECTION +#if CXIMAGE_SUPPORT_ALPHA + ima.AlphaCopy(*this); +#endif //CXIMAGE_SUPPORT_ALPHA + BYTE *img=ima.GetBits(); + long l8=ima.GetEffWidth(); + long l=head.biWidth * 3; + for(long y=0; y < head.biHeight; y++) { + for(long x=0,x8=0; x < l; x+=3,x8++) { + img[x8+y*l8]=(BYTE)RGB2GRAY(*(iSrc+x+2),*(iSrc+x+1),*(iSrc+x+0)); + } + iSrc+=info.dwEffWidth; + } + Transfer(ima); + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa Mirror + * \author [qhbo] + */ +bool CxImage::Flip(bool bFlipSelection, bool bFlipAlpha) +{ + if (!pDib) return false; + + BYTE *buff = (BYTE*)malloc(info.dwEffWidth); + if (!buff) return false; + + BYTE *iSrc,*iDst; + iSrc = GetBits(head.biHeight-1); + iDst = GetBits(0); + for (long i=0; i<(head.biHeight/2); ++i) + { + memcpy(buff, iSrc, info.dwEffWidth); + memcpy(iSrc, iDst, info.dwEffWidth); + memcpy(iDst, buff, info.dwEffWidth); + iSrc-=info.dwEffWidth; + iDst+=info.dwEffWidth; + } + + free(buff); + + if (bFlipSelection){ +#if CXIMAGE_SUPPORT_SELECTION + SelectionFlip(); +#endif //CXIMAGE_SUPPORT_SELECTION + } + + if (bFlipAlpha){ +#if CXIMAGE_SUPPORT_ALPHA + AlphaFlip(); +#endif //CXIMAGE_SUPPORT_ALPHA + } + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \sa Flip + */ +bool CxImage::Mirror(bool bMirrorSelection, bool bMirrorAlpha) +{ + if (!pDib) return false; + + CxImage* imatmp = new CxImage(*this,false,true,true); + if (!imatmp) return false; + if (!imatmp->IsValid()){ + delete imatmp; + return false; + } + + BYTE *iSrc,*iDst; + long wdt=(head.biWidth-1) * (head.biBitCount==24 ? 3:1); + iSrc=info.pImage + wdt; + iDst=imatmp->info.pImage; + long x,y; + switch (head.biBitCount){ + case 24: + for(y=0; y < head.biHeight; y++){ + for(x=0; x <= wdt; x+=3){ + *(iDst+x)=*(iSrc-x); + *(iDst+x+1)=*(iSrc-x+1); + *(iDst+x+2)=*(iSrc-x+2); + } + iSrc+=info.dwEffWidth; + iDst+=info.dwEffWidth; + } + break; + case 8: + for(y=0; y < head.biHeight; y++){ + for(x=0; x <= wdt; x++) + *(iDst+x)=*(iSrc-x); + iSrc+=info.dwEffWidth; + iDst+=info.dwEffWidth; + } + break; + default: + for(y=0; y < head.biHeight; y++){ + for(x=0; x <= wdt; x++) + imatmp->SetPixelIndex(x,y,GetPixelIndex(wdt-x,y)); + } + } + + if (bMirrorSelection){ +#if CXIMAGE_SUPPORT_SELECTION + imatmp->SelectionMirror(); +#endif //CXIMAGE_SUPPORT_SELECTION + } + + if (bMirrorAlpha){ +#if CXIMAGE_SUPPORT_ALPHA + imatmp->AlphaMirror(); +#endif //CXIMAGE_SUPPORT_ALPHA + } + + Transfer(*imatmp); + delete imatmp; + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +#define RBLOCK 64 + +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::RotateLeft(CxImage* iDst) +{ + if (!pDib) return false; + + long newWidth = GetHeight(); + long newHeight = GetWidth(); + + CxImage imgDest; + imgDest.CopyInfo(*this); + imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); + imgDest.SetPalette(GetPalette()); + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) imgDest.AlphaCreate(); +#endif + +#if CXIMAGE_SUPPORT_SELECTION + if (SelectionIsValid()) imgDest.SelectionCreate(); +#endif + + long x,x2,y,dlineup; + + // Speedy rotate for BW images + if (head.biBitCount == 1) { + + BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp; + ldiv_t div_r; + + BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits(); + dbitsmax = bdest + imgDest.head.biSizeImage - 1; + dlineup = 8 * imgDest.info.dwEffWidth - imgDest.head.biWidth; + + imgDest.Clear(0); + for (y = 0; y < head.biHeight; y++) { + // Figure out the Column we are going to be copying to + div_r = ldiv(y + dlineup, (long)8); + // set bit pos of src column byte + bitpos = (BYTE)(1 << div_r.rem); + srcdisp = bsrc + y * info.dwEffWidth; + for (x = 0; x < (long)info.dwEffWidth; x++) { + // Get Source Bits + sbits = srcdisp + x; + // Get destination column + nrow = bdest + (x * 8) * imgDest.info.dwEffWidth + imgDest.info.dwEffWidth - 1 - div_r.quot; + for (long z = 0; z < 8; z++) { + // Get Destination Byte + dbits = nrow + z * imgDest.info.dwEffWidth; + if ((dbits < bdest) || (dbits > dbitsmax)) break; + if (*sbits & (128 >> z)) *dbits |= bitpos; + } + } + }//for y + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) { + for (x = 0; x < newWidth; x++){ + x2=newWidth-x-1; + for (y = 0; y < newHeight; y++){ + imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2)); + }//for y + }//for x + } +#endif //CXIMAGE_SUPPORT_ALPHA + +#if CXIMAGE_SUPPORT_SELECTION + if (SelectionIsValid()) { + imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top; + imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom; + imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left; + imgDest.info.rSelectionBox.top = info.rSelectionBox.right; + for (x = 0; x < newWidth; x++){ + x2=newWidth-x-1; + for (y = 0; y < newHeight; y++){ + imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2)); + }//for y + }//for x + } +#endif //CXIMAGE_SUPPORT_SELECTION + + } else { + //anything other than BW: + //bd, 10. 2004: This optimized version of rotation rotates image by smaller blocks. It is quite + //a bit faster than obvious algorithm, because it produces much less CPU cache misses. + //This optimization can be tuned by changing block size (RBLOCK). 96 is good value for current + //CPUs (tested on Athlon XP and Celeron D). Larger value (if CPU has enough cache) will increase + //speed somehow, but once you drop out of CPU's cache, things will slow down drastically. + //For older CPUs with less cache, lower value would yield better results. + + BYTE *srcPtr, *dstPtr; //source and destionation for 24-bit version + int xs, ys; //x-segment and y-segment + for (xs = 0; xs < newWidth; xs+=RBLOCK) { //for all image blocks of RBLOCK*RBLOCK pixels + for (ys = 0; ys < newHeight; ys+=RBLOCK) { + if (head.biBitCount==24) { + //RGB24 optimized pixel access: + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ //do rotation + info.nProgress = (long)(100*x/newWidth); + x2=newWidth-x-1; + dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(x,ys); + srcPtr = (BYTE*) BlindGetPixelPointer(ys, x2); + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + //imgDest.SetPixelColor(x, y, GetPixelColor(y, x2)); + *(dstPtr) = *(srcPtr); + *(dstPtr+1) = *(srcPtr+1); + *(dstPtr+2) = *(srcPtr+2); + srcPtr += 3; + dstPtr += imgDest.info.dwEffWidth; + }//for y + }//for x + } else { + //anything else than 24bpp (and 1bpp): palette + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ + info.nProgress = (long)(100*x/newWidth); // + x2=newWidth-x-1; + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y, x2)); + }//for y + }//for x + }//if (version selection) +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) { + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ + x2=newWidth-x-1; + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2)); + }//for y + }//for x + }//if (alpha channel) +#endif //CXIMAGE_SUPPORT_ALPHA + +#if CXIMAGE_SUPPORT_SELECTION + if (SelectionIsValid()) { + imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top; + imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom; + imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left; + imgDest.info.rSelectionBox.top = info.rSelectionBox.right; + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ + x2=newWidth-x-1; + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2)); + }//for y + }//for x + }//if (selection) +#endif //CXIMAGE_SUPPORT_SELECTION + }//for ys + }//for xs + }//if + + //select the destination + if (iDst) iDst->Transfer(imgDest); + else Transfer(imgDest); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::RotateRight(CxImage* iDst) +{ + if (!pDib) return false; + + long newWidth = GetHeight(); + long newHeight = GetWidth(); + + CxImage imgDest; + imgDest.CopyInfo(*this); + imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); + imgDest.SetPalette(GetPalette()); + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) imgDest.AlphaCreate(); +#endif + +#if CXIMAGE_SUPPORT_SELECTION + if (SelectionIsValid()) imgDest.SelectionCreate(); +#endif + + long x,y,y2; + // Speedy rotate for BW images + if (head.biBitCount == 1) { + + BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp; + ldiv_t div_r; + + BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits(); + dbitsmax = bdest + imgDest.head.biSizeImage - 1; + + imgDest.Clear(0); + for (y = 0; y < head.biHeight; y++) { + // Figure out the Column we are going to be copying to + div_r = ldiv(y, (long)8); + // set bit pos of src column byte + bitpos = (BYTE)(128 >> div_r.rem); + srcdisp = bsrc + y * info.dwEffWidth; + for (x = 0; x < (long)info.dwEffWidth; x++) { + // Get Source Bits + sbits = srcdisp + x; + // Get destination column + nrow = bdest + (imgDest.head.biHeight-1-(x*8)) * imgDest.info.dwEffWidth + div_r.quot; + for (long z = 0; z < 8; z++) { + // Get Destination Byte + dbits = nrow - z * imgDest.info.dwEffWidth; + if ((dbits < bdest) || (dbits > dbitsmax)) break; + if (*sbits & (128 >> z)) *dbits |= bitpos; + } + } + } + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()){ + for (y = 0; y < newHeight; y++){ + y2=newHeight-y-1; + for (x = 0; x < newWidth; x++){ + imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x)); + } + } + } +#endif //CXIMAGE_SUPPORT_ALPHA + +#if CXIMAGE_SUPPORT_SELECTION + if (SelectionIsValid()){ + imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom; + imgDest.info.rSelectionBox.right = info.rSelectionBox.top; + imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right; + imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left; + for (y = 0; y < newHeight; y++){ + y2=newHeight-y-1; + for (x = 0; x < newWidth; x++){ + imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x)); + } + } + } +#endif //CXIMAGE_SUPPORT_SELECTION + + } else { + //anything else but BW + BYTE *srcPtr, *dstPtr; //source and destionation for 24-bit version + int xs, ys; //x-segment and y-segment + for (xs = 0; xs < newWidth; xs+=RBLOCK) { + for (ys = 0; ys < newHeight; ys+=RBLOCK) { + if (head.biBitCount==24) { + //RGB24 optimized pixel access: + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + info.nProgress = (long)(100*y/newHeight); // + y2=newHeight-y-1; + dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(xs,y); + srcPtr = (BYTE*) BlindGetPixelPointer(y2, xs); + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ + //imgDest.SetPixelColor(x, y, GetPixelColor(y2, x)); + *(dstPtr) = *(srcPtr); + *(dstPtr+1) = *(srcPtr+1); + *(dstPtr+2) = *(srcPtr+2); + dstPtr += 3; + srcPtr += info.dwEffWidth; + }//for x + }//for y + } else { + //anything else than BW & RGB24: palette + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + info.nProgress = (long)(100*y/newHeight); // + y2=newHeight-y-1; + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ + imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y2, x)); + }//for x + }//for y + }//if +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()){ + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + y2=newHeight-y-1; + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ + imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x)); + }//for x + }//for y + }//if (has alpha) +#endif //CXIMAGE_SUPPORT_ALPHA + +#if CXIMAGE_SUPPORT_SELECTION + if (SelectionIsValid()){ + imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom; + imgDest.info.rSelectionBox.right = info.rSelectionBox.top; + imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right; + imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left; + for (y = ys; y < min(newHeight, ys+RBLOCK); y++){ + y2=newHeight-y-1; + for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ + imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x)); + }//for x + }//for y + }//if (has alpha) +#endif //CXIMAGE_SUPPORT_SELECTION + }//for ys + }//for xs + }//if + + //select the destination + if (iDst) iDst->Transfer(imgDest); + else Transfer(imgDest); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::Negative() +{ + if (!pDib) return false; + + if (head.biBitCount<=8){ + if (IsGrayScale()){ //GRAYSCALE, selection + if (pSelection){ + for(long y=info.rSelectionBox.bottom; y invert transparent color too + info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue); + info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen); + info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed); + } + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_TRANSFORMATION +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::Rotate(float angle, CxImage* iDst) +{ + if (!pDib) return false; + + // Copyright (c) 1996-1998 Ulrich von Zadow + + // Negative the angle, because the y-axis is negative. + double ang = -angle*acos((float)0)/90; + int newWidth, newHeight; + int nWidth = GetWidth(); + int nHeight= GetHeight(); + double cos_angle = cos(ang); + double sin_angle = sin(ang); + + // Calculate the size of the new bitmap + POINT p1={0,0}; + POINT p2={nWidth,0}; + POINT p3={0,nHeight}; + POINT p4={nWidth,nHeight}; + CxPoint2 newP1,newP2,newP3,newP4, leftTop, rightTop, leftBottom, rightBottom; + + newP1.x = (float)p1.x; + newP1.y = (float)p1.y; + newP2.x = (float)(p2.x*cos_angle - p2.y*sin_angle); + newP2.y = (float)(p2.x*sin_angle + p2.y*cos_angle); + newP3.x = (float)(p3.x*cos_angle - p3.y*sin_angle); + newP3.y = (float)(p3.x*sin_angle + p3.y*cos_angle); + newP4.x = (float)(p4.x*cos_angle - p4.y*sin_angle); + newP4.y = (float)(p4.x*sin_angle + p4.y*cos_angle); + + leftTop.x = min(min(newP1.x,newP2.x),min(newP3.x,newP4.x)); + leftTop.y = min(min(newP1.y,newP2.y),min(newP3.y,newP4.y)); + rightBottom.x = max(max(newP1.x,newP2.x),max(newP3.x,newP4.x)); + rightBottom.y = max(max(newP1.y,newP2.y),max(newP3.y,newP4.y)); + leftBottom.x = leftTop.x; + leftBottom.y = rightBottom.y; + rightTop.x = rightBottom.x; + rightTop.y = leftTop.y; + + newWidth = (int) floor(0.5f + rightTop.x - leftTop.x); + newHeight= (int) floor(0.5f + leftBottom.y - leftTop.y); + CxImage imgDest; + imgDest.CopyInfo(*this); + imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); + imgDest.SetPalette(GetPalette()); + +#if CXIMAGE_SUPPORT_ALPHA + if(AlphaIsValid()) //MTA: Fix for rotation problem when the image has an alpha channel + { + imgDest.AlphaCreate(); + imgDest.AlphaClear(); + } +#endif //CXIMAGE_SUPPORT_ALPHA + + int x,y,newX,newY,oldX,oldY; + + if (head.biClrUsed==0){ //RGB + for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){ + info.nProgress = (long)(100*newY/newHeight); + if (info.nEscape) break; + for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){ + oldX = (long)(x*cos_angle + y*sin_angle + 0.5); + oldY = (long)(y*cos_angle - x*sin_angle + 0.5); + imgDest.SetPixelColor(newX,newY,GetPixelColor(oldX,oldY)); +#if CXIMAGE_SUPPORT_ALPHA + imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value +#endif //CXIMAGE_SUPPORT_ALPHA + } + } + } else { //PALETTE + for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){ + info.nProgress = (long)(100*newY/newHeight); + if (info.nEscape) break; + for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){ + oldX = (long)(x*cos_angle + y*sin_angle + 0.5); + oldY = (long)(y*cos_angle - x*sin_angle + 0.5); + imgDest.SetPixelIndex(newX,newY,GetPixelIndex(oldX,oldY)); +#if CXIMAGE_SUPPORT_ALPHA + imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value +#endif //CXIMAGE_SUPPORT_ALPHA + } + } + } + //select the destination + if (iDst) iDst->Transfer(imgDest); + else Transfer(imgDest); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Rotates image around it's center. + * Method can use interpolation with paletted images, but does not change pallete, so results vary. + * (If you have only four colours in a palette, there's not much room for interpolation.) + * + * \param angle - angle in degrees (positive values rotate clockwise) + * \param *iDst - destination image (if null, this image is changed) + * \param inMethod - interpolation method used + * (IM_NEAREST_NEIGHBOUR produces aliasing (fast), IM_BILINEAR softens picture a bit (slower) + * IM_SHARPBICUBIC is slower and produces some halos...) + * \param ofMethod - overflow method (how to choose colour of pixels that have no source) + * \param replColor - replacement colour to use (OM_COLOR, OM_BACKGROUND with no background colour...) + * \param optimizeRightAngles - call faster methods for 90, 180, and 270 degree rotations. Faster methods + * are called for angles, where error (in location of corner pixels) is less + * than 0.25 pixels. + * \param bKeepOriginalSize - rotates the image without resizing. + * + * \author ***bd*** 2.2004 + */ +bool CxImage::Rotate2(float angle, + CxImage *iDst, + InterpolationMethod inMethod, + OverflowMethod ofMethod, + RGBQUAD *replColor, + bool const optimizeRightAngles, + bool const bKeepOriginalSize) +{ + if (!pDib) return false; //no dib no go + + double ang = -angle*acos(0.0f)/90.0f; //convert angle to radians and invert (positive angle performs clockwise rotation) + float cos_angle = (float) cos(ang); //these two are needed later (to rotate) + float sin_angle = (float) sin(ang); + + //Calculate the size of the new bitmap (rotate corners of image) + CxPoint2 p[4]; //original corners of the image + p[0]=CxPoint2(-0.5f,-0.5f); + p[1]=CxPoint2(GetWidth()-0.5f,-0.5f); + p[2]=CxPoint2(-0.5f,GetHeight()-0.5f); + p[3]=CxPoint2(GetWidth()-0.5f,GetHeight()-0.5f); + CxPoint2 newp[4]; //rotated positions of corners + //(rotate corners) + if (bKeepOriginalSize){ + for (int i=0; i<4; i++) { + newp[i].x = p[i].x; + newp[i].y = p[i].y; + }//for + } else { + for (int i=0; i<4; i++) { + newp[i].x = (p[i].x*cos_angle - p[i].y*sin_angle); + newp[i].y = (p[i].x*sin_angle + p[i].y*cos_angle); + }//for i + + if (optimizeRightAngles) { + //For rotations of 90, -90 or 180 or 0 degrees, call faster routines + if (newp[3].Distance(CxPoint2(GetHeight()-0.5f, 0.5f-GetWidth())) < 0.25) + //rotation right for circa 90 degrees (diagonal pixels less than 0.25 pixel away from 90 degree rotation destination) + return RotateRight(iDst); + if (newp[3].Distance(CxPoint2(0.5f-GetHeight(), -0.5f+GetWidth())) < 0.25) + //rotation left for ~90 degrees + return RotateLeft(iDst); + if (newp[3].Distance(CxPoint2(0.5f-GetWidth(), 0.5f-GetHeight())) < 0.25) + //rotation left for ~180 degrees + return Rotate180(iDst); + if (newp[3].Distance(p[3]) < 0.25) { + //rotation not significant + if (iDst) iDst->Copy(*this); //copy image to iDst, if required + return true; //and we're done + }//if + }//if + }//if + + //(read new dimensions from location of corners) + float minx = (float) min(min(newp[0].x,newp[1].x),min(newp[2].x,newp[3].x)); + float miny = (float) min(min(newp[0].y,newp[1].y),min(newp[2].y,newp[3].y)); + float maxx = (float) max(max(newp[0].x,newp[1].x),max(newp[2].x,newp[3].x)); + float maxy = (float) max(max(newp[0].y,newp[1].y),max(newp[2].y,newp[3].y)); + int newWidth = (int) floor(maxx-minx+0.5f); + int newHeight= (int) floor(maxy-miny+0.5f); + float ssx=((maxx+minx)- ((float) newWidth-1))/2.0f; //start for x + float ssy=((maxy+miny)- ((float) newHeight-1))/2.0f; //start for y + + float newxcenteroffset = 0.5f * newWidth; + float newycenteroffset = 0.5f * newHeight; + if (bKeepOriginalSize){ + ssx -= 0.5f * GetWidth(); + ssy -= 0.5f * GetHeight(); + } + + //create destination image + CxImage imgDest; + imgDest.CopyInfo(*this); + imgDest.Create(newWidth,newHeight,GetBpp(),GetType()); + imgDest.SetPalette(GetPalette()); +#if CXIMAGE_SUPPORT_ALPHA + if(AlphaIsValid()) imgDest.AlphaCreate(); //MTA: Fix for rotation problem when the image has an alpha channel +#endif //CXIMAGE_SUPPORT_ALPHA + + RGBQUAD rgb; //pixel colour + RGBQUAD rc; + if (replColor!=0) + rc=*replColor; + else { + rc.rgbRed=255; rc.rgbGreen=255; rc.rgbBlue=255; rc.rgbReserved=0; + }//if + float x,y; //destination location (float, with proper offset) + float origx, origy; //origin location + int destx, desty; //destination location + + y=ssy; //initialize y + if (!IsIndexed()){ //RGB24 + //optimized RGB24 implementation (direct write to destination): + BYTE *pxptr; +#if CXIMAGE_SUPPORT_ALPHA + BYTE *pxptra=0; +#endif //CXIMAGE_SUPPORT_ALPHA + for (desty=0; destyTransfer(imgDest); + else Transfer(imgDest); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::Rotate180(CxImage* iDst) +{ + if (!pDib) return false; + + long wid = GetWidth(); + long ht = GetHeight(); + + CxImage imgDest; + imgDest.CopyInfo(*this); + imgDest.Create(wid,ht,GetBpp(),GetType()); + imgDest.SetPalette(GetPalette()); + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) imgDest.AlphaCreate(); +#endif //CXIMAGE_SUPPORT_ALPHA + + long x,y,y2; + for (y = 0; y < ht; y++){ + info.nProgress = (long)(100*y/ht); // + y2=ht-y-1; + for (x = 0; x < wid; x++){ + if(head.biClrUsed==0)//RGB + imgDest.SetPixelColor(wid-x-1, y2, BlindGetPixelColor(x, y)); + else //PALETTE + imgDest.SetPixelIndex(wid-x-1, y2, BlindGetPixelIndex(x, y)); + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) imgDest.AlphaSet(wid-x-1, y2,BlindAlphaGet(x, y)); +#endif //CXIMAGE_SUPPORT_ALPHA + + } + } + + //select the destination + if (iDst) iDst->Transfer(imgDest); + else Transfer(imgDest); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Resizes the image. mode can be 0 for slow (bilinear) method , + * 1 for fast (nearest pixel) method, or 2 for accurate (bicubic spline interpolation) method. + * The function is faster with 24 and 1 bpp images, slow for 4 bpp images and slowest for 8 bpp images. + */ +bool CxImage::Resample(long newx, long newy, int mode, CxImage* iDst) +{ + if (newx==0 || newy==0) return false; + + if (head.biWidth==newx && head.biHeight==newy){ + if (iDst) iDst->Copy(*this); + return true; + } + + float xScale, yScale, fX, fY; + xScale = (float)head.biWidth / (float)newx; + yScale = (float)head.biHeight / (float)newy; + + CxImage newImage; + newImage.CopyInfo(*this); + newImage.Create(newx,newy,head.biBitCount,GetType()); + newImage.SetPalette(GetPalette()); + if (!newImage.IsValid()){ + strcpy(info.szLastError,newImage.GetLastError()); + return false; + } + + switch (mode) { + case 1: // nearest pixel + { + for(long y=0; y=head.biHeight) yy = head.biHeight-1; + for(int n=-1; n<3; n++) { + r2 = r1 * KernelBSpline(b - (float)n); + xx = i_x+n; + if (xx<0) xx=0; + if (xx>=head.biWidth) xx=head.biWidth-1; + + if (head.biClrUsed){ + rgb = GetPixelColor(xx,yy); + } else { + iDst = info.pImage + yy*info.dwEffWidth + xx*3; + rgb.rgbBlue = *iDst++; + rgb.rgbGreen= *iDst++; + rgb.rgbRed = *iDst; + } + + rr += rgb.rgbRed * r2; + gg += rgb.rgbGreen * r2; + bb += rgb.rgbBlue * r2; + } + } + + if (head.biClrUsed) + newImage.SetPixelColor(x,y,RGB(rr,gg,bb)); + else { + iDst = newImage.info.pImage + y*newImage.info.dwEffWidth + x*3; + *iDst++ = (BYTE)bb; + *iDst++ = (BYTE)gg; + *iDst = (BYTE)rr; + } + + } + } + break; + } + default: // bilinear interpolation + if (!(head.biWidth>newx && head.biHeight>newy && head.biBitCount==24)) { + // (c) 1999 Steve McMahon (steve@dogma.demon.co.uk) + long ifX, ifY, ifX1, ifY1, xmax, ymax; + float ir1, ir2, ig1, ig2, ib1, ib2, dx, dy; + BYTE r,g,b; + RGBQUAD rgb1, rgb2, rgb3, rgb4; + xmax = head.biWidth-1; + ymax = head.biHeight-1; + for(long y=0; y + const long ACCURACY = 1000; + long i,j; // index for faValue + long x,y; // coordinates in source image + BYTE* pSource; + BYTE* pDest = newImage.info.pImage; + long* naAccu = new long[3 * newx + 3]; + long* naCarry = new long[3 * newx + 3]; + long* naTemp; + long nWeightX,nWeightY; + float fEndX; + long nScale = (long)(ACCURACY * xScale * yScale); + + memset(naAccu, 0, sizeof(long) * 3 * newx); + memset(naCarry, 0, sizeof(long) * 3 * newx); + + int u, v = 0; // coordinates in dest image + float fEndY = yScale - 1.0f; + for (y = 0; y < head.biHeight; y++){ + info.nProgress = (long)(100*y/head.biHeight); // + if (info.nEscape) break; + pSource = info.pImage + y * info.dwEffWidth; + u = i = 0; + fEndX = xScale - 1.0f; + if ((float)y < fEndY) { // complete source row goes into dest row + for (x = 0; x < head.biWidth; x++){ + if ((float)x < fEndX){ // complete source pixel goes into dest pixel + for (j = 0; j < 3; j++) naAccu[i + j] += (*pSource++) * ACCURACY; + } else { // source pixel is splitted for 2 dest pixels + nWeightX = (long)(((float)x - fEndX) * ACCURACY); + for (j = 0; j < 3; j++){ + naAccu[i] += (ACCURACY - nWeightX) * (*pSource); + naAccu[3 + i++] += nWeightX * (*pSource++); + } + fEndX += xScale; + u++; + } + } + } else { // source row is splitted for 2 dest rows + nWeightY = (long)(((float)y - fEndY) * ACCURACY); + for (x = 0; x < head.biWidth; x++){ + if ((float)x < fEndX){ // complete source pixel goes into 2 pixel + for (j = 0; j < 3; j++){ + naAccu[i + j] += ((ACCURACY - nWeightY) * (*pSource)); + naCarry[i + j] += nWeightY * (*pSource++); + } + } else { // source pixel is splitted for 4 dest pixels + nWeightX = (int)(((float)x - fEndX) * ACCURACY); + for (j = 0; j < 3; j++) { + naAccu[i] += ((ACCURACY - nWeightY) * (ACCURACY - nWeightX)) * (*pSource) / ACCURACY; + *pDest++ = (BYTE)(naAccu[i] / nScale); + naCarry[i] += (nWeightY * (ACCURACY - nWeightX) * (*pSource)) / ACCURACY; + naAccu[i + 3] += ((ACCURACY - nWeightY) * nWeightX * (*pSource)) / ACCURACY; + naCarry[i + 3] = (nWeightY * nWeightX * (*pSource)) / ACCURACY; + i++; + pSource++; + } + fEndX += xScale; + u++; + } + } + if (u < newx){ // possibly not completed due to rounding errors + for (j = 0; j < 3; j++) *pDest++ = (BYTE)(naAccu[i++] / nScale); + } + naTemp = naCarry; + naCarry = naAccu; + naAccu = naTemp; + memset(naCarry, 0, sizeof(int) * 3); // need only to set first pixel zero + pDest = newImage.info.pImage + (++v * newImage.info.dwEffWidth); + fEndY += yScale; + } + } + if (v < newy){ // possibly not completed due to rounding errors + for (i = 0; i < 3 * newx; i++) *pDest++ = (BYTE)(naAccu[i] / nScale); + } + delete [] naAccu; + delete [] naCarry; + } + } + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()){ + newImage.AlphaCreate(); + for(long y=0; yTransfer(newImage); + else Transfer(newImage); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * New simpler resample. Adds new interpolation methods and simplifies code (using GetPixelColorInterpolated + * and GetAreaColorInterpolated). It also (unlike old method) interpolates alpha layer. + * + * \param newx, newy - size of resampled image + * \param inMethod - interpolation method to use (see comments at GetPixelColorInterpolated) + * If image size is being reduced, averaging is used instead (or simultaneously with) inMethod. + * \param ofMethod - what to replace outside pixels by (only significant for bordering pixels of enlarged image) + * \param iDst - pointer to destination CxImage or NULL. + * \param disableAveraging - force no averaging when shrinking images (Produces aliasing. + * You probably just want to leave this off...) + * + * \author ***bd*** 2.2004 + */ +bool CxImage::Resample2( + long newx, long newy, + InterpolationMethod const inMethod, + OverflowMethod const ofMethod, + CxImage* const iDst, + bool const disableAveraging) +{ + if (newx<=0 || newy<=0 || !pDib) return false; + + if (head.biWidth==newx && head.biHeight==newy) { + //image already correct size (just copy and return) + if (iDst) iDst->Copy(*this); + return true; + }//if + + //calculate scale of new image (less than 1 for enlarge) + float xScale, yScale; + xScale = (float)head.biWidth / (float)newx; + yScale = (float)head.biHeight / (float)newy; + + //create temporary destination image + CxImage newImage; + newImage.CopyInfo(*this); + newImage.Create(newx,newy,head.biBitCount,GetType()); + newImage.SetPalette(GetPalette()); + if (!newImage.IsValid()){ + strcpy(info.szLastError,newImage.GetLastError()); + return false; + } + + //and alpha channel if required +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) newImage.AlphaCreate(); + BYTE *pxptra = 0; // destination alpha data +#endif + + float sX, sY; //source location + long dX,dY; //destination pixel (int value) + if ((xScale<=1 && yScale<=1) || disableAveraging) { + //image is being enlarged (or interpolation on demand) + if (!IsIndexed()) { + //RGB24 image (optimized version with direct writes) + RGBQUAD q; //pixel colour + BYTE *pxptr; //pointer to destination pixel + for(dY=0; dYTransfer(newImage); + else + Transfer(newImage); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Reduces the number of bits per pixel to nbit (1, 4 or 8). + * ppal points to a valid palette for the final image; if not supplied the function will use a standard palette. + * ppal is not necessary for reduction to 1 bpp. + */ +bool CxImage::DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal, DWORD clrimportant) +{ + if (!pDib) return false; + if (head.biBitCount < nbit){ + strcpy(info.szLastError,"DecreaseBpp: target BPP greater than source BPP"); + return false; + } + if (head.biBitCount == nbit){ + if (clrimportant==0) return true; + if (head.biClrImportant && (head.biClrImportant4) return false; + + CxImage tmp; + tmp.CopyInfo(*this); + tmp.Create(head.biWidth,head.biHeight,4,info.dwType); + tmp.SetPalette(GetPalette(),GetNumColors()); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + +#if CXIMAGE_SUPPORT_SELECTION + tmp.SelectionCopy(*this); +#endif //CXIMAGE_SUPPORT_SELECTION + +#if CXIMAGE_SUPPORT_ALPHA + tmp.AlphaCopy(*this); +#endif //CXIMAGE_SUPPORT_ALPHA + + for (long y=0;y8) return false; + + CxImage tmp; + tmp.CopyInfo(*this); + tmp.Create(head.biWidth,head.biHeight,8,info.dwType); + tmp.SetPalette(GetPalette(),GetNumColors()); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + +#if CXIMAGE_SUPPORT_SELECTION + tmp.SelectionCopy(*this); +#endif //CXIMAGE_SUPPORT_SELECTION + +#if CXIMAGE_SUPPORT_ALPHA + tmp.AlphaCopy(*this); +#endif //CXIMAGE_SUPPORT_ALPHA + + for (long y=0;y24) return false; + + CxImage tmp; + tmp.CopyInfo(*this); + tmp.Create(head.biWidth,head.biHeight,24,info.dwType); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + if (info.nBkgndIndex>=0) //translate transparency + tmp.info.nBkgndColor=GetPaletteColor((BYTE)info.nBkgndIndex); + +#if CXIMAGE_SUPPORT_SELECTION + tmp.SelectionCopy(*this); +#endif //CXIMAGE_SUPPORT_SELECTION + +#if CXIMAGE_SUPPORT_ALPHA + tmp.AlphaCopy(*this); + if (AlphaPaletteIsValid() && !AlphaIsValid()) tmp.AlphaCreate(); +#endif //CXIMAGE_SUPPORT_ALPHA + + for (long y=0;y 128) { + tmp.SetPixelIndex(x, y, 1); + error = level - 255; + } else { + tmp.SetPixelIndex(x, y, 0); + error = level; + } + + nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 1, y, level); + nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 2, y, level); + int i; + for (i = -2; i < 3; i++) { + switch (i) { + case -2: + coeff = 2; + break; + case -1: + coeff = 4; + break; + case 0: + coeff = 8; + break; + case 1: + coeff = 4; + break; + case 2: + coeff = 2; + break; + } + nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + i, y + 1, level); + } + } + } + break; + } + case 3: + { + //Stucki error diffusion (Thanks to Franco Gerevini) + int TotalCoeffSum = 42; + long error, nlevel, coeff=1; + BYTE level; + + for (long y = 0; y < head.biHeight; y++) { + info.nProgress = (long)(100 * y / head.biHeight); + if (info.nEscape) + break; + for (long x = 0; x < head.biWidth; x++) { + level = BlindGetPixelIndex(x, y); + if (level > 128) { + tmp.SetPixelIndex(x, y, 1); + error = level - 255; + } else { + tmp.SetPixelIndex(x, y, 0); + error = level; + } + + nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 1, y, level); + nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 2, y, level); + int i; + for (i = -2; i < 3; i++) { + switch (i) { + case -2: + coeff = 2; + break; + case -1: + coeff = 4; + break; + case 0: + coeff = 8; + break; + case 1: + coeff = 4; + break; + case 2: + coeff = 2; + break; + } + nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + i, y + 1, level); + } + for (i = -2; i < 3; i++) { + switch (i) { + case -2: + coeff = 1; + break; + case -1: + coeff = 2; + break; + case 0: + coeff = 4; + break; + case 1: + coeff = 2; + break; + case 2: + coeff = 1; + break; + } + nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + i, y + 2, level); + } + } + } + break; + } + case 4: + { + //Jarvis, Judice and Ninke error diffusion (Thanks to Franco Gerevini) + int TotalCoeffSum = 48; + long error, nlevel, coeff=1; + BYTE level; + + for (long y = 0; y < head.biHeight; y++) { + info.nProgress = (long)(100 * y / head.biHeight); + if (info.nEscape) + break; + for (long x = 0; x < head.biWidth; x++) { + level = BlindGetPixelIndex(x, y); + if (level > 128) { + tmp.SetPixelIndex(x, y, 1); + error = level - 255; + } else { + tmp.SetPixelIndex(x, y, 0); + error = level; + } + + nlevel = GetPixelIndex(x + 1, y) + (error * 7) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 1, y, level); + nlevel = GetPixelIndex(x + 2, y) + (error * 5) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 2, y, level); + int i; + for (i = -2; i < 3; i++) { + switch (i) { + case -2: + coeff = 3; + break; + case -1: + coeff = 5; + break; + case 0: + coeff = 7; + break; + case 1: + coeff = 5; + break; + case 2: + coeff = 3; + break; + } + nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + i, y + 1, level); + } + for (i = -2; i < 3; i++) { + switch (i) { + case -2: + coeff = 1; + break; + case -1: + coeff = 3; + break; + case 0: + coeff = 5; + break; + case 1: + coeff = 3; + break; + case 2: + coeff = 1; + break; + } + nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + i, y + 2, level); + } + } + } + break; + } + case 5: + { + //Sierra error diffusion (Thanks to Franco Gerevini) + int TotalCoeffSum = 32; + long error, nlevel, coeff=1; + BYTE level; + + for (long y = 0; y < head.biHeight; y++) { + info.nProgress = (long)(100 * y / head.biHeight); + if (info.nEscape) + break; + for (long x = 0; x < head.biWidth; x++) { + level = BlindGetPixelIndex(x, y); + if (level > 128) { + tmp.SetPixelIndex(x, y, 1); + error = level - 255; + } else { + tmp.SetPixelIndex(x, y, 0); + error = level; + } + + nlevel = GetPixelIndex(x + 1, y) + (error * 5) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 1, y, level); + nlevel = GetPixelIndex(x + 2, y) + (error * 3) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + 2, y, level); + int i; + for (i = -2; i < 3; i++) { + switch (i) { + case -2: + coeff = 2; + break; + case -1: + coeff = 4; + break; + case 0: + coeff = 5; + break; + case 1: + coeff = 4; + break; + case 2: + coeff = 2; + break; + } + nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + i, y + 1, level); + } + for (i = -1; i < 2; i++) { + switch (i) { + case -1: + coeff = 2; + break; + case 0: + coeff = 3; + break; + case 1: + coeff = 2; + break; + } + nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(x + i, y + 2, level); + } + } + } + break; + } + case 6: + { + //Stevenson and Arce error diffusion (Thanks to Franco Gerevini) + int TotalCoeffSum = 200; + long error, nlevel; + BYTE level; + + for (long y = 0; y < head.biHeight; y++) { + info.nProgress = (long)(100 * y / head.biHeight); + if (info.nEscape) + break; + for (long x = 0; x < head.biWidth; x++) { + level = BlindGetPixelIndex(x, y); + if (level > 128) { + tmp.SetPixelIndex(x, y, 1); + error = level - 255; + } else { + tmp.SetPixelIndex(x, y, 0); + error = level; + } + + int tmp_index_x = x + 2; + int tmp_index_y = y; + int tmp_coeff = 32; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x - 3; + tmp_index_y = y + 1; + tmp_coeff = 12; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x - 1; + tmp_coeff = 26; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x + 1; + tmp_coeff = 30; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x + 3; + tmp_coeff = 16; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x - 2; + tmp_index_y = y + 2; + tmp_coeff = 12; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x; + tmp_coeff = 26; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x + 2; + tmp_coeff = 12; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x - 3; + tmp_index_y = y + 3; + tmp_coeff = 5; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x - 1; + tmp_coeff = 12; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x + 1; + tmp_coeff = 12; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + + tmp_index_x = x + 3; + tmp_coeff = 5; + nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum; + level = (BYTE)min(255, max(0, (int)nlevel)); + SetPixelIndex(tmp_index_x, tmp_index_y, level); + } + } + break; + } + case 7: + { + // Bayer ordered dither + int order = 4; + //create Bayer matrix + if (order>4) order = 4; + int size = (1 << (2*order)); + BYTE* Bmatrix = (BYTE*) malloc(size * sizeof(BYTE)); + for(int i = 0; i < size; i++) { + int n = order; + int x = i / n; + int y = i % n; + int dither = 0; + while (n-- > 0){ + dither = (((dither<<1)|((x&1) ^ (y&1)))<<1) | (y&1); + x >>= 1; + y >>= 1; + } + Bmatrix[i] = (BYTE)(dither); + } + + int scale = max(0,(8-2*order)); + int level; + for (long y=0;y> scale; + if(level > Bmatrix[ (x % order) + order * (y % order) ]){ + tmp.SetPixelIndex(x,y,1); + } else { + tmp.SetPixelIndex(x,y,0); + } + } + } + + free(Bmatrix); + + break; + } + default: + { + // Floyd-Steinberg error diffusion (Thanks to Steve McMahon) + long error,nlevel,coeff=1; + BYTE level; + + for (long y=0;y 128){ + tmp.SetPixelIndex(x,y,1); + error = level-255; + } else { + tmp.SetPixelIndex(x,y,0); + error = level; + } + + nlevel = GetPixelIndex(x+1,y) + (error * 7)/16; + level = (BYTE)min(255,max(0,(int)nlevel)); + SetPixelIndex(x+1,y,level); + for(int i=-1; i<2; i++){ + switch(i){ + case -1: + coeff=3; break; + case 0: + coeff=5; break; + case 1: + coeff=1; break; + } + nlevel = GetPixelIndex(x+i,y+1) + (error * coeff)/16; + level = (BYTE)min(255,max(0,(int)nlevel)); + SetPixelIndex(x+i,y+1,level); + } + } + } + } + } + + tmp.SetPaletteColor(0,0,0,0); + tmp.SetPaletteColor(1,255,255,255); + Transfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * CropRotatedRectangle + * \param topx,topy : topmost and leftmost point of the rectangle + (topmost, and if there are 2 topmost points, the left one) + * \param width : size of the right hand side of rect, from (topx,topy) roundwalking clockwise + * \param height : size of the left hand side of rect, from (topx,topy) roundwalking clockwise + * \param angle : angle of the right hand side of rect, from (topx,topy) + * \param iDst : pointer to destination image (if 0, this image is modified) + * \author [VATI] + */ +bool CxImage::CropRotatedRectangle( long topx, long topy, long width, long height, float angle, CxImage* iDst) +{ + if (!pDib) return false; + + + long startx,starty,endx,endy; + double cos_angle = cos(angle/*/57.295779513082320877*/); + double sin_angle = sin(angle/*/57.295779513082320877*/); + + // if there is nothing special, call the original Crop(): + if ( fabs(angle)<0.0002 ) + return Crop( topx, topy, topx+width, topy+height, iDst); + + startx = min(topx, topx - (long)(sin_angle*(double)height)); + endx = topx + (long)(cos_angle*(double)width); + endy = topy + (long)(cos_angle*(double)height + sin_angle*(double)width); + // check: corners of the rectangle must be inside + if ( IsInside( startx, topy )==false || + IsInside( endx, endy ) == false ) + return false; + + // first crop to bounding rectangle + CxImage tmp(*this, true, false, true); + // tmp.Copy(*this, true, false, true); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + if (!tmp.Crop( startx, topy, endx, endy)){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + // the midpoint of the image now became the same as the midpoint of the rectangle + // rotate new image with minus angle amount + if ( false == tmp.Rotate( (float)(-angle*57.295779513082320877) ) ) // Rotate expects angle in degrees + return false; + + // crop rotated image to the original selection rectangle + endx = (tmp.head.biWidth+width)/2; + startx = (tmp.head.biWidth-width)/2; + starty = (tmp.head.biHeight+height)/2; + endy = (tmp.head.biHeight-height)/2; + if ( false == tmp.Crop( startx, starty, endx, endy ) ) + return false; + + if (iDst) iDst->Transfer(tmp); + else Transfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::Crop(const RECT& rect, CxImage* iDst) +{ + return Crop(rect.left, rect.top, rect.right, rect.bottom, iDst); +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::Crop(long left, long top, long right, long bottom, CxImage* iDst) +{ + if (!pDib) return false; + + long startx = max(0L,min(left,head.biWidth)); + long endx = max(0L,min(right,head.biWidth)); + long starty = head.biHeight - max(0L,min(top,head.biHeight)); + long endy = head.biHeight - max(0L,min(bottom,head.biHeight)); + + if (startx==endx || starty==endy) return false; + + if (startx>endx) {long tmp=startx; startx=endx; endx=tmp;} + if (starty>endy) {long tmp=starty; starty=endy; endy=tmp;} + + CxImage tmp(endx-startx,endy-starty,head.biBitCount,info.dwType); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + tmp.SetPalette(GetPalette(),head.biClrUsed); + tmp.info.nBkgndIndex = info.nBkgndIndex; + tmp.info.nBkgndColor = info.nBkgndColor; + + switch (head.biBitCount) { + case 1: + case 4: + { + for(long y=starty, yd=0; y + for(long x=startx, xd=0; x> 3; + BYTE* pDest = tmp.info.pImage; + BYTE* pSrc = info.pImage + starty * info.dwEffWidth + (startx*head.biBitCount >> 3); + for(long y=starty; y + memcpy(pDest,pSrc,linelen); + pDest+=tmp.info.dwEffWidth; + pSrc+=info.dwEffWidth; + } + } + } + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()){ // + tmp.AlphaCreate(); + if (!tmp.AlphaIsValid()) return false; + BYTE* pDest = tmp.pAlpha; + BYTE* pSrc = pAlpha + startx + starty*head.biWidth; + for (long y=starty; yTransfer(tmp); + else Transfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * \param xgain, ygain : can be from 0 to 1. + * \param xpivot, ypivot : is the center of the transformation. + * \param bEnableInterpolation : if true, enables bilinear interpolation. + * \return true if everything is ok + */ +bool CxImage::Skew(float xgain, float ygain, long xpivot, long ypivot, bool bEnableInterpolation) +{ + if (!pDib) return false; + float nx,ny; + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + long xmin,xmax,ymin,ymax; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + for(long y=ymin; y top) || (x < left) || (x > right)) { + tmp.SetPixelIndex(x,y, pixel); + } else { + tmp.SetPixelIndex(x,y,GetPixelIndex(x-left,y-bottom)); + } + } + } + break; + } + case 8: + case 24: + { + if (head.biBitCount == 8) { + BYTE pixel = tmp.GetNearestIndex( canvascolor); + memset(tmp.info.pImage, pixel, + (tmp.info.dwEffWidth * newHeight)); + } else { + for (long y = 0; y < newHeight; ++y) { + BYTE *pDest = tmp.info.pImage + (y * tmp.info.dwEffWidth); + for (long x = 0; x < newWidth; ++x) { + *pDest++ = canvascolor.rgbBlue; + *pDest++ = canvascolor.rgbGreen; + *pDest++ = canvascolor.rgbRed; + } + } + } + + BYTE* pDest = tmp.info.pImage + (tmp.info.dwEffWidth * bottom) + (left*(head.biBitCount >> 3)); + BYTE* pSrc = info.pImage; + for(long y=bottom; y <= top; y++){ + info.nProgress = (long)(100*y/(1 + top - bottom)); + memcpy(pDest,pSrc,(head.biBitCount >> 3) * (right - left + 1)); + pDest+=tmp.info.dwEffWidth; + pSrc+=info.dwEffWidth; + } + } + } + +#if CXIMAGE_SUPPORT_SELECTION + if (SelectionIsValid()){ + if (!tmp.SelectionCreate()) + return false; + BYTE* pSrc = SelectionGetPointer(); + BYTE* pDst = tmp.SelectionGetPointer(left,bottom); + for(long y=bottom; y <= top; y++){ + memcpy(pDst,pSrc, (right - left + 1)); + pSrc+=head.biWidth; + pDst+=tmp.head.biWidth; + } + tmp.info.rSelectionBox.left = info.rSelectionBox.left + left; + tmp.info.rSelectionBox.right = info.rSelectionBox.right + left; + tmp.info.rSelectionBox.top = info.rSelectionBox.top + bottom; + tmp.info.rSelectionBox.bottom = info.rSelectionBox.bottom + bottom; + } +#endif //CXIMAGE_SUPPORT_SELECTION + +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()){ + if (!tmp.AlphaCreate()) + return false; + tmp.AlphaSet(canvascolor.rgbReserved); + BYTE* pSrc = AlphaGetPointer(); + BYTE* pDst = tmp.AlphaGetPointer(left,bottom); + for(long y=bottom; y <= top; y++){ + memcpy(pDst,pSrc, (right - left + 1)); + pSrc+=head.biWidth; + pDst+=tmp.head.biWidth; + } + } +#endif //CXIMAGE_SUPPORT_ALPHA + + //select the destination + if (iDst) iDst->Transfer(tmp); + else Transfer(tmp); + + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImage::Expand(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst) +{ + //thanks to + + if (!pDib) return false; + + if ((newx < head.biWidth) || (newy < head.biHeight)) return false; + + int nAddLeft = (newx - head.biWidth) / 2; + int nAddTop = (newy - head.biHeight) / 2; + + return Expand(nAddLeft, nAddTop, newx - (head.biWidth + nAddLeft), newy - (head.biHeight + nAddTop), canvascolor, iDst); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Resamples the image with the correct aspect ratio, and fills the borders. + * \param newx, newy = thumbnail size. + * \param canvascolor = border color. + * \param iDst = pointer to destination image (if it's 0, this image is modified). + * \return true if everything is ok. + * \author [Colin Urquhart] + */ +bool CxImage::Thumbnail(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst) +{ + if (!pDib) return false; + + if ((newx <= 0) || (newy <= 0)) return false; + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + // determine whether we need to shrink the image + if ((head.biWidth > newx) || (head.biHeight > newy)) { + float fScale; + float fAspect = (float) newx / (float) newy; + if (fAspect * head.biHeight > head.biWidth) { + fScale = (float) newy / head.biHeight; + } else { + fScale = (float) newx / head.biWidth; + } + tmp.Resample((long) (fScale * head.biWidth), (long) (fScale * head.biHeight), 0); + } + + // expand the frame + tmp.Expand(newx, newy, canvascolor, iDst); + + //select the destination + if (iDst) iDst->Transfer(tmp); + else Transfer(tmp); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Perform circle_based transformations. + * \param type - for different transformations + * - 0 for normal (proturberant) FishEye + * - 1 for reverse (concave) FishEye + * - 2 for Swirle + * - 3 for Cilinder mirror + * - 4 for bathroom + * + * \param rmax - effect radius. If 0, the whole image is processed + * \param Koeff - only for swirle + * \author Arkadiy Olovyannikov ark(at)msun(dot)ru + */ +bool CxImage::CircleTransform(int type,long rmax,float Koeff) +{ + if (!pDib) return false; + + long nx,ny; + double angle,radius,rnew; + + CxImage tmp(*this); + if (!tmp.IsValid()){ + strcpy(info.szLastError,tmp.GetLastError()); + return false; + } + + long xmin,xmax,ymin,ymax,xmid,ymid; + if (pSelection){ + xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right; + ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top; + } else { + xmin = ymin = 0; + xmax = head.biWidth; ymax=head.biHeight; + } + + xmid = (long) (tmp.GetWidth()/2); + ymid = (long) (tmp.GetHeight()/2); + + if (!rmax) rmax=(long)sqrt((float)((xmid-xmin)*(xmid-xmin)+(ymid-ymin)*(ymid-ymin))); + if (Koeff==0.0f) Koeff=1.0f; + + for(long y=ymin; yhead.biWidth || newy>head.biHeight) { + //let me repeat... this method can't enlarge image + strcpy(info.szLastError,"QIShrink can't enlarge image"); + return false; + } + + if (newx==head.biWidth && newy==head.biHeight) { + //image already correct size (just copy and return) + if (iDst) iDst->Copy(*this); + return true; + }//if + + //create temporary destination image + CxImage newImage; + newImage.CopyInfo(*this); + newImage.Create(newx,newy,(bChangeBpp)?24:head.biBitCount,GetType()); + newImage.SetPalette(GetPalette()); + if (!newImage.IsValid()){ + strcpy(info.szLastError,newImage.GetLastError()); + return false; + } + + //and alpha channel if required +#if CXIMAGE_SUPPORT_ALPHA + if (AlphaIsValid()) newImage.AlphaCreate(); +#endif + + const int oldx = head.biWidth; + const int oldy = head.biHeight; + + int accuCellSize = 4; +#if CXIMAGE_SUPPORT_ALPHA + BYTE *alphaPtr; + if (AlphaIsValid()) accuCellSize=5; +#endif + + unsigned int *accu = new unsigned int[newx*accuCellSize]; //array for suming pixels... one pixel for every destination column + unsigned int *accuPtr; //pointer for walking through accu + //each cell consists of blue, red, green component and count of pixels summed in this cell + memset(accu, 0, newx * accuCellSize * sizeof(unsigned int)); //clear accu + + if (!IsIndexed()) { + //RGB24 version with pointers + BYTE *destPtr, *srcPtr, *destPtrS, *srcPtrS; //destination and source pixel, and beginnings of current row + srcPtrS=(BYTE*)BlindGetPixelPointer(0,0); + destPtrS=(BYTE*)newImage.BlindGetPixelPointer(0,0); + int ex=0, ey=0; //ex and ey replace division... + int dy=0; + //(we just add pixels, until by adding newx or newy we get a number greater than old size... then + // it's time to move to next pixel) + + for(int y=0; yoldx) { //when we reach oldx, it's time to move to new slot + accuPtr += accuCellSize; + ex -= oldx; //(substract oldx from ex and resume from there on) + }//if (ex overflow) + }//for x + + if (ey>=oldy) { //now when this happens + ey -= oldy; //it's time to move to new destination row + destPtr = destPtrS; //reset pointers to proper initial values + accuPtr = accu; +#if CXIMAGE_SUPPORT_ALPHA + alphaPtr = newImage.AlphaGetPointer(0, dy++); +#endif + for (int k=0; koldx) { //when we reach oldx, it's time to move to new slot + accuPtr += accuCellSize; + ex -= oldx; //(substract oldx from ex and resume from there on) + }//if (ex overflow) + }//for x + + if (ey>=oldy) { //now when this happens + ey -= oldy; //it's time to move to new destination row + accuPtr = accu; + for (int dx=0; dxTransfer(newImage); + else + Transfer(newImage); + return true; + +} + +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_TRANSFORMATION diff --git a/utilities/CxImage/ximawbmp.cpp b/utilities/CxImage/ximawbmp.cpp index bbf6683..6b9151e 100644 --- a/utilities/CxImage/ximawbmp.cpp +++ b/utilities/CxImage/ximawbmp.cpp @@ -1,134 +1,134 @@ -/* - * File: ximawbmp.cpp - * Purpose: Platform Independent WBMP Image Class Loader and Writer - * 12/Jul/2002 Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximawbmp.h" - -#if CXIMAGE_SUPPORT_WBMP - -#include "ximaiter.h" - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageWBMP::Decode(CxFile *hFile) -{ - if (hFile == NULL) return false; - - WBMPHEADER wbmpHead; - - cx_try - { - ReadOctet(hFile, &wbmpHead.Type); - - DWORD dat; - ReadOctet(hFile, &dat); - wbmpHead.FixHeader = (BYTE)dat; - - ReadOctet(hFile, &wbmpHead.ImageWidth); - ReadOctet(hFile, &wbmpHead.ImageHeight); - - if (hFile->Eof()) - cx_throw("Not a WBMP"); - - if (wbmpHead.Type != 0) - cx_throw("Unsupported WBMP type"); - - head.biWidth = wbmpHead.ImageWidth; - head.biHeight= wbmpHead.ImageHeight; - - if (head.biWidth<=0 || head.biHeight<=0) - cx_throw("Corrupted WBMP"); - - if (info.nEscape == -1){ - info.dwType = CXIMAGE_FORMAT_WBMP; - return true; - } - - Create(head.biWidth, head.biHeight, 1, CXIMAGE_FORMAT_WBMP); - if (!IsValid()) cx_throw("WBMP Create failed"); - SetGrayPalette(); - - int linewidth=(head.biWidth+7)/8; - CImageIterator iter(this); - iter.Upset(); - for (long y=0; y < head.biHeight; y++){ - hFile->Read(iter.GetRow(),linewidth,1); - iter.PrevRow(); - } - - } cx_catch { - if (strcmp(message,"")) strncpy(info.szLastError,message,255); - return FALSE; - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImageWBMP::ReadOctet(CxFile * hFile, DWORD *data) -{ - BYTE c; - *data = 0; - do { - if (hFile->Eof()) return false; - c = (BYTE)hFile->GetC(); - *data <<= 7; - *data |= (c & 0x7F); - } while ((c&0x80)!=0); - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageWBMP::Encode(CxFile * hFile) -{ - if (EncodeSafeCheck(hFile)) return false; - - //check format limits - if (head.biBitCount!=1){ - strcpy(info.szLastError,"Can't save this image as WBMP"); - return false; - } - - WBMPHEADER wbmpHead; - wbmpHead.Type=0; - wbmpHead.FixHeader=0; - wbmpHead.ImageWidth=head.biWidth; - wbmpHead.ImageHeight=head.biHeight; - - // Write the file header - hFile->PutC('\0'); - hFile->PutC('\0'); - WriteOctet(hFile,wbmpHead.ImageWidth); - WriteOctet(hFile,wbmpHead.ImageHeight); - // Write the pixels - int linewidth=(wbmpHead.ImageWidth+7)/8; - CImageIterator iter(this); - iter.Upset(); - for (DWORD y=0; y < wbmpHead.ImageHeight; y++){ - hFile->Write(iter.GetRow(),linewidth,1); - iter.PrevRow(); - } - return true; -} -//////////////////////////////////////////////////////////////////////////////// -bool CxImageWBMP::WriteOctet(CxFile * hFile, const DWORD data) -{ - int ns = 0; - while (data>>(ns+7)) ns+=7; - while (ns>0){ - if (!hFile->PutC(0x80 | (BYTE)(data>>ns))) return false; - ns-=7; - } - if (!(hFile->PutC((BYTE)(0x7F & data)))) return false; - return true; -} -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_ENCODE -//////////////////////////////////////////////////////////////////////////////// -#endif // CXIMAGE_SUPPORT_WBMP - +/* + * File: ximawbmp.cpp + * Purpose: Platform Independent WBMP Image Class Loader and Writer + * 12/Jul/2002 Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximawbmp.h" + +#if CXIMAGE_SUPPORT_WBMP + +#include "ximaiter.h" + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageWBMP::Decode(CxFile *hFile) +{ + if (hFile == NULL) return false; + + WBMPHEADER wbmpHead; + + cx_try + { + ReadOctet(hFile, &wbmpHead.Type); + + DWORD dat; + ReadOctet(hFile, &dat); + wbmpHead.FixHeader = (BYTE)dat; + + ReadOctet(hFile, &wbmpHead.ImageWidth); + ReadOctet(hFile, &wbmpHead.ImageHeight); + + if (hFile->Eof()) + cx_throw("Not a WBMP"); + + if (wbmpHead.Type != 0) + cx_throw("Unsupported WBMP type"); + + head.biWidth = wbmpHead.ImageWidth; + head.biHeight= wbmpHead.ImageHeight; + + if (head.biWidth<=0 || head.biHeight<=0) + cx_throw("Corrupted WBMP"); + + if (info.nEscape == -1){ + info.dwType = CXIMAGE_FORMAT_WBMP; + return true; + } + + Create(head.biWidth, head.biHeight, 1, CXIMAGE_FORMAT_WBMP); + if (!IsValid()) cx_throw("WBMP Create failed"); + SetGrayPalette(); + + int linewidth=(head.biWidth+7)/8; + CImageIterator iter(this); + iter.Upset(); + for (long y=0; y < head.biHeight; y++){ + hFile->Read(iter.GetRow(),linewidth,1); + iter.PrevRow(); + } + + } cx_catch { + if (strcmp(message,"")) strncpy(info.szLastError,message,255); + return FALSE; + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImageWBMP::ReadOctet(CxFile * hFile, DWORD *data) +{ + BYTE c; + *data = 0; + do { + if (hFile->Eof()) return false; + c = (BYTE)hFile->GetC(); + *data <<= 7; + *data |= (c & 0x7F); + } while ((c&0x80)!=0); + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageWBMP::Encode(CxFile * hFile) +{ + if (EncodeSafeCheck(hFile)) return false; + + //check format limits + if (head.biBitCount!=1){ + strcpy(info.szLastError,"Can't save this image as WBMP"); + return false; + } + + WBMPHEADER wbmpHead; + wbmpHead.Type=0; + wbmpHead.FixHeader=0; + wbmpHead.ImageWidth=head.biWidth; + wbmpHead.ImageHeight=head.biHeight; + + // Write the file header + hFile->PutC('\0'); + hFile->PutC('\0'); + WriteOctet(hFile,wbmpHead.ImageWidth); + WriteOctet(hFile,wbmpHead.ImageHeight); + // Write the pixels + int linewidth=(wbmpHead.ImageWidth+7)/8; + CImageIterator iter(this); + iter.Upset(); + for (DWORD y=0; y < wbmpHead.ImageHeight; y++){ + hFile->Write(iter.GetRow(),linewidth,1); + iter.PrevRow(); + } + return true; +} +//////////////////////////////////////////////////////////////////////////////// +bool CxImageWBMP::WriteOctet(CxFile * hFile, const DWORD data) +{ + int ns = 0; + while (data>>(ns+7)) ns+=7; + while (ns>0){ + if (!hFile->PutC(0x80 | (BYTE)(data>>ns))) return false; + ns-=7; + } + if (!(hFile->PutC((BYTE)(0x7F & data)))) return false; + return true; +} +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_ENCODE +//////////////////////////////////////////////////////////////////////////////// +#endif // CXIMAGE_SUPPORT_WBMP + diff --git a/utilities/CxImage/ximawbmp.h b/utilities/CxImage/ximawbmp.h index 8103345..f523684 100644 --- a/utilities/CxImage/ximawbmp.h +++ b/utilities/CxImage/ximawbmp.h @@ -1,49 +1,49 @@ -/* - * File: ximawbmp.h - * Purpose: WBMP Image Class Loader and Writer - */ -/* ========================================================== - * CxImageWBMP (c) 12/Jul/2002 Davide Pizzolato - www.xdp.it - * For conditions of distribution and use, see copyright notice in ximage.h - * ========================================================== - */ -#if !defined(__ximaWBMP_h) -#define __ximaWBMP_h - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_WBMP - -class CxImageWBMP: public CxImage -{ -#pragma pack(1) -typedef struct tagWbmpHeader -{ - DWORD Type; // 0 - BYTE FixHeader; // 0 - DWORD ImageWidth; // Image Width - DWORD ImageHeight; // Image Height -} WBMPHEADER; -#pragma pack() -public: - CxImageWBMP(): CxImage(CXIMAGE_FORMAT_WBMP) {} - -// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_WBMP);} -// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_WBMP);} - bool Decode(CxFile * hFile); - bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } -protected: - bool ReadOctet(CxFile * hFile, DWORD *data); - -public: -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -protected: - bool WriteOctet(CxFile * hFile, const DWORD data); -#endif // CXIMAGE_SUPPORT_ENCODE -}; - -#endif - -#endif +/* + * File: ximawbmp.h + * Purpose: WBMP Image Class Loader and Writer + */ +/* ========================================================== + * CxImageWBMP (c) 12/Jul/2002 Davide Pizzolato - www.xdp.it + * For conditions of distribution and use, see copyright notice in ximage.h + * ========================================================== + */ +#if !defined(__ximaWBMP_h) +#define __ximaWBMP_h + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_WBMP + +class CxImageWBMP: public CxImage +{ +#pragma pack(1) +typedef struct tagWbmpHeader +{ + DWORD Type; // 0 + BYTE FixHeader; // 0 + DWORD ImageWidth; // Image Width + DWORD ImageHeight; // Image Height +} WBMPHEADER; +#pragma pack() +public: + CxImageWBMP(): CxImage(CXIMAGE_FORMAT_WBMP) {} + +// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_WBMP);} +// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_WBMP);} + bool Decode(CxFile * hFile); + bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); } +protected: + bool ReadOctet(CxFile * hFile, DWORD *data); + +public: +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +protected: + bool WriteOctet(CxFile * hFile, const DWORD data); +#endif // CXIMAGE_SUPPORT_ENCODE +}; + +#endif + +#endif diff --git a/utilities/CxImage/ximawmf.cpp b/utilities/CxImage/ximawmf.cpp index 97ebf12..1ca3080 100644 --- a/utilities/CxImage/ximawmf.cpp +++ b/utilities/CxImage/ximawmf.cpp @@ -1,483 +1,483 @@ -/* -********************************************************************* - * File: ximawmf.cpp - * Purpose: Windows Metafile Class Loader and Writer - * Author: Volker Horch - vhorch@gmx.de - * created: 13-Jun-2002 - * - * Note: If the code below works, i wrote it. - * If it doesn't work, i don't know who wrote it. -********************************************************************* - */ - -/* -********************************************************************* - Note by Author: -********************************************************************* - - Metafile Formats: - ================= - - There are 2 kinds of Windows Metafiles: - - Standard Windows Metafile - - Placeable Windows Metafile - - A StandardWindows Metafile looks like: - - Metafile Header (MEATAHEADER) - - Metafile Records - - A Placeable Metafile looks like: - - Aldus Header (METAFILEHEADER) - - Metafile Header (METAHEADER) - - Metafile Records - - The "Metafile Header" and the "Metafile Records" are the same - for both formats. However, the Standard Metafile does not contain any - information about the original dimensions or x/y ratio of the Metafile. - - I decided, to allow only placeable Metafiles here. If you also want to - enable Standard Metafiles, you will have to guess the dimensions of - the image. - -********************************************************************* - Limitations: see ximawmf.h - you may configure some stuff there -********************************************************************* -*/ - -#include "ximawmf.h" - -#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -bool CxImageWMF::Decode(CxFile *hFile, long nForceWidth, long nForceHeight) -{ - if (hFile == NULL) return false; - - HENHMETAFILE hMeta; - HDC hDC; - int cx,cy; - - //save the current position of the file - long pos = hFile->Tell(); - - // Read the Metafile and convert to an Enhanced Metafile - METAFILEHEADER mfh; - hMeta = ConvertWmfFiletoEmf(hFile, &mfh); - if (hMeta) { // ok, it's a WMF - -///////////////////////////////////////////////////////////////////// -// We use the original WMF size information, because conversion to -// EMF adjusts the Metafile to Full Screen or does not set rclBounds at all -// ENHMETAHEADER emh; -// UINT uRet; -// uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile -// sizeof(ENHMETAHEADER), // size of buffer, in bytes -// &emh); // address of buffer to receive data -// if (!uRet){ -// DeleteEnhMetaFile(hMeta); -// return false; -// } -// // calculate size -// cx = emh.rclBounds.right - emh.rclBounds.left; -// cy = emh.rclBounds.bottom - emh.rclBounds.top; -///////////////////////////////////////////////////////////////////// - - // calculate size - // scale the metafile (pixels/inch of metafile => pixels/inch of display) - // mfh.inch already checked to be <> 0 - - hDC = ::GetDC(0); - int cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX); - int cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY); - ::ReleaseDC(0, hDC); - - cx = (mfh.inch/2 + (mfh.bbox.right - mfh.bbox.left) * cx1) / mfh.inch; - cy = (mfh.inch/2 + (mfh.bbox.bottom - mfh.bbox.top) * cy1) / mfh.inch; - - } else { // maybe it's an EMF... - - hFile->Seek(pos,SEEK_SET); - - ENHMETAHEADER emh; - hMeta = ConvertEmfFiletoEmf(hFile, &emh); - - if (!hMeta){ - strcpy(info.szLastError,"corrupted WMF"); - return false; // definitively give up - } - - // ok, it's an EMF; calculate canvas size - cx = emh.rclBounds.right - emh.rclBounds.left; - cy = emh.rclBounds.bottom - emh.rclBounds.top; - - // alternative methods, sometime not so reliable... [DP] - //cx = emh.szlDevice.cx; - //cy = emh.szlDevice.cy; - // - //hDC = ::GetDC(0); - //float hscale = (float)GetDeviceCaps(hDC, HORZRES)/(100.0f * GetDeviceCaps(hDC, HORZSIZE)); - //float vscale = (float)GetDeviceCaps(hDC, VERTRES)/(100.0f * GetDeviceCaps(hDC, VERTSIZE)); - //::ReleaseDC(0, hDC); - //cx = (long)((emh.rclFrame.right - emh.rclFrame.left) * hscale); - //cy = (long)((emh.rclFrame.bottom - emh.rclFrame.top) * vscale); - } - - if (info.nEscape == -1) { // Check if cancelled - head.biWidth = cx; - head.biHeight= cy; - info.dwType = CXIMAGE_FORMAT_WMF; - DeleteEnhMetaFile(hMeta); - strcpy(info.szLastError,"output dimensions returned"); - return true; - } - - if (!cx || !cy) { - DeleteEnhMetaFile(hMeta); - strcpy(info.szLastError,"empty WMF"); - return false; - } - - if (nForceWidth) cx=nForceWidth; - if (nForceHeight) cy=nForceHeight; - ShrinkMetafile(cx, cy); // !! Otherwise Bitmap may have bombastic size - - HDC hDC0 = ::GetDC(0); // DC of screen - HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display - hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen - ::ReleaseDC(0, hDC0); // don't need anymore. get rid of it. - - if (hDC){ - if (hBitmap){ - RECT rc = {0,0,cx,cy}; - int bpp = ::GetDeviceCaps(hDC, BITSPIXEL); - - HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap); - - // clear out the entire bitmap with windows background - // because the MetaFile may not contain background information - DWORD dwBack = XMF_COLOR_BACK; -#if XMF_SUPPORT_TRANSPARENCY - if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT; -#endif - DWORD OldColor = SetBkColor(hDC, dwBack); - ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); - SetBkColor(hDC, OldColor); - - //retrieves optional palette entries from the specified enhanced metafile - PLOGPALETTE plogPal; - PBYTE pjTmp; - HPALETTE hPal; - int iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL); - if (iEntries) { - if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, - sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) { - DeleteObject(hBitmap); - DeleteDC(hDC); - DeleteEnhMetaFile(hMeta); - strcpy(info.szLastError,"Cancelled"); - return false; - } - - plogPal->palVersion = 0x300; - plogPal->palNumEntries = (WORD) iEntries; - pjTmp = (PBYTE) plogPal; - pjTmp += 4; - - GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp); - hPal = CreatePalette(plogPal); - GlobalFree(plogPal); - - SelectPalette(hDC, hPal, FALSE); - RealizePalette(hDC); - } - - // Play the Metafile into Memory DC - BOOL bRet = PlayEnhMetaFile(hDC, // handle to a device context - hMeta, // handle to an enhanced metafile - &rc); // pointer to bounding rectangle - - SelectObject(hDC, hBitmapOld); - DeleteEnhMetaFile(hMeta); // we are done with this one - - if (info.nEscape) { // Check if cancelled - DeleteObject(hBitmap); - DeleteDC(hDC); - strcpy(info.szLastError,"Cancelled"); - return false; - } - - // the Bitmap now has the image. - // Create our DIB and convert the DDB into DIB - if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) { - DeleteObject(hBitmap); - DeleteDC(hDC); - return false; - } - -#if XMF_SUPPORT_TRANSPARENCY - if (bpp == 24) { - RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT }; - SetTransColor(rgbTrans); - } -#endif - // We're finally ready to get the DIB. Call the driver and let - // it party on our bitmap. It will fill in the color table, - // and bitmap bits of our global memory block. - bRet = GetDIBits(hDC, hBitmap, 0, - (UINT)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS); - - DeleteObject(hBitmap); - DeleteDC(hDC); - - return (bRet!=0); - } else { - DeleteDC(hDC); - } - } else { - if (hBitmap) DeleteObject(hBitmap); - } - - DeleteEnhMetaFile(hMeta); - - return false; -} - -/********************************************************************** - Function: CheckMetafileHeader - Purpose: Check if the Metafileheader of a file is valid -**********************************************************************/ -BOOL CxImageWMF::CheckMetafileHeader(METAFILEHEADER *metafileheader) -{ - WORD *pw; - WORD cs; - int i; - - // check magic # - if (metafileheader->key != 0x9ac6cdd7L) return false; - - // test checksum of header - pw = (WORD *)metafileheader; - cs = *pw; - pw++; - for (i = 0; i < 9; i++) { - cs ^= *pw; - pw++; - } - - if (cs != metafileheader->checksum) return false; - - // check resolution - if ((metafileheader->inch <= 0) || (metafileheader->inch > 2540)) return false; - - return true; -} - -/********************************************************************** - Function: ConvertWmfFiletoEmf - Purpose: Converts a Windows Metafile into an Enhanced Metafile -**********************************************************************/ -HENHMETAFILE CxImageWMF::ConvertWmfFiletoEmf(CxFile *fp, METAFILEHEADER *metafileheader) -{ - HENHMETAFILE hMeta; - long lenFile; - long len; - BYTE *p; - METAHEADER mfHeader; - DWORD seekpos; - - hMeta = 0; - - // get length of the file - lenFile = fp->Size(); - - // a placeable metafile starts with a METAFILEHEADER - // read it and check metafileheader - len = fp->Read(metafileheader, 1, sizeof(METAFILEHEADER)); - if (len < sizeof(METAFILEHEADER)) return (hMeta); - - if (CheckMetafileHeader(metafileheader)) { - // This is a placeable metafile - // Convert the placeable format into something that can - // be used with GDI metafile functions - seekpos = sizeof(METAFILEHEADER); - } else { - // Not a placeable wmf. A windows metafile? - // at least not scaleable. - // we could try to convert, but would loose ratio. don't allow this - return (hMeta); - - //metafileheader->bbox.right = ?; - //metafileheader->bbox.left = ?; - //metafileheader->bbox.bottom = ?; - //metafileheader->bbox.top = ?; - //metafileheader->inch = ?; - // - //seekpos = 0; - // fp->Seek(0, SEEK_SET); // rewind - } - - // At this point we have a metaheader regardless of whether - // the metafile was a windows metafile or a placeable metafile - // so check to see if it is valid. There is really no good - // way to do this so just make sure that the mtType is either - // 1 or 2 (memory or disk file) - // in addition we compare the length of the METAHEADER against - // the length of the file. if filelength < len => no Metafile - - len = fp->Read(&mfHeader, 1, sizeof(METAHEADER)); - if (len < sizeof(METAHEADER)) return (hMeta); - - if ((mfHeader.mtType != 1) && (mfHeader.mtType != 2)) return (hMeta); - - // Length in Bytes from METAHEADER - len = mfHeader.mtSize * 2; - if (len > lenFile) return (hMeta); - - // Allocate memory for the metafile bits - p = (BYTE *)malloc(len); - if (!p) return (hMeta); - - // seek back to METAHEADER and read all the stuff at once - fp->Seek(seekpos, SEEK_SET); - lenFile = fp->Read(p, 1, len); - if (lenFile != len) { - free(p); - return (hMeta); - } - - // the following (commented code) works, but adjusts rclBound of the - // Enhanced Metafile to full screen. - // the METAFILEHEADER from above is needed to scale the image - -// hMeta = SetWinMetaFileBits(len, p, NULL, NULL); - - // scale the metafile (pixels/inch of metafile => pixels/inch of display) - - METAFILEPICT mfp; - int cx1, cy1; - HDC hDC; - - hDC = ::GetDC(0); - cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX); - cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY); - - memset(&mfp, 0, sizeof(mfp)); - - mfp.mm = MM_ANISOTROPIC; - mfp.xExt = 10000; //(metafileheader->bbox.right - metafileheader->bbox.left) * cx1 / metafileheader->inch; - mfp.yExt = 10000; //(metafileheader->bbox.bottom - metafileheader->bbox.top) * cy1 / metafileheader->inch; - mfp.hMF = 0; - - // in MM_ANISOTROPIC mode xExt and yExt are in MM_HIENGLISH - // MM_HIENGLISH means: Each logical unit is converted to 0.001 inch - //mfp.xExt *= 1000; - //mfp.yExt *= 1000; - // ???? - //int k = 332800 / ::GetSystemMetrics(SM_CXSCREEN); - //mfp.xExt *= k; mfp.yExt *= k; - - // fix for Win9x - while ((mfp.xExt < 6554) && (mfp.yExt < 6554)) - { - mfp.xExt *= 10; - mfp.yExt *= 10; - } - - hMeta = SetWinMetaFileBits(len, p, hDC, &mfp); - - if (!hMeta){ //try 2nd conversion using a different mapping - mfp.mm = MM_TEXT; - hMeta = SetWinMetaFileBits(len, p, hDC, &mfp); - } - - ::ReleaseDC(0, hDC); - - // Free Memory - free(p); - - return (hMeta); -} -///////////////////////////////////////////////////////////////////// -HENHMETAFILE CxImageWMF::ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh) -{ - HENHMETAFILE hMeta; - long iLen = pFile->Size(); - - // Check the header first: - long pos = pFile->Tell(); - long iLenRead = pFile->Read(pemfh, 1, sizeof(ENHMETAHEADER)); - if (iLenRead < sizeof(ENHMETAHEADER)) return NULL; - if (pemfh->iType != EMR_HEADER) return NULL; - if (pemfh->dSignature != ENHMETA_SIGNATURE) return NULL; - //if (pemfh->nBytes != (DWORD)iLen) return NULL; - pFile->Seek(pos,SEEK_SET); - - BYTE* pBuff = (BYTE *)malloc(iLen); - if (!pBuff) return (FALSE); - - // Read the Enhanced Metafile - iLenRead = pFile->Read(pBuff, 1, iLen); - if (iLenRead != iLen) { - free(pBuff); - return NULL; - } - - // Make it a Memory Metafile - hMeta = SetEnhMetaFileBits(iLen, pBuff); - - free(pBuff); // finished with this one - - if (!hMeta) return NULL; // oops. - - // Get the Enhanced Metafile Header - UINT uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile - sizeof(ENHMETAHEADER), // size of buffer, in bytes - pemfh); // address of buffer to receive data - - if (!uRet) { - DeleteEnhMetaFile(hMeta); - return NULL; - } - - return (hMeta); -} -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_DECODE -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_ENCODE -///////////////////////////////////////////////////////////////////// -bool CxImageWMF::Encode(CxFile * hFile) -{ - if (hFile == NULL) return false; - strcpy(info.szLastError, "Save WMF not supported"); - return false; -} -#endif // CXIMAGE_SUPPORT_ENCODE -///////////////////////////////////////////////////////////////////// - -/********************************************************************** -Function: ShrinkMetafile -Purpose: Shrink the size of a metafile to be not larger than - the definition -**********************************************************************/ -void CxImageWMF::ShrinkMetafile(int &cx, int &cy) -{ - int xScreen = XMF_MAXSIZE_CX; - int yScreen = XMF_MAXSIZE_CY; - - if (cx > xScreen){ - cy = cy * xScreen / cx; - cx = xScreen; - } - - if (cy > yScreen){ - cx = cx * yScreen / cy; - cy = yScreen; - } -} - -#endif // CIMAGE_SUPPORT_WMF - +/* +********************************************************************* + * File: ximawmf.cpp + * Purpose: Windows Metafile Class Loader and Writer + * Author: Volker Horch - vhorch@gmx.de + * created: 13-Jun-2002 + * + * Note: If the code below works, i wrote it. + * If it doesn't work, i don't know who wrote it. +********************************************************************* + */ + +/* +********************************************************************* + Note by Author: +********************************************************************* + + Metafile Formats: + ================= + + There are 2 kinds of Windows Metafiles: + - Standard Windows Metafile + - Placeable Windows Metafile + + A StandardWindows Metafile looks like: + - Metafile Header (MEATAHEADER) + - Metafile Records + + A Placeable Metafile looks like: + - Aldus Header (METAFILEHEADER) + - Metafile Header (METAHEADER) + - Metafile Records + + The "Metafile Header" and the "Metafile Records" are the same + for both formats. However, the Standard Metafile does not contain any + information about the original dimensions or x/y ratio of the Metafile. + + I decided, to allow only placeable Metafiles here. If you also want to + enable Standard Metafiles, you will have to guess the dimensions of + the image. + +********************************************************************* + Limitations: see ximawmf.h + you may configure some stuff there +********************************************************************* +*/ + +#include "ximawmf.h" + +#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +bool CxImageWMF::Decode(CxFile *hFile, long nForceWidth, long nForceHeight) +{ + if (hFile == NULL) return false; + + HENHMETAFILE hMeta; + HDC hDC; + int cx,cy; + + //save the current position of the file + long pos = hFile->Tell(); + + // Read the Metafile and convert to an Enhanced Metafile + METAFILEHEADER mfh; + hMeta = ConvertWmfFiletoEmf(hFile, &mfh); + if (hMeta) { // ok, it's a WMF + +///////////////////////////////////////////////////////////////////// +// We use the original WMF size information, because conversion to +// EMF adjusts the Metafile to Full Screen or does not set rclBounds at all +// ENHMETAHEADER emh; +// UINT uRet; +// uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile +// sizeof(ENHMETAHEADER), // size of buffer, in bytes +// &emh); // address of buffer to receive data +// if (!uRet){ +// DeleteEnhMetaFile(hMeta); +// return false; +// } +// // calculate size +// cx = emh.rclBounds.right - emh.rclBounds.left; +// cy = emh.rclBounds.bottom - emh.rclBounds.top; +///////////////////////////////////////////////////////////////////// + + // calculate size + // scale the metafile (pixels/inch of metafile => pixels/inch of display) + // mfh.inch already checked to be <> 0 + + hDC = ::GetDC(0); + int cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX); + int cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY); + ::ReleaseDC(0, hDC); + + cx = (mfh.inch/2 + (mfh.bbox.right - mfh.bbox.left) * cx1) / mfh.inch; + cy = (mfh.inch/2 + (mfh.bbox.bottom - mfh.bbox.top) * cy1) / mfh.inch; + + } else { // maybe it's an EMF... + + hFile->Seek(pos,SEEK_SET); + + ENHMETAHEADER emh; + hMeta = ConvertEmfFiletoEmf(hFile, &emh); + + if (!hMeta){ + strcpy(info.szLastError,"corrupted WMF"); + return false; // definitively give up + } + + // ok, it's an EMF; calculate canvas size + cx = emh.rclBounds.right - emh.rclBounds.left; + cy = emh.rclBounds.bottom - emh.rclBounds.top; + + // alternative methods, sometime not so reliable... [DP] + //cx = emh.szlDevice.cx; + //cy = emh.szlDevice.cy; + // + //hDC = ::GetDC(0); + //float hscale = (float)GetDeviceCaps(hDC, HORZRES)/(100.0f * GetDeviceCaps(hDC, HORZSIZE)); + //float vscale = (float)GetDeviceCaps(hDC, VERTRES)/(100.0f * GetDeviceCaps(hDC, VERTSIZE)); + //::ReleaseDC(0, hDC); + //cx = (long)((emh.rclFrame.right - emh.rclFrame.left) * hscale); + //cy = (long)((emh.rclFrame.bottom - emh.rclFrame.top) * vscale); + } + + if (info.nEscape == -1) { // Check if cancelled + head.biWidth = cx; + head.biHeight= cy; + info.dwType = CXIMAGE_FORMAT_WMF; + DeleteEnhMetaFile(hMeta); + strcpy(info.szLastError,"output dimensions returned"); + return true; + } + + if (!cx || !cy) { + DeleteEnhMetaFile(hMeta); + strcpy(info.szLastError,"empty WMF"); + return false; + } + + if (nForceWidth) cx=nForceWidth; + if (nForceHeight) cy=nForceHeight; + ShrinkMetafile(cx, cy); // !! Otherwise Bitmap may have bombastic size + + HDC hDC0 = ::GetDC(0); // DC of screen + HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display + hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen + ::ReleaseDC(0, hDC0); // don't need anymore. get rid of it. + + if (hDC){ + if (hBitmap){ + RECT rc = {0,0,cx,cy}; + int bpp = ::GetDeviceCaps(hDC, BITSPIXEL); + + HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap); + + // clear out the entire bitmap with windows background + // because the MetaFile may not contain background information + DWORD dwBack = XMF_COLOR_BACK; +#if XMF_SUPPORT_TRANSPARENCY + if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT; +#endif + DWORD OldColor = SetBkColor(hDC, dwBack); + ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); + SetBkColor(hDC, OldColor); + + //retrieves optional palette entries from the specified enhanced metafile + PLOGPALETTE plogPal; + PBYTE pjTmp; + HPALETTE hPal; + int iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL); + if (iEntries) { + if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, + sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) { + DeleteObject(hBitmap); + DeleteDC(hDC); + DeleteEnhMetaFile(hMeta); + strcpy(info.szLastError,"Cancelled"); + return false; + } + + plogPal->palVersion = 0x300; + plogPal->palNumEntries = (WORD) iEntries; + pjTmp = (PBYTE) plogPal; + pjTmp += 4; + + GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp); + hPal = CreatePalette(plogPal); + GlobalFree(plogPal); + + SelectPalette(hDC, hPal, FALSE); + RealizePalette(hDC); + } + + // Play the Metafile into Memory DC + BOOL bRet = PlayEnhMetaFile(hDC, // handle to a device context + hMeta, // handle to an enhanced metafile + &rc); // pointer to bounding rectangle + + SelectObject(hDC, hBitmapOld); + DeleteEnhMetaFile(hMeta); // we are done with this one + + if (info.nEscape) { // Check if cancelled + DeleteObject(hBitmap); + DeleteDC(hDC); + strcpy(info.szLastError,"Cancelled"); + return false; + } + + // the Bitmap now has the image. + // Create our DIB and convert the DDB into DIB + if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) { + DeleteObject(hBitmap); + DeleteDC(hDC); + return false; + } + +#if XMF_SUPPORT_TRANSPARENCY + if (bpp == 24) { + RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT }; + SetTransColor(rgbTrans); + } +#endif + // We're finally ready to get the DIB. Call the driver and let + // it party on our bitmap. It will fill in the color table, + // and bitmap bits of our global memory block. + bRet = GetDIBits(hDC, hBitmap, 0, + (UINT)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS); + + DeleteObject(hBitmap); + DeleteDC(hDC); + + return (bRet!=0); + } else { + DeleteDC(hDC); + } + } else { + if (hBitmap) DeleteObject(hBitmap); + } + + DeleteEnhMetaFile(hMeta); + + return false; +} + +/********************************************************************** + Function: CheckMetafileHeader + Purpose: Check if the Metafileheader of a file is valid +**********************************************************************/ +BOOL CxImageWMF::CheckMetafileHeader(METAFILEHEADER *metafileheader) +{ + WORD *pw; + WORD cs; + int i; + + // check magic # + if (metafileheader->key != 0x9ac6cdd7L) return false; + + // test checksum of header + pw = (WORD *)metafileheader; + cs = *pw; + pw++; + for (i = 0; i < 9; i++) { + cs ^= *pw; + pw++; + } + + if (cs != metafileheader->checksum) return false; + + // check resolution + if ((metafileheader->inch <= 0) || (metafileheader->inch > 2540)) return false; + + return true; +} + +/********************************************************************** + Function: ConvertWmfFiletoEmf + Purpose: Converts a Windows Metafile into an Enhanced Metafile +**********************************************************************/ +HENHMETAFILE CxImageWMF::ConvertWmfFiletoEmf(CxFile *fp, METAFILEHEADER *metafileheader) +{ + HENHMETAFILE hMeta; + long lenFile; + long len; + BYTE *p; + METAHEADER mfHeader; + DWORD seekpos; + + hMeta = 0; + + // get length of the file + lenFile = fp->Size(); + + // a placeable metafile starts with a METAFILEHEADER + // read it and check metafileheader + len = fp->Read(metafileheader, 1, sizeof(METAFILEHEADER)); + if (len < sizeof(METAFILEHEADER)) return (hMeta); + + if (CheckMetafileHeader(metafileheader)) { + // This is a placeable metafile + // Convert the placeable format into something that can + // be used with GDI metafile functions + seekpos = sizeof(METAFILEHEADER); + } else { + // Not a placeable wmf. A windows metafile? + // at least not scaleable. + // we could try to convert, but would loose ratio. don't allow this + return (hMeta); + + //metafileheader->bbox.right = ?; + //metafileheader->bbox.left = ?; + //metafileheader->bbox.bottom = ?; + //metafileheader->bbox.top = ?; + //metafileheader->inch = ?; + // + //seekpos = 0; + // fp->Seek(0, SEEK_SET); // rewind + } + + // At this point we have a metaheader regardless of whether + // the metafile was a windows metafile or a placeable metafile + // so check to see if it is valid. There is really no good + // way to do this so just make sure that the mtType is either + // 1 or 2 (memory or disk file) + // in addition we compare the length of the METAHEADER against + // the length of the file. if filelength < len => no Metafile + + len = fp->Read(&mfHeader, 1, sizeof(METAHEADER)); + if (len < sizeof(METAHEADER)) return (hMeta); + + if ((mfHeader.mtType != 1) && (mfHeader.mtType != 2)) return (hMeta); + + // Length in Bytes from METAHEADER + len = mfHeader.mtSize * 2; + if (len > lenFile) return (hMeta); + + // Allocate memory for the metafile bits + p = (BYTE *)malloc(len); + if (!p) return (hMeta); + + // seek back to METAHEADER and read all the stuff at once + fp->Seek(seekpos, SEEK_SET); + lenFile = fp->Read(p, 1, len); + if (lenFile != len) { + free(p); + return (hMeta); + } + + // the following (commented code) works, but adjusts rclBound of the + // Enhanced Metafile to full screen. + // the METAFILEHEADER from above is needed to scale the image + +// hMeta = SetWinMetaFileBits(len, p, NULL, NULL); + + // scale the metafile (pixels/inch of metafile => pixels/inch of display) + + METAFILEPICT mfp; + int cx1, cy1; + HDC hDC; + + hDC = ::GetDC(0); + cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX); + cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY); + + memset(&mfp, 0, sizeof(mfp)); + + mfp.mm = MM_ANISOTROPIC; + mfp.xExt = 10000; //(metafileheader->bbox.right - metafileheader->bbox.left) * cx1 / metafileheader->inch; + mfp.yExt = 10000; //(metafileheader->bbox.bottom - metafileheader->bbox.top) * cy1 / metafileheader->inch; + mfp.hMF = 0; + + // in MM_ANISOTROPIC mode xExt and yExt are in MM_HIENGLISH + // MM_HIENGLISH means: Each logical unit is converted to 0.001 inch + //mfp.xExt *= 1000; + //mfp.yExt *= 1000; + // ???? + //int k = 332800 / ::GetSystemMetrics(SM_CXSCREEN); + //mfp.xExt *= k; mfp.yExt *= k; + + // fix for Win9x + while ((mfp.xExt < 6554) && (mfp.yExt < 6554)) + { + mfp.xExt *= 10; + mfp.yExt *= 10; + } + + hMeta = SetWinMetaFileBits(len, p, hDC, &mfp); + + if (!hMeta){ //try 2nd conversion using a different mapping + mfp.mm = MM_TEXT; + hMeta = SetWinMetaFileBits(len, p, hDC, &mfp); + } + + ::ReleaseDC(0, hDC); + + // Free Memory + free(p); + + return (hMeta); +} +///////////////////////////////////////////////////////////////////// +HENHMETAFILE CxImageWMF::ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh) +{ + HENHMETAFILE hMeta; + long iLen = pFile->Size(); + + // Check the header first: + long pos = pFile->Tell(); + long iLenRead = pFile->Read(pemfh, 1, sizeof(ENHMETAHEADER)); + if (iLenRead < sizeof(ENHMETAHEADER)) return NULL; + if (pemfh->iType != EMR_HEADER) return NULL; + if (pemfh->dSignature != ENHMETA_SIGNATURE) return NULL; + //if (pemfh->nBytes != (DWORD)iLen) return NULL; + pFile->Seek(pos,SEEK_SET); + + BYTE* pBuff = (BYTE *)malloc(iLen); + if (!pBuff) return (FALSE); + + // Read the Enhanced Metafile + iLenRead = pFile->Read(pBuff, 1, iLen); + if (iLenRead != iLen) { + free(pBuff); + return NULL; + } + + // Make it a Memory Metafile + hMeta = SetEnhMetaFileBits(iLen, pBuff); + + free(pBuff); // finished with this one + + if (!hMeta) return NULL; // oops. + + // Get the Enhanced Metafile Header + UINT uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile + sizeof(ENHMETAHEADER), // size of buffer, in bytes + pemfh); // address of buffer to receive data + + if (!uRet) { + DeleteEnhMetaFile(hMeta); + return NULL; + } + + return (hMeta); +} +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_DECODE +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_ENCODE +///////////////////////////////////////////////////////////////////// +bool CxImageWMF::Encode(CxFile * hFile) +{ + if (hFile == NULL) return false; + strcpy(info.szLastError, "Save WMF not supported"); + return false; +} +#endif // CXIMAGE_SUPPORT_ENCODE +///////////////////////////////////////////////////////////////////// + +/********************************************************************** +Function: ShrinkMetafile +Purpose: Shrink the size of a metafile to be not larger than + the definition +**********************************************************************/ +void CxImageWMF::ShrinkMetafile(int &cx, int &cy) +{ + int xScreen = XMF_MAXSIZE_CX; + int yScreen = XMF_MAXSIZE_CY; + + if (cx > xScreen){ + cy = cy * xScreen / cx; + cx = xScreen; + } + + if (cy > yScreen){ + cx = cx * yScreen / cy; + cy = yScreen; + } +} + +#endif // CIMAGE_SUPPORT_WMF + diff --git a/utilities/CxImage/ximawmf.h b/utilities/CxImage/ximawmf.h index fb59452..75e119a 100644 --- a/utilities/CxImage/ximawmf.h +++ b/utilities/CxImage/ximawmf.h @@ -1,154 +1,154 @@ -/* -********************************************************************* - * File: ximawmf.h - * Purpose: Windows Metafile Class Loader and Writer - * Author: Volker Horch - vhorch@gmx.de - * created: 13-Jun-2002 -********************************************************************* - */ - -/* -********************************************************************* - Notes by Author: -********************************************************************* - - Limitations: - ============ - - a) Transparency: - - A Metafile is vector graphics, which has transparency by design. - This class always converts into a Bitmap format. Transparency is - supported, but there is no good way to find out, which parts - of the Metafile are transparent. There are two ways how we can - handle this: - - - Clear the Background of the Bitmap with the background color - you like (i have used COLOR_WINDOW) and don't support transparency. - - below #define XMF_SUPPORT_TRANSPARENCY 0 - #define XMF_COLOR_BACK RGB(Background color you like) - - - Clear the Background of the Bitmap with a very unusual color - (which one ?) and use this color as the transparent color - - below #define XMF_SUPPORT_TRANSPARENCY 1 - #define XMF_COLOR_TRANSPARENT_R ... - #define XMF_COLOR_TRANSPARENT_G ... - #define XMF_COLOR_TRANSPARENT_B ... - - b) Resolution - - Once we have converted the Metafile into a Bitmap and we zoom in - or out, the image may not look very good. If we still had the - original Metafile, zooming would produce good results always. - - c) Size - - Although the filesize of a Metafile may be very small, it might - produce a Bitmap with a bombastic size. Assume you have a Metafile - with an image size of 6000*4000, which contains just one Metafile - record ((e.g. a line from (0,0) to (6000, 4000)). The filesize - of this Metafile would be let's say 100kB. If we convert it to - a 6000*4000 Bitmap with 24 Bits/Pixes, the Bitmap would consume - about 68MB of memory. - - I have choosen, to limit the size of the Bitmap to max. - screensize, to avoid memory problems. - - If you want something else, - modify #define XMF_MAXSIZE_CX / XMF_MAXSIZE_CY below - -********************************************************************* -*/ - -#ifndef _XIMAWMF_H -#define _XIMAWMF_H - -#include "ximage.h" - -#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS - -class CxImageWMF: public CxImage -{ - -#pragma pack(1) - -typedef struct tagRECT16 -{ - short int left; - short int top; - short int right; - short int bottom; -} RECT16; - -// taken from Windos 3.11 SDK Documentation (Programmer's Reference Volume 4: Resources) -typedef struct tagMETAFILEHEADER -{ - DWORD key; // always 0x9ac6cdd7 - WORD reserved1; // reserved = 0 - RECT16 bbox; // bounding rectangle in metafile units as defined in "inch" - WORD inch; // number of metafile units per inch (should be < 1440) - DWORD reserved2; // reserved = 0 - WORD checksum; // sum of the first 10 WORDS (using XOR operator) -} METAFILEHEADER; - -#pragma pack() - -public: - CxImageWMF(): CxImage(CXIMAGE_FORMAT_WMF) { } - - bool Decode(CxFile * hFile, long nForceWidth=0, long nForceHeight=0); - bool Decode(FILE *hFile, long nForceWidth=0, long nForceHeight=0) - { CxIOFile file(hFile); return Decode(&file,nForceWidth,nForceHeight); } - -#if CXIMAGE_SUPPORT_ENCODE - bool Encode(CxFile * hFile); - bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } -#endif // CXIMAGE_SUPPORT_ENCODE - -protected: - void ShrinkMetafile(int &cx, int &cy); - BOOL CheckMetafileHeader(METAFILEHEADER *pmetafileheader); - HENHMETAFILE ConvertWmfFiletoEmf(CxFile *pFile, METAFILEHEADER *pmetafileheader); - HENHMETAFILE ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh); - -}; - -#define METAFILEKEY 0x9ac6cdd7L - -// Background color definition (if no transparency). see Notes above -#define XMF_COLOR_BACK GetSysColor(COLOR_WINDOW) -// alternatives -//#define XMF_COLOR_BACK RGB(192, 192, 192) // lite gray -//#define XMF_COLOR_BACK RGB( 0, 0, 0) // black -//#define XMF_COLOR_BACK RGB(255, 255, 255) // white - - -// transparency support. see Notes above -#define XMF_SUPPORT_TRANSPARENCY 0 -#define XMF_COLOR_TRANSPARENT_R 211 -#define XMF_COLOR_TRANSPARENT_G 121 -#define XMF_COLOR_TRANSPARENT_B 112 -// don't change -#define XMF_COLOR_TRANSPARENT RGB (XMF_COLOR_TRANSPARENT_R, \ - XMF_COLOR_TRANSPARENT_G, \ - XMF_COLOR_TRANSPARENT_B) -// don't change -#define XMF_RGBQUAD_TRANSPARENT XMF_COLOR_TRANSPARENT_B, \ - XMF_COLOR_TRANSPARENT_G, \ - XMF_COLOR_TRANSPARENT_R, \ - 0 -// max. size. see Notes above -// alternatives -//#define XMF_MAXSIZE_CX (GetSystemMetrics(SM_CXSCREEN)-10) -//#define XMF_MAXSIZE_CY (GetSystemMetrics(SM_CYSCREEN)-50) -//#define XMF_MAXSIZE_CX (2*GetSystemMetrics(SM_CXSCREEN)/3) -//#define XMF_MAXSIZE_CY (2*GetSystemMetrics(SM_CYSCREEN)/3) -#define XMF_MAXSIZE_CX 4000 -#define XMF_MAXSIZE_CY 4000 - - -#endif - -#endif +/* +********************************************************************* + * File: ximawmf.h + * Purpose: Windows Metafile Class Loader and Writer + * Author: Volker Horch - vhorch@gmx.de + * created: 13-Jun-2002 +********************************************************************* + */ + +/* +********************************************************************* + Notes by Author: +********************************************************************* + + Limitations: + ============ + + a) Transparency: + + A Metafile is vector graphics, which has transparency by design. + This class always converts into a Bitmap format. Transparency is + supported, but there is no good way to find out, which parts + of the Metafile are transparent. There are two ways how we can + handle this: + + - Clear the Background of the Bitmap with the background color + you like (i have used COLOR_WINDOW) and don't support transparency. + + below #define XMF_SUPPORT_TRANSPARENCY 0 + #define XMF_COLOR_BACK RGB(Background color you like) + + - Clear the Background of the Bitmap with a very unusual color + (which one ?) and use this color as the transparent color + + below #define XMF_SUPPORT_TRANSPARENCY 1 + #define XMF_COLOR_TRANSPARENT_R ... + #define XMF_COLOR_TRANSPARENT_G ... + #define XMF_COLOR_TRANSPARENT_B ... + + b) Resolution + + Once we have converted the Metafile into a Bitmap and we zoom in + or out, the image may not look very good. If we still had the + original Metafile, zooming would produce good results always. + + c) Size + + Although the filesize of a Metafile may be very small, it might + produce a Bitmap with a bombastic size. Assume you have a Metafile + with an image size of 6000*4000, which contains just one Metafile + record ((e.g. a line from (0,0) to (6000, 4000)). The filesize + of this Metafile would be let's say 100kB. If we convert it to + a 6000*4000 Bitmap with 24 Bits/Pixes, the Bitmap would consume + about 68MB of memory. + + I have choosen, to limit the size of the Bitmap to max. + screensize, to avoid memory problems. + + If you want something else, + modify #define XMF_MAXSIZE_CX / XMF_MAXSIZE_CY below + +********************************************************************* +*/ + +#ifndef _XIMAWMF_H +#define _XIMAWMF_H + +#include "ximage.h" + +#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS + +class CxImageWMF: public CxImage +{ + +#pragma pack(1) + +typedef struct tagRECT16 +{ + short int left; + short int top; + short int right; + short int bottom; +} RECT16; + +// taken from Windos 3.11 SDK Documentation (Programmer's Reference Volume 4: Resources) +typedef struct tagMETAFILEHEADER +{ + DWORD key; // always 0x9ac6cdd7 + WORD reserved1; // reserved = 0 + RECT16 bbox; // bounding rectangle in metafile units as defined in "inch" + WORD inch; // number of metafile units per inch (should be < 1440) + DWORD reserved2; // reserved = 0 + WORD checksum; // sum of the first 10 WORDS (using XOR operator) +} METAFILEHEADER; + +#pragma pack() + +public: + CxImageWMF(): CxImage(CXIMAGE_FORMAT_WMF) { } + + bool Decode(CxFile * hFile, long nForceWidth=0, long nForceHeight=0); + bool Decode(FILE *hFile, long nForceWidth=0, long nForceHeight=0) + { CxIOFile file(hFile); return Decode(&file,nForceWidth,nForceHeight); } + +#if CXIMAGE_SUPPORT_ENCODE + bool Encode(CxFile * hFile); + bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); } +#endif // CXIMAGE_SUPPORT_ENCODE + +protected: + void ShrinkMetafile(int &cx, int &cy); + BOOL CheckMetafileHeader(METAFILEHEADER *pmetafileheader); + HENHMETAFILE ConvertWmfFiletoEmf(CxFile *pFile, METAFILEHEADER *pmetafileheader); + HENHMETAFILE ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh); + +}; + +#define METAFILEKEY 0x9ac6cdd7L + +// Background color definition (if no transparency). see Notes above +#define XMF_COLOR_BACK GetSysColor(COLOR_WINDOW) +// alternatives +//#define XMF_COLOR_BACK RGB(192, 192, 192) // lite gray +//#define XMF_COLOR_BACK RGB( 0, 0, 0) // black +//#define XMF_COLOR_BACK RGB(255, 255, 255) // white + + +// transparency support. see Notes above +#define XMF_SUPPORT_TRANSPARENCY 0 +#define XMF_COLOR_TRANSPARENT_R 211 +#define XMF_COLOR_TRANSPARENT_G 121 +#define XMF_COLOR_TRANSPARENT_B 112 +// don't change +#define XMF_COLOR_TRANSPARENT RGB (XMF_COLOR_TRANSPARENT_R, \ + XMF_COLOR_TRANSPARENT_G, \ + XMF_COLOR_TRANSPARENT_B) +// don't change +#define XMF_RGBQUAD_TRANSPARENT XMF_COLOR_TRANSPARENT_B, \ + XMF_COLOR_TRANSPARENT_G, \ + XMF_COLOR_TRANSPARENT_R, \ + 0 +// max. size. see Notes above +// alternatives +//#define XMF_MAXSIZE_CX (GetSystemMetrics(SM_CXSCREEN)-10) +//#define XMF_MAXSIZE_CY (GetSystemMetrics(SM_CYSCREEN)-50) +//#define XMF_MAXSIZE_CX (2*GetSystemMetrics(SM_CXSCREEN)/3) +//#define XMF_MAXSIZE_CY (2*GetSystemMetrics(SM_CYSCREEN)/3) +#define XMF_MAXSIZE_CX 4000 +#define XMF_MAXSIZE_CY 4000 + + +#endif + +#endif diff --git a/utilities/CxImage/ximawnd.cpp b/utilities/CxImage/ximawnd.cpp index 9e75a37..2ae2f93 100644 --- a/utilities/CxImage/ximawnd.cpp +++ b/utilities/CxImage/ximawnd.cpp @@ -1,1409 +1,1409 @@ -// xImaWnd.cpp : Windows functions -/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it - * CxImage version 6.0.0 02/Feb/2008 - */ - -#include "ximage.h" - -#include "ximaiter.h" -#include "ximabmp.h" - -//////////////////////////////////////////////////////////////////////////////// -#if defined (_WIN32_WCE) - -#ifndef DEFAULT_GUI_FONT -#define DEFAULT_GUI_FONT 17 -#endif - -#ifndef PROOF_QUALITY -#define PROOF_QUALITY 2 -#endif - -struct DIBINFO : public BITMAPINFO -{ - RGBQUAD arColors[255]; // Color table info - adds an extra 255 entries to palette - operator LPBITMAPINFO() { return (LPBITMAPINFO) this; } - operator LPBITMAPINFOHEADER() { return &bmiHeader; } - RGBQUAD* ColorTable() { return bmiColors; } -}; - -int BytesPerLine(int nWidth, int nBitsPerPixel) -{ - return ( (nWidth * nBitsPerPixel + 31) & (~31) ) / 8; -} - -int NumColorEntries(int nBitsPerPixel, int nCompression, DWORD biClrUsed) -{ - int nColors = 0; - switch (nBitsPerPixel) - { - case 1: - nColors = 2; break; - case 2: - nColors = 4; break; // winCE only - case 4: - nColors = 16; break; - case 8: - nColors =256; break; - case 24: - nColors = 0; break; - case 16: - case 32: - nColors = 3; break; // I've found that PocketPCs need this regardless of BI_RGB or BI_BITFIELDS - default: - ASSERT(FALSE); - } - // If biClrUsed is provided, and it is a legal value, use it - if (biClrUsed > 0 && biClrUsed <= (DWORD)nColors) - return biClrUsed; - - return nColors; -} - -int GetDIBits( - HDC hdc, // handle to DC - HBITMAP hbmp, // handle to bitmap - UINT uStartScan, // first scan line to set - UINT cScanLines, // number of scan lines to copy - LPVOID lpvBits, // array for bitmap bits - LPBITMAPINFO lpbi, // bitmap data buffer - UINT uUsage // RGB or palette index -) -{ - UINT iColorTableSize = 0; - - if (!hbmp) - return 0; - - // Get dimensions of bitmap - BITMAP bm; - if (!::GetObject(hbmp, sizeof(bm),(LPVOID)&bm)) - return 0; - - //3. Creating new bitmap and receive pointer to it's bits. - HBITMAP hTargetBitmap; - void *pBuffer; - - //3.1 Initilize DIBINFO structure - DIBINFO dibInfo; - dibInfo.bmiHeader.biBitCount = 24; - dibInfo.bmiHeader.biClrImportant = 0; - dibInfo.bmiHeader.biClrUsed = 0; - dibInfo.bmiHeader.biCompression = 0; - dibInfo.bmiHeader.biHeight = bm.bmHeight; - dibInfo.bmiHeader.biPlanes = 1; - dibInfo.bmiHeader.biSize = 40; - dibInfo.bmiHeader.biSizeImage = bm.bmHeight*BytesPerLine(bm.bmWidth,24); - dibInfo.bmiHeader.biWidth = bm.bmWidth; - dibInfo.bmiHeader.biXPelsPerMeter = 3780; - dibInfo.bmiHeader.biYPelsPerMeter = 3780; - dibInfo.bmiColors[0].rgbBlue = 0; - dibInfo.bmiColors[0].rgbGreen = 0; - dibInfo.bmiColors[0].rgbRed = 0; - dibInfo.bmiColors[0].rgbReserved = 0; - - //3.2 Create bitmap and receive pointer to points into pBuffer - HDC hDC = ::GetDC(NULL); - ASSERT(hDC); - hTargetBitmap = CreateDIBSection( - hDC, - (const BITMAPINFO*)dibInfo, - DIB_RGB_COLORS, - (void**)&pBuffer, - NULL, - 0); - - ::ReleaseDC(NULL, hDC); - - //4. Copy source bitmap into the target bitmap. - - //4.1 Create 2 device contexts - HDC memDc = CreateCompatibleDC(NULL); - if (!memDc) { - ASSERT(FALSE); - } - - HDC targetDc = CreateCompatibleDC(NULL); - if (!targetDc) { - ASSERT(FALSE); - } - - //4.2 Select source bitmap into one DC, target into another - HBITMAP hOldBitmap1 = (HBITMAP)::SelectObject(memDc, hbmp); - HBITMAP hOldBitmap2 = (HBITMAP)::SelectObject(targetDc, hTargetBitmap); - - //4.3 Copy source bitmap into the target one - BitBlt(targetDc, 0, 0, bm.bmWidth, bm.bmHeight, memDc, 0, 0, SRCCOPY); - - //4.4 Restore device contexts - ::SelectObject(memDc, hOldBitmap1); - ::SelectObject(targetDc, hOldBitmap2); - DeleteDC(memDc); - DeleteDC(targetDc); - - //Here we can bitmap bits: pBuffer. Note: - // 1. pBuffer contains 3 bytes per point - // 2. Lines ane from the bottom to the top! - // 3. Points in the line are from the left to the right - // 4. Bytes in one point are BGR (blue, green, red) not RGB - // 5. Don't delete pBuffer, it will be automatically deleted - // when delete hTargetBitmap - lpvBits = pBuffer; - - DeleteObject(hbmp); - //DeleteObject(hTargetBitmap); - - return 1; -} -#endif - -//////////////////////////////////////////////////////////////////////////////// -#if CXIMAGE_SUPPORT_WINDOWS -//////////////////////////////////////////////////////////////////////////////// -long CxImage::Blt(HDC pDC, long x, long y) -{ - if((pDib==0)||(pDC==0)||(!info.bEnabled)) return 0; - - HBRUSH brImage = CreateDIBPatternBrushPt(pDib, DIB_RGB_COLORS); - POINT pt; - SetBrushOrgEx(pDC,x,y,&pt); // - HBRUSH brOld = (HBRUSH) SelectObject(pDC, brImage); - PatBlt(pDC, x, y, head.biWidth, head.biHeight, PATCOPY); - SelectObject(pDC, brOld); - SetBrushOrgEx(pDC,pt.x,pt.y,NULL); - DeleteObject(brImage); - return 1; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Transfer the image in a global bitmap handle (clipboard copy) - */ -HANDLE CxImage::CopyToHandle() -{ - HANDLE hMem=NULL; - if (pDib){ - hMem= GlobalAlloc(GHND, GetSize()); - if (hMem){ - BYTE* pDst=(BYTE*)GlobalLock(hMem); - if (pDst){ - memcpy(pDst,pDib,GetSize()); - } - GlobalUnlock(hMem); - } - } - return hMem; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Global object (clipboard paste) constructor - * \param hMem: source bitmap object, the clipboard format must be CF_DIB - * \return true if everything is ok - */ -bool CxImage::CreateFromHANDLE(HANDLE hMem) -{ - if (!Destroy()) - return false; - - DWORD dwSize = GlobalSize(hMem); - if (!dwSize) return false; - - BYTE *lpVoid; //pointer to the bitmap - lpVoid = (BYTE *)GlobalLock(hMem); - BITMAPINFOHEADER *pHead; //pointer to the bitmap header - pHead = (BITMAPINFOHEADER *)lpVoid; - if (lpVoid){ - - //CxMemFile hFile(lpVoid,dwSize); - - //copy the bitmap header - memcpy(&head,pHead,sizeof(BITMAPINFOHEADER)); - //check if it's a top-down bitmap - bool bTopDownDib = head.biHeight<0; - if (bTopDownDib) head.biHeight=-head.biHeight; - //create the image - if(!Create(head.biWidth,head.biHeight,head.biBitCount)){ - GlobalUnlock(lpVoid); - return false; - } - //preserve DPI - SetXDPI((long)floor(head.biXPelsPerMeter * 254.0 / 10000.0 + 0.5)); - SetYDPI((long)floor(head.biYPelsPerMeter * 254.0 / 10000.0 + 0.5)); - - /*//copy the pixels (old way) - if((pHead->biCompression != BI_RGB) || (pHead->biBitCount == 32)){ // - // BITFIELD case - // set the internal header in the dib - memcpy(pDib,&head,sizeof(head)); - // get the bitfield masks - DWORD bf[3]; - memcpy(bf,lpVoid+pHead->biSize,12); - // transform into RGB - Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount); - } else { //normal bitmap - memcpy(pDib,lpVoid,GetSize()); - }*/ - - // - // fill in color map - bool bIsOldBmp = (head.biSize == sizeof(BITMAPCOREHEADER)); - RGBQUAD *pRgb = GetPalette(); - if (pRgb) { - // number of colors to fill in - int nColors = DibNumColors(pHead); - if (bIsOldBmp) { - /* get pointer to BITMAPCOREINFO (old style 1.x) */ - LPBITMAPCOREINFO lpbmc = (LPBITMAPCOREINFO)lpVoid; - for (int i = nColors - 1; i >= 0; i--) { - pRgb[i].rgbRed = lpbmc->bmciColors[i].rgbtRed; - pRgb[i].rgbGreen = lpbmc->bmciColors[i].rgbtGreen; - pRgb[i].rgbBlue = lpbmc->bmciColors[i].rgbtBlue; - pRgb[i].rgbReserved = (BYTE)0; - } - } else { - /* get pointer to BITMAPINFO (new style 3.x) */ - LPBITMAPINFO lpbmi = (LPBITMAPINFO)lpVoid; - for (int i = nColors - 1; i >= 0; i--) { - pRgb[i].rgbRed = lpbmi->bmiColors[i].rgbRed; - pRgb[i].rgbGreen = lpbmi->bmiColors[i].rgbGreen; - pRgb[i].rgbBlue = lpbmi->bmiColors[i].rgbBlue; - pRgb[i].rgbReserved = (BYTE)0; - } - } - } - - // - DWORD dwCompression = pHead->biCompression; - // compressed bitmap ? - if(dwCompression!=BI_RGB || pHead->biBitCount==32 || pHead->biBitCount ==16) { - // get the bitmap bits - LPSTR lpDIBBits = (LPSTR)((BYTE*)pHead + *(DWORD*)pHead + (WORD)(GetNumColors() * sizeof(RGBQUAD))); - // decode and copy them to our image - switch (pHead->biBitCount) { - case 32 : - { - // BITFIELD case - if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB) { - // get the bitfield masks - DWORD bf[3]; - memcpy(bf,lpVoid+pHead->biSize,12); - // transform into RGB - Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount); - } else { - // "unknown compression"; - GlobalUnlock(lpVoid); - return false; - } - } - break; - case 16 : - { - // get the bitfield masks - long offset=0; - DWORD bf[3]; - if (dwCompression == BI_BITFIELDS) { - memcpy(bf,lpVoid+pHead->biSize,12); - offset= 12; - } else { - bf[0] = 0x7C00; - bf[1] = 0x3E0; - bf[2] = 0x1F; // RGB555 - } - // copy the pixels - memcpy(info.pImage, lpDIBBits + offset, head.biHeight*((head.biWidth+1)/2)*4); - // transform into RGB - Bitfield2RGB(info.pImage, bf[0], bf[1], bf[2], 16); - } - break; - case 8 : - case 4 : - case 1 : - { - switch (dwCompression) { - case BI_RLE4: - { - BYTE status_byte = 0; - BYTE second_byte = 0; - int scanline = 0; - int bits = 0; - BOOL low_nibble = FALSE; - CImageIterator iter(this); - - for (BOOL bContinue = TRUE; bContinue; ) { - status_byte = *(lpDIBBits++); - switch (status_byte) { - case RLE_COMMAND : - status_byte = *(lpDIBBits++); - switch (status_byte) { - case RLE_ENDOFLINE : - bits = 0; - scanline++; - low_nibble = FALSE; - break; - case RLE_ENDOFBITMAP : - bContinue = FALSE; - break; - case RLE_DELTA : - { - // read the delta values - BYTE delta_x; - BYTE delta_y; - delta_x = *(lpDIBBits++); - delta_y = *(lpDIBBits++); - // apply them - bits += delta_x / 2; - scanline += delta_y; - break; - } - default : - second_byte = *(lpDIBBits++); - BYTE* sline = iter.GetRow(scanline); - for (int i = 0; i < status_byte; i++) { - if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ - if (low_nibble) { - if (i&1) - *(sline + bits) |= (second_byte & 0x0f); - else - *(sline + bits) |= (second_byte & 0xf0)>>4; - bits++; - } else { - if (i&1) - *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; - else - *(sline + bits) = (BYTE)(second_byte & 0xf0); - } - } - - if ((i & 1) && (i != (status_byte - 1))) - second_byte = *(lpDIBBits++); - - low_nibble = !low_nibble; - } - if ((((status_byte+1) >> 1) & 1 ) == 1) - second_byte = *(lpDIBBits++); - break; - }; - break; - default : - { - BYTE* sline = iter.GetRow(scanline); - second_byte = *(lpDIBBits++); - for (unsigned i = 0; i < status_byte; i++) { - if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ - if (low_nibble) { - if (i&1) - *(sline + bits) |= (second_byte & 0x0f); - else - *(sline + bits) |= (second_byte & 0xf0)>>4; - bits++; - } else { - if (i&1) - *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; - else - *(sline + bits) = (BYTE)(second_byte & 0xf0); - } - } - low_nibble = !low_nibble; - } - } - break; - }; - } - } - break; - case BI_RLE8 : - { - BYTE status_byte = 0; - BYTE second_byte = 0; - int scanline = 0; - int bits = 0; - CImageIterator iter(this); - - for (BOOL bContinue = TRUE; bContinue; ) { - status_byte = *(lpDIBBits++); - if (status_byte==RLE_COMMAND) { - status_byte = *(lpDIBBits++); - switch (status_byte) { - case RLE_ENDOFLINE : - bits = 0; - scanline++; - break; - case RLE_ENDOFBITMAP : - bContinue = FALSE; - break; - case RLE_DELTA : - { - // read the delta values - BYTE delta_x; - BYTE delta_y; - delta_x = *(lpDIBBits++); - delta_y = *(lpDIBBits++); - // apply them - bits += delta_x; - scanline += delta_y; - } - break; - default : - int nNumBytes = sizeof(BYTE) * status_byte; - memcpy((void *)(iter.GetRow(scanline) + bits), lpDIBBits, nNumBytes); - lpDIBBits += nNumBytes; - // align run length to even number of bytes - if ((status_byte & 1) == 1) - second_byte = *(lpDIBBits++); - bits += status_byte; - break; - }; - } else { - BYTE *sline = iter.GetRow(scanline); - second_byte = *(lpDIBBits++); - for (unsigned i = 0; i < status_byte; i++) { - if ((DWORD)bits - // // Create a device-independent bitmap - // return CreateBitmap(head.biWidth,head.biHeight, 1, head.biBitCount, GetBits()); - // use instead this code - HDC hMemDC = CreateCompatibleDC(NULL); - LPVOID pBit32; - HBITMAP bmp = CreateDIBSection(hMemDC,(LPBITMAPINFO)pDib,DIB_RGB_COLORS, &pBit32, NULL, 0); - if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage); - DeleteDC(hMemDC); - return bmp; - } - - // this single line seems to work very well - //HBITMAP bmp = CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)pDib, CBM_INIT, - // GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS); - // this alternative works also with _WIN32_WCE - LPVOID pBit32; - HBITMAP bmp = CreateDIBSection(hdc, (LPBITMAPINFO)pDib, DIB_RGB_COLORS, &pBit32, NULL, 0); - if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage); - - return bmp; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Bitmap resource constructor - * \param hbmp : bitmap resource handle - * \param hpal : (optional) palette, useful for 8bpp DC - * \return true if everything is ok - */ -bool CxImage::CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal) -{ - if (!Destroy()) - return false; - - if (hbmp) { - BITMAP bm; - // get informations about the bitmap - GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm); - // create the image - if (!Create(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0)) - return false; - // create a device context for the bitmap - HDC dc = ::GetDC(NULL); - if (!dc) - return false; - - if (hpal){ - SelectObject(dc,hpal); //the palette you should get from the user or have a stock one - RealizePalette(dc); - } - - // copy the pixels - if (GetDIBits(dc, hbmp, 0, head.biHeight, info.pImage, - (LPBITMAPINFO)pDib, DIB_RGB_COLORS) == 0){ //replace &head with pDib - strcpy(info.szLastError,"GetDIBits failed"); - ::ReleaseDC(NULL, dc); - return false; - } - ::ReleaseDC(NULL, dc); - return true; - } - return false; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * icon resource constructor - * \param hico : icon resource handle - * \return true if everything is ok - * \author []; changes [Arlen Albert Keshabian] - */ -#if !defined (_WIN32_WCE) -bool CxImage::CreateFromHICON(HICON hico) -{ - if (!Destroy() || !hico) - return false; - - bool l_bResult = true; - - ICONINFO iinfo; - GetIconInfo(hico,&iinfo); - - BITMAP l_Bitmap; - GetObject(iinfo.hbmColor, sizeof(BITMAP), &l_Bitmap); - - if(l_Bitmap.bmBitsPixel == 32) - { - BITMAPINFO l_BitmapInfo; - l_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - l_BitmapInfo.bmiHeader.biWidth = l_Bitmap.bmWidth; - l_BitmapInfo.bmiHeader.biHeight = l_Bitmap.bmHeight; - l_BitmapInfo.bmiHeader.biPlanes = l_Bitmap.bmPlanes; - l_BitmapInfo.bmiHeader.biBitCount = l_Bitmap.bmBitsPixel; - l_BitmapInfo.bmiHeader.biCompression = BI_RGB; - - RGBQUAD *l_pRawBytes = new RGBQUAD[l_Bitmap.bmWidth * l_Bitmap.bmHeight]; - - HDC dc = ::GetDC(NULL); - - if(dc) - { - if(GetDIBits(dc, iinfo.hbmColor, 0, l_Bitmap.bmHeight, l_pRawBytes, &l_BitmapInfo, DIB_RGB_COLORS)) - l_bResult = CreateFromArray((BYTE*)l_pRawBytes, l_Bitmap.bmWidth, l_Bitmap.bmHeight, l_Bitmap.bmBitsPixel, l_Bitmap.bmWidthBytes, false); - else - l_bResult = false; - - ::ReleaseDC(NULL, dc); - } - else - l_bResult = false; - - delete [] l_pRawBytes; - } - else - { - l_bResult = CreateFromHBITMAP(iinfo.hbmColor); -#if CXIMAGE_SUPPORT_ALPHA - if(l_bResult) - { - CxImage mask; - mask.CreateFromHBITMAP(iinfo.hbmMask); - mask.GrayScale(); - mask.Negative(); - AlphaSet(mask); - } -#endif - } - - DeleteObject(iinfo.hbmColor); // - DeleteObject(iinfo.hbmMask); // - - return l_bResult; -} -#endif //_WIN32_WCE -//////////////////////////////////////////////////////////////////////////////// -long CxImage::Draw(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth) -{ - return Draw(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Draws the image in the specified device context, with support for alpha channel, alpha palette, transparency, opacity. - * \param hdc : destination device context - * \param x,y : (optional) offset - * \param cx,cy : (optional) size. - * - If cx or cy are not specified (or less than 0), the normal width or height will be used - * - If cx or cy are different than width or height, the image will be stretched - * - * \param pClipRect : limit the drawing operations inside a given rectangle in the output device context. - * \param bSmooth : activates a bilinear filter that will enhance the appearence for zommed pictures. - * Quite slow. Needs CXIMAGE_SUPPORT_INTERPOLATION. - * \return true if everything is ok - */ -long CxImage::Draw(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth) -{ - if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0; - - if (cx < 0) cx = head.biWidth; - if (cy < 0) cy = head.biHeight; - bool bTransparent = info.nBkgndIndex >= 0; - bool bAlpha = pAlpha != 0; - - //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield] - int hdc_Restore = ::SaveDC(hdc); - if (!hdc_Restore) - return 0; - -#if !defined (_WIN32_WCE) - RECT mainbox; // (experimental) - if (pClipRect){ - GetClipBox(hdc,&mainbox); - HRGN rgn = CreateRectRgnIndirect(pClipRect); - ExtSelectClipRgn(hdc,rgn,RGN_AND); - DeleteObject(rgn); - } -#endif - - //find the smallest area to paint - RECT clipbox,paintbox; - GetClipBox(hdc,&clipbox); - - paintbox.top = min(clipbox.bottom,max(clipbox.top,y)); - paintbox.left = min(clipbox.right,max(clipbox.left,x)); - paintbox.right = max(clipbox.left,min(clipbox.right,x+cx)); - paintbox.bottom = max(clipbox.top,min(clipbox.bottom,y+cy)); - - long destw = paintbox.right - paintbox.left; - long desth = paintbox.bottom - paintbox.top; - - if (!(bTransparent || bAlpha || info.bAlphaPaletteEnabled)){ - if (cx==head.biWidth && cy==head.biHeight){ //NORMAL -#if !defined (_WIN32_WCE) - SetStretchBltMode(hdc,COLORONCOLOR); -#endif - SetDIBitsToDevice(hdc, x, y, cx, cy, 0, 0, 0, cy, - info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS); - } else { //STRETCH - //pixel informations - RGBQUAD c={0,0,0,0}; - //Preparing Bitmap Info - BITMAPINFO bmInfo; - memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); - bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); - bmInfo.bmiHeader.biWidth=destw; - bmInfo.bmiHeader.biHeight=desth; - bmInfo.bmiHeader.biPlanes=1; - bmInfo.bmiHeader.biBitCount=24; - BYTE *pbase; //points to the final dib - BYTE *pdst; //current pixel from pbase - BYTE *ppix; //current pixel from image - //get the background - HDC TmpDC=CreateCompatibleDC(hdc); - HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); - HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); - - if (pbase){ - long xx,yy; - long sx,sy; - float dx,dy; - BYTE *psrc; - - long ew = ((((24 * destw) + 31) / 32) * 4); - long ymax = paintbox.bottom; - long xmin = paintbox.left; - float fx=(float)head.biWidth/(float)cx; - float fy=(float)head.biHeight/(float)cy; - - for(yy=0;yy 1 && fy > 1) { - c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); - } else { - c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); - } - } else -#endif //CXIMAGE_SUPPORT_INTERPOLATION - { - if (head.biClrUsed){ - c=GetPaletteColor(GetPixelIndex(sx,sy)); - } else { - ppix = psrc + sx*3; - c.rgbBlue = *ppix++; - c.rgbGreen= *ppix++; - c.rgbRed = *ppix; - } - } - *pdst++=c.rgbBlue; - *pdst++=c.rgbGreen; - *pdst++=c.rgbRed; - } - } - } - //paint the image & cleanup - SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0); - DeleteObject(SelectObject(TmpDC,TmpObj)); - DeleteDC(TmpDC); - } - } else { // draw image with transparent/alpha blending - ////////////////////////////////////////////////////////////////// - //Alpha blend - Thanks to Florian Egel - - //pixel informations - RGBQUAD c={0,0,0,0}; - RGBQUAD ct = GetTransColor(); - long* pc = (long*)&c; - long* pct= (long*)&ct; - long cit = GetTransIndex(); - long ci = 0; - - //Preparing Bitmap Info - BITMAPINFO bmInfo; - memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); - bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); - bmInfo.bmiHeader.biWidth=destw; - bmInfo.bmiHeader.biHeight=desth; - bmInfo.bmiHeader.biPlanes=1; - bmInfo.bmiHeader.biBitCount=24; - - BYTE *pbase; //points to the final dib - BYTE *pdst; //current pixel from pbase - BYTE *ppix; //current pixel from image - - //get the background - HDC TmpDC=CreateCompatibleDC(hdc); - HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); - HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); - BitBlt(TmpDC,0,0,destw,desth,hdc,paintbox.left,paintbox.top,SRCCOPY); - - if (pbase){ - long xx,yy,alphaoffset,ix,iy; - BYTE a,a1,*psrc; - long ew = ((((24 * destw) + 31) / 32) * 4); - long ymax = paintbox.bottom; - long xmin = paintbox.left; - - if (cx!=head.biWidth || cy!=head.biHeight){ - //STRETCH - float fx=(float)head.biWidth/(float)cx; - float fy=(float)head.biHeight/(float)cy; - float dx,dy; - long sx,sy; - - for(yy=0;yy>8); - - if (head.biClrUsed){ - ci = GetPixelIndex(sx,sy); -#if CXIMAGE_SUPPORT_INTERPOLATION - if (bSmooth){ - if (fx > 1 && fy > 1) { - c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); - } else { - c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); - } - } else -#endif //CXIMAGE_SUPPORT_INTERPOLATION - { - c = GetPaletteColor(GetPixelIndex(sx,sy)); - } - if (info.bAlphaPaletteEnabled){ - a = (BYTE)((a*(1+c.rgbReserved))>>8); - } - } else { -#if CXIMAGE_SUPPORT_INTERPOLATION - if (bSmooth){ - if (fx > 1 && fy > 1) { - c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); - } else { - c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); - } - } else -#endif //CXIMAGE_SUPPORT_INTERPOLATION - { - ppix = psrc + sx*3; - c.rgbBlue = *ppix++; - c.rgbGreen= *ppix++; - c.rgbRed = *ppix; - } - } - //if (*pc!=*pct || !bTransparent){ - //if ((head.biClrUsed && ci!=cit) || ((!head.biClrUsed||bSmooth) && *pc!=*pct) || !bTransparent){ - if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){ - // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication - if (a == 0) { // Transparent, retain dest - pdst+=3; - } else if (a == 255) { // opaque, ignore dest - *pdst++= c.rgbBlue; - *pdst++= c.rgbGreen; - *pdst++= c.rgbRed; - } else { // semi transparent - a1=(BYTE)~a; - *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); - *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); - *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); - } - } else { - pdst+=3; - } - } - } - } else { - //NORMAL - iy=head.biHeight-ymax+y; - for(yy=0;yy>8); - - if (head.biClrUsed){ - ci = GetPixelIndex(ix,iy); - c = GetPaletteColor((BYTE)ci); - if (info.bAlphaPaletteEnabled){ - a = (BYTE)((a*(1+c.rgbReserved))>>8); - } - } else { - c.rgbBlue = *ppix++; - c.rgbGreen= *ppix++; - c.rgbRed = *ppix++; - } - - //if (*pc!=*pct || !bTransparent){ - if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){ - // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication - if (a == 0) { // Transparent, retain dest - pdst+=3; - } else if (a == 255) { // opaque, ignore dest - *pdst++= c.rgbBlue; - *pdst++= c.rgbGreen; - *pdst++= c.rgbRed; - } else { // semi transparent - a1=(BYTE)~a; - *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); - *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); - *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); - } - } else { - pdst+=3; - } - } - } - } - } - //paint the image & cleanup - SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0); - DeleteObject(SelectObject(TmpDC,TmpObj)); - DeleteDC(TmpDC); - } - -#if !defined (_WIN32_WCE) - if (pClipRect){ // (experimental) - HRGN rgn = CreateRectRgnIndirect(&mainbox); - ExtSelectClipRgn(hdc,rgn,RGN_OR); - DeleteObject(rgn); - } -#endif - - ::RestoreDC(hdc,hdc_Restore); - return 1; -} -//////////////////////////////////////////////////////////////////////////////// -long CxImage::Draw2(HDC hdc, const RECT& rect) -{ - return Draw2(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Draws (stretch) the image with single transparency support - * \param hdc : destination device context - * \param x,y : (optional) offset - * \param cx,cy : (optional) size. - * - If cx or cy are not specified (or less than 0), the normal width or height will be used - * - If cx or cy are different than width or height, the image will be stretched - * - * \return true if everything is ok - */ -long CxImage::Draw2(HDC hdc, long x, long y, long cx, long cy) -{ - if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0; - if (cx < 0) cx = head.biWidth; - if (cy < 0) cy = head.biHeight; - bool bTransparent = (info.nBkgndIndex >= 0); - - //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield] - int hdc_Restore = ::SaveDC(hdc); - if (!hdc_Restore) - return 0; - - if (!bTransparent){ -#if !defined (_WIN32_WCE) - SetStretchBltMode(hdc,COLORONCOLOR); -#endif - StretchDIBits(hdc, x, y, cx, cy, 0, 0, head.biWidth, head.biHeight, - info.pImage,(BITMAPINFO*)pDib, DIB_RGB_COLORS,SRCCOPY); - } else { - // draw image with transparent background - const int safe = 0; // or else GDI fails in the following - sometimes - RECT rcDst = {x+safe, y+safe, x+cx, y+cy}; - if (RectVisible(hdc, &rcDst)){ - ///////////////////////////////////////////////////////////////// - // True Mask Method - Thanks to Paul Reynolds and Ron Gery - int nWidth = head.biWidth; - int nHeight = head.biHeight; - // Create two memory dcs for the image and the mask - HDC dcImage=CreateCompatibleDC(hdc); - HDC dcTrans=CreateCompatibleDC(hdc); - // Select the image into the appropriate dc - HBITMAP bm = CreateCompatibleBitmap(hdc, nWidth, nHeight); - HBITMAP pOldBitmapImage = (HBITMAP)SelectObject(dcImage,bm); -#if !defined (_WIN32_WCE) - SetStretchBltMode(dcImage,COLORONCOLOR); -#endif - StretchDIBits(dcImage, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight, - info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,SRCCOPY); - - // Create the mask bitmap - HBITMAP bitmapTrans = CreateBitmap(nWidth, nHeight, 1, 1, NULL); - // Select the mask bitmap into the appropriate dc - HBITMAP pOldBitmapTrans = (HBITMAP)SelectObject(dcTrans, bitmapTrans); - // Build mask based on transparent colour - RGBQUAD rgbBG; - if (head.biBitCount<24) rgbBG = GetPaletteColor((BYTE)info.nBkgndIndex); - else rgbBG = info.nBkgndColor; - COLORREF crColour = RGB(rgbBG.rgbRed, rgbBG.rgbGreen, rgbBG.rgbBlue); - COLORREF crOldBack = SetBkColor(dcImage,crColour); - BitBlt(dcTrans,0, 0, nWidth, nHeight, dcImage, 0, 0, SRCCOPY); - - // Do the work - True Mask method - cool if not actual display - StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT); - StretchBlt(hdc,x, y,cx,cy, dcTrans, 0, 0, nWidth, nHeight, SRCAND); - StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT); - - // Restore settings - SelectObject(dcImage,pOldBitmapImage); - SelectObject(dcTrans,pOldBitmapTrans); - SetBkColor(hdc,crOldBack); - DeleteObject( bitmapTrans ); // RG 29/01/2002 - DeleteDC(dcImage); - DeleteDC(dcTrans); - DeleteObject(bm); - } - } - ::RestoreDC(hdc,hdc_Restore); - return 1; -} -//////////////////////////////////////////////////////////////////////////////// -long CxImage::Stretch(HDC hdc, const RECT& rect, DWORD dwRop) -{ - return Stretch(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, dwRop); -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Stretch the image. Obsolete: use Draw() or Draw2() - * \param hdc : destination device context - * \param xoffset,yoffset : (optional) offset - * \param xsize,ysize : size. - * \param dwRop : raster operation code (see BitBlt documentation) - * \return true if everything is ok - */ -long CxImage::Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop) -{ - if((pDib)&&(hdc)) { - //palette must be correctly filled -#if !defined (_WIN32_WCE) - SetStretchBltMode(hdc,COLORONCOLOR); -#endif - StretchDIBits(hdc, xoffset, yoffset, - xsize, ysize, 0, 0, head.biWidth, head.biHeight, - info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,dwRop); - return 1; - } - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -/** - * Tiles the device context in the specified rectangle with the image. - * \param hdc : destination device context - * \param rc : tiled rectangle in the output device context - * \return true if everything is ok - */ -long CxImage::Tile(HDC hdc, RECT *rc) -{ - if((pDib)&&(hdc)&&(rc)) { - int w = rc->right - rc->left; - int h = rc->bottom - rc->top; - int x,y,z; - int bx=head.biWidth; - int by=head.biHeight; - for (y = 0 ; y < h ; y += by){ - if ((y+by)>h) by=h-y; - z=bx; - for (x = 0 ; x < w ; x += z){ - if ((x+z)>w) z=w-x; - RECT r = {rc->left + x,rc->top + y,rc->left + x + z,rc->top + y + by}; - Draw(hdc,rc->left + x, rc->top + y,-1,-1,&r); - } - } - return 1; - } - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -// For UNICODE support: char -> TCHAR -long CxImage::DrawString(HDC hdc, long x, long y, const TCHAR* text, RGBQUAD color, const TCHAR* font, long lSize, long lWeight, BYTE bItalic, BYTE bUnderline, bool bSetAlpha) -//long CxImage::DrawString(HDC hdc, long x, long y, const char* text, RGBQUAD color, const char* font, long lSize, long lWeight, BYTE bItalic, BYTE bUnderline, bool bSetAlpha) -{ - if (IsValid()){ - //get the background - HDC pDC; - if (hdc) pDC=hdc; else pDC = ::GetDC(0); - if (pDC==NULL) return 0; - HDC TmpDC=CreateCompatibleDC(pDC); - if (hdc==NULL) ::ReleaseDC(0, pDC); - if (TmpDC==NULL) return 0; - //choose the font - HFONT m_Font; - LOGFONT* m_pLF; - m_pLF=(LOGFONT*)calloc(1,sizeof(LOGFONT)); - _tcsncpy(m_pLF->lfFaceName,font,31); // For UNICODE support - //strncpy(m_pLF->lfFaceName,font,31); - m_pLF->lfHeight=lSize; - m_pLF->lfWeight=lWeight; - m_pLF->lfItalic=bItalic; - m_pLF->lfUnderline=bUnderline; - m_Font=CreateFontIndirect(m_pLF); - //select the font in the dc - HFONT pOldFont=NULL; - if (m_Font) - pOldFont = (HFONT)SelectObject(TmpDC,m_Font); - else - pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT)); - - //Set text color - SetTextColor(TmpDC,RGB(255,255,255)); - SetBkColor(TmpDC,RGB(0,0,0)); - //draw the text - SetBkMode(TmpDC,OPAQUE); - //Set text position; - RECT pos = {0,0,0,0}; - //long len = (long)strlen(text); - long len = (long)_tcslen(text); // For UNICODE support - ::DrawText(TmpDC,text,len,&pos,DT_CALCRECT); - pos.right+=pos.bottom; //for italics - - //Preparing Bitmap Info - long width=pos.right; - long height=pos.bottom; - BITMAPINFO bmInfo; - memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); - bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); - bmInfo.bmiHeader.biWidth=width; - bmInfo.bmiHeader.biHeight=height; - bmInfo.bmiHeader.biPlanes=1; - bmInfo.bmiHeader.biBitCount=24; - BYTE *pbase; //points to the final dib - - HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); - HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); - memset(pbase,0,height*((((24 * width) + 31) / 32) * 4)); - - ::DrawText(TmpDC,text,len,&pos,0); - - CxImage itext; - itext.CreateFromHBITMAP(TmpBmp); - - y=head.biHeight-y-1; - for (long ix=0;ix -long CxImage::DrawStringEx(HDC hdc, long x, long y, CXTEXTINFO *pTextType, bool bSetAlpha ) -{ - if (!IsValid()) - return -1; - - //get the background - HDC pDC; - if (hdc) pDC=hdc; else pDC = ::GetDC(0); - if (pDC==NULL) return 0; - HDC TmpDC=CreateCompatibleDC(pDC); - if (hdc==NULL) ::ReleaseDC(0, pDC); - if (TmpDC==NULL) return 0; - - //choose the font - HFONT m_Font; - m_Font=CreateFontIndirect( &pTextType->lfont ); - - // get colors in RGBQUAD - RGBQUAD p_forecolor = RGBtoRGBQUAD(pTextType->fcolor); - RGBQUAD p_backcolor = RGBtoRGBQUAD(pTextType->bcolor); - - // check alignment and re-set default if necessary - if ( pTextType->align != DT_CENTER && - pTextType->align != DT_LEFT && - pTextType->align != DT_RIGHT ) - pTextType->align = DT_CENTER; - - // check rounding radius and re-set default if necessary - if ( pTextType->b_round > 50 ) - pTextType->b_round = 10; - - // check opacity and re-set default if necessary - if ( pTextType->b_opacity > 1. || pTextType->b_opacity < .0 ) - pTextType->b_opacity = 0.; - - //select the font in the dc - HFONT pOldFont=NULL; - if (m_Font) - pOldFont = (HFONT)SelectObject(TmpDC,m_Font); - else - pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT)); - - //Set text color - SetTextColor(TmpDC,RGB(255,255,255)); - SetBkColor(TmpDC,RGB(0,0,0)); - SetBkMode(TmpDC,OPAQUE); - //Set text position; - RECT pos = {0,0,0,0}; - - // get text length and number of lines - long i=0, numlines=1, len=(long)_tcsclen(pTextType->text); - while (itext[i++]==13 ) - numlines++; - } - - ::DrawText(TmpDC, pTextType->text, len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX | DT_CALCRECT ); - - // increase only if it's really italics, and only one line height - if ( pTextType->lfont.lfItalic ) - pos.right += pos.bottom/2/numlines; - - // background frame and rounding radius - int frame = 0, roundR = 0; - if ( pTextType->opaque ) - { - roundR= (int)(pos.bottom/numlines * pTextType->b_round / 100 ) ; - frame = (int)(/*3.5 + */0.29289*roundR ) ; - pos.right += pos.bottom/numlines/3 ; // JUST FOR BEAUTY - } - - //Preparing Bitmap Info - long width=pos.right +frame*2; - long height=pos.bottom +frame*2; - BITMAPINFO bmInfo; - memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); - bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); - bmInfo.bmiHeader.biWidth=width; - bmInfo.bmiHeader.biHeight=height; - bmInfo.bmiHeader.biPlanes=1; - bmInfo.bmiHeader.biBitCount=24; - BYTE *pbase; //points to the final dib - - HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); - HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); - memset(pbase,0,height*((((24 * width) + 31) / 32) * 4)); - - ::DrawText(TmpDC,pTextType->text,len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX| pTextType->align ); - - CxImage itext; - itext.CreateFromHBITMAP(TmpBmp); - y=head.biHeight-y-1; - - itext.Negative(); - - if (pTextType->smooth==FALSE){ - itext.Threshold(128); - } else { - //itext.TextBlur(); - } - - //move the insertion point according to alignment type - // DT_CENTER: cursor points to the center of text rectangle - // DT_RIGHT: cursor points to right side end of text rectangle - // DT_LEFT: cursor points to left end of text rectangle - if ( pTextType->align == DT_CENTER ) - x -= width/2; - else if ( pTextType->align == DT_RIGHT ) - x -= width; - if (x<0) x=0; - - //draw the background first, if it exists - long ix,iy; - if ( pTextType->opaque ) - { - int ixf=0; - for (ix=0;ix=width-roundR-1 ) - ixf = (int)(.5+roundR-sqrt((float)(roundR*roundR-(width-1-ix-roundR)*(width-1-ix-roundR)))); - else - ixf=0; - - for (iy=0;iy height-ixf-1 || iy < ixf )) || - (ix>=width-roundR-1 && ( iy > height-ixf-1 || iy < ixf )) ) - continue; - else - if ( pTextType->b_opacity > 0.0 && pTextType->b_opacity < 1.0 ) - { - RGBQUAD bcolor, pcolor; - // calculate a transition color from original image to background color: - pcolor = GetPixelColor(x+ix,y+iy); - bcolor.rgbBlue = (unsigned char)(pTextType->b_opacity * pcolor.rgbBlue + (1.0-pTextType->b_opacity) * p_backcolor.rgbBlue ); - bcolor.rgbRed = (unsigned char)(pTextType->b_opacity * pcolor.rgbRed + (1.0-pTextType->b_opacity) * p_backcolor.rgbRed ) ; - bcolor.rgbGreen = (unsigned char)(pTextType->b_opacity * pcolor.rgbGreen + (1.0-pTextType->b_opacity) * p_backcolor.rgbGreen ) ; - bcolor.rgbReserved = 0; - SetPixelColor(x+ix,y+iy,bcolor,bSetAlpha); - } - else - SetPixelColor(x+ix,y+iy,p_backcolor,bSetAlpha); - } - } - } - - // draw the text itself - for (ix=0;ixlfont.lfHeight = -36; - txt->lfont.lfCharSet = EASTEUROPE_CHARSET; // just for Central-European users - txt->lfont.lfWeight = FW_NORMAL; - txt->lfont.lfWidth = 0; - txt->lfont.lfEscapement = 0; - txt->lfont.lfOrientation = 0; - txt->lfont.lfItalic = FALSE; - txt->lfont.lfUnderline = FALSE; - txt->lfont.lfStrikeOut = FALSE; - txt->lfont.lfOutPrecision = OUT_DEFAULT_PRECIS; - txt->lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - txt->lfont.lfQuality = PROOF_QUALITY; - txt->lfont.lfPitchAndFamily= DEFAULT_PITCH | FF_DONTCARE ; - _stprintf( txt->lfont.lfFaceName, _T("Arial")); //use TCHAR mappings - - // initial colors - txt->fcolor = RGB( 255,255,160 ); // default foreground: light goldyellow - txt->bcolor = RGB( 0, 80,160 ); // default background: light blue - - // background - txt->opaque = TRUE; // text has a non-transparent background; - txt->smooth = TRUE; - txt->b_opacity = 0.0; // default: opaque background - txt->b_outline = 0; // default: no outline (OUTLINE NOT IMPLEMENTED AT THIS TIME) - txt->b_round = 20; // default: rounding radius is 20% of the rectangle height - // the text - _stprintf( txt->text, _T("Sample Text 01234õû")); // text use TCHAR mappings - txt->align = DT_CENTER; - return; -} - -#if CXIMAGE_SUPPORT_LAYERS -//////////////////////////////////////////////////////////////////////////////// -long CxImage::LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth) -{ - return LayerDrawAll(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth); -} -//////////////////////////////////////////////////////////////////////////////// -long CxImage::LayerDrawAll(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth) -{ - long n=0; - CxImage* pLayer; - while(pLayer=GetLayer(n++)){ - if (pLayer->Draw(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0) - return 0; - if (pLayer->LayerDrawAll(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0) - return 0; - } - return 1; -} -#endif //CXIMAGE_SUPPORT_LAYERS - -//////////////////////////////////////////////////////////////////////////////// -#endif //CXIMAGE_SUPPORT_WINDOWS -//////////////////////////////////////////////////////////////////////////////// +// xImaWnd.cpp : Windows functions +/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it + * CxImage version 6.0.0 02/Feb/2008 + */ + +#include "ximage.h" + +#include "ximaiter.h" +#include "ximabmp.h" + +//////////////////////////////////////////////////////////////////////////////// +#if defined (_WIN32_WCE) + +#ifndef DEFAULT_GUI_FONT +#define DEFAULT_GUI_FONT 17 +#endif + +#ifndef PROOF_QUALITY +#define PROOF_QUALITY 2 +#endif + +struct DIBINFO : public BITMAPINFO +{ + RGBQUAD arColors[255]; // Color table info - adds an extra 255 entries to palette + operator LPBITMAPINFO() { return (LPBITMAPINFO) this; } + operator LPBITMAPINFOHEADER() { return &bmiHeader; } + RGBQUAD* ColorTable() { return bmiColors; } +}; + +int BytesPerLine(int nWidth, int nBitsPerPixel) +{ + return ( (nWidth * nBitsPerPixel + 31) & (~31) ) / 8; +} + +int NumColorEntries(int nBitsPerPixel, int nCompression, DWORD biClrUsed) +{ + int nColors = 0; + switch (nBitsPerPixel) + { + case 1: + nColors = 2; break; + case 2: + nColors = 4; break; // winCE only + case 4: + nColors = 16; break; + case 8: + nColors =256; break; + case 24: + nColors = 0; break; + case 16: + case 32: + nColors = 3; break; // I've found that PocketPCs need this regardless of BI_RGB or BI_BITFIELDS + default: + ASSERT(FALSE); + } + // If biClrUsed is provided, and it is a legal value, use it + if (biClrUsed > 0 && biClrUsed <= (DWORD)nColors) + return biClrUsed; + + return nColors; +} + +int GetDIBits( + HDC hdc, // handle to DC + HBITMAP hbmp, // handle to bitmap + UINT uStartScan, // first scan line to set + UINT cScanLines, // number of scan lines to copy + LPVOID lpvBits, // array for bitmap bits + LPBITMAPINFO lpbi, // bitmap data buffer + UINT uUsage // RGB or palette index +) +{ + UINT iColorTableSize = 0; + + if (!hbmp) + return 0; + + // Get dimensions of bitmap + BITMAP bm; + if (!::GetObject(hbmp, sizeof(bm),(LPVOID)&bm)) + return 0; + + //3. Creating new bitmap and receive pointer to it's bits. + HBITMAP hTargetBitmap; + void *pBuffer; + + //3.1 Initilize DIBINFO structure + DIBINFO dibInfo; + dibInfo.bmiHeader.biBitCount = 24; + dibInfo.bmiHeader.biClrImportant = 0; + dibInfo.bmiHeader.biClrUsed = 0; + dibInfo.bmiHeader.biCompression = 0; + dibInfo.bmiHeader.biHeight = bm.bmHeight; + dibInfo.bmiHeader.biPlanes = 1; + dibInfo.bmiHeader.biSize = 40; + dibInfo.bmiHeader.biSizeImage = bm.bmHeight*BytesPerLine(bm.bmWidth,24); + dibInfo.bmiHeader.biWidth = bm.bmWidth; + dibInfo.bmiHeader.biXPelsPerMeter = 3780; + dibInfo.bmiHeader.biYPelsPerMeter = 3780; + dibInfo.bmiColors[0].rgbBlue = 0; + dibInfo.bmiColors[0].rgbGreen = 0; + dibInfo.bmiColors[0].rgbRed = 0; + dibInfo.bmiColors[0].rgbReserved = 0; + + //3.2 Create bitmap and receive pointer to points into pBuffer + HDC hDC = ::GetDC(NULL); + ASSERT(hDC); + hTargetBitmap = CreateDIBSection( + hDC, + (const BITMAPINFO*)dibInfo, + DIB_RGB_COLORS, + (void**)&pBuffer, + NULL, + 0); + + ::ReleaseDC(NULL, hDC); + + //4. Copy source bitmap into the target bitmap. + + //4.1 Create 2 device contexts + HDC memDc = CreateCompatibleDC(NULL); + if (!memDc) { + ASSERT(FALSE); + } + + HDC targetDc = CreateCompatibleDC(NULL); + if (!targetDc) { + ASSERT(FALSE); + } + + //4.2 Select source bitmap into one DC, target into another + HBITMAP hOldBitmap1 = (HBITMAP)::SelectObject(memDc, hbmp); + HBITMAP hOldBitmap2 = (HBITMAP)::SelectObject(targetDc, hTargetBitmap); + + //4.3 Copy source bitmap into the target one + BitBlt(targetDc, 0, 0, bm.bmWidth, bm.bmHeight, memDc, 0, 0, SRCCOPY); + + //4.4 Restore device contexts + ::SelectObject(memDc, hOldBitmap1); + ::SelectObject(targetDc, hOldBitmap2); + DeleteDC(memDc); + DeleteDC(targetDc); + + //Here we can bitmap bits: pBuffer. Note: + // 1. pBuffer contains 3 bytes per point + // 2. Lines ane from the bottom to the top! + // 3. Points in the line are from the left to the right + // 4. Bytes in one point are BGR (blue, green, red) not RGB + // 5. Don't delete pBuffer, it will be automatically deleted + // when delete hTargetBitmap + lpvBits = pBuffer; + + DeleteObject(hbmp); + //DeleteObject(hTargetBitmap); + + return 1; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +#if CXIMAGE_SUPPORT_WINDOWS +//////////////////////////////////////////////////////////////////////////////// +long CxImage::Blt(HDC pDC, long x, long y) +{ + if((pDib==0)||(pDC==0)||(!info.bEnabled)) return 0; + + HBRUSH brImage = CreateDIBPatternBrushPt(pDib, DIB_RGB_COLORS); + POINT pt; + SetBrushOrgEx(pDC,x,y,&pt); // + HBRUSH brOld = (HBRUSH) SelectObject(pDC, brImage); + PatBlt(pDC, x, y, head.biWidth, head.biHeight, PATCOPY); + SelectObject(pDC, brOld); + SetBrushOrgEx(pDC,pt.x,pt.y,NULL); + DeleteObject(brImage); + return 1; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Transfer the image in a global bitmap handle (clipboard copy) + */ +HANDLE CxImage::CopyToHandle() +{ + HANDLE hMem=NULL; + if (pDib){ + hMem= GlobalAlloc(GHND, GetSize()); + if (hMem){ + BYTE* pDst=(BYTE*)GlobalLock(hMem); + if (pDst){ + memcpy(pDst,pDib,GetSize()); + } + GlobalUnlock(hMem); + } + } + return hMem; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Global object (clipboard paste) constructor + * \param hMem: source bitmap object, the clipboard format must be CF_DIB + * \return true if everything is ok + */ +bool CxImage::CreateFromHANDLE(HANDLE hMem) +{ + if (!Destroy()) + return false; + + DWORD dwSize = GlobalSize(hMem); + if (!dwSize) return false; + + BYTE *lpVoid; //pointer to the bitmap + lpVoid = (BYTE *)GlobalLock(hMem); + BITMAPINFOHEADER *pHead; //pointer to the bitmap header + pHead = (BITMAPINFOHEADER *)lpVoid; + if (lpVoid){ + + //CxMemFile hFile(lpVoid,dwSize); + + //copy the bitmap header + memcpy(&head,pHead,sizeof(BITMAPINFOHEADER)); + //check if it's a top-down bitmap + bool bTopDownDib = head.biHeight<0; + if (bTopDownDib) head.biHeight=-head.biHeight; + //create the image + if(!Create(head.biWidth,head.biHeight,head.biBitCount)){ + GlobalUnlock(lpVoid); + return false; + } + //preserve DPI + SetXDPI((long)floor(head.biXPelsPerMeter * 254.0 / 10000.0 + 0.5)); + SetYDPI((long)floor(head.biYPelsPerMeter * 254.0 / 10000.0 + 0.5)); + + /*//copy the pixels (old way) + if((pHead->biCompression != BI_RGB) || (pHead->biBitCount == 32)){ // + // BITFIELD case + // set the internal header in the dib + memcpy(pDib,&head,sizeof(head)); + // get the bitfield masks + DWORD bf[3]; + memcpy(bf,lpVoid+pHead->biSize,12); + // transform into RGB + Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount); + } else { //normal bitmap + memcpy(pDib,lpVoid,GetSize()); + }*/ + + // + // fill in color map + bool bIsOldBmp = (head.biSize == sizeof(BITMAPCOREHEADER)); + RGBQUAD *pRgb = GetPalette(); + if (pRgb) { + // number of colors to fill in + int nColors = DibNumColors(pHead); + if (bIsOldBmp) { + /* get pointer to BITMAPCOREINFO (old style 1.x) */ + LPBITMAPCOREINFO lpbmc = (LPBITMAPCOREINFO)lpVoid; + for (int i = nColors - 1; i >= 0; i--) { + pRgb[i].rgbRed = lpbmc->bmciColors[i].rgbtRed; + pRgb[i].rgbGreen = lpbmc->bmciColors[i].rgbtGreen; + pRgb[i].rgbBlue = lpbmc->bmciColors[i].rgbtBlue; + pRgb[i].rgbReserved = (BYTE)0; + } + } else { + /* get pointer to BITMAPINFO (new style 3.x) */ + LPBITMAPINFO lpbmi = (LPBITMAPINFO)lpVoid; + for (int i = nColors - 1; i >= 0; i--) { + pRgb[i].rgbRed = lpbmi->bmiColors[i].rgbRed; + pRgb[i].rgbGreen = lpbmi->bmiColors[i].rgbGreen; + pRgb[i].rgbBlue = lpbmi->bmiColors[i].rgbBlue; + pRgb[i].rgbReserved = (BYTE)0; + } + } + } + + // + DWORD dwCompression = pHead->biCompression; + // compressed bitmap ? + if(dwCompression!=BI_RGB || pHead->biBitCount==32 || pHead->biBitCount ==16) { + // get the bitmap bits + LPSTR lpDIBBits = (LPSTR)((BYTE*)pHead + *(DWORD*)pHead + (WORD)(GetNumColors() * sizeof(RGBQUAD))); + // decode and copy them to our image + switch (pHead->biBitCount) { + case 32 : + { + // BITFIELD case + if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB) { + // get the bitfield masks + DWORD bf[3]; + memcpy(bf,lpVoid+pHead->biSize,12); + // transform into RGB + Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount); + } else { + // "unknown compression"; + GlobalUnlock(lpVoid); + return false; + } + } + break; + case 16 : + { + // get the bitfield masks + long offset=0; + DWORD bf[3]; + if (dwCompression == BI_BITFIELDS) { + memcpy(bf,lpVoid+pHead->biSize,12); + offset= 12; + } else { + bf[0] = 0x7C00; + bf[1] = 0x3E0; + bf[2] = 0x1F; // RGB555 + } + // copy the pixels + memcpy(info.pImage, lpDIBBits + offset, head.biHeight*((head.biWidth+1)/2)*4); + // transform into RGB + Bitfield2RGB(info.pImage, bf[0], bf[1], bf[2], 16); + } + break; + case 8 : + case 4 : + case 1 : + { + switch (dwCompression) { + case BI_RLE4: + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + BOOL low_nibble = FALSE; + CImageIterator iter(this); + + for (BOOL bContinue = TRUE; bContinue; ) { + status_byte = *(lpDIBBits++); + switch (status_byte) { + case RLE_COMMAND : + status_byte = *(lpDIBBits++); + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + low_nibble = FALSE; + break; + case RLE_ENDOFBITMAP : + bContinue = FALSE; + break; + case RLE_DELTA : + { + // read the delta values + BYTE delta_x; + BYTE delta_y; + delta_x = *(lpDIBBits++); + delta_y = *(lpDIBBits++); + // apply them + bits += delta_x / 2; + scanline += delta_y; + break; + } + default : + second_byte = *(lpDIBBits++); + BYTE* sline = iter.GetRow(scanline); + for (int i = 0; i < status_byte; i++) { + if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ + if (low_nibble) { + if (i&1) + *(sline + bits) |= (second_byte & 0x0f); + else + *(sline + bits) |= (second_byte & 0xf0)>>4; + bits++; + } else { + if (i&1) + *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; + else + *(sline + bits) = (BYTE)(second_byte & 0xf0); + } + } + + if ((i & 1) && (i != (status_byte - 1))) + second_byte = *(lpDIBBits++); + + low_nibble = !low_nibble; + } + if ((((status_byte+1) >> 1) & 1 ) == 1) + second_byte = *(lpDIBBits++); + break; + }; + break; + default : + { + BYTE* sline = iter.GetRow(scanline); + second_byte = *(lpDIBBits++); + for (unsigned i = 0; i < status_byte; i++) { + if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){ + if (low_nibble) { + if (i&1) + *(sline + bits) |= (second_byte & 0x0f); + else + *(sline + bits) |= (second_byte & 0xf0)>>4; + bits++; + } else { + if (i&1) + *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4; + else + *(sline + bits) = (BYTE)(second_byte & 0xf0); + } + } + low_nibble = !low_nibble; + } + } + break; + }; + } + } + break; + case BI_RLE8 : + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + CImageIterator iter(this); + + for (BOOL bContinue = TRUE; bContinue; ) { + status_byte = *(lpDIBBits++); + if (status_byte==RLE_COMMAND) { + status_byte = *(lpDIBBits++); + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + break; + case RLE_ENDOFBITMAP : + bContinue = FALSE; + break; + case RLE_DELTA : + { + // read the delta values + BYTE delta_x; + BYTE delta_y; + delta_x = *(lpDIBBits++); + delta_y = *(lpDIBBits++); + // apply them + bits += delta_x; + scanline += delta_y; + } + break; + default : + int nNumBytes = sizeof(BYTE) * status_byte; + memcpy((void *)(iter.GetRow(scanline) + bits), lpDIBBits, nNumBytes); + lpDIBBits += nNumBytes; + // align run length to even number of bytes + if ((status_byte & 1) == 1) + second_byte = *(lpDIBBits++); + bits += status_byte; + break; + }; + } else { + BYTE *sline = iter.GetRow(scanline); + second_byte = *(lpDIBBits++); + for (unsigned i = 0; i < status_byte; i++) { + if ((DWORD)bits + // // Create a device-independent bitmap + // return CreateBitmap(head.biWidth,head.biHeight, 1, head.biBitCount, GetBits()); + // use instead this code + HDC hMemDC = CreateCompatibleDC(NULL); + LPVOID pBit32; + HBITMAP bmp = CreateDIBSection(hMemDC,(LPBITMAPINFO)pDib,DIB_RGB_COLORS, &pBit32, NULL, 0); + if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage); + DeleteDC(hMemDC); + return bmp; + } + + // this single line seems to work very well + //HBITMAP bmp = CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)pDib, CBM_INIT, + // GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS); + // this alternative works also with _WIN32_WCE + LPVOID pBit32; + HBITMAP bmp = CreateDIBSection(hdc, (LPBITMAPINFO)pDib, DIB_RGB_COLORS, &pBit32, NULL, 0); + if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage); + + return bmp; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Bitmap resource constructor + * \param hbmp : bitmap resource handle + * \param hpal : (optional) palette, useful for 8bpp DC + * \return true if everything is ok + */ +bool CxImage::CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal) +{ + if (!Destroy()) + return false; + + if (hbmp) { + BITMAP bm; + // get informations about the bitmap + GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm); + // create the image + if (!Create(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0)) + return false; + // create a device context for the bitmap + HDC dc = ::GetDC(NULL); + if (!dc) + return false; + + if (hpal){ + SelectObject(dc,hpal); //the palette you should get from the user or have a stock one + RealizePalette(dc); + } + + // copy the pixels + if (GetDIBits(dc, hbmp, 0, head.biHeight, info.pImage, + (LPBITMAPINFO)pDib, DIB_RGB_COLORS) == 0){ //replace &head with pDib + strcpy(info.szLastError,"GetDIBits failed"); + ::ReleaseDC(NULL, dc); + return false; + } + ::ReleaseDC(NULL, dc); + return true; + } + return false; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * icon resource constructor + * \param hico : icon resource handle + * \return true if everything is ok + * \author []; changes [Arlen Albert Keshabian] + */ +#if !defined (_WIN32_WCE) +bool CxImage::CreateFromHICON(HICON hico) +{ + if (!Destroy() || !hico) + return false; + + bool l_bResult = true; + + ICONINFO iinfo; + GetIconInfo(hico,&iinfo); + + BITMAP l_Bitmap; + GetObject(iinfo.hbmColor, sizeof(BITMAP), &l_Bitmap); + + if(l_Bitmap.bmBitsPixel == 32) + { + BITMAPINFO l_BitmapInfo; + l_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + l_BitmapInfo.bmiHeader.biWidth = l_Bitmap.bmWidth; + l_BitmapInfo.bmiHeader.biHeight = l_Bitmap.bmHeight; + l_BitmapInfo.bmiHeader.biPlanes = l_Bitmap.bmPlanes; + l_BitmapInfo.bmiHeader.biBitCount = l_Bitmap.bmBitsPixel; + l_BitmapInfo.bmiHeader.biCompression = BI_RGB; + + RGBQUAD *l_pRawBytes = new RGBQUAD[l_Bitmap.bmWidth * l_Bitmap.bmHeight]; + + HDC dc = ::GetDC(NULL); + + if(dc) + { + if(GetDIBits(dc, iinfo.hbmColor, 0, l_Bitmap.bmHeight, l_pRawBytes, &l_BitmapInfo, DIB_RGB_COLORS)) + l_bResult = CreateFromArray((BYTE*)l_pRawBytes, l_Bitmap.bmWidth, l_Bitmap.bmHeight, l_Bitmap.bmBitsPixel, l_Bitmap.bmWidthBytes, false); + else + l_bResult = false; + + ::ReleaseDC(NULL, dc); + } + else + l_bResult = false; + + delete [] l_pRawBytes; + } + else + { + l_bResult = CreateFromHBITMAP(iinfo.hbmColor); +#if CXIMAGE_SUPPORT_ALPHA + if(l_bResult) + { + CxImage mask; + mask.CreateFromHBITMAP(iinfo.hbmMask); + mask.GrayScale(); + mask.Negative(); + AlphaSet(mask); + } +#endif + } + + DeleteObject(iinfo.hbmColor); // + DeleteObject(iinfo.hbmMask); // + + return l_bResult; +} +#endif //_WIN32_WCE +//////////////////////////////////////////////////////////////////////////////// +long CxImage::Draw(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth) +{ + return Draw(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Draws the image in the specified device context, with support for alpha channel, alpha palette, transparency, opacity. + * \param hdc : destination device context + * \param x,y : (optional) offset + * \param cx,cy : (optional) size. + * - If cx or cy are not specified (or less than 0), the normal width or height will be used + * - If cx or cy are different than width or height, the image will be stretched + * + * \param pClipRect : limit the drawing operations inside a given rectangle in the output device context. + * \param bSmooth : activates a bilinear filter that will enhance the appearence for zommed pictures. + * Quite slow. Needs CXIMAGE_SUPPORT_INTERPOLATION. + * \return true if everything is ok + */ +long CxImage::Draw(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth) +{ + if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0; + + if (cx < 0) cx = head.biWidth; + if (cy < 0) cy = head.biHeight; + bool bTransparent = info.nBkgndIndex >= 0; + bool bAlpha = pAlpha != 0; + + //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield] + int hdc_Restore = ::SaveDC(hdc); + if (!hdc_Restore) + return 0; + +#if !defined (_WIN32_WCE) + RECT mainbox; // (experimental) + if (pClipRect){ + GetClipBox(hdc,&mainbox); + HRGN rgn = CreateRectRgnIndirect(pClipRect); + ExtSelectClipRgn(hdc,rgn,RGN_AND); + DeleteObject(rgn); + } +#endif + + //find the smallest area to paint + RECT clipbox,paintbox; + GetClipBox(hdc,&clipbox); + + paintbox.top = min(clipbox.bottom,max(clipbox.top,y)); + paintbox.left = min(clipbox.right,max(clipbox.left,x)); + paintbox.right = max(clipbox.left,min(clipbox.right,x+cx)); + paintbox.bottom = max(clipbox.top,min(clipbox.bottom,y+cy)); + + long destw = paintbox.right - paintbox.left; + long desth = paintbox.bottom - paintbox.top; + + if (!(bTransparent || bAlpha || info.bAlphaPaletteEnabled)){ + if (cx==head.biWidth && cy==head.biHeight){ //NORMAL +#if !defined (_WIN32_WCE) + SetStretchBltMode(hdc,COLORONCOLOR); +#endif + SetDIBitsToDevice(hdc, x, y, cx, cy, 0, 0, 0, cy, + info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS); + } else { //STRETCH + //pixel informations + RGBQUAD c={0,0,0,0}; + //Preparing Bitmap Info + BITMAPINFO bmInfo; + memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); + bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + bmInfo.bmiHeader.biWidth=destw; + bmInfo.bmiHeader.biHeight=desth; + bmInfo.bmiHeader.biPlanes=1; + bmInfo.bmiHeader.biBitCount=24; + BYTE *pbase; //points to the final dib + BYTE *pdst; //current pixel from pbase + BYTE *ppix; //current pixel from image + //get the background + HDC TmpDC=CreateCompatibleDC(hdc); + HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); + HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); + + if (pbase){ + long xx,yy; + long sx,sy; + float dx,dy; + BYTE *psrc; + + long ew = ((((24 * destw) + 31) / 32) * 4); + long ymax = paintbox.bottom; + long xmin = paintbox.left; + float fx=(float)head.biWidth/(float)cx; + float fy=(float)head.biHeight/(float)cy; + + for(yy=0;yy 1 && fy > 1) { + c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); + } else { + c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); + } + } else +#endif //CXIMAGE_SUPPORT_INTERPOLATION + { + if (head.biClrUsed){ + c=GetPaletteColor(GetPixelIndex(sx,sy)); + } else { + ppix = psrc + sx*3; + c.rgbBlue = *ppix++; + c.rgbGreen= *ppix++; + c.rgbRed = *ppix; + } + } + *pdst++=c.rgbBlue; + *pdst++=c.rgbGreen; + *pdst++=c.rgbRed; + } + } + } + //paint the image & cleanup + SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0); + DeleteObject(SelectObject(TmpDC,TmpObj)); + DeleteDC(TmpDC); + } + } else { // draw image with transparent/alpha blending + ////////////////////////////////////////////////////////////////// + //Alpha blend - Thanks to Florian Egel + + //pixel informations + RGBQUAD c={0,0,0,0}; + RGBQUAD ct = GetTransColor(); + long* pc = (long*)&c; + long* pct= (long*)&ct; + long cit = GetTransIndex(); + long ci = 0; + + //Preparing Bitmap Info + BITMAPINFO bmInfo; + memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); + bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + bmInfo.bmiHeader.biWidth=destw; + bmInfo.bmiHeader.biHeight=desth; + bmInfo.bmiHeader.biPlanes=1; + bmInfo.bmiHeader.biBitCount=24; + + BYTE *pbase; //points to the final dib + BYTE *pdst; //current pixel from pbase + BYTE *ppix; //current pixel from image + + //get the background + HDC TmpDC=CreateCompatibleDC(hdc); + HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); + HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); + BitBlt(TmpDC,0,0,destw,desth,hdc,paintbox.left,paintbox.top,SRCCOPY); + + if (pbase){ + long xx,yy,alphaoffset,ix,iy; + BYTE a,a1,*psrc; + long ew = ((((24 * destw) + 31) / 32) * 4); + long ymax = paintbox.bottom; + long xmin = paintbox.left; + + if (cx!=head.biWidth || cy!=head.biHeight){ + //STRETCH + float fx=(float)head.biWidth/(float)cx; + float fy=(float)head.biHeight/(float)cy; + float dx,dy; + long sx,sy; + + for(yy=0;yy>8); + + if (head.biClrUsed){ + ci = GetPixelIndex(sx,sy); +#if CXIMAGE_SUPPORT_INTERPOLATION + if (bSmooth){ + if (fx > 1 && fy > 1) { + c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); + } else { + c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); + } + } else +#endif //CXIMAGE_SUPPORT_INTERPOLATION + { + c = GetPaletteColor(GetPixelIndex(sx,sy)); + } + if (info.bAlphaPaletteEnabled){ + a = (BYTE)((a*(1+c.rgbReserved))>>8); + } + } else { +#if CXIMAGE_SUPPORT_INTERPOLATION + if (bSmooth){ + if (fx > 1 && fy > 1) { + c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); + } else { + c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); + } + } else +#endif //CXIMAGE_SUPPORT_INTERPOLATION + { + ppix = psrc + sx*3; + c.rgbBlue = *ppix++; + c.rgbGreen= *ppix++; + c.rgbRed = *ppix; + } + } + //if (*pc!=*pct || !bTransparent){ + //if ((head.biClrUsed && ci!=cit) || ((!head.biClrUsed||bSmooth) && *pc!=*pct) || !bTransparent){ + if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){ + // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication + if (a == 0) { // Transparent, retain dest + pdst+=3; + } else if (a == 255) { // opaque, ignore dest + *pdst++= c.rgbBlue; + *pdst++= c.rgbGreen; + *pdst++= c.rgbRed; + } else { // semi transparent + a1=(BYTE)~a; + *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); + *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); + *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); + } + } else { + pdst+=3; + } + } + } + } else { + //NORMAL + iy=head.biHeight-ymax+y; + for(yy=0;yy>8); + + if (head.biClrUsed){ + ci = GetPixelIndex(ix,iy); + c = GetPaletteColor((BYTE)ci); + if (info.bAlphaPaletteEnabled){ + a = (BYTE)((a*(1+c.rgbReserved))>>8); + } + } else { + c.rgbBlue = *ppix++; + c.rgbGreen= *ppix++; + c.rgbRed = *ppix++; + } + + //if (*pc!=*pct || !bTransparent){ + if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){ + // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication + if (a == 0) { // Transparent, retain dest + pdst+=3; + } else if (a == 255) { // opaque, ignore dest + *pdst++= c.rgbBlue; + *pdst++= c.rgbGreen; + *pdst++= c.rgbRed; + } else { // semi transparent + a1=(BYTE)~a; + *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); + *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); + *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); + } + } else { + pdst+=3; + } + } + } + } + } + //paint the image & cleanup + SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0); + DeleteObject(SelectObject(TmpDC,TmpObj)); + DeleteDC(TmpDC); + } + +#if !defined (_WIN32_WCE) + if (pClipRect){ // (experimental) + HRGN rgn = CreateRectRgnIndirect(&mainbox); + ExtSelectClipRgn(hdc,rgn,RGN_OR); + DeleteObject(rgn); + } +#endif + + ::RestoreDC(hdc,hdc_Restore); + return 1; +} +//////////////////////////////////////////////////////////////////////////////// +long CxImage::Draw2(HDC hdc, const RECT& rect) +{ + return Draw2(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Draws (stretch) the image with single transparency support + * \param hdc : destination device context + * \param x,y : (optional) offset + * \param cx,cy : (optional) size. + * - If cx or cy are not specified (or less than 0), the normal width or height will be used + * - If cx or cy are different than width or height, the image will be stretched + * + * \return true if everything is ok + */ +long CxImage::Draw2(HDC hdc, long x, long y, long cx, long cy) +{ + if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0; + if (cx < 0) cx = head.biWidth; + if (cy < 0) cy = head.biHeight; + bool bTransparent = (info.nBkgndIndex >= 0); + + //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield] + int hdc_Restore = ::SaveDC(hdc); + if (!hdc_Restore) + return 0; + + if (!bTransparent){ +#if !defined (_WIN32_WCE) + SetStretchBltMode(hdc,COLORONCOLOR); +#endif + StretchDIBits(hdc, x, y, cx, cy, 0, 0, head.biWidth, head.biHeight, + info.pImage,(BITMAPINFO*)pDib, DIB_RGB_COLORS,SRCCOPY); + } else { + // draw image with transparent background + const int safe = 0; // or else GDI fails in the following - sometimes + RECT rcDst = {x+safe, y+safe, x+cx, y+cy}; + if (RectVisible(hdc, &rcDst)){ + ///////////////////////////////////////////////////////////////// + // True Mask Method - Thanks to Paul Reynolds and Ron Gery + int nWidth = head.biWidth; + int nHeight = head.biHeight; + // Create two memory dcs for the image and the mask + HDC dcImage=CreateCompatibleDC(hdc); + HDC dcTrans=CreateCompatibleDC(hdc); + // Select the image into the appropriate dc + HBITMAP bm = CreateCompatibleBitmap(hdc, nWidth, nHeight); + HBITMAP pOldBitmapImage = (HBITMAP)SelectObject(dcImage,bm); +#if !defined (_WIN32_WCE) + SetStretchBltMode(dcImage,COLORONCOLOR); +#endif + StretchDIBits(dcImage, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight, + info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,SRCCOPY); + + // Create the mask bitmap + HBITMAP bitmapTrans = CreateBitmap(nWidth, nHeight, 1, 1, NULL); + // Select the mask bitmap into the appropriate dc + HBITMAP pOldBitmapTrans = (HBITMAP)SelectObject(dcTrans, bitmapTrans); + // Build mask based on transparent colour + RGBQUAD rgbBG; + if (head.biBitCount<24) rgbBG = GetPaletteColor((BYTE)info.nBkgndIndex); + else rgbBG = info.nBkgndColor; + COLORREF crColour = RGB(rgbBG.rgbRed, rgbBG.rgbGreen, rgbBG.rgbBlue); + COLORREF crOldBack = SetBkColor(dcImage,crColour); + BitBlt(dcTrans,0, 0, nWidth, nHeight, dcImage, 0, 0, SRCCOPY); + + // Do the work - True Mask method - cool if not actual display + StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT); + StretchBlt(hdc,x, y,cx,cy, dcTrans, 0, 0, nWidth, nHeight, SRCAND); + StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT); + + // Restore settings + SelectObject(dcImage,pOldBitmapImage); + SelectObject(dcTrans,pOldBitmapTrans); + SetBkColor(hdc,crOldBack); + DeleteObject( bitmapTrans ); // RG 29/01/2002 + DeleteDC(dcImage); + DeleteDC(dcTrans); + DeleteObject(bm); + } + } + ::RestoreDC(hdc,hdc_Restore); + return 1; +} +//////////////////////////////////////////////////////////////////////////////// +long CxImage::Stretch(HDC hdc, const RECT& rect, DWORD dwRop) +{ + return Stretch(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, dwRop); +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Stretch the image. Obsolete: use Draw() or Draw2() + * \param hdc : destination device context + * \param xoffset,yoffset : (optional) offset + * \param xsize,ysize : size. + * \param dwRop : raster operation code (see BitBlt documentation) + * \return true if everything is ok + */ +long CxImage::Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop) +{ + if((pDib)&&(hdc)) { + //palette must be correctly filled +#if !defined (_WIN32_WCE) + SetStretchBltMode(hdc,COLORONCOLOR); +#endif + StretchDIBits(hdc, xoffset, yoffset, + xsize, ysize, 0, 0, head.biWidth, head.biHeight, + info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,dwRop); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +/** + * Tiles the device context in the specified rectangle with the image. + * \param hdc : destination device context + * \param rc : tiled rectangle in the output device context + * \return true if everything is ok + */ +long CxImage::Tile(HDC hdc, RECT *rc) +{ + if((pDib)&&(hdc)&&(rc)) { + int w = rc->right - rc->left; + int h = rc->bottom - rc->top; + int x,y,z; + int bx=head.biWidth; + int by=head.biHeight; + for (y = 0 ; y < h ; y += by){ + if ((y+by)>h) by=h-y; + z=bx; + for (x = 0 ; x < w ; x += z){ + if ((x+z)>w) z=w-x; + RECT r = {rc->left + x,rc->top + y,rc->left + x + z,rc->top + y + by}; + Draw(hdc,rc->left + x, rc->top + y,-1,-1,&r); + } + } + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +// For UNICODE support: char -> TCHAR +long CxImage::DrawString(HDC hdc, long x, long y, const TCHAR* text, RGBQUAD color, const TCHAR* font, long lSize, long lWeight, BYTE bItalic, BYTE bUnderline, bool bSetAlpha) +//long CxImage::DrawString(HDC hdc, long x, long y, const char* text, RGBQUAD color, const char* font, long lSize, long lWeight, BYTE bItalic, BYTE bUnderline, bool bSetAlpha) +{ + if (IsValid()){ + //get the background + HDC pDC; + if (hdc) pDC=hdc; else pDC = ::GetDC(0); + if (pDC==NULL) return 0; + HDC TmpDC=CreateCompatibleDC(pDC); + if (hdc==NULL) ::ReleaseDC(0, pDC); + if (TmpDC==NULL) return 0; + //choose the font + HFONT m_Font; + LOGFONT* m_pLF; + m_pLF=(LOGFONT*)calloc(1,sizeof(LOGFONT)); + _tcsncpy(m_pLF->lfFaceName,font,31); // For UNICODE support + //strncpy(m_pLF->lfFaceName,font,31); + m_pLF->lfHeight=lSize; + m_pLF->lfWeight=lWeight; + m_pLF->lfItalic=bItalic; + m_pLF->lfUnderline=bUnderline; + m_Font=CreateFontIndirect(m_pLF); + //select the font in the dc + HFONT pOldFont=NULL; + if (m_Font) + pOldFont = (HFONT)SelectObject(TmpDC,m_Font); + else + pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT)); + + //Set text color + SetTextColor(TmpDC,RGB(255,255,255)); + SetBkColor(TmpDC,RGB(0,0,0)); + //draw the text + SetBkMode(TmpDC,OPAQUE); + //Set text position; + RECT pos = {0,0,0,0}; + //long len = (long)strlen(text); + long len = (long)_tcslen(text); // For UNICODE support + ::DrawText(TmpDC,text,len,&pos,DT_CALCRECT); + pos.right+=pos.bottom; //for italics + + //Preparing Bitmap Info + long width=pos.right; + long height=pos.bottom; + BITMAPINFO bmInfo; + memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); + bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + bmInfo.bmiHeader.biWidth=width; + bmInfo.bmiHeader.biHeight=height; + bmInfo.bmiHeader.biPlanes=1; + bmInfo.bmiHeader.biBitCount=24; + BYTE *pbase; //points to the final dib + + HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); + HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); + memset(pbase,0,height*((((24 * width) + 31) / 32) * 4)); + + ::DrawText(TmpDC,text,len,&pos,0); + + CxImage itext; + itext.CreateFromHBITMAP(TmpBmp); + + y=head.biHeight-y-1; + for (long ix=0;ix +long CxImage::DrawStringEx(HDC hdc, long x, long y, CXTEXTINFO *pTextType, bool bSetAlpha ) +{ + if (!IsValid()) + return -1; + + //get the background + HDC pDC; + if (hdc) pDC=hdc; else pDC = ::GetDC(0); + if (pDC==NULL) return 0; + HDC TmpDC=CreateCompatibleDC(pDC); + if (hdc==NULL) ::ReleaseDC(0, pDC); + if (TmpDC==NULL) return 0; + + //choose the font + HFONT m_Font; + m_Font=CreateFontIndirect( &pTextType->lfont ); + + // get colors in RGBQUAD + RGBQUAD p_forecolor = RGBtoRGBQUAD(pTextType->fcolor); + RGBQUAD p_backcolor = RGBtoRGBQUAD(pTextType->bcolor); + + // check alignment and re-set default if necessary + if ( pTextType->align != DT_CENTER && + pTextType->align != DT_LEFT && + pTextType->align != DT_RIGHT ) + pTextType->align = DT_CENTER; + + // check rounding radius and re-set default if necessary + if ( pTextType->b_round > 50 ) + pTextType->b_round = 10; + + // check opacity and re-set default if necessary + if ( pTextType->b_opacity > 1. || pTextType->b_opacity < .0 ) + pTextType->b_opacity = 0.; + + //select the font in the dc + HFONT pOldFont=NULL; + if (m_Font) + pOldFont = (HFONT)SelectObject(TmpDC,m_Font); + else + pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT)); + + //Set text color + SetTextColor(TmpDC,RGB(255,255,255)); + SetBkColor(TmpDC,RGB(0,0,0)); + SetBkMode(TmpDC,OPAQUE); + //Set text position; + RECT pos = {0,0,0,0}; + + // get text length and number of lines + long i=0, numlines=1, len=(long)_tcsclen(pTextType->text); + while (itext[i++]==13 ) + numlines++; + } + + ::DrawText(TmpDC, pTextType->text, len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX | DT_CALCRECT ); + + // increase only if it's really italics, and only one line height + if ( pTextType->lfont.lfItalic ) + pos.right += pos.bottom/2/numlines; + + // background frame and rounding radius + int frame = 0, roundR = 0; + if ( pTextType->opaque ) + { + roundR= (int)(pos.bottom/numlines * pTextType->b_round / 100 ) ; + frame = (int)(/*3.5 + */0.29289*roundR ) ; + pos.right += pos.bottom/numlines/3 ; // JUST FOR BEAUTY + } + + //Preparing Bitmap Info + long width=pos.right +frame*2; + long height=pos.bottom +frame*2; + BITMAPINFO bmInfo; + memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); + bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + bmInfo.bmiHeader.biWidth=width; + bmInfo.bmiHeader.biHeight=height; + bmInfo.bmiHeader.biPlanes=1; + bmInfo.bmiHeader.biBitCount=24; + BYTE *pbase; //points to the final dib + + HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0); + HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp); + memset(pbase,0,height*((((24 * width) + 31) / 32) * 4)); + + ::DrawText(TmpDC,pTextType->text,len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX| pTextType->align ); + + CxImage itext; + itext.CreateFromHBITMAP(TmpBmp); + y=head.biHeight-y-1; + + itext.Negative(); + + if (pTextType->smooth==FALSE){ + itext.Threshold(128); + } else { + //itext.TextBlur(); + } + + //move the insertion point according to alignment type + // DT_CENTER: cursor points to the center of text rectangle + // DT_RIGHT: cursor points to right side end of text rectangle + // DT_LEFT: cursor points to left end of text rectangle + if ( pTextType->align == DT_CENTER ) + x -= width/2; + else if ( pTextType->align == DT_RIGHT ) + x -= width; + if (x<0) x=0; + + //draw the background first, if it exists + long ix,iy; + if ( pTextType->opaque ) + { + int ixf=0; + for (ix=0;ix=width-roundR-1 ) + ixf = (int)(.5+roundR-sqrt((float)(roundR*roundR-(width-1-ix-roundR)*(width-1-ix-roundR)))); + else + ixf=0; + + for (iy=0;iy height-ixf-1 || iy < ixf )) || + (ix>=width-roundR-1 && ( iy > height-ixf-1 || iy < ixf )) ) + continue; + else + if ( pTextType->b_opacity > 0.0 && pTextType->b_opacity < 1.0 ) + { + RGBQUAD bcolor, pcolor; + // calculate a transition color from original image to background color: + pcolor = GetPixelColor(x+ix,y+iy); + bcolor.rgbBlue = (unsigned char)(pTextType->b_opacity * pcolor.rgbBlue + (1.0-pTextType->b_opacity) * p_backcolor.rgbBlue ); + bcolor.rgbRed = (unsigned char)(pTextType->b_opacity * pcolor.rgbRed + (1.0-pTextType->b_opacity) * p_backcolor.rgbRed ) ; + bcolor.rgbGreen = (unsigned char)(pTextType->b_opacity * pcolor.rgbGreen + (1.0-pTextType->b_opacity) * p_backcolor.rgbGreen ) ; + bcolor.rgbReserved = 0; + SetPixelColor(x+ix,y+iy,bcolor,bSetAlpha); + } + else + SetPixelColor(x+ix,y+iy,p_backcolor,bSetAlpha); + } + } + } + + // draw the text itself + for (ix=0;ixlfont.lfHeight = -36; + txt->lfont.lfCharSet = EASTEUROPE_CHARSET; // just for Central-European users + txt->lfont.lfWeight = FW_NORMAL; + txt->lfont.lfWidth = 0; + txt->lfont.lfEscapement = 0; + txt->lfont.lfOrientation = 0; + txt->lfont.lfItalic = FALSE; + txt->lfont.lfUnderline = FALSE; + txt->lfont.lfStrikeOut = FALSE; + txt->lfont.lfOutPrecision = OUT_DEFAULT_PRECIS; + txt->lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + txt->lfont.lfQuality = PROOF_QUALITY; + txt->lfont.lfPitchAndFamily= DEFAULT_PITCH | FF_DONTCARE ; + _stprintf( txt->lfont.lfFaceName, _T("Arial")); //use TCHAR mappings + + // initial colors + txt->fcolor = RGB( 255,255,160 ); // default foreground: light goldyellow + txt->bcolor = RGB( 0, 80,160 ); // default background: light blue + + // background + txt->opaque = TRUE; // text has a non-transparent background; + txt->smooth = TRUE; + txt->b_opacity = 0.0; // default: opaque background + txt->b_outline = 0; // default: no outline (OUTLINE NOT IMPLEMENTED AT THIS TIME) + txt->b_round = 20; // default: rounding radius is 20% of the rectangle height + // the text + _stprintf( txt->text, _T("Sample Text 01234õû")); // text use TCHAR mappings + txt->align = DT_CENTER; + return; +} + +#if CXIMAGE_SUPPORT_LAYERS +//////////////////////////////////////////////////////////////////////////////// +long CxImage::LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth) +{ + return LayerDrawAll(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth); +} +//////////////////////////////////////////////////////////////////////////////// +long CxImage::LayerDrawAll(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth) +{ + long n=0; + CxImage* pLayer; + while(pLayer=GetLayer(n++)){ + if (pLayer->Draw(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0) + return 0; + if (pLayer->LayerDrawAll(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0) + return 0; + } + return 1; +} +#endif //CXIMAGE_SUPPORT_LAYERS + +//////////////////////////////////////////////////////////////////////////////// +#endif //CXIMAGE_SUPPORT_WINDOWS +//////////////////////////////////////////////////////////////////////////////// diff --git a/utilities/CxImage/xiofile.h b/utilities/CxImage/xiofile.h index 0cb7e1d..f111af6 100644 --- a/utilities/CxImage/xiofile.h +++ b/utilities/CxImage/xiofile.h @@ -1,125 +1,125 @@ -#if !defined(__xiofile_h) -#define __xiofile_h - -#include "xfile.h" -//#include - -class DLL_EXP CxIOFile : public CxFile - { -public: - CxIOFile(FILE* fp = NULL) - { - m_fp = fp; - m_bCloseFile = (bool)(fp==0); - } - - ~CxIOFile() - { - Close(); - } -////////////////////////////////////////////////////////// - bool Open(LPCTSTR filename, LPCTSTR mode) - { - if (m_fp) return false; // Can't re-open without closing first - - m_fp = _tfopen(filename, mode); - if (!m_fp) return false; - - m_bCloseFile = true; - - return true; - } -////////////////////////////////////////////////////////// - virtual bool Close() - { - int iErr = 0; - if ( (m_fp) && (m_bCloseFile) ){ - iErr = fclose(m_fp); - m_fp = NULL; - } - return (bool)(iErr==0); - } -////////////////////////////////////////////////////////// - virtual size_t Read(void *buffer, size_t size, size_t count) - { - if (!m_fp) return 0; - return fread(buffer, size, count, m_fp); - } -////////////////////////////////////////////////////////// - virtual size_t Write(const void *buffer, size_t size, size_t count) - { - if (!m_fp) return 0; - return fwrite(buffer, size, count, m_fp); - } -////////////////////////////////////////////////////////// - virtual bool Seek(long offset, int origin) - { - if (!m_fp) return false; - return (bool)(fseek(m_fp, offset, origin) == 0); - } -////////////////////////////////////////////////////////// - virtual long Tell() - { - if (!m_fp) return 0; - return ftell(m_fp); - } -////////////////////////////////////////////////////////// - virtual long Size() - { - if (!m_fp) return -1; - long pos,size; - pos = ftell(m_fp); - fseek(m_fp, 0, SEEK_END); - size = ftell(m_fp); - fseek(m_fp, pos,SEEK_SET); - return size; - } -////////////////////////////////////////////////////////// - virtual bool Flush() - { - if (!m_fp) return false; - return (bool)(fflush(m_fp) == 0); - } -////////////////////////////////////////////////////////// - virtual bool Eof() - { - if (!m_fp) return true; - return (bool)(feof(m_fp) != 0); - } -////////////////////////////////////////////////////////// - virtual long Error() - { - if (!m_fp) return -1; - return ferror(m_fp); - } -////////////////////////////////////////////////////////// - virtual bool PutC(unsigned char c) - { - if (!m_fp) return false; - return (bool)(fputc(c, m_fp) == c); - } -////////////////////////////////////////////////////////// - virtual long GetC() - { - if (!m_fp) return EOF; - return getc(m_fp); - } -////////////////////////////////////////////////////////// - virtual char * GetS(char *string, int n) - { - if (!m_fp) return NULL; - return fgets(string,n,m_fp); - } -////////////////////////////////////////////////////////// - virtual long Scanf(const char *format, void* output) - { - if (!m_fp) return EOF; - return fscanf(m_fp, format, output); - } -////////////////////////////////////////////////////////// -protected: - FILE *m_fp; - bool m_bCloseFile; - }; - -#endif +#if !defined(__xiofile_h) +#define __xiofile_h + +#include "xfile.h" +//#include + +class DLL_EXP CxIOFile : public CxFile + { +public: + CxIOFile(FILE* fp = NULL) + { + m_fp = fp; + m_bCloseFile = (bool)(fp==0); + } + + ~CxIOFile() + { + Close(); + } +////////////////////////////////////////////////////////// + bool Open(LPCTSTR filename, LPCTSTR mode) + { + if (m_fp) return false; // Can't re-open without closing first + + m_fp = _tfopen(filename, mode); + if (!m_fp) return false; + + m_bCloseFile = true; + + return true; + } +////////////////////////////////////////////////////////// + virtual bool Close() + { + int iErr = 0; + if ( (m_fp) && (m_bCloseFile) ){ + iErr = fclose(m_fp); + m_fp = NULL; + } + return (bool)(iErr==0); + } +////////////////////////////////////////////////////////// + virtual size_t Read(void *buffer, size_t size, size_t count) + { + if (!m_fp) return 0; + return fread(buffer, size, count, m_fp); + } +////////////////////////////////////////////////////////// + virtual size_t Write(const void *buffer, size_t size, size_t count) + { + if (!m_fp) return 0; + return fwrite(buffer, size, count, m_fp); + } +////////////////////////////////////////////////////////// + virtual bool Seek(long offset, int origin) + { + if (!m_fp) return false; + return (bool)(fseek(m_fp, offset, origin) == 0); + } +////////////////////////////////////////////////////////// + virtual long Tell() + { + if (!m_fp) return 0; + return ftell(m_fp); + } +////////////////////////////////////////////////////////// + virtual long Size() + { + if (!m_fp) return -1; + long pos,size; + pos = ftell(m_fp); + fseek(m_fp, 0, SEEK_END); + size = ftell(m_fp); + fseek(m_fp, pos,SEEK_SET); + return size; + } +////////////////////////////////////////////////////////// + virtual bool Flush() + { + if (!m_fp) return false; + return (bool)(fflush(m_fp) == 0); + } +////////////////////////////////////////////////////////// + virtual bool Eof() + { + if (!m_fp) return true; + return (bool)(feof(m_fp) != 0); + } +////////////////////////////////////////////////////////// + virtual long Error() + { + if (!m_fp) return -1; + return ferror(m_fp); + } +////////////////////////////////////////////////////////// + virtual bool PutC(unsigned char c) + { + if (!m_fp) return false; + return (bool)(fputc(c, m_fp) == c); + } +////////////////////////////////////////////////////////// + virtual long GetC() + { + if (!m_fp) return EOF; + return getc(m_fp); + } +////////////////////////////////////////////////////////// + virtual char * GetS(char *string, int n) + { + if (!m_fp) return NULL; + return fgets(string,n,m_fp); + } +////////////////////////////////////////////////////////// + virtual long Scanf(const char *format, void* output) + { + if (!m_fp) return EOF; + return fscanf(m_fp, format, output); + } +////////////////////////////////////////////////////////// +protected: + FILE *m_fp; + bool m_bCloseFile; + }; + +#endif diff --git a/utilities/CxImage/xmemfile.cpp b/utilities/CxImage/xmemfile.cpp index 22348b9..af8db94 100644 --- a/utilities/CxImage/xmemfile.cpp +++ b/utilities/CxImage/xmemfile.cpp @@ -1,202 +1,202 @@ -#include "xmemfile.h" - -////////////////////////////////////////////////////////// -CxMemFile::CxMemFile(BYTE* pBuffer, DWORD size) -{ - m_pBuffer = pBuffer; - m_Position = 0; - m_Size = m_Edge = size; - m_bFreeOnClose = (bool)(pBuffer==0); -} -////////////////////////////////////////////////////////// -CxMemFile::~CxMemFile() -{ - Close(); -} -////////////////////////////////////////////////////////// -bool CxMemFile::Close() -{ - if ( (m_pBuffer) && (m_bFreeOnClose) ){ - free(m_pBuffer); - m_pBuffer = NULL; - m_Size = 0; - } - return true; -} -////////////////////////////////////////////////////////// -bool CxMemFile::Open() -{ - if (m_pBuffer) return false; // Can't re-open without closing first - - m_Position = m_Size = m_Edge = 0; - m_pBuffer=(BYTE*)malloc(1); - m_bFreeOnClose = true; - - return (m_pBuffer!=0); -} -////////////////////////////////////////////////////////// -BYTE* CxMemFile::GetBuffer(bool bDetachBuffer) -{ - //can only detach, avoid inadvertantly attaching to - // memory that may not be ours [Jason De Arte] - if( bDetachBuffer ) - m_bFreeOnClose = false; - return m_pBuffer; -} -////////////////////////////////////////////////////////// -size_t CxMemFile::Read(void *buffer, size_t size, size_t count) -{ - if (buffer==NULL) return 0; - - if (m_pBuffer==NULL) return 0; - if (m_Position >= (long)m_Size) return 0; - - long nCount = (long)(count*size); - if (nCount == 0) return 0; - - long nRead; - if (m_Position + nCount > (long)m_Size) - nRead = (m_Size - m_Position); - else - nRead = nCount; - - memcpy(buffer, m_pBuffer + m_Position, nRead); - m_Position += nRead; - - return (size_t)(nRead/size); -} -////////////////////////////////////////////////////////// -size_t CxMemFile::Write(const void *buffer, size_t size, size_t count) -{ - if (m_pBuffer==NULL) return 0; - if (buffer==NULL) return 0; - - long nCount = (long)(count*size); - if (nCount == 0) return 0; - - if (m_Position + nCount > m_Edge){ - if (!Alloc(m_Position + nCount)){ - return false; - } - } - - memcpy(m_pBuffer + m_Position, buffer, nCount); - - m_Position += nCount; - - if (m_Position > (long)m_Size) m_Size = m_Position; - - return count; -} -////////////////////////////////////////////////////////// -bool CxMemFile::Seek(long offset, int origin) -{ - if (m_pBuffer==NULL) return false; - long lNewPos = m_Position; - - if (origin == SEEK_SET) lNewPos = offset; - else if (origin == SEEK_CUR) lNewPos += offset; - else if (origin == SEEK_END) lNewPos = m_Size + offset; - else return false; - - if (lNewPos < 0) lNewPos = 0; - - m_Position = lNewPos; - return true; -} -////////////////////////////////////////////////////////// -long CxMemFile::Tell() -{ - if (m_pBuffer==NULL) return -1; - return m_Position; -} -////////////////////////////////////////////////////////// -long CxMemFile::Size() -{ - if (m_pBuffer==NULL) return -1; - return m_Size; -} -////////////////////////////////////////////////////////// -bool CxMemFile::Flush() -{ - if (m_pBuffer==NULL) return false; - return true; -} -////////////////////////////////////////////////////////// -bool CxMemFile::Eof() -{ - if (m_pBuffer==NULL) return true; - return (m_Position >= (long)m_Size); -} -////////////////////////////////////////////////////////// -long CxMemFile::Error() -{ - if (m_pBuffer==NULL) return -1; - return (m_Position > (long)m_Size); -} -////////////////////////////////////////////////////////// -bool CxMemFile::PutC(unsigned char c) -{ - if (m_pBuffer==NULL) return false; - - if (m_Position >= m_Edge){ - if (!Alloc(m_Position + 1)){ - return false; - } - } - - m_pBuffer[m_Position++] = c; - - if (m_Position > (long)m_Size) m_Size = m_Position; - - return true; -} -////////////////////////////////////////////////////////// -long CxMemFile::GetC() -{ - if (Eof()) return EOF; - return *(BYTE*)((BYTE*)m_pBuffer + m_Position++); -} -////////////////////////////////////////////////////////// -char * CxMemFile::GetS(char *string, int n) -{ - n--; - long c,i=0; - while (i (DWORD)m_Edge) - { - // find new buffer size - DWORD dwNewBufferSize = (DWORD)(((dwNewLen>>16)+1)<<16); - - // allocate new buffer - if (m_pBuffer == NULL) m_pBuffer = (BYTE*)malloc(dwNewBufferSize); - else m_pBuffer = (BYTE*)realloc(m_pBuffer, dwNewBufferSize); - // I own this buffer now (caller knows nothing about it) - m_bFreeOnClose = true; - - m_Edge = dwNewBufferSize; - } - return (m_pBuffer!=0); -} -////////////////////////////////////////////////////////// -void CxMemFile::Free() -{ - Close(); -} -////////////////////////////////////////////////////////// +#include "xmemfile.h" + +////////////////////////////////////////////////////////// +CxMemFile::CxMemFile(BYTE* pBuffer, DWORD size) +{ + m_pBuffer = pBuffer; + m_Position = 0; + m_Size = m_Edge = size; + m_bFreeOnClose = (bool)(pBuffer==0); +} +////////////////////////////////////////////////////////// +CxMemFile::~CxMemFile() +{ + Close(); +} +////////////////////////////////////////////////////////// +bool CxMemFile::Close() +{ + if ( (m_pBuffer) && (m_bFreeOnClose) ){ + free(m_pBuffer); + m_pBuffer = NULL; + m_Size = 0; + } + return true; +} +////////////////////////////////////////////////////////// +bool CxMemFile::Open() +{ + if (m_pBuffer) return false; // Can't re-open without closing first + + m_Position = m_Size = m_Edge = 0; + m_pBuffer=(BYTE*)malloc(1); + m_bFreeOnClose = true; + + return (m_pBuffer!=0); +} +////////////////////////////////////////////////////////// +BYTE* CxMemFile::GetBuffer(bool bDetachBuffer) +{ + //can only detach, avoid inadvertantly attaching to + // memory that may not be ours [Jason De Arte] + if( bDetachBuffer ) + m_bFreeOnClose = false; + return m_pBuffer; +} +////////////////////////////////////////////////////////// +size_t CxMemFile::Read(void *buffer, size_t size, size_t count) +{ + if (buffer==NULL) return 0; + + if (m_pBuffer==NULL) return 0; + if (m_Position >= (long)m_Size) return 0; + + long nCount = (long)(count*size); + if (nCount == 0) return 0; + + long nRead; + if (m_Position + nCount > (long)m_Size) + nRead = (m_Size - m_Position); + else + nRead = nCount; + + memcpy(buffer, m_pBuffer + m_Position, nRead); + m_Position += nRead; + + return (size_t)(nRead/size); +} +////////////////////////////////////////////////////////// +size_t CxMemFile::Write(const void *buffer, size_t size, size_t count) +{ + if (m_pBuffer==NULL) return 0; + if (buffer==NULL) return 0; + + long nCount = (long)(count*size); + if (nCount == 0) return 0; + + if (m_Position + nCount > m_Edge){ + if (!Alloc(m_Position + nCount)){ + return false; + } + } + + memcpy(m_pBuffer + m_Position, buffer, nCount); + + m_Position += nCount; + + if (m_Position > (long)m_Size) m_Size = m_Position; + + return count; +} +////////////////////////////////////////////////////////// +bool CxMemFile::Seek(long offset, int origin) +{ + if (m_pBuffer==NULL) return false; + long lNewPos = m_Position; + + if (origin == SEEK_SET) lNewPos = offset; + else if (origin == SEEK_CUR) lNewPos += offset; + else if (origin == SEEK_END) lNewPos = m_Size + offset; + else return false; + + if (lNewPos < 0) lNewPos = 0; + + m_Position = lNewPos; + return true; +} +////////////////////////////////////////////////////////// +long CxMemFile::Tell() +{ + if (m_pBuffer==NULL) return -1; + return m_Position; +} +////////////////////////////////////////////////////////// +long CxMemFile::Size() +{ + if (m_pBuffer==NULL) return -1; + return m_Size; +} +////////////////////////////////////////////////////////// +bool CxMemFile::Flush() +{ + if (m_pBuffer==NULL) return false; + return true; +} +////////////////////////////////////////////////////////// +bool CxMemFile::Eof() +{ + if (m_pBuffer==NULL) return true; + return (m_Position >= (long)m_Size); +} +////////////////////////////////////////////////////////// +long CxMemFile::Error() +{ + if (m_pBuffer==NULL) return -1; + return (m_Position > (long)m_Size); +} +////////////////////////////////////////////////////////// +bool CxMemFile::PutC(unsigned char c) +{ + if (m_pBuffer==NULL) return false; + + if (m_Position >= m_Edge){ + if (!Alloc(m_Position + 1)){ + return false; + } + } + + m_pBuffer[m_Position++] = c; + + if (m_Position > (long)m_Size) m_Size = m_Position; + + return true; +} +////////////////////////////////////////////////////////// +long CxMemFile::GetC() +{ + if (Eof()) return EOF; + return *(BYTE*)((BYTE*)m_pBuffer + m_Position++); +} +////////////////////////////////////////////////////////// +char * CxMemFile::GetS(char *string, int n) +{ + n--; + long c,i=0; + while (i (DWORD)m_Edge) + { + // find new buffer size + DWORD dwNewBufferSize = (DWORD)(((dwNewLen>>16)+1)<<16); + + // allocate new buffer + if (m_pBuffer == NULL) m_pBuffer = (BYTE*)malloc(dwNewBufferSize); + else m_pBuffer = (BYTE*)realloc(m_pBuffer, dwNewBufferSize); + // I own this buffer now (caller knows nothing about it) + m_bFreeOnClose = true; + + m_Edge = dwNewBufferSize; + } + return (m_pBuffer!=0); +} +////////////////////////////////////////////////////////// +void CxMemFile::Free() +{ + Close(); +} +////////////////////////////////////////////////////////// diff --git a/utilities/CxImage/xmemfile.h b/utilities/CxImage/xmemfile.h index ac4c412..f87e4f9 100644 --- a/utilities/CxImage/xmemfile.h +++ b/utilities/CxImage/xmemfile.h @@ -1,41 +1,41 @@ -#if !defined(__xmemfile_h) -#define __xmemfile_h - -#include "xfile.h" - -////////////////////////////////////////////////////////// -class DLL_EXP CxMemFile : public CxFile -{ -public: - CxMemFile(BYTE* pBuffer = NULL, DWORD size = 0); - ~CxMemFile(); - - bool Open(); - BYTE* GetBuffer(bool bDetachBuffer = true); - - virtual bool Close(); - virtual size_t Read(void *buffer, size_t size, size_t count); - virtual size_t Write(const void *buffer, size_t size, size_t count); - virtual bool Seek(long offset, int origin); - virtual long Tell(); - virtual long Size(); - virtual bool Flush(); - virtual bool Eof(); - virtual long Error(); - virtual bool PutC(unsigned char c); - virtual long GetC(); - virtual char * GetS(char *string, int n); - virtual long Scanf(const char *format, void* output); - -protected: - bool Alloc(DWORD nBytes); - void Free(); - - BYTE* m_pBuffer; - DWORD m_Size; - bool m_bFreeOnClose; - long m_Position; //current position - long m_Edge; //buffer size -}; - -#endif +#if !defined(__xmemfile_h) +#define __xmemfile_h + +#include "xfile.h" + +////////////////////////////////////////////////////////// +class DLL_EXP CxMemFile : public CxFile +{ +public: + CxMemFile(BYTE* pBuffer = NULL, DWORD size = 0); + ~CxMemFile(); + + bool Open(); + BYTE* GetBuffer(bool bDetachBuffer = true); + + virtual bool Close(); + virtual size_t Read(void *buffer, size_t size, size_t count); + virtual size_t Write(const void *buffer, size_t size, size_t count); + virtual bool Seek(long offset, int origin); + virtual long Tell(); + virtual long Size(); + virtual bool Flush(); + virtual bool Eof(); + virtual long Error(); + virtual bool PutC(unsigned char c); + virtual long GetC(); + virtual char * GetS(char *string, int n); + virtual long Scanf(const char *format, void* output); + +protected: + bool Alloc(DWORD nBytes); + void Free(); + + BYTE* m_pBuffer; + DWORD m_Size; + bool m_bFreeOnClose; + long m_Position; //current position + long m_Edge; //buffer size +}; + +#endif diff --git a/vv/vvIcon.rc b/vv/vvIcon.rc index f06ba51..7f87ae2 100644 --- a/vv/vvIcon.rc +++ b/vv/vvIcon.rc @@ -1,4 +1,4 @@ -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ICON1 ICON "icons/ducky.ico" - +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "icons/ducky.ico" + diff --git a/vv/vvSlicerManager.cxx b/vv/vvSlicerManager.cxx index 1b43263..12928af 100644 --- a/vv/vvSlicerManager.cxx +++ b/vv/vvSlicerManager.cxx @@ -1,1659 +1,1659 @@ -/*========================================================================= - Program: vv http://www.creatis.insa-lyon.fr/rio/vv - - Authors belong to: - - University of LYON http://www.universite-lyon.fr/ - - Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr - - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr - - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. See the copyright notices for more information. - - It is distributed under dual licence - - - BSD See included LICENSE.txt file - - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html - ======================================================================-====*/ - -#include "vvSlicerManager.h" -#include "vvSlicer.h" -#include "vvImage.h" -#include "vvSlicerManagerCommand.h" -#include "vvInteractorStyleNavigator.h" -#include "vvLandmarks.h" -#include "vvMesh.h" -#include "vvBlendImageActor.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -//---------------------------------------------------------------------------- -vvSlicerManager::vvSlicerManager(int numberOfSlicers) -{ - - connect(this, SIGNAL(callAddLandmark(float,float,float,float)), this, SLOT(AddLandmark(float,float,float,float))); - - mFileName = ""; - mId = ""; - mVFName = ""; - mOverlayName = ""; - mFusionName = ""; - mVFId = ""; - mLastError = ""; - mType = vvImageReader::UNDEFINEDIMAGETYPE; - mColorMap = 0; - mPreset = 0; - mOverlayColor = 130; - - mFusionOpacity = 30; - mFusionThresOpacity = 1; - mFusionColorMap = 3; - mFusionWindow = 1000; - mFusionLevel = 1000; - mFusionShowLegend = true; - - mFusionSequenceInvolvementCode = -1; - mFusionSequenceIndexLinkedManager = -1; - mFusionSequenceFrameIndex = -1; - mFusionSequenceNbFrames = 0; - mFusionSequenceSpatialSyncFlag = false; - mFusionSequenceTemporalSyncFlag = false; - - mLandmarks = NULL; - mLinkedId.resize(0); - - for ( int i = 0; i < numberOfSlicers; i++) { - mSlicers.push_back(vtkSmartPointer::New()); - mSlicers[i]->SetSlicerNumber(i); - } - mSelectedSlicer = -1; - - mPreviousSlice.resize(numberOfSlicers, 0); - mPreviousTSlice.resize(numberOfSlicers, 0); - mSlicingPreset = WORLD_SLICING; - - -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -vvSlicerManager::~vvSlicerManager() -{ - if (mLandmarks) - delete mLandmarks; -} -//---------------------------------------------------------------------------- - - -//------------------------------------------------------------------------------ -void vvSlicerManager::SetFilename(std::string filename, int number) -{ - mFileName = filename; - mFileName = vtksys::SystemTools::GetFilenameName(mFileName); - mBaseFileName = vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(mFileName)); - mBaseFileNameNumber = number; - - mFileName = mBaseFileName; - if (number != 0) { - mFileName.append("_"+clitk::toString(number)); - } - mFileName.append(vtksys::SystemTools::GetFilenameLastExtension(filename)); - - for(unsigned int i=0; iSetFileName(mFileName);//vtksys::SystemTools::GetFilenameWithoutLastExtension(filename)); - } - -} -//------------------------------------------------------------------------------ - - -//---------------------------------------------------------------------------- -void vvSlicerManager::AddContour(vvMesh::Pointer contour,bool propagate) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->AddContour(contour,propagate); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::ToggleContourSuperposition() -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) - mSlicers[i]->ToggleContourSuperposition(); -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -std::string vvSlicerManager::GetListOfAbsoluteFilePathInOneString(const std::string &actorType) -{ - vvImageReader *reader = NULL; - - if(actorType=="image") - reader = mReader; - else if(actorType=="overlay") - reader = mOverlayReader; - else if(actorType=="fusion") - reader = mFusionReader; - else if(actorType=="vector") - reader = mVectorReader; - else if(actorType=="fusionSequence") - reader = mFusionSequenceReader; - - if(!reader) - return ""; - - std::string list; - for(unsigned int i=0; iGetInputFilenames().size(); i++){ - QFileInfo fileinfo(reader->GetInputFilenames()[i].c_str()); //Do not show the path - if(i) - list += '\n'; - list += fileinfo.absoluteFilePath().toStdString(); - } - return list; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -bool vvSlicerManager::SetImage(std::string filename, vvImageReader::LoadedImageType type, int n, unsigned int slice) -{ - mType = type; - if (mReader.IsNull()) - mReader = vvImageReader::New(); - std::vector filenames; - filenames.push_back(filename); - mReader->SetInputFilenames(filenames); - mReader->SetSlice(slice); // Only used for SLICED type - mReader->Update(type); - - SetFilename(filename, n); - // mFileName = vtksys::SystemTools::GetFilenameName(mFileName); - //mBaseFileName = vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(mFileName)); - //mBaseFileNameNumber = n; - - if (mReader->GetLastError().size() == 0) { - mImage=mReader->GetOutput(); - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFileName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename)); - mSlicers[i]->SetImage(mReader->GetOutput()); - } - } else { - mLastError = mReader->GetLastError(); - return false; - } - // if (n!=0) { - // mFileName.append("_"+clitk::toString(n)); - // } - return true; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetImage(vvImage::Pointer image) -{ - mImage=image; - for (unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetImage(image); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -bool vvSlicerManager::SetImages(std::vector filenames, vvImageReader::LoadedImageType type, int n) -{ - mType = type; - std::string fileWithoutExtension = vtksys::SystemTools::GetFilenameWithoutExtension(filenames[0]); - if (type == vvImageReader::DICOM) - fileWithoutExtension += "_dicom"; - else if (type == vvImageReader::MERGED) - fileWithoutExtension += "_merged"; - else if (type == vvImageReader::MERGEDWITHTIME) - fileWithoutExtension += "_merged_wt"; - - mFileName = vtksys::SystemTools::GetFilenameName(mFileName); - mFileName = fileWithoutExtension + vtksys::SystemTools::GetFilenameExtension(filenames[0]); - if (mReader.IsNull()) - mReader = vvImageReader::New(); - mReader->SetInputFilenames(filenames); - mReader->Update(type); - - mBaseFileName = vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(mFileName)); - mBaseFileNameNumber = n; - - if (mReader->GetLastError().size() == 0) { - mImage=mReader->GetOutput(); - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFileName(fileWithoutExtension); - mSlicers[i]->SetImage(mReader->GetOutput()); - } - } else { - mLastError = mReader->GetLastError(); - return false; - } - if (n!=0) { - mFileName.append("_"+clitk::toString(n)); - } - return true; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -bool vvSlicerManager::SetOverlay(std::vector filenames,int dim, std::string component, vvImageReader::LoadedImageType type) -{ - mOverlayName = filenames[0]; - mOverlayComponent = component; - if (dim > mImage->GetNumberOfDimensions()) { - mLastError = " Overlay dimension cannot be greater than reference image!"; - return false; - } - if (mOverlayReader.IsNull()) - mOverlayReader = vvImageReader::New(); - mOverlayReader->SetInputFilenames(filenames); - mOverlayReader->Update(type); - if (mOverlayReader->GetLastError().size() == 0) { - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetOverlay(mOverlayReader->GetOutput()); - } - } else { - mLastError = mOverlayReader->GetLastError(); - return false; - } - return true; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -bool vvSlicerManager::SetFusion(std::vector filenames,int dim, std::string component, vvImageReader::LoadedImageType type) -{ - mFusionName = filenames[0]; - mFusionComponent = component; - if (dim > mImage->GetNumberOfDimensions()) { - mLastError = " Fusion dimension cannot be greater than reference image!"; - return false; - } - if (mFusionReader.IsNull()) - mFusionReader = vvImageReader::New(); - mFusionReader->SetInputFilenames(filenames); - mFusionReader->Update(type); - if (mFusionReader->GetLastError().size() == 0) { - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFusion(mFusionReader->GetOutput()); - } - } else { - mLastError = mFusionReader->GetLastError(); - return false; - } - double *fusRange = mFusionReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); - mFusionLevel = (fusRange[0]+fusRange[1])/2; - mFusionWindow = fusRange[1]-fusRange[0]; - - return true; -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -//this function is called by vvMainWindow::AddFusionSequence for the primary sequence (CT), while the given files constitute the secondary sequence. -bool vvSlicerManager::SetFusionSequence(std::vector filenames, int dim, std::string component, vvImageReader::LoadedImageType type) -{ - mFusionSequenceInvolvementCode = 0; - - mFusionName = filenames[0]; - mFusionComponent = component; - - if (dim > mImage->GetNumberOfDimensions()) { - mLastError = " Fusion Sequence dimension cannot be greater than reference image!"; - return false; - } - - if (mFusionSequenceReader.IsNull()) - mFusionSequenceReader = vvImageReader::New(); - - mFusionSequenceReader->SetInputFilenames(filenames); - mFusionSequenceReader->Update(type); - - - if (mFusionSequenceReader->GetLastError().size() == 0) { - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), mFusionSequenceInvolvementCode); - } - } else { - mLastError = mFusionSequenceReader->GetLastError(); - return false; - } - double *fusRange = mFusionSequenceReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); - mFusionLevel = (fusRange[0]+fusRange[1])/2; - mFusionWindow = fusRange[1]-fusRange[0]; - - //store the initial transform matrices of each frame, and reset them to identity - mFusionSequenceListInitialTransformMatrices.clear(); - for (unsigned i=0 ; iGetOutput()->GetTransform().size() ; i++) { - AddFusionSequenceInitialTransformMatrices( mFusionSequenceReader->GetOutput()->GetTransform()[i]->GetMatrix() ); - mFusionSequenceReader->GetOutput()->GetTransform()[i]->Identity(); - mFusionSequenceReader->GetOutput()->GetTransform()[i]->Update(); - } - - //adjust the time slider in the overlay panel - mFusionSequenceNbFrames = mFusionSequenceReader->GetOutput()->GetTransform().size(); - mFusionSequenceFrameIndex = std::max( 0, std::min(mFusionSequenceFrameIndex, mFusionSequenceNbFrames)); - - return true; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -bool vvSlicerManager::SetVF(std::string filename) -{ - if (mVectorReader.IsNull()) - mVectorReader = vvImageReader::New(); - mVectorReader->SetInputFilename(filename); - - if (mType == vvImageReader::IMAGEWITHTIME) - mVectorReader->Update(vvImageReader::VECTORFIELDWITHTIME); - else - mVectorReader->Update(vvImageReader::VECTORFIELD); - if (mVectorReader->GetLastError().size() != 0) { - mLastError = mVectorReader->GetLastError(); - return false; - } else - return SetVF(mVectorReader->GetOutput(),filename); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -bool vvSlicerManager::SetVF(vvImage::Pointer vf,std::string filename) -{ - if (vf->GetNumberOfDimensions() > mImage->GetNumberOfDimensions()) { - mLastError = "Sorry, vector field dimension cannot be greater then reference image."; - return false; - } - if (vf->GetNumberOfDimensions() == 4) { - if (vf->GetSpacing()[3] != mImage->GetSpacing()[3]) { - mLastError = "Sorry, vector field time spacing cannot be different from time spacing of the reference image."; - return false; - } - if (vf->GetOrigin()[3] != mImage->GetOrigin()[3]) { - mLastError = "Sorry, vector field time origin cannot be different from time origin of the reference image."; - return false; - } - } - mVF=vf; - mVFName = filename; - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetVF(vf); - } - return true; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -vvSlicer* vvSlicerManager::GetSlicer(int i) -{ - return mSlicers[i]; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateSlicer(int num, bool state) -{ - if (mSlicers[num]->GetImage()) { - mSlicers[num]->SetDisplayMode(state); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetSlicerWindow(int i, vtkRenderWindow* RW) -{ - mSlicers[i]->SetRenderWindow(i,RW); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetInteractorStyleNavigator(int i, vtkInteractorStyle* style) -{ - vvSlicerManagerCommand *smc = vvSlicerManagerCommand::New(); - smc->SM = this; - smc->SetSlicerNumber(i); - mSlicers[i]->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); - - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::KeyPressEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::WindowLevelEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::EndWindowLevelEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::StartWindowLevelEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::PickEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::StartPickEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::LeaveEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::UserEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::MouseWheelForwardEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::MouseWheelBackwardEvent, smc); - // mSlicers[i]->GetRenderWindow()->GetInteractor()-> - // GetInteractorStyle()->AddObserver(vtkCommand::LeftButtonReleaseEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::EndPickEvent, smc); - mSlicers[i]->GetRenderWindow()->GetInteractor()-> - GetInteractorStyle()->AddObserver(vtkCommand::EndInteractionEvent, smc); - smc->Delete(); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::LeftButtonReleaseEvent(int slicer) -{ - emit LeftButtonReleaseSignal(slicer); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::EmitMousePositionUpdated(int slicer) -{ - emit MousePositionUpdatedSignal(slicer); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::EmitKeyPressed(std::string KeyPress) -{ - emit KeyPressedSignal(KeyPress); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetSliceOrientation(int slicer, int orientation) -{ - mSlicers[slicer]->SetSliceOrientation(orientation); - emit UpdateOrientation(slicer, orientation); -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -int vvSlicerManager::GetTSlice() -{ - return mSlicers[0]->GetTSlice(); -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetTSlice(int slice, bool updateLinkedImages) -{ - if (!updateLinkedImages) { //for fusionSequence, TMax / MaxCurrentTSlice are irrelevant. - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetTSlice(slice, updateLinkedImages); - UpdateTSlice(i); - } - return; - } - - if (slice < 0) - slice = 0; - else if (slice > mSlicers[0]->GetTMax()) - slice = mSlicers[0]->GetTMax(); - if (mLandmarks) - mLandmarks->SetTime(slice); - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - if (slice != mSlicers[i]->GetMaxCurrentTSlice()) { - mSlicers[i]->SetTSlice(slice, updateLinkedImages); - UpdateTSlice(i); - } - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetFusionSequenceTSlice(int slice) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFusionSequenceTSlice(slice); - UpdateTSlice(i); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetNextTSlice(int originating_slicer) -{ - int t = mSlicers[0]->GetMaxCurrentTSlice(); - t++; - if (t > mSlicers[0]->GetTMax()) - t = 0; - emit UpdateTSlice(originating_slicer,t, mFusionSequenceInvolvementCode); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetPreviousTSlice(int originating_slicer) -{ - int t = mSlicers[0]->GetMaxCurrentTSlice(); - t--; - if (t < 0) - t = mSlicers[0]->GetTMax(); - emit UpdateTSlice(originating_slicer,t, mFusionSequenceInvolvementCode); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::ToggleInterpolation() -{ - bool interpolate=!(mSlicers[0]->GetImageActor()->GetInterpolate()); - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->GetImageActor()->SetInterpolate(interpolate); - if (mSlicers[i]->GetOverlayActor()) - mSlicers[i]->GetOverlayActor()->SetInterpolate(interpolate); - if (mSlicers[i]->GetFusionActor()) - mSlicers[i]->GetFusionActor()->SetInterpolate(interpolate); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetTSliceInSlicer(int tslice, int slicer) -{ - if (tslice < 0) - tslice = 0; - else if (tslice > mSlicers[slicer]->GetTMax()) - tslice = mSlicers[slicer]->GetTMax(); - if (mLandmarks) - mLandmarks->SetTime(tslice); - - if (mSlicers[slicer]->GetMaxCurrentTSlice() == tslice) return; - - mSlicers[slicer]->SetTSlice(tslice); - - if(mSlicingPreset==VOXELS_SLICING) { - vtkMatrix4x4 *imageTransformInverse = vtkMatrix4x4::New(); - mImage->GetTransform()[mSlicers[slicer]->GetTSlice()]->GetInverse(imageTransformInverse); - this->GetSlicer(slicer)->GetSlicingTransform()->SetMatrix(imageTransformInverse); - imageTransformInverse->Delete(); - } - - UpdateTSlice(slicer); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetColorWindow(double s) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetColorWindow(s); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetColorLevel(double s) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetColorLevel(s); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetOverlayColorWindow(double s) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetOverlayColorWindow(s); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetOverlayColorLevel(double s) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetOverlayColorLevel(s); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetLinkOverlayWindowLevel(bool b) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetLinkOverlayWindowLevel(b); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetCursorAndCornerAnnotationVisibility(int s) -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetCursorVisibility(s); - mSlicers[i]->SetCornerAnnotationVisibility(s); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetOpacity(int i, double factor) -{ - mSlicers[i]->SetOpacity(1/factor); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateViews(int current,int slicer) -{ - double p[3], pt[3]; - p[0] = mSlicers[slicer]->GetCurrentPosition()[0]; - p[1] = mSlicers[slicer]->GetCurrentPosition()[1]; - p[2] = mSlicers[slicer]->GetCurrentPosition()[2]; - mSlicers[slicer]->GetSlicingTransform()->GetInverse()->TransformPoint(p, pt); - - double x = (pt[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0]) - /mSlicers[slicer]->GetInput()->GetSpacing()[0]; - double y = (pt[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1]) - /mSlicers[slicer]->GetInput()->GetSpacing()[1]; - double z = (pt[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2]) - /mSlicers[slicer]->GetInput()->GetSpacing()[2]; -#if VTK_MAJOR_VERSION <= 5 - if (x >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0]-0.5 && - x <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1]+0.5 && - y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2]-0.5 && - y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3]+0.5 && - z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4]-0.5 && - z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]+0.5) -#else -int extentImageReslice[6]; -mSlicers[slicer]->GetRegisterExtent(extentImageReslice); - if (x >= extentImageReslice[0]-0.5 && - x <= extentImageReslice[1]+0.5 && - y >= extentImageReslice[2]-0.5 && - y <= extentImageReslice[3]+0.5 && - z >= extentImageReslice[4]-0.5 && - z <= extentImageReslice[5]+0.5) -#endif - { - mSlicers[slicer]->UpdateCursorPosition(); - mSlicers[slicer]->SetCursorColor(10,212,255); - mSelectedSlicer = slicer; - - switch (mSlicers[slicer]->GetSliceOrientation()) { - case vtkImageViewer2::SLICE_ORIENTATION_XY: - if (mSlicers[slicer]->GetSlice() != (int)lrint(z)) - mSlicers[slicer]->SetSlice((int)lrint(z)); - break; - - case vtkImageViewer2::SLICE_ORIENTATION_XZ: - if (mSlicers[slicer]->GetSlice() != (int)lrint(y)) - mSlicers[slicer]->SetSlice((int)lrint(y)); - break; - - case vtkImageViewer2::SLICE_ORIENTATION_YZ: - if (mSlicers[slicer]->GetSlice() != (int)lrint(x)) - mSlicers[slicer]->SetSlice((int)lrint(x)); - break; - } - mSlicers[slicer]->Render(); - - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - if (i != (unsigned int)slicer - && mSlicers[i]->GetRenderer()->GetDraw() - && mSlicers[i]->GetRenderWindow()->GetSize()[0] > 2 - && mSlicers[i]->GetRenderWindow()->GetSize()[1] > 2) { - mSlicers[i]->SetCurrentPosition(p[0], p[1], p[2], mSlicers[slicer]->GetMaxCurrentTSlice()); - mSlicers[i]->UpdateCursorPosition(); - if (current) { //do not display corner annotation if image is the one picked - mSlicers[i]->SetCurrentPosition(-VTK_DOUBLE_MAX,-VTK_DOUBLE_MAX, - -VTK_DOUBLE_MAX, mSlicers[slicer]->GetMaxCurrentTSlice()); - mSlicers[i]->SetCursorColor(255,10,212); - } else { - mSlicers[i]->SetCursorColor(150,10,282); - } - switch (mSlicers[i]->GetSliceOrientation()) { - case vtkImageViewer2::SLICE_ORIENTATION_XY: - if (mSlicers[i]->GetSlice() != (int)lrint(z)) - mSlicers[i]->SetSlice((int)lrint(z)); - break; - - case vtkImageViewer2::SLICE_ORIENTATION_XZ: - if (mSlicers[i]->GetSlice() != (int)lrint(y)) - mSlicers[i]->SetSlice((int)lrint(y)); - break; - - case vtkImageViewer2::SLICE_ORIENTATION_YZ: - if (mSlicers[i]->GetSlice() != (int)lrint(x)) - mSlicers[i]->SetSlice((int)lrint(x)); - break; - } - - mSlicers[i]->Render(); - - UpdateSlice(i); - UpdateTSlice(i); - } - } - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateLinked(int slicer) -{ - double p[3], pt[3]; - p[0] = mSlicers[slicer]->GetCurrentPosition()[0]; - p[1] = mSlicers[slicer]->GetCurrentPosition()[1]; - p[2] = mSlicers[slicer]->GetCurrentPosition()[2]; - mSlicers[slicer]->GetSlicingTransform()->GetInverse()->TransformPoint(p, pt); - double x = (pt[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0]) / mSlicers[slicer]->GetInput()->GetSpacing()[0]; - double y = (pt[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1]) / mSlicers[slicer]->GetInput()->GetSpacing()[1]; - double z = (pt[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2]) / mSlicers[slicer]->GetInput()->GetSpacing()[2]; -#if VTK_MAJOR_VERSION <= 5 - if (x >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0]-0.5 && - x <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1]+0.5 && - y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2]-0.5 && - y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3]+0.5 && - z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4]-0.5 && - z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]+0.5) -#else -int extentImageReslice[6]; -mSlicers[slicer]->GetRegisterExtent(extentImageReslice); - if (x >= extentImageReslice[0]-0.5 && - x <= extentImageReslice[1]+0.5 && - y >= extentImageReslice[2]-0.5 && - y <= extentImageReslice[3]+0.5 && - z >= extentImageReslice[4]-0.5 && - z <= extentImageReslice[5]+0.5) -#endif - { - for (std::list::const_iterator i = mLinkedId.begin(); i != mLinkedId.end(); i++) { - if (this->IsInvolvedInFusionSequence()) { - //this SlicerManager is involved in fusionSequence => do not synchronize the times - emit UpdateLinkManager(*i, slicer, p[0], p[1], p[2], -1); - } - else { - emit UpdateLinkManager(*i, slicer, p[0], p[1], p[2], mSlicers[slicer]->GetMaxCurrentTSlice()); - } - } - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateLinkedNavigation(vvSlicer *refSlicer, bool bPropagate) -{ - vtkCamera *refCam = refSlicer->GetRenderer()->GetActiveCamera(); - - double refPosition[3]; - refCam->GetPosition(refPosition); - refPosition[refSlicer->GetSliceOrientation()] = refSlicer->GetSlice() * - refSlicer->GetInput()->GetSpacing()[refSlicer->GetSliceOrientation()] + - refSlicer->GetInput()->GetOrigin()[refSlicer->GetSliceOrientation()]; - - refSlicer->GetSlicingTransform()->TransformPoint(refPosition, refPosition); - mSlicers[0]->GetSlicingTransform()->GetInverse()->TransformPoint(refPosition, refPosition); - - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - vtkCamera *camera = mSlicers[i]->GetRenderer()->GetActiveCamera(); - camera->SetParallelScale(refCam->GetParallelScale()); - - double position[3], focal[3]; - camera->GetPosition(position); - camera->GetFocalPoint(focal); - - for(int j=0; j<3; j++) { - if(j!=mSlicers[i]->GetSliceOrientation()) { - position[j] = refPosition[j]; - focal[j] = refPosition[j]; - } - } - - camera->SetFocalPoint(focal); - camera->SetPosition(position); - - //Fix for bug #243 - mSlicers[i]->ForceUpdateDisplayExtent(); - } - - Render(); - if(bPropagate) - for (std::list::const_iterator i = mLinkedId.begin(); i != mLinkedId.end(); i++) - emit UpdateLinkedNavigation(*i, this, refSlicer); -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -double vvSlicerManager::GetColorWindow() const -{ - if (mSlicers.size()) - return mSlicers[0]->GetColorWindow(); - return -1; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -double vvSlicerManager::GetColorLevel() const -{ - if (mSlicers.size()) - return mSlicers[0]->GetColorLevel(); - return -1; -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -double vvSlicerManager::GetOverlayColorWindow() const -{ - if (mSlicers.size()) - return mSlicers[0]->GetOverlayColorWindow(); - return -1; -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -double vvSlicerManager::GetOverlayColorLevel() const -{ - if (mSlicers.size()) - return mSlicers[0]->GetOverlayColorLevel(); - return -1; -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -bool vvSlicerManager::GetLinkOverlayWindowLevel() const -{ - if (mSlicers.size()) - return mSlicers[0]->GetLinkOverlayWindowLevel(); - return -1; -} -//---------------------------------------------------------------------------- - -//------------------------------------------------------------------------------ -void vvSlicerManager::ResetTransformationToIdentity(const std::string actorType) -{ - if(actorType == "image") - for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) - this->GetImage()->GetTransform()[i]->Identity(); - else if(actorType == "overlay") - for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) - this->GetSlicer(0)->GetOverlay()->GetTransform()[i]->Identity(); - else if(actorType == "fusion") - for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) - this->GetSlicer(0)->GetFusion()->GetTransform()[i]->Identity(); - else if(actorType == "fusionSequence") //TODO: Check what should really be done here - for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) - this->GetSlicer(0)->GetFusion()->GetTransform()[i]->Identity(); - else if(actorType == "vf") - for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) - this->GetVF()->GetTransform()[i]->Identity(); - else - return; - - for(int i=0; i< this->GetNumberOfSlicers(); i++){ - this->GetSlicer(i)->ForceUpdateDisplayExtent(); - this->GetSlicer(i)->ResetCamera(); - this->GetSlicer(i)->Render(); - } -} -//------------------------------------------------------------------------------ - -//---------------------------------------------------------------------------- -void vvSlicerManager::Render() -{ - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->Render(); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::GenerateDefaultLookupTable() -{ - SetPreset(mPreset); - SetColorMap(mColorMap); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::Reload() -{ - mReader->Update(mType); - mImage=mReader->GetOutput(); - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetImage(mImage); - } - - //if this image is the primary sequence of a fusion sequence, then the main transform matrix should be updated. - if (this->IsMainSequenceOfFusionSequence()) { - SetFusionSequenceMainTransformMatrix( mImage->GetTransform()[0]->GetMatrix() ); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::ReloadFusion() -{ - mFusionReader->Update(mImage->GetNumberOfDimensions(),mFusionComponent.c_str(),mType); - - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFusion(mFusionReader->GetOutput()); - mSlicers[i]->Render(); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -//the secondary sequence is being reloaded. -void vvSlicerManager::ReloadFusionSequence() -{ - // this is to keep the slice thickness, which needs to be artificially increased for visualization - double sp_x, sp_y, sp_z; - this->GetImage()->GetVTKImages()[0]->GetSpacing(sp_x, sp_y, sp_z); - - mFusionSequenceReader->Update(mImage->GetNumberOfDimensions(),mFusionComponent.c_str(),vvImageReader::MERGEDWITHTIME); - - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), 1); - mSlicers[i]->Render(); - } - - //Update the slider - mFusionSequenceNbFrames = mFusionSequenceReader->GetOutput()->GetTransform().size(); - if (mFusionSequenceFrameIndex>=mFusionSequenceNbFrames) { - mFusionSequenceFrameIndex=0; - } - - //Update the list of initial transforms - mFusionSequenceListInitialTransformMatrices.clear(); - for (unsigned i=0 ; iAddFusionSequenceInitialTransformMatrices( mFusionSequenceReader->GetOutput()->GetTransform()[i]->GetMatrix() ); - } - - // also update the slice thickness - for (unsigned i=0 ; iGetImage()->GetTransform().size() ; i++) { - sp_x = this->GetImage()->GetVTKImages()[i]->GetSpacing()[0]; - sp_y = this->GetImage()->GetVTKImages()[i]->GetSpacing()[1]; - this->GetImage()->GetVTKImages()[i]->SetSpacing( sp_x, sp_y, sp_z); - } - -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::ReloadOverlay() -{ - mOverlayReader->Update(mImage->GetNumberOfDimensions(),mOverlayComponent.c_str(),mType); - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetOverlay(mOverlayReader->GetOutput()); - mSlicers[i]->Render(); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::ReloadVF() -{ - mVectorReader->Update(vvImageReader::VECTORFIELD); //deletes the old images through the VF::Init() function - mVF=mVectorReader->GetOutput(); - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetVF(mVF); - mSlicers[i]->Render(); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::RemoveActor(const std::string& actor_type, int overlay_index) -{ - if (actor_type =="overlay") - mOverlayReader = NULL; - - if (actor_type =="fusion") - mFusionReader = NULL; - - if (actor_type =="fusionSequence") { - mFusionSequenceReader = NULL; - } - - for (unsigned int i = 0; i < mSlicers.size(); i++) - mSlicers[i]->RemoveActor(actor_type,overlay_index); - - if (actor_type=="vector") { - mVF=NULL; - mVectorReader=NULL; - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::RemoveActors() -{ - ///This method leaks a few objects. See RemoveActor for what a - ///correct implementation would look like - //DS -> probably due to the reader (now released in the - //RemoveActor() function. (I hope) - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetDisplayMode(0); - mSlicers[i]->GetRenderer()->RemoveActor(mSlicers[i]->GetImageActor()); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateInfoOnCursorPosition(int slicer) -{ - // int view = mSlicers[slicer]->GetSliceOrientation(); - // int slice = mSlicers[slicer]->GetSlice(); - double x = mSlicers[slicer]->GetCurrentPosition()[0]; - double y = mSlicers[slicer]->GetCurrentPosition()[1]; - double z = mSlicers[slicer]->GetCurrentPosition()[2]; - double xyz[3], xyzTransform[3]; - xyz[0] = x; - xyz[1] = y; - xyz[2] = z; - mSlicers[slicer]->GetSlicingTransform()->GetInverse()->TransformPoint(xyz, xyzTransform); - double X = (xyzTransform[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0])/mSlicers[slicer]->GetInput()->GetSpacing()[0]; - double Y = (xyzTransform[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1])/mSlicers[slicer]->GetInput()->GetSpacing()[1]; - double Z = (xyzTransform[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2])/mSlicers[slicer]->GetInput()->GetSpacing()[2]; - double value = -VTK_DOUBLE_MAX; - int displayVec = 0; - double xVec=0, yVec=0, zVec=0, valueVec=0; - int displayOver = 0; - int displayFus = 0; - double valueOver=0, valueFus=0; -#if VTK_MAJOR_VERSION <= 5 - if (X >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0] -0.5 && - X <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1] +0.5 && - Y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2] -0.5 && - Y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3] +0.5 && - Z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4] -0.5 && - Z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5] +0.5) -#else -int extentImageReslice[6]; -mSlicers[slicer]->GetRegisterExtent(extentImageReslice); - if (X >= extentImageReslice[0] -0.5 && - X <= extentImageReslice[1] +0.5 && - Y >= extentImageReslice[2] -0.5 && - Y <= extentImageReslice[3] +0.5 && - Z >= extentImageReslice[4] -0.5 && - Z <= extentImageReslice[5] +0.5) -#endif - { - value = this->GetScalarComponentAsDouble(mSlicers[slicer]->GetInput(), X, Y, Z); - - if (mSlicers[slicer]->GetVFActor() ) { - displayVec = 1; - unsigned int currentTime = mSlicers[slicer]->GetMaxCurrentTSlice(); - vtkImageData *vf = NULL; - - if (mSlicers[slicer]->GetVF()->GetVTKImages().size() > currentTime) - vf = mSlicers[slicer]->GetVF()->GetVTKImages()[currentTime]; - else - vf = mSlicers[slicer]->GetVF()->GetVTKImages()[0]; - - if (vf) { - double Xvf = (x - vf->GetOrigin()[0])/ vf->GetSpacing()[0]; - double Yvf = (y - vf->GetOrigin()[1])/ vf->GetSpacing()[1]; - double Zvf = (z - vf->GetOrigin()[2])/ vf->GetSpacing()[2]; - xVec = this->GetScalarComponentAsDouble( vf, Xvf, Yvf, Zvf, 0); - yVec = this->GetScalarComponentAsDouble( vf, Xvf, Yvf, Zvf, 1); - zVec = this->GetScalarComponentAsDouble( vf, Xvf, Yvf, Zvf, 2); - valueVec = sqrt(xVec*xVec + yVec*yVec + zVec*zVec); - } - } - if (mSlicers[slicer]->GetOverlayActor() ) { - displayOver = 1; - vtkImageData *overlay = dynamic_cast(mSlicers[slicer]->GetOverlayMapper()->GetInput()); - double Xover = (x - overlay->GetOrigin()[0]) / overlay->GetSpacing()[0]; - double Yover = (y - overlay->GetOrigin()[1]) / overlay->GetSpacing()[1]; - double Zover = (z - overlay->GetOrigin()[2]) / overlay->GetSpacing()[2]; - valueOver = this->GetScalarComponentAsDouble(overlay, Xover, Yover, Zover); - } - - if ( mSlicers[slicer]->GetFusionActor() ) { - displayFus = 1; - vtkImageData *fusion = dynamic_cast(mSlicers[slicer]->GetFusionMapper()->GetInput()); - double Xover = (x - fusion->GetOrigin()[0]) / fusion->GetSpacing()[0]; - double Yover = (y - fusion->GetOrigin()[1]) / fusion->GetSpacing()[1]; - double Zover = (z - fusion->GetOrigin()[2]) / fusion->GetSpacing()[2]; - valueFus = this->GetScalarComponentAsDouble(fusion, Xover, Yover, Zover); - } - else if (this->IsInvolvedInFusionSequence()) { - //if the cursor moves over the 'independent' version of the secondary sequence - //do not update the panel, just keep it as it is. - displayFus = 1; - valueFus = std::numeric_limits::quiet_NaN(); - } - - emit UpdatePosition(mSlicers[slicer]->GetCursorVisibility(), - x,y,z,X,Y,Z,value); - emit UpdateVector(displayVec,xVec, yVec, zVec, valueVec); - emit UpdateOverlay(displayOver,valueOver,value); - emit UpdateFusion(displayFus,valueFus); - } -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::Activated() -{ - emit currentImageChanged(mId); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::Picked() -{ - emit currentPickedImageChanged(mId); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateWindowLevel() -{ - emit WindowLevelChanged(); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateSlice(int slicer) -{ - if (mPreviousSlice[slicer] == mSlicers[slicer]->GetSlice()) { - //DD("============= NOTHING"); - return; - } - emit UpdateSlice(slicer, mSlicers[slicer]->GetSlice()); - mSlicers[slicer]->Render(); // DS <-- I add this, this could/must be the only Render ... - mPreviousSlice[slicer] = mSlicers[slicer]->GetSlice(); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateTSlice(int slicer) -{ - int slice = mSlicers[slicer]->GetSlice(); - - int tslice = mSlicers[slicer]->GetMaxCurrentTSlice(); - //if (this->IsInvolvedInFusionSequence()) tslice = mSlicers[slicer]->GetTSlice(); //actually, this is handled by the Slicer - - if (mPreviousSlice[slicer] == slice) { - if (mPreviousTSlice[slicer] == tslice) { - // DD("************** NOTHING ***********"); - return; - } - } - mPreviousSlice[slicer] = slice; - mPreviousTSlice[slicer] = tslice; - - emit UpdateTSlice(slicer, tslice, mFusionSequenceInvolvementCode); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::UpdateSliceRange(int slicer) -{ - emit UpdateSliceRange(slicer, - mSlicers[slicer]->GetSliceRange()[0], mSlicers[slicer]->GetSliceRange()[1], - 0,mSlicers[slicer]->GetTMax()); -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetSlicingPreset(SlicingPresetType preset) -{ - if(mSlicingPreset==preset) - return; - - vtkMatrix4x4 *imageTransformInverse = vtkMatrix4x4::New(); - mImage->GetTransform()[this->GetTSlice()]->GetInverse(imageTransformInverse); - - for(int i=0; i< this->GetNumberOfSlicers(); i++){ - vvSlicer *s = this->GetSlicer(i); - switch(preset) - { - case WORLD_SLICING: - s->GetSlicingTransform()->Identity(); - break; - case VOXELS_SLICING: - s->GetSlicingTransform()->SetMatrix(imageTransformInverse); - break; - default: - imageTransformInverse->Delete(); - return; - } - s->ForceUpdateDisplayExtent(); -#if VTK_MAJOR_VERSION <= 5 - s->SetSlice((s->GetInput()->GetWholeExtent()[s->GetSliceOrientation()*2+1] - +s->GetInput()->GetWholeExtent()[s->GetSliceOrientation()*2])/2.0); -#else - int extentImageReslice[6]; - s->GetRegisterExtent(extentImageReslice); - s->SetSlice((extentImageReslice[s->GetSliceOrientation()*2+1] - +extentImageReslice[s->GetSliceOrientation()*2])/2.0); -#endif - s->ResetCamera(); - s->Render(); - } - - imageTransformInverse->Delete(); - mSlicingPreset = preset; -} - -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetPreset(int preset) -{ - - //vtkLookupTable* LUT = static_cast(mSlicers[0]->GetWindowLevel()->GetLookupTable()); - double window = mSlicers[0]->GetColorWindow(); - double level = mSlicers[0]->GetColorLevel(); - - std::string component_type=mImage->GetScalarTypeAsITKString(); - switch (preset) { - case WL_AUTO: - double range[2]; - mImage->GetScalarRange(range); - window = range[1] - range[0]; - level = (range[1] + range[0])* 0.5; - break; - case WL_HOUNSFIELD: - window = 2000; - level = 0; - break; - case WL_SOFTTISSUE: - window = 400; - level = 20; - break; - case WL_LUNGS: // lungs (same as FOCAL) - window = 1700; - level = -300; - break; - case WL_BONES: - window = 1000; - level = 500; - break; - case WL_HEAD: - window = 200; - level = 70; - break; - case WL_BINARY: - window = 1; - level = 0.5; - break; - case WL_USER: - break; - case WL_VENTILATION: - window=1.; - level=0.; - break; - } - mPreset = preset; - this->SetColorWindow(window); - this->SetColorLevel(level); - - //if (LUT) - //{ - // SetColorMap(-1); - //} -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetLocalColorWindowing(const int slicer, const bool bCtrlKey) -{ - double min, max; - if(bCtrlKey && this->mSlicers[slicer]->GetFusion()) { - int t = mSlicers[slicer]->GetFusionTSlice(); - this->mSlicers[slicer]->GetExtremasAroundMousePointer(min, max, - this->mSlicers[slicer]->GetFusion()->GetVTKImages()[t], - this->mSlicers[slicer]->GetConcatenatedFusionTransform()); - this->SetFusionWindow(max-min); - this->SetFusionLevel(0.5*(min+max)); - this->SetColorMap(mColorMap); - } - else if(bCtrlKey && this->mSlicers[slicer]->GetOverlay()) { - int t = mSlicers[slicer]->GetOverlayTSlice(); - this->mSlicers[slicer]->GetExtremasAroundMousePointer(min, max, - this->mSlicers[slicer]->GetOverlay()->GetVTKImages()[t], - this->mSlicers[slicer]->GetConcatenatedOverlayTransform()); - if(this->mSlicers[slicer]->GetLinkOverlayWindowLevel()){ - this->SetColorWindow(max-min); - this->SetColorLevel(0.5*(min+max)); - } else { - this->SetOverlayColorWindow(max-min); - this->SetOverlayColorLevel(0.5*(min+max)); - } - } - else { - int t = this->GetTSlice(); - this->mSlicers[slicer]->GetExtremasAroundMousePointer(min, max, - this->mSlicers[slicer]->GetImage()->GetVTKImages()[t], - this->mSlicers[slicer]->GetConcatenatedTransform()); - this->SetColorWindow(max-min); - this->SetColorLevel(0.5*(min+max)); - this->SetPreset(WL_USER); - } - this->Render(); - this->UpdateWindowLevel(); -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -void vvSlicerManager::SetColorMap(int colormap) -{ - double range[2]; - - range[0] = mSlicers[0]->GetInput()->GetScalarRange()[0]; - range[1] = mSlicers[0]->GetInput()->GetScalarRange()[1]; - - double window = mSlicers[0]->GetWindowLevel()->GetWindow(); - double level = mSlicers[0]->GetWindowLevel()->GetLevel(); - - vtkLookupTable* LUT = static_cast(mSlicers[0]->GetWindowLevel()->GetLookupTable()); - switch (colormap) { - case -1: - break; - case 0: - LUT = NULL; - break; - case 1: - if (LUT == NULL) - LUT = vtkLookupTable::New(); - LUT->SetValueRange(0,1); - LUT->SetSaturationRange(1,1); - LUT->SetHueRange(0,0.18); - break; - case 2: - if (LUT == NULL) - LUT = vtkLookupTable::New(); - LUT->SetValueRange(0,1); - LUT->SetSaturationRange(1,1); - LUT->SetHueRange(0.4,0.80); - break; - case 3: - if (LUT == NULL) - LUT = vtkLookupTable::New(); - LUT->SetValueRange(0.5,1); - LUT->SetSaturationRange(1,1); - LUT->SetHueRange(0.666,0); - break; - case 4: - if (LUT == NULL) - LUT = vtkLookupTable::New(); - LUT->SetValueRange(1,1); - LUT->SetSaturationRange(1,1); - LUT->SetHueRange(0,1); - LUT->SetAlphaRange(1, 1); - break; - case 5: - if (LUT == NULL) - LUT = vtkLookupTable::New(); - LUT->SetValueRange(1,1); - LUT->SetSaturationRange(1,1); - LUT->SetHueRange(1,0.1); - //LUT->SetRampToLinear(); - break; - } - if (LUT) { - LUT->SetTableRange(level-fabs(window)/2,level+fabs(window)/2); - LUT->Build(); - } - vtkWindowLevelLookupTable* fusLUT = NULL; - - //FUSION / FUSION SEQUENCE - if (mSlicers[0]->GetFusion()) { // && mFusionColorMap >= 0) { - fusLUT = vtkWindowLevelLookupTable::New(); - double fusRange [2]; - fusRange[0] = mFusionLevel - mFusionWindow/2; - fusRange[1] = mFusionLevel + mFusionWindow/2; - - //check whether it is actually a fusionSequence or a fusion, before invoking mFusionReader... - double* frange; - if (this->IsInvolvedInFusionSequence()) - frange = mFusionSequenceReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); - else - frange = mFusionReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); - - fusLUT->SetTableRange(frange); - fusLUT->SetValueRange(1,1); - fusLUT->SetSaturationRange(1,1); - fusLUT->SetAlphaRange(1, 1); - fusLUT->SetWindow(mFusionWindow); - fusLUT->SetLevel(mFusionLevel); - if (mFusionColorMap == 1) - fusLUT->SetHueRange(0,0.18); - else if (mFusionColorMap == 2) - fusLUT->SetHueRange(0.4,0.80); - else if (mFusionColorMap == 3) - { - fusLUT->SetHueRange(0.666, 0); - fusLUT->SetValueRange(0.5, 1); - } - else if (mFusionColorMap == 4) - fusLUT->SetHueRange(0,1); - else if (mFusionColorMap <= 0) - { - fusLUT->SetValueRange(0,1); - fusLUT->SetSaturationRange(0,0); - } - - fusLUT->ForceBuild(); - double v[4]; - // set color table transparency - //double alpha_range=(double)mFusionThresOpacity/10; - double range_end = fusRange[0] + (double)mFusionThresOpacity*(fusRange[1] - fusRange[0])/100; - double curr_value = fusRange[0]; - int nvalues = fusLUT->GetNumberOfTableValues(); - for (double i = 0; curr_value < range_end; i++) { - fusLUT->GetTableValue(i, v); - v[3] = 0; - //if (curr_value >= -alpha_range && curr_value <= alpha_range) v[3] = pow(fabs(curr_value/alpha_range),2); - //else v[3] = 1; - fusLUT->SetTableValue(i, v); - curr_value += (fusRange[1] - fusRange[0])/nvalues; - } - } - for ( unsigned int i = 0; i < mSlicers.size(); i++) { - - if (mSlicers[i]->GetOverlay()) { - vtkLookupTable* supLUT = vtkLookupTable::New(); - supLUT->SetTableRange(range[0],range[1]); - supLUT->SetValueRange(1,1); - supLUT->SetSaturationRange(1,1); - supLUT->SetHueRange(double(mOverlayColor)/360,double(mOverlayColor)/360); - supLUT->Build(); - vtkLookupTable* invLUT = vtkLookupTable::New(); - invLUT->SetTableRange(range[0],range[1]); - invLUT->SetValueRange(1,1); - invLUT->SetSaturationRange(1,1); - invLUT->SetHueRange(double((mOverlayColor+180)%360)/360,double((mOverlayColor+180)%360)/360); - invLUT->Build(); - mSlicers[i]->GetWindowLevel()->SetLookupTable(supLUT); - mSlicers[i]->GetOverlayMapper()->SetLookupTable(invLUT); - invLUT->Delete(); - supLUT->Delete(); - } else if (mSlicers[i]->GetOverlay()) { - mSlicers[i]->GetWindowLevel()->SetLookupTable(LUT); - } else { - mSlicers[i]->GetWindowLevel()->SetLookupTable(LUT); - } - - if (mSlicers[i]->GetFusion()) { - mSlicers[i]->ShowFusionLegend(mFusionShowLegend); - mSlicers[i]->GetFusionMapper()->SetLookupTable(fusLUT); - mSlicers[i]->GetFusionActor()->SetOpacity(double(mFusionOpacity)/100); - } - } - if (fusLUT) - fusLUT->Delete(); - if (colormap >= 0) - mColorMap = colormap; -} -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -vvLandmarks* vvSlicerManager::GetLandmarks() -{ - if (mLandmarks == NULL) { - mLandmarks = new vvLandmarks(mSlicers[0]->GetTMax()+1); - for (unsigned int i = 0; i < mSlicers.size(); i++) - mSlicers[i]->SetLandmarks(mLandmarks); - } - return mLandmarks; -} -//---------------------------------------------------------------------------- -void vvSlicerManager::AddNewLandmark(float x,float y,float z,float t) -{ - emit callAddLandmark(x,y,z,t); -} - -//---------------------------------------------------------------------------- -void vvSlicerManager::AddLandmark(float x,float y,float z,float t) -{ - double x_index = (x - mSlicers[0]->GetInput()->GetOrigin()[0])/mSlicers[0]->GetInput()->GetSpacing()[0]; - double y_index = (y - mSlicers[0]->GetInput()->GetOrigin()[1])/mSlicers[0]->GetInput()->GetSpacing()[1]; - double z_index = (z - mSlicers[0]->GetInput()->GetOrigin()[2])/mSlicers[0]->GetInput()->GetSpacing()[2]; -#if VTK_MAJOR_VERSION <= 5 - if (x_index >= mSlicers[0]->GetInput()->GetWholeExtent()[0]-0.5 && - x_index <= mSlicers[0]->GetInput()->GetWholeExtent()[1]+0.5 && - y_index >= mSlicers[0]->GetInput()->GetWholeExtent()[2]-0.5 && - y_index <= mSlicers[0]->GetInput()->GetWholeExtent()[3]+0.5 && - z_index >= mSlicers[0]->GetInput()->GetWholeExtent()[4]-0.5 && - z_index <= mSlicers[0]->GetInput()->GetWholeExtent()[5]+0.5) -#else - int extentImageReslice[6]; - mSlicers[0]->GetRegisterExtent(extentImageReslice); - if (x_index >= extentImageReslice[0]-0.5 && - x_index <= extentImageReslice[1]+0.5 && - y_index >= extentImageReslice[2]-0.5 && - y_index <= extentImageReslice[3]+0.5 && - z_index >= extentImageReslice[4]-0.5 && - z_index <= extentImageReslice[5]+0.5) -#endif - { - double value = this->GetScalarComponentAsDouble(mSlicers[mSelectedSlicer]->GetInput(), x_index, y_index, z_index); //Value in selected Slicer (not 0): bug #2848 - this->GetLandmarks()->AddLandmark(x,y,z,t,value); - emit LandmarkAdded(); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::AddLandmarkProfile(float x,float y,float z,float t) -{ - double x_index = (x - mSlicers[0]->GetInput()->GetOrigin()[0])/mSlicers[0]->GetInput()->GetSpacing()[0]; - double y_index = (y - mSlicers[0]->GetInput()->GetOrigin()[1])/mSlicers[0]->GetInput()->GetSpacing()[1]; - double z_index = (z - mSlicers[0]->GetInput()->GetOrigin()[2])/mSlicers[0]->GetInput()->GetSpacing()[2]; -#if VTK_MAJOR_VERSION <= 5 - if (x_index >= mSlicers[0]->GetInput()->GetWholeExtent()[0]-0.5 && - x_index <= mSlicers[0]->GetInput()->GetWholeExtent()[1]+0.5 && - y_index >= mSlicers[0]->GetInput()->GetWholeExtent()[2]-0.5 && - y_index <= mSlicers[0]->GetInput()->GetWholeExtent()[3]+0.5 && - z_index >= mSlicers[0]->GetInput()->GetWholeExtent()[4]-0.5 && - z_index <= mSlicers[0]->GetInput()->GetWholeExtent()[5]+0.5) -#else - int extentImageReslice[6]; - mSlicers[0]->GetRegisterExtent(extentImageReslice); - if (x_index >= extentImageReslice[0]-0.5 && - x_index <= extentImageReslice[1]+0.5 && - y_index >= extentImageReslice[2]-0.5 && - y_index <= extentImageReslice[3]+0.5 && - z_index >= extentImageReslice[4]-0.5 && - z_index <= extentImageReslice[5]+0.5) -#endif - { - double value = this->GetScalarComponentAsDouble(mSlicers[mSelectedSlicer]->GetInput(), x_index, y_index, z_index); //Value in selected Slicer (not 0): bug #2848 - this->GetLandmarks()->AddLandmark(x,y,z,t,value); - } -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::PrevImage(int slicer) -{ - emit ChangeImageWithIndexOffset(this, slicer, -1); -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::NextImage(int slicer) -{ - emit ChangeImageWithIndexOffset(this, slicer, 1); -} -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -void vvSlicerManager::VerticalSliderHasChanged(int slicer, int slice) -{ - emit AVerticalSliderHasChanged(slicer, slice); -} - -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- -double vvSlicerManager::GetScalarComponentAsDouble(vtkImageData *image, double X, double Y, double Z, int component) -{ - int ix, iy, iz; - return mSlicers[0]->GetScalarComponentAsDouble(image, X, Y, Z, ix, iy, iz, component); -} -//---------------------------------------------------------------------------- +/*========================================================================= + Program: vv http://www.creatis.insa-lyon.fr/rio/vv + + Authors belong to: + - University of LYON http://www.universite-lyon.fr/ + - Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr + - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the copyright notices for more information. + + It is distributed under dual licence + + - BSD See included LICENSE.txt file + - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html + ======================================================================-====*/ + +#include "vvSlicerManager.h" +#include "vvSlicer.h" +#include "vvImage.h" +#include "vvSlicerManagerCommand.h" +#include "vvInteractorStyleNavigator.h" +#include "vvLandmarks.h" +#include "vvMesh.h" +#include "vvBlendImageActor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +//---------------------------------------------------------------------------- +vvSlicerManager::vvSlicerManager(int numberOfSlicers) +{ + + connect(this, SIGNAL(callAddLandmark(float,float,float,float)), this, SLOT(AddLandmark(float,float,float,float))); + + mFileName = ""; + mId = ""; + mVFName = ""; + mOverlayName = ""; + mFusionName = ""; + mVFId = ""; + mLastError = ""; + mType = vvImageReader::UNDEFINEDIMAGETYPE; + mColorMap = 0; + mPreset = 0; + mOverlayColor = 130; + + mFusionOpacity = 30; + mFusionThresOpacity = 1; + mFusionColorMap = 3; + mFusionWindow = 1000; + mFusionLevel = 1000; + mFusionShowLegend = true; + + mFusionSequenceInvolvementCode = -1; + mFusionSequenceIndexLinkedManager = -1; + mFusionSequenceFrameIndex = -1; + mFusionSequenceNbFrames = 0; + mFusionSequenceSpatialSyncFlag = false; + mFusionSequenceTemporalSyncFlag = false; + + mLandmarks = NULL; + mLinkedId.resize(0); + + for ( int i = 0; i < numberOfSlicers; i++) { + mSlicers.push_back(vtkSmartPointer::New()); + mSlicers[i]->SetSlicerNumber(i); + } + mSelectedSlicer = -1; + + mPreviousSlice.resize(numberOfSlicers, 0); + mPreviousTSlice.resize(numberOfSlicers, 0); + mSlicingPreset = WORLD_SLICING; + + +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +vvSlicerManager::~vvSlicerManager() +{ + if (mLandmarks) + delete mLandmarks; +} +//---------------------------------------------------------------------------- + + +//------------------------------------------------------------------------------ +void vvSlicerManager::SetFilename(std::string filename, int number) +{ + mFileName = filename; + mFileName = vtksys::SystemTools::GetFilenameName(mFileName); + mBaseFileName = vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(mFileName)); + mBaseFileNameNumber = number; + + mFileName = mBaseFileName; + if (number != 0) { + mFileName.append("_"+clitk::toString(number)); + } + mFileName.append(vtksys::SystemTools::GetFilenameLastExtension(filename)); + + for(unsigned int i=0; iSetFileName(mFileName);//vtksys::SystemTools::GetFilenameWithoutLastExtension(filename)); + } + +} +//------------------------------------------------------------------------------ + + +//---------------------------------------------------------------------------- +void vvSlicerManager::AddContour(vvMesh::Pointer contour,bool propagate) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->AddContour(contour,propagate); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::ToggleContourSuperposition() +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) + mSlicers[i]->ToggleContourSuperposition(); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +std::string vvSlicerManager::GetListOfAbsoluteFilePathInOneString(const std::string &actorType) +{ + vvImageReader *reader = NULL; + + if(actorType=="image") + reader = mReader; + else if(actorType=="overlay") + reader = mOverlayReader; + else if(actorType=="fusion") + reader = mFusionReader; + else if(actorType=="vector") + reader = mVectorReader; + else if(actorType=="fusionSequence") + reader = mFusionSequenceReader; + + if(!reader) + return ""; + + std::string list; + for(unsigned int i=0; iGetInputFilenames().size(); i++){ + QFileInfo fileinfo(reader->GetInputFilenames()[i].c_str()); //Do not show the path + if(i) + list += '\n'; + list += fileinfo.absoluteFilePath().toStdString(); + } + return list; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +bool vvSlicerManager::SetImage(std::string filename, vvImageReader::LoadedImageType type, int n, unsigned int slice) +{ + mType = type; + if (mReader.IsNull()) + mReader = vvImageReader::New(); + std::vector filenames; + filenames.push_back(filename); + mReader->SetInputFilenames(filenames); + mReader->SetSlice(slice); // Only used for SLICED type + mReader->Update(type); + + SetFilename(filename, n); + // mFileName = vtksys::SystemTools::GetFilenameName(mFileName); + //mBaseFileName = vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(mFileName)); + //mBaseFileNameNumber = n; + + if (mReader->GetLastError().size() == 0) { + mImage=mReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetFileName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename)); + mSlicers[i]->SetImage(mReader->GetOutput()); + } + } else { + mLastError = mReader->GetLastError(); + return false; + } + // if (n!=0) { + // mFileName.append("_"+clitk::toString(n)); + // } + return true; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetImage(vvImage::Pointer image) +{ + mImage=image; + for (unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetImage(image); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +bool vvSlicerManager::SetImages(std::vector filenames, vvImageReader::LoadedImageType type, int n) +{ + mType = type; + std::string fileWithoutExtension = vtksys::SystemTools::GetFilenameWithoutExtension(filenames[0]); + if (type == vvImageReader::DICOM) + fileWithoutExtension += "_dicom"; + else if (type == vvImageReader::MERGED) + fileWithoutExtension += "_merged"; + else if (type == vvImageReader::MERGEDWITHTIME) + fileWithoutExtension += "_merged_wt"; + + mFileName = vtksys::SystemTools::GetFilenameName(mFileName); + mFileName = fileWithoutExtension + vtksys::SystemTools::GetFilenameExtension(filenames[0]); + if (mReader.IsNull()) + mReader = vvImageReader::New(); + mReader->SetInputFilenames(filenames); + mReader->Update(type); + + mBaseFileName = vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(mFileName)); + mBaseFileNameNumber = n; + + if (mReader->GetLastError().size() == 0) { + mImage=mReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetFileName(fileWithoutExtension); + mSlicers[i]->SetImage(mReader->GetOutput()); + } + } else { + mLastError = mReader->GetLastError(); + return false; + } + if (n!=0) { + mFileName.append("_"+clitk::toString(n)); + } + return true; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +bool vvSlicerManager::SetOverlay(std::vector filenames,int dim, std::string component, vvImageReader::LoadedImageType type) +{ + mOverlayName = filenames[0]; + mOverlayComponent = component; + if (dim > mImage->GetNumberOfDimensions()) { + mLastError = " Overlay dimension cannot be greater than reference image!"; + return false; + } + if (mOverlayReader.IsNull()) + mOverlayReader = vvImageReader::New(); + mOverlayReader->SetInputFilenames(filenames); + mOverlayReader->Update(type); + if (mOverlayReader->GetLastError().size() == 0) { + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetOverlay(mOverlayReader->GetOutput()); + } + } else { + mLastError = mOverlayReader->GetLastError(); + return false; + } + return true; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +bool vvSlicerManager::SetFusion(std::vector filenames,int dim, std::string component, vvImageReader::LoadedImageType type) +{ + mFusionName = filenames[0]; + mFusionComponent = component; + if (dim > mImage->GetNumberOfDimensions()) { + mLastError = " Fusion dimension cannot be greater than reference image!"; + return false; + } + if (mFusionReader.IsNull()) + mFusionReader = vvImageReader::New(); + mFusionReader->SetInputFilenames(filenames); + mFusionReader->Update(type); + if (mFusionReader->GetLastError().size() == 0) { + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetFusion(mFusionReader->GetOutput()); + } + } else { + mLastError = mFusionReader->GetLastError(); + return false; + } + double *fusRange = mFusionReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); + mFusionLevel = (fusRange[0]+fusRange[1])/2; + mFusionWindow = fusRange[1]-fusRange[0]; + + return true; +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +//this function is called by vvMainWindow::AddFusionSequence for the primary sequence (CT), while the given files constitute the secondary sequence. +bool vvSlicerManager::SetFusionSequence(std::vector filenames, int dim, std::string component, vvImageReader::LoadedImageType type) +{ + mFusionSequenceInvolvementCode = 0; + + mFusionName = filenames[0]; + mFusionComponent = component; + + if (dim > mImage->GetNumberOfDimensions()) { + mLastError = " Fusion Sequence dimension cannot be greater than reference image!"; + return false; + } + + if (mFusionSequenceReader.IsNull()) + mFusionSequenceReader = vvImageReader::New(); + + mFusionSequenceReader->SetInputFilenames(filenames); + mFusionSequenceReader->Update(type); + + + if (mFusionSequenceReader->GetLastError().size() == 0) { + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), mFusionSequenceInvolvementCode); + } + } else { + mLastError = mFusionSequenceReader->GetLastError(); + return false; + } + double *fusRange = mFusionSequenceReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); + mFusionLevel = (fusRange[0]+fusRange[1])/2; + mFusionWindow = fusRange[1]-fusRange[0]; + + //store the initial transform matrices of each frame, and reset them to identity + mFusionSequenceListInitialTransformMatrices.clear(); + for (unsigned i=0 ; iGetOutput()->GetTransform().size() ; i++) { + AddFusionSequenceInitialTransformMatrices( mFusionSequenceReader->GetOutput()->GetTransform()[i]->GetMatrix() ); + mFusionSequenceReader->GetOutput()->GetTransform()[i]->Identity(); + mFusionSequenceReader->GetOutput()->GetTransform()[i]->Update(); + } + + //adjust the time slider in the overlay panel + mFusionSequenceNbFrames = mFusionSequenceReader->GetOutput()->GetTransform().size(); + mFusionSequenceFrameIndex = std::max( 0, std::min(mFusionSequenceFrameIndex, mFusionSequenceNbFrames)); + + return true; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +bool vvSlicerManager::SetVF(std::string filename) +{ + if (mVectorReader.IsNull()) + mVectorReader = vvImageReader::New(); + mVectorReader->SetInputFilename(filename); + + if (mType == vvImageReader::IMAGEWITHTIME) + mVectorReader->Update(vvImageReader::VECTORFIELDWITHTIME); + else + mVectorReader->Update(vvImageReader::VECTORFIELD); + if (mVectorReader->GetLastError().size() != 0) { + mLastError = mVectorReader->GetLastError(); + return false; + } else + return SetVF(mVectorReader->GetOutput(),filename); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +bool vvSlicerManager::SetVF(vvImage::Pointer vf,std::string filename) +{ + if (vf->GetNumberOfDimensions() > mImage->GetNumberOfDimensions()) { + mLastError = "Sorry, vector field dimension cannot be greater then reference image."; + return false; + } + if (vf->GetNumberOfDimensions() == 4) { + if (vf->GetSpacing()[3] != mImage->GetSpacing()[3]) { + mLastError = "Sorry, vector field time spacing cannot be different from time spacing of the reference image."; + return false; + } + if (vf->GetOrigin()[3] != mImage->GetOrigin()[3]) { + mLastError = "Sorry, vector field time origin cannot be different from time origin of the reference image."; + return false; + } + } + mVF=vf; + mVFName = filename; + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetVF(vf); + } + return true; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +vvSlicer* vvSlicerManager::GetSlicer(int i) +{ + return mSlicers[i]; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateSlicer(int num, bool state) +{ + if (mSlicers[num]->GetImage()) { + mSlicers[num]->SetDisplayMode(state); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetSlicerWindow(int i, vtkRenderWindow* RW) +{ + mSlicers[i]->SetRenderWindow(i,RW); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetInteractorStyleNavigator(int i, vtkInteractorStyle* style) +{ + vvSlicerManagerCommand *smc = vvSlicerManagerCommand::New(); + smc->SM = this; + smc->SetSlicerNumber(i); + mSlicers[i]->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); + + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::KeyPressEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::WindowLevelEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::EndWindowLevelEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::StartWindowLevelEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::PickEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::StartPickEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::LeaveEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::UserEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::MouseWheelForwardEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::MouseWheelBackwardEvent, smc); + // mSlicers[i]->GetRenderWindow()->GetInteractor()-> + // GetInteractorStyle()->AddObserver(vtkCommand::LeftButtonReleaseEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::EndPickEvent, smc); + mSlicers[i]->GetRenderWindow()->GetInteractor()-> + GetInteractorStyle()->AddObserver(vtkCommand::EndInteractionEvent, smc); + smc->Delete(); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::LeftButtonReleaseEvent(int slicer) +{ + emit LeftButtonReleaseSignal(slicer); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::EmitMousePositionUpdated(int slicer) +{ + emit MousePositionUpdatedSignal(slicer); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::EmitKeyPressed(std::string KeyPress) +{ + emit KeyPressedSignal(KeyPress); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetSliceOrientation(int slicer, int orientation) +{ + mSlicers[slicer]->SetSliceOrientation(orientation); + emit UpdateOrientation(slicer, orientation); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +int vvSlicerManager::GetTSlice() +{ + return mSlicers[0]->GetTSlice(); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetTSlice(int slice, bool updateLinkedImages) +{ + if (!updateLinkedImages) { //for fusionSequence, TMax / MaxCurrentTSlice are irrelevant. + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetTSlice(slice, updateLinkedImages); + UpdateTSlice(i); + } + return; + } + + if (slice < 0) + slice = 0; + else if (slice > mSlicers[0]->GetTMax()) + slice = mSlicers[0]->GetTMax(); + if (mLandmarks) + mLandmarks->SetTime(slice); + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + if (slice != mSlicers[i]->GetMaxCurrentTSlice()) { + mSlicers[i]->SetTSlice(slice, updateLinkedImages); + UpdateTSlice(i); + } + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetFusionSequenceTSlice(int slice) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetFusionSequenceTSlice(slice); + UpdateTSlice(i); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetNextTSlice(int originating_slicer) +{ + int t = mSlicers[0]->GetMaxCurrentTSlice(); + t++; + if (t > mSlicers[0]->GetTMax()) + t = 0; + emit UpdateTSlice(originating_slicer,t, mFusionSequenceInvolvementCode); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetPreviousTSlice(int originating_slicer) +{ + int t = mSlicers[0]->GetMaxCurrentTSlice(); + t--; + if (t < 0) + t = mSlicers[0]->GetTMax(); + emit UpdateTSlice(originating_slicer,t, mFusionSequenceInvolvementCode); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::ToggleInterpolation() +{ + bool interpolate=!(mSlicers[0]->GetImageActor()->GetInterpolate()); + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->GetImageActor()->SetInterpolate(interpolate); + if (mSlicers[i]->GetOverlayActor()) + mSlicers[i]->GetOverlayActor()->SetInterpolate(interpolate); + if (mSlicers[i]->GetFusionActor()) + mSlicers[i]->GetFusionActor()->SetInterpolate(interpolate); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetTSliceInSlicer(int tslice, int slicer) +{ + if (tslice < 0) + tslice = 0; + else if (tslice > mSlicers[slicer]->GetTMax()) + tslice = mSlicers[slicer]->GetTMax(); + if (mLandmarks) + mLandmarks->SetTime(tslice); + + if (mSlicers[slicer]->GetMaxCurrentTSlice() == tslice) return; + + mSlicers[slicer]->SetTSlice(tslice); + + if(mSlicingPreset==VOXELS_SLICING) { + vtkMatrix4x4 *imageTransformInverse = vtkMatrix4x4::New(); + mImage->GetTransform()[mSlicers[slicer]->GetTSlice()]->GetInverse(imageTransformInverse); + this->GetSlicer(slicer)->GetSlicingTransform()->SetMatrix(imageTransformInverse); + imageTransformInverse->Delete(); + } + + UpdateTSlice(slicer); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetColorWindow(double s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetColorWindow(s); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetColorLevel(double s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetColorLevel(s); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetOverlayColorWindow(double s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetOverlayColorWindow(s); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetOverlayColorLevel(double s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetOverlayColorLevel(s); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetLinkOverlayWindowLevel(bool b) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetLinkOverlayWindowLevel(b); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetCursorAndCornerAnnotationVisibility(int s) +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetCursorVisibility(s); + mSlicers[i]->SetCornerAnnotationVisibility(s); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetOpacity(int i, double factor) +{ + mSlicers[i]->SetOpacity(1/factor); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateViews(int current,int slicer) +{ + double p[3], pt[3]; + p[0] = mSlicers[slicer]->GetCurrentPosition()[0]; + p[1] = mSlicers[slicer]->GetCurrentPosition()[1]; + p[2] = mSlicers[slicer]->GetCurrentPosition()[2]; + mSlicers[slicer]->GetSlicingTransform()->GetInverse()->TransformPoint(p, pt); + + double x = (pt[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0]) + /mSlicers[slicer]->GetInput()->GetSpacing()[0]; + double y = (pt[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1]) + /mSlicers[slicer]->GetInput()->GetSpacing()[1]; + double z = (pt[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2]) + /mSlicers[slicer]->GetInput()->GetSpacing()[2]; +#if VTK_MAJOR_VERSION <= 5 + if (x >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0]-0.5 && + x <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1]+0.5 && + y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2]-0.5 && + y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3]+0.5 && + z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4]-0.5 && + z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]+0.5) +#else +int extentImageReslice[6]; +mSlicers[slicer]->GetRegisterExtent(extentImageReslice); + if (x >= extentImageReslice[0]-0.5 && + x <= extentImageReslice[1]+0.5 && + y >= extentImageReslice[2]-0.5 && + y <= extentImageReslice[3]+0.5 && + z >= extentImageReslice[4]-0.5 && + z <= extentImageReslice[5]+0.5) +#endif + { + mSlicers[slicer]->UpdateCursorPosition(); + mSlicers[slicer]->SetCursorColor(10,212,255); + mSelectedSlicer = slicer; + + switch (mSlicers[slicer]->GetSliceOrientation()) { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + if (mSlicers[slicer]->GetSlice() != (int)lrint(z)) + mSlicers[slicer]->SetSlice((int)lrint(z)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + if (mSlicers[slicer]->GetSlice() != (int)lrint(y)) + mSlicers[slicer]->SetSlice((int)lrint(y)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + if (mSlicers[slicer]->GetSlice() != (int)lrint(x)) + mSlicers[slicer]->SetSlice((int)lrint(x)); + break; + } + mSlicers[slicer]->Render(); + + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + if (i != (unsigned int)slicer + && mSlicers[i]->GetRenderer()->GetDraw() + && mSlicers[i]->GetRenderWindow()->GetSize()[0] > 2 + && mSlicers[i]->GetRenderWindow()->GetSize()[1] > 2) { + mSlicers[i]->SetCurrentPosition(p[0], p[1], p[2], mSlicers[slicer]->GetMaxCurrentTSlice()); + mSlicers[i]->UpdateCursorPosition(); + if (current) { //do not display corner annotation if image is the one picked + mSlicers[i]->SetCurrentPosition(-VTK_DOUBLE_MAX,-VTK_DOUBLE_MAX, + -VTK_DOUBLE_MAX, mSlicers[slicer]->GetMaxCurrentTSlice()); + mSlicers[i]->SetCursorColor(255,10,212); + } else { + mSlicers[i]->SetCursorColor(150,10,282); + } + switch (mSlicers[i]->GetSliceOrientation()) { + case vtkImageViewer2::SLICE_ORIENTATION_XY: + if (mSlicers[i]->GetSlice() != (int)lrint(z)) + mSlicers[i]->SetSlice((int)lrint(z)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_XZ: + if (mSlicers[i]->GetSlice() != (int)lrint(y)) + mSlicers[i]->SetSlice((int)lrint(y)); + break; + + case vtkImageViewer2::SLICE_ORIENTATION_YZ: + if (mSlicers[i]->GetSlice() != (int)lrint(x)) + mSlicers[i]->SetSlice((int)lrint(x)); + break; + } + + mSlicers[i]->Render(); + + UpdateSlice(i); + UpdateTSlice(i); + } + } + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateLinked(int slicer) +{ + double p[3], pt[3]; + p[0] = mSlicers[slicer]->GetCurrentPosition()[0]; + p[1] = mSlicers[slicer]->GetCurrentPosition()[1]; + p[2] = mSlicers[slicer]->GetCurrentPosition()[2]; + mSlicers[slicer]->GetSlicingTransform()->GetInverse()->TransformPoint(p, pt); + double x = (pt[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0]) / mSlicers[slicer]->GetInput()->GetSpacing()[0]; + double y = (pt[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1]) / mSlicers[slicer]->GetInput()->GetSpacing()[1]; + double z = (pt[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2]) / mSlicers[slicer]->GetInput()->GetSpacing()[2]; +#if VTK_MAJOR_VERSION <= 5 + if (x >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0]-0.5 && + x <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1]+0.5 && + y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2]-0.5 && + y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3]+0.5 && + z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4]-0.5 && + z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]+0.5) +#else +int extentImageReslice[6]; +mSlicers[slicer]->GetRegisterExtent(extentImageReslice); + if (x >= extentImageReslice[0]-0.5 && + x <= extentImageReslice[1]+0.5 && + y >= extentImageReslice[2]-0.5 && + y <= extentImageReslice[3]+0.5 && + z >= extentImageReslice[4]-0.5 && + z <= extentImageReslice[5]+0.5) +#endif + { + for (std::list::const_iterator i = mLinkedId.begin(); i != mLinkedId.end(); i++) { + if (this->IsInvolvedInFusionSequence()) { + //this SlicerManager is involved in fusionSequence => do not synchronize the times + emit UpdateLinkManager(*i, slicer, p[0], p[1], p[2], -1); + } + else { + emit UpdateLinkManager(*i, slicer, p[0], p[1], p[2], mSlicers[slicer]->GetMaxCurrentTSlice()); + } + } + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateLinkedNavigation(vvSlicer *refSlicer, bool bPropagate) +{ + vtkCamera *refCam = refSlicer->GetRenderer()->GetActiveCamera(); + + double refPosition[3]; + refCam->GetPosition(refPosition); + refPosition[refSlicer->GetSliceOrientation()] = refSlicer->GetSlice() * + refSlicer->GetInput()->GetSpacing()[refSlicer->GetSliceOrientation()] + + refSlicer->GetInput()->GetOrigin()[refSlicer->GetSliceOrientation()]; + + refSlicer->GetSlicingTransform()->TransformPoint(refPosition, refPosition); + mSlicers[0]->GetSlicingTransform()->GetInverse()->TransformPoint(refPosition, refPosition); + + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + vtkCamera *camera = mSlicers[i]->GetRenderer()->GetActiveCamera(); + camera->SetParallelScale(refCam->GetParallelScale()); + + double position[3], focal[3]; + camera->GetPosition(position); + camera->GetFocalPoint(focal); + + for(int j=0; j<3; j++) { + if(j!=mSlicers[i]->GetSliceOrientation()) { + position[j] = refPosition[j]; + focal[j] = refPosition[j]; + } + } + + camera->SetFocalPoint(focal); + camera->SetPosition(position); + + //Fix for bug #243 + mSlicers[i]->ForceUpdateDisplayExtent(); + } + + Render(); + if(bPropagate) + for (std::list::const_iterator i = mLinkedId.begin(); i != mLinkedId.end(); i++) + emit UpdateLinkedNavigation(*i, this, refSlicer); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +double vvSlicerManager::GetColorWindow() const +{ + if (mSlicers.size()) + return mSlicers[0]->GetColorWindow(); + return -1; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +double vvSlicerManager::GetColorLevel() const +{ + if (mSlicers.size()) + return mSlicers[0]->GetColorLevel(); + return -1; +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +double vvSlicerManager::GetOverlayColorWindow() const +{ + if (mSlicers.size()) + return mSlicers[0]->GetOverlayColorWindow(); + return -1; +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +double vvSlicerManager::GetOverlayColorLevel() const +{ + if (mSlicers.size()) + return mSlicers[0]->GetOverlayColorLevel(); + return -1; +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +bool vvSlicerManager::GetLinkOverlayWindowLevel() const +{ + if (mSlicers.size()) + return mSlicers[0]->GetLinkOverlayWindowLevel(); + return -1; +} +//---------------------------------------------------------------------------- + +//------------------------------------------------------------------------------ +void vvSlicerManager::ResetTransformationToIdentity(const std::string actorType) +{ + if(actorType == "image") + for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) + this->GetImage()->GetTransform()[i]->Identity(); + else if(actorType == "overlay") + for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) + this->GetSlicer(0)->GetOverlay()->GetTransform()[i]->Identity(); + else if(actorType == "fusion") + for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) + this->GetSlicer(0)->GetFusion()->GetTransform()[i]->Identity(); + else if(actorType == "fusionSequence") //TODO: Check what should really be done here + for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) + this->GetSlicer(0)->GetFusion()->GetTransform()[i]->Identity(); + else if(actorType == "vf") + for(unsigned int i=0; iGetImage()->GetTransform().size(); i++) + this->GetVF()->GetTransform()[i]->Identity(); + else + return; + + for(int i=0; i< this->GetNumberOfSlicers(); i++){ + this->GetSlicer(i)->ForceUpdateDisplayExtent(); + this->GetSlicer(i)->ResetCamera(); + this->GetSlicer(i)->Render(); + } +} +//------------------------------------------------------------------------------ + +//---------------------------------------------------------------------------- +void vvSlicerManager::Render() +{ + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->Render(); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::GenerateDefaultLookupTable() +{ + SetPreset(mPreset); + SetColorMap(mColorMap); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::Reload() +{ + mReader->Update(mType); + mImage=mReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetImage(mImage); + } + + //if this image is the primary sequence of a fusion sequence, then the main transform matrix should be updated. + if (this->IsMainSequenceOfFusionSequence()) { + SetFusionSequenceMainTransformMatrix( mImage->GetTransform()[0]->GetMatrix() ); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::ReloadFusion() +{ + mFusionReader->Update(mImage->GetNumberOfDimensions(),mFusionComponent.c_str(),mType); + + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetFusion(mFusionReader->GetOutput()); + mSlicers[i]->Render(); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +//the secondary sequence is being reloaded. +void vvSlicerManager::ReloadFusionSequence() +{ + // this is to keep the slice thickness, which needs to be artificially increased for visualization + double sp_x, sp_y, sp_z; + this->GetImage()->GetVTKImages()[0]->GetSpacing(sp_x, sp_y, sp_z); + + mFusionSequenceReader->Update(mImage->GetNumberOfDimensions(),mFusionComponent.c_str(),vvImageReader::MERGEDWITHTIME); + + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), 1); + mSlicers[i]->Render(); + } + + //Update the slider + mFusionSequenceNbFrames = mFusionSequenceReader->GetOutput()->GetTransform().size(); + if (mFusionSequenceFrameIndex>=mFusionSequenceNbFrames) { + mFusionSequenceFrameIndex=0; + } + + //Update the list of initial transforms + mFusionSequenceListInitialTransformMatrices.clear(); + for (unsigned i=0 ; iAddFusionSequenceInitialTransformMatrices( mFusionSequenceReader->GetOutput()->GetTransform()[i]->GetMatrix() ); + } + + // also update the slice thickness + for (unsigned i=0 ; iGetImage()->GetTransform().size() ; i++) { + sp_x = this->GetImage()->GetVTKImages()[i]->GetSpacing()[0]; + sp_y = this->GetImage()->GetVTKImages()[i]->GetSpacing()[1]; + this->GetImage()->GetVTKImages()[i]->SetSpacing( sp_x, sp_y, sp_z); + } + +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::ReloadOverlay() +{ + mOverlayReader->Update(mImage->GetNumberOfDimensions(),mOverlayComponent.c_str(),mType); + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetOverlay(mOverlayReader->GetOutput()); + mSlicers[i]->Render(); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::ReloadVF() +{ + mVectorReader->Update(vvImageReader::VECTORFIELD); //deletes the old images through the VF::Init() function + mVF=mVectorReader->GetOutput(); + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetVF(mVF); + mSlicers[i]->Render(); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::RemoveActor(const std::string& actor_type, int overlay_index) +{ + if (actor_type =="overlay") + mOverlayReader = NULL; + + if (actor_type =="fusion") + mFusionReader = NULL; + + if (actor_type =="fusionSequence") { + mFusionSequenceReader = NULL; + } + + for (unsigned int i = 0; i < mSlicers.size(); i++) + mSlicers[i]->RemoveActor(actor_type,overlay_index); + + if (actor_type=="vector") { + mVF=NULL; + mVectorReader=NULL; + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::RemoveActors() +{ + ///This method leaks a few objects. See RemoveActor for what a + ///correct implementation would look like + //DS -> probably due to the reader (now released in the + //RemoveActor() function. (I hope) + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + mSlicers[i]->SetDisplayMode(0); + mSlicers[i]->GetRenderer()->RemoveActor(mSlicers[i]->GetImageActor()); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateInfoOnCursorPosition(int slicer) +{ + // int view = mSlicers[slicer]->GetSliceOrientation(); + // int slice = mSlicers[slicer]->GetSlice(); + double x = mSlicers[slicer]->GetCurrentPosition()[0]; + double y = mSlicers[slicer]->GetCurrentPosition()[1]; + double z = mSlicers[slicer]->GetCurrentPosition()[2]; + double xyz[3], xyzTransform[3]; + xyz[0] = x; + xyz[1] = y; + xyz[2] = z; + mSlicers[slicer]->GetSlicingTransform()->GetInverse()->TransformPoint(xyz, xyzTransform); + double X = (xyzTransform[0] - mSlicers[slicer]->GetInput()->GetOrigin()[0])/mSlicers[slicer]->GetInput()->GetSpacing()[0]; + double Y = (xyzTransform[1] - mSlicers[slicer]->GetInput()->GetOrigin()[1])/mSlicers[slicer]->GetInput()->GetSpacing()[1]; + double Z = (xyzTransform[2] - mSlicers[slicer]->GetInput()->GetOrigin()[2])/mSlicers[slicer]->GetInput()->GetSpacing()[2]; + double value = -VTK_DOUBLE_MAX; + int displayVec = 0; + double xVec=0, yVec=0, zVec=0, valueVec=0; + int displayOver = 0; + int displayFus = 0; + double valueOver=0, valueFus=0; +#if VTK_MAJOR_VERSION <= 5 + if (X >= mSlicers[slicer]->GetInput()->GetWholeExtent()[0] -0.5 && + X <= mSlicers[slicer]->GetInput()->GetWholeExtent()[1] +0.5 && + Y >= mSlicers[slicer]->GetInput()->GetWholeExtent()[2] -0.5 && + Y <= mSlicers[slicer]->GetInput()->GetWholeExtent()[3] +0.5 && + Z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4] -0.5 && + Z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5] +0.5) +#else +int extentImageReslice[6]; +mSlicers[slicer]->GetRegisterExtent(extentImageReslice); + if (X >= extentImageReslice[0] -0.5 && + X <= extentImageReslice[1] +0.5 && + Y >= extentImageReslice[2] -0.5 && + Y <= extentImageReslice[3] +0.5 && + Z >= extentImageReslice[4] -0.5 && + Z <= extentImageReslice[5] +0.5) +#endif + { + value = this->GetScalarComponentAsDouble(mSlicers[slicer]->GetInput(), X, Y, Z); + + if (mSlicers[slicer]->GetVFActor() ) { + displayVec = 1; + unsigned int currentTime = mSlicers[slicer]->GetMaxCurrentTSlice(); + vtkImageData *vf = NULL; + + if (mSlicers[slicer]->GetVF()->GetVTKImages().size() > currentTime) + vf = mSlicers[slicer]->GetVF()->GetVTKImages()[currentTime]; + else + vf = mSlicers[slicer]->GetVF()->GetVTKImages()[0]; + + if (vf) { + double Xvf = (x - vf->GetOrigin()[0])/ vf->GetSpacing()[0]; + double Yvf = (y - vf->GetOrigin()[1])/ vf->GetSpacing()[1]; + double Zvf = (z - vf->GetOrigin()[2])/ vf->GetSpacing()[2]; + xVec = this->GetScalarComponentAsDouble( vf, Xvf, Yvf, Zvf, 0); + yVec = this->GetScalarComponentAsDouble( vf, Xvf, Yvf, Zvf, 1); + zVec = this->GetScalarComponentAsDouble( vf, Xvf, Yvf, Zvf, 2); + valueVec = sqrt(xVec*xVec + yVec*yVec + zVec*zVec); + } + } + if (mSlicers[slicer]->GetOverlayActor() ) { + displayOver = 1; + vtkImageData *overlay = dynamic_cast(mSlicers[slicer]->GetOverlayMapper()->GetInput()); + double Xover = (x - overlay->GetOrigin()[0]) / overlay->GetSpacing()[0]; + double Yover = (y - overlay->GetOrigin()[1]) / overlay->GetSpacing()[1]; + double Zover = (z - overlay->GetOrigin()[2]) / overlay->GetSpacing()[2]; + valueOver = this->GetScalarComponentAsDouble(overlay, Xover, Yover, Zover); + } + + if ( mSlicers[slicer]->GetFusionActor() ) { + displayFus = 1; + vtkImageData *fusion = dynamic_cast(mSlicers[slicer]->GetFusionMapper()->GetInput()); + double Xover = (x - fusion->GetOrigin()[0]) / fusion->GetSpacing()[0]; + double Yover = (y - fusion->GetOrigin()[1]) / fusion->GetSpacing()[1]; + double Zover = (z - fusion->GetOrigin()[2]) / fusion->GetSpacing()[2]; + valueFus = this->GetScalarComponentAsDouble(fusion, Xover, Yover, Zover); + } + else if (this->IsInvolvedInFusionSequence()) { + //if the cursor moves over the 'independent' version of the secondary sequence + //do not update the panel, just keep it as it is. + displayFus = 1; + valueFus = std::numeric_limits::quiet_NaN(); + } + + emit UpdatePosition(mSlicers[slicer]->GetCursorVisibility(), + x,y,z,X,Y,Z,value); + emit UpdateVector(displayVec,xVec, yVec, zVec, valueVec); + emit UpdateOverlay(displayOver,valueOver,value); + emit UpdateFusion(displayFus,valueFus); + } +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::Activated() +{ + emit currentImageChanged(mId); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::Picked() +{ + emit currentPickedImageChanged(mId); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateWindowLevel() +{ + emit WindowLevelChanged(); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateSlice(int slicer) +{ + if (mPreviousSlice[slicer] == mSlicers[slicer]->GetSlice()) { + //DD("============= NOTHING"); + return; + } + emit UpdateSlice(slicer, mSlicers[slicer]->GetSlice()); + mSlicers[slicer]->Render(); // DS <-- I add this, this could/must be the only Render ... + mPreviousSlice[slicer] = mSlicers[slicer]->GetSlice(); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateTSlice(int slicer) +{ + int slice = mSlicers[slicer]->GetSlice(); + + int tslice = mSlicers[slicer]->GetMaxCurrentTSlice(); + //if (this->IsInvolvedInFusionSequence()) tslice = mSlicers[slicer]->GetTSlice(); //actually, this is handled by the Slicer + + if (mPreviousSlice[slicer] == slice) { + if (mPreviousTSlice[slicer] == tslice) { + // DD("************** NOTHING ***********"); + return; + } + } + mPreviousSlice[slicer] = slice; + mPreviousTSlice[slicer] = tslice; + + emit UpdateTSlice(slicer, tslice, mFusionSequenceInvolvementCode); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::UpdateSliceRange(int slicer) +{ + emit UpdateSliceRange(slicer, + mSlicers[slicer]->GetSliceRange()[0], mSlicers[slicer]->GetSliceRange()[1], + 0,mSlicers[slicer]->GetTMax()); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetSlicingPreset(SlicingPresetType preset) +{ + if(mSlicingPreset==preset) + return; + + vtkMatrix4x4 *imageTransformInverse = vtkMatrix4x4::New(); + mImage->GetTransform()[this->GetTSlice()]->GetInverse(imageTransformInverse); + + for(int i=0; i< this->GetNumberOfSlicers(); i++){ + vvSlicer *s = this->GetSlicer(i); + switch(preset) + { + case WORLD_SLICING: + s->GetSlicingTransform()->Identity(); + break; + case VOXELS_SLICING: + s->GetSlicingTransform()->SetMatrix(imageTransformInverse); + break; + default: + imageTransformInverse->Delete(); + return; + } + s->ForceUpdateDisplayExtent(); +#if VTK_MAJOR_VERSION <= 5 + s->SetSlice((s->GetInput()->GetWholeExtent()[s->GetSliceOrientation()*2+1] + +s->GetInput()->GetWholeExtent()[s->GetSliceOrientation()*2])/2.0); +#else + int extentImageReslice[6]; + s->GetRegisterExtent(extentImageReslice); + s->SetSlice((extentImageReslice[s->GetSliceOrientation()*2+1] + +extentImageReslice[s->GetSliceOrientation()*2])/2.0); +#endif + s->ResetCamera(); + s->Render(); + } + + imageTransformInverse->Delete(); + mSlicingPreset = preset; +} + +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetPreset(int preset) +{ + + //vtkLookupTable* LUT = static_cast(mSlicers[0]->GetWindowLevel()->GetLookupTable()); + double window = mSlicers[0]->GetColorWindow(); + double level = mSlicers[0]->GetColorLevel(); + + std::string component_type=mImage->GetScalarTypeAsITKString(); + switch (preset) { + case WL_AUTO: + double range[2]; + mImage->GetScalarRange(range); + window = range[1] - range[0]; + level = (range[1] + range[0])* 0.5; + break; + case WL_HOUNSFIELD: + window = 2000; + level = 0; + break; + case WL_SOFTTISSUE: + window = 400; + level = 20; + break; + case WL_LUNGS: // lungs (same as FOCAL) + window = 1700; + level = -300; + break; + case WL_BONES: + window = 1000; + level = 500; + break; + case WL_HEAD: + window = 200; + level = 70; + break; + case WL_BINARY: + window = 1; + level = 0.5; + break; + case WL_USER: + break; + case WL_VENTILATION: + window=1.; + level=0.; + break; + } + mPreset = preset; + this->SetColorWindow(window); + this->SetColorLevel(level); + + //if (LUT) + //{ + // SetColorMap(-1); + //} +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetLocalColorWindowing(const int slicer, const bool bCtrlKey) +{ + double min, max; + if(bCtrlKey && this->mSlicers[slicer]->GetFusion()) { + int t = mSlicers[slicer]->GetFusionTSlice(); + this->mSlicers[slicer]->GetExtremasAroundMousePointer(min, max, + this->mSlicers[slicer]->GetFusion()->GetVTKImages()[t], + this->mSlicers[slicer]->GetConcatenatedFusionTransform()); + this->SetFusionWindow(max-min); + this->SetFusionLevel(0.5*(min+max)); + this->SetColorMap(mColorMap); + } + else if(bCtrlKey && this->mSlicers[slicer]->GetOverlay()) { + int t = mSlicers[slicer]->GetOverlayTSlice(); + this->mSlicers[slicer]->GetExtremasAroundMousePointer(min, max, + this->mSlicers[slicer]->GetOverlay()->GetVTKImages()[t], + this->mSlicers[slicer]->GetConcatenatedOverlayTransform()); + if(this->mSlicers[slicer]->GetLinkOverlayWindowLevel()){ + this->SetColorWindow(max-min); + this->SetColorLevel(0.5*(min+max)); + } else { + this->SetOverlayColorWindow(max-min); + this->SetOverlayColorLevel(0.5*(min+max)); + } + } + else { + int t = this->GetTSlice(); + this->mSlicers[slicer]->GetExtremasAroundMousePointer(min, max, + this->mSlicers[slicer]->GetImage()->GetVTKImages()[t], + this->mSlicers[slicer]->GetConcatenatedTransform()); + this->SetColorWindow(max-min); + this->SetColorLevel(0.5*(min+max)); + this->SetPreset(WL_USER); + } + this->Render(); + this->UpdateWindowLevel(); +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +void vvSlicerManager::SetColorMap(int colormap) +{ + double range[2]; + + range[0] = mSlicers[0]->GetInput()->GetScalarRange()[0]; + range[1] = mSlicers[0]->GetInput()->GetScalarRange()[1]; + + double window = mSlicers[0]->GetWindowLevel()->GetWindow(); + double level = mSlicers[0]->GetWindowLevel()->GetLevel(); + + vtkLookupTable* LUT = static_cast(mSlicers[0]->GetWindowLevel()->GetLookupTable()); + switch (colormap) { + case -1: + break; + case 0: + LUT = NULL; + break; + case 1: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetValueRange(0,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(0,0.18); + break; + case 2: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetValueRange(0,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(0.4,0.80); + break; + case 3: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetValueRange(0.5,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(0.666,0); + break; + case 4: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetValueRange(1,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(0,1); + LUT->SetAlphaRange(1, 1); + break; + case 5: + if (LUT == NULL) + LUT = vtkLookupTable::New(); + LUT->SetValueRange(1,1); + LUT->SetSaturationRange(1,1); + LUT->SetHueRange(1,0.1); + //LUT->SetRampToLinear(); + break; + } + if (LUT) { + LUT->SetTableRange(level-fabs(window)/2,level+fabs(window)/2); + LUT->Build(); + } + vtkWindowLevelLookupTable* fusLUT = NULL; + + //FUSION / FUSION SEQUENCE + if (mSlicers[0]->GetFusion()) { // && mFusionColorMap >= 0) { + fusLUT = vtkWindowLevelLookupTable::New(); + double fusRange [2]; + fusRange[0] = mFusionLevel - mFusionWindow/2; + fusRange[1] = mFusionLevel + mFusionWindow/2; + + //check whether it is actually a fusionSequence or a fusion, before invoking mFusionReader... + double* frange; + if (this->IsInvolvedInFusionSequence()) + frange = mFusionSequenceReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); + else + frange = mFusionReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); + + fusLUT->SetTableRange(frange); + fusLUT->SetValueRange(1,1); + fusLUT->SetSaturationRange(1,1); + fusLUT->SetAlphaRange(1, 1); + fusLUT->SetWindow(mFusionWindow); + fusLUT->SetLevel(mFusionLevel); + if (mFusionColorMap == 1) + fusLUT->SetHueRange(0,0.18); + else if (mFusionColorMap == 2) + fusLUT->SetHueRange(0.4,0.80); + else if (mFusionColorMap == 3) + { + fusLUT->SetHueRange(0.666, 0); + fusLUT->SetValueRange(0.5, 1); + } + else if (mFusionColorMap == 4) + fusLUT->SetHueRange(0,1); + else if (mFusionColorMap <= 0) + { + fusLUT->SetValueRange(0,1); + fusLUT->SetSaturationRange(0,0); + } + + fusLUT->ForceBuild(); + double v[4]; + // set color table transparency + //double alpha_range=(double)mFusionThresOpacity/10; + double range_end = fusRange[0] + (double)mFusionThresOpacity*(fusRange[1] - fusRange[0])/100; + double curr_value = fusRange[0]; + int nvalues = fusLUT->GetNumberOfTableValues(); + for (double i = 0; curr_value < range_end; i++) { + fusLUT->GetTableValue(i, v); + v[3] = 0; + //if (curr_value >= -alpha_range && curr_value <= alpha_range) v[3] = pow(fabs(curr_value/alpha_range),2); + //else v[3] = 1; + fusLUT->SetTableValue(i, v); + curr_value += (fusRange[1] - fusRange[0])/nvalues; + } + } + for ( unsigned int i = 0; i < mSlicers.size(); i++) { + + if (mSlicers[i]->GetOverlay()) { + vtkLookupTable* supLUT = vtkLookupTable::New(); + supLUT->SetTableRange(range[0],range[1]); + supLUT->SetValueRange(1,1); + supLUT->SetSaturationRange(1,1); + supLUT->SetHueRange(double(mOverlayColor)/360,double(mOverlayColor)/360); + supLUT->Build(); + vtkLookupTable* invLUT = vtkLookupTable::New(); + invLUT->SetTableRange(range[0],range[1]); + invLUT->SetValueRange(1,1); + invLUT->SetSaturationRange(1,1); + invLUT->SetHueRange(double((mOverlayColor+180)%360)/360,double((mOverlayColor+180)%360)/360); + invLUT->Build(); + mSlicers[i]->GetWindowLevel()->SetLookupTable(supLUT); + mSlicers[i]->GetOverlayMapper()->SetLookupTable(invLUT); + invLUT->Delete(); + supLUT->Delete(); + } else if (mSlicers[i]->GetOverlay()) { + mSlicers[i]->GetWindowLevel()->SetLookupTable(LUT); + } else { + mSlicers[i]->GetWindowLevel()->SetLookupTable(LUT); + } + + if (mSlicers[i]->GetFusion()) { + mSlicers[i]->ShowFusionLegend(mFusionShowLegend); + mSlicers[i]->GetFusionMapper()->SetLookupTable(fusLUT); + mSlicers[i]->GetFusionActor()->SetOpacity(double(mFusionOpacity)/100); + } + } + if (fusLUT) + fusLUT->Delete(); + if (colormap >= 0) + mColorMap = colormap; +} +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +vvLandmarks* vvSlicerManager::GetLandmarks() +{ + if (mLandmarks == NULL) { + mLandmarks = new vvLandmarks(mSlicers[0]->GetTMax()+1); + for (unsigned int i = 0; i < mSlicers.size(); i++) + mSlicers[i]->SetLandmarks(mLandmarks); + } + return mLandmarks; +} +//---------------------------------------------------------------------------- +void vvSlicerManager::AddNewLandmark(float x,float y,float z,float t) +{ + emit callAddLandmark(x,y,z,t); +} + +//---------------------------------------------------------------------------- +void vvSlicerManager::AddLandmark(float x,float y,float z,float t) +{ + double x_index = (x - mSlicers[0]->GetInput()->GetOrigin()[0])/mSlicers[0]->GetInput()->GetSpacing()[0]; + double y_index = (y - mSlicers[0]->GetInput()->GetOrigin()[1])/mSlicers[0]->GetInput()->GetSpacing()[1]; + double z_index = (z - mSlicers[0]->GetInput()->GetOrigin()[2])/mSlicers[0]->GetInput()->GetSpacing()[2]; +#if VTK_MAJOR_VERSION <= 5 + if (x_index >= mSlicers[0]->GetInput()->GetWholeExtent()[0]-0.5 && + x_index <= mSlicers[0]->GetInput()->GetWholeExtent()[1]+0.5 && + y_index >= mSlicers[0]->GetInput()->GetWholeExtent()[2]-0.5 && + y_index <= mSlicers[0]->GetInput()->GetWholeExtent()[3]+0.5 && + z_index >= mSlicers[0]->GetInput()->GetWholeExtent()[4]-0.5 && + z_index <= mSlicers[0]->GetInput()->GetWholeExtent()[5]+0.5) +#else + int extentImageReslice[6]; + mSlicers[0]->GetRegisterExtent(extentImageReslice); + if (x_index >= extentImageReslice[0]-0.5 && + x_index <= extentImageReslice[1]+0.5 && + y_index >= extentImageReslice[2]-0.5 && + y_index <= extentImageReslice[3]+0.5 && + z_index >= extentImageReslice[4]-0.5 && + z_index <= extentImageReslice[5]+0.5) +#endif + { + double value = this->GetScalarComponentAsDouble(mSlicers[mSelectedSlicer]->GetInput(), x_index, y_index, z_index); //Value in selected Slicer (not 0): bug #2848 + this->GetLandmarks()->AddLandmark(x,y,z,t,value); + emit LandmarkAdded(); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::AddLandmarkProfile(float x,float y,float z,float t) +{ + double x_index = (x - mSlicers[0]->GetInput()->GetOrigin()[0])/mSlicers[0]->GetInput()->GetSpacing()[0]; + double y_index = (y - mSlicers[0]->GetInput()->GetOrigin()[1])/mSlicers[0]->GetInput()->GetSpacing()[1]; + double z_index = (z - mSlicers[0]->GetInput()->GetOrigin()[2])/mSlicers[0]->GetInput()->GetSpacing()[2]; +#if VTK_MAJOR_VERSION <= 5 + if (x_index >= mSlicers[0]->GetInput()->GetWholeExtent()[0]-0.5 && + x_index <= mSlicers[0]->GetInput()->GetWholeExtent()[1]+0.5 && + y_index >= mSlicers[0]->GetInput()->GetWholeExtent()[2]-0.5 && + y_index <= mSlicers[0]->GetInput()->GetWholeExtent()[3]+0.5 && + z_index >= mSlicers[0]->GetInput()->GetWholeExtent()[4]-0.5 && + z_index <= mSlicers[0]->GetInput()->GetWholeExtent()[5]+0.5) +#else + int extentImageReslice[6]; + mSlicers[0]->GetRegisterExtent(extentImageReslice); + if (x_index >= extentImageReslice[0]-0.5 && + x_index <= extentImageReslice[1]+0.5 && + y_index >= extentImageReslice[2]-0.5 && + y_index <= extentImageReslice[3]+0.5 && + z_index >= extentImageReslice[4]-0.5 && + z_index <= extentImageReslice[5]+0.5) +#endif + { + double value = this->GetScalarComponentAsDouble(mSlicers[mSelectedSlicer]->GetInput(), x_index, y_index, z_index); //Value in selected Slicer (not 0): bug #2848 + this->GetLandmarks()->AddLandmark(x,y,z,t,value); + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::PrevImage(int slicer) +{ + emit ChangeImageWithIndexOffset(this, slicer, -1); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::NextImage(int slicer) +{ + emit ChangeImageWithIndexOffset(this, slicer, 1); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicerManager::VerticalSliderHasChanged(int slicer, int slice) +{ + emit AVerticalSliderHasChanged(slicer, slice); +} + +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +double vvSlicerManager::GetScalarComponentAsDouble(vtkImageData *image, double X, double Y, double Z, int component) +{ + int ix, iy, iz; + return mSlicers[0]->GetScalarComponentAsDouble(image, X, Y, Z, ix, iy, iz, component); +} +//----------------------------------------------------------------------------