--- /dev/null
+// CxImageCrtDll.cpp : Defines the entry point for the CxImageCrtDll application.\r
+//\r
+\r
+#include "stdcrt.h"\r
+\r
+BOOL APIENTRY DllMain( HANDLE /*hModule*/, \r
+ DWORD /*ul_reason_for_call*/, \r
+ LPVOID /*lpReserved*/\r
+ )\r
+{\r
+ return TRUE;\r
+}\r
+\r
--- /dev/null
+# Microsoft Developer Studio Project File - Name="CxImageCrtDll" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=CxImageCrtDll - Win32 Unicode Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "CxImageCrtDll.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "CxImageCrtDll.mak" CFG="CxImageCrtDll - Win32 Unicode Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "CxImageCrtDll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "CxImageCrtDll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "CxImageCrtDll - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "CxImageCrtDll - Win32 Unicode Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF "$(CFG)" == "CxImageCrtDll - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtd.dll" /pdbtype:sept\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrt.dll"\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Unicode Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "CxImageCrtDll___Win32_Unicode_Debug"\r
+# PROP BASE Intermediate_Dir "CxImageCrtDll___Win32_Unicode_Debug"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Unicode_Debug"\r
+# PROP Intermediate_Dir "Unicode_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# SUBTRACT BASE CPP /YX /Yc /Yu\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtd.dll" /pdbtype:sept\r
+# SUBTRACT BASE LINK32 /pdb:none\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /debug /machine:I386 /out:"../../bin/cximagecrtdu.dll" /pdbtype:sept\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ELSEIF "$(CFG)" == "CxImageCrtDll - Win32 Unicode Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "CxImageCrtDll___Win32_Unicode_Release"\r
+# PROP BASE Intermediate_Dir "CxImageCrtDll___Win32_Unicode_Release"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Unicode_Release"\r
+# PROP Intermediate_Dir "Unicode_Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# SUBTRACT BASE CPP /YX /Yc /Yu\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrt.dll"\r
+# SUBTRACT BASE LINK32 /pdb:none\r
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /dll /machine:I386 /out:"../../bin/cximagecrtu.dll"\r
+# SUBTRACT LINK32 /pdb:none\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "CxImageCrtDll - Win32 Debug"\r
+# Name "CxImageCrtDll - Win32 Release"\r
+# Name "CxImageCrtDll - Win32 Unicode Debug"\r
+# Name "CxImageCrtDll - Win32 Unicode Release"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\CxImageCrtDll.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CxImageCrtDll.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\tif_xfile.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximabmp.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximadsp.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaenc.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaexif.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximage.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximagif.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximahist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaico.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximainfo.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaint.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajas.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajbg.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajpg.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximalpha.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximalyr.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximamng.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapal.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapcx.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapng.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaraw.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximasel.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaska.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatga.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximath.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatif.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatran.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawbmp.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawmf.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawnd.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xmemfile.cpp\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\StdCrt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xfile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximabmp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximadefs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xImage.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximagif.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaico.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaiter.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajas.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajbg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajpg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximamng.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapcx.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapng.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaraw.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatga.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximath.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatif.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawbmp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawmf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xiofile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xmemfile.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
--- /dev/null
+//Microsoft Developer Studio generated resource script.\r
+//\r
+#include "resrc1.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "resource.h"\r
+#include "winres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Neutral resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifndef _MAC\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION 6,0,0,0\r
+ PRODUCTVERSION 6,0,0,0\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+ BLOCK "StringFileInfo"\r
+ BEGIN\r
+ BLOCK "000004b0"\r
+ BEGIN\r
+ VALUE "Comments", "CxImage 6.0.0.0 CRT DLL\0"\r
+ VALUE "CompanyName", "Pizzolato Davide - www.xdp.it\0"\r
+ VALUE "FileDescription", "cximage\0"\r
+ VALUE "FileVersion", "6, 0, 0, 0\0"\r
+ VALUE "InternalName", "cximage\0"\r
+ VALUE "LegalCopyright", "Copyright ยฉ 2001 - 2008\0"\r
+ VALUE "LegalTrademarks", "\0"\r
+ VALUE "OriginalFilename", "cximagecrt.dll\0"\r
+ VALUE "PrivateBuild", "\0"\r
+ VALUE "ProductName", "cximage\0"\r
+ VALUE "ProductVersion", "6, 0, 0, 0\0"\r
+ VALUE "SpecialBuild", "\0"\r
+ END\r
+ END\r
+ BLOCK "VarFileInfo"\r
+ BEGIN\r
+ VALUE "Translation", 0x0, 1200\r
+ END\r
+END\r
+\r
+#endif // !_MAC\r
+\r
+#endif // Neutral resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Italian (Italy) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+ "resrc1.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+ "#include ""resource.h""\r\n"\r
+ "#include ""winresrc.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+ "\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+#endif // Italian (Italy) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
+\r
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "CxImageCrtDll"=.\CxImageCrtDll.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+ Begin Project Dependency\r
+ Project_Dep_Name j2000\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name jbig\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name jpeg\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name png\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name tiff\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name zlib\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name j2k\r
+ End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "CxImageMfcDll"=.\cximagemfcdll.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+ Begin Project Dependency\r
+ Project_Dep_Name j2k\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name jbig\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name jpeg\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name png\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name tiff\r
+ End Project Dependency\r
+ Begin Project Dependency\r
+ Project_Dep_Name zlib\r
+ End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "j2k"=..\..\j2k\j2k.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "jbig"=..\..\jbig\jbig.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "jpeg"=..\..\jpeg\Jpeg.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "png"=..\..\png\png.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "tiff"=..\..\tiff\Tiff.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "zlib"=..\..\zlib\zlib.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
--- /dev/null
+; CLW file contains information for the MFC ClassWizard\r
+\r
+[General Info]\r
+Version=1\r
+ClassCount=1\r
+Class1=CcximagemfcdllApp\r
+LastClass=CcximagemfcdllApp\r
+NewFileInclude2=#include "cximagemfcdll.h"\r
+ResourceCount=0\r
+NewFileInclude1=#include "stdafx.h"\r
+\r
+[CLS:CcximagemfcdllApp]\r
+Type=0\r
+HeaderFile=cximagemfcdll.h\r
+ImplementationFile=cximagemfcdll.cpp\r
+Filter=N\r
--- /dev/null
+// cximagemfcdll.cpp : Defines the initialization routines for the DLL.\r
+//\r
+\r
+#include "stdafx.h"\r
+#include "cximagemfcdll.h"\r
+\r
+#ifdef _DEBUG\r
+#define new DEBUG_NEW\r
+#undef THIS_FILE\r
+static char THIS_FILE[] = __FILE__;\r
+#endif\r
+\r
+//\r
+// Note!\r
+//\r
+// If this DLL is dynamically linked against the MFC\r
+// DLLs, any functions exported from this DLL which\r
+// call into MFC must have the AFX_MANAGE_STATE macro\r
+// added at the very beginning of the function.\r
+//\r
+// For example:\r
+//\r
+// extern "C" BOOL PASCAL EXPORT ExportedFunction()\r
+// {\r
+// AFX_MANAGE_STATE(AfxGetStaticModuleState());\r
+// // normal function body here\r
+// }\r
+//\r
+// It is very important that this macro appear in each\r
+// function, prior to any calls into MFC. This means that\r
+// it must appear as the first statement within the \r
+// function, even before any object variable declarations\r
+// as their constructors may generate calls into the MFC\r
+// DLL.\r
+//\r
+// Please see MFC Technical Notes 33 and 58 for additional\r
+// details.\r
+//\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CcximagemfcdllApp\r
+\r
+BEGIN_MESSAGE_MAP(CcximagemfcdllApp, CWinApp)\r
+ //{{AFX_MSG_MAP(CcximagemfcdllApp)\r
+ // NOTE - the ClassWizard will add and remove mapping macros here.\r
+ // DO NOT EDIT what you see in these blocks of generated code!\r
+ //}}AFX_MSG_MAP\r
+END_MESSAGE_MAP()\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CcximagemfcdllApp construction\r
+\r
+CcximagemfcdllApp::CcximagemfcdllApp()\r
+{\r
+ // TODO: add construction code here,\r
+ // Place all significant initialization in InitInstance\r
+}\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// The one and only CcximagemfcdllApp object\r
+\r
+CcximagemfcdllApp theApp;\r
--- /dev/null
+// cximagemfcdll.h : main header file for the cximagemfcdll DLL\r
+//\r
+\r
+#if !defined(AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_)\r
+#define AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_\r
+\r
+#if _MSC_VER > 1000\r
+#pragma once\r
+#endif // _MSC_VER > 1000\r
+\r
+#ifndef __AFXWIN_H__\r
+ #error include 'stdafx.h' before including this file for PCH\r
+#endif\r
+\r
+#include "resource.h" // main symbols\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CcximagemfcdllApp\r
+// See cximagemfcdll.cpp for the implementation of this class\r
+//\r
+\r
+class CcximagemfcdllApp : public CWinApp\r
+{\r
+public:\r
+ CcximagemfcdllApp();\r
+\r
+// Overrides\r
+ // ClassWizard generated virtual function overrides\r
+ //{{AFX_VIRTUAL(CcximagemfcdllApp)\r
+ //}}AFX_VIRTUAL\r
+\r
+ //{{AFX_MSG(CcximagemfcdllApp)\r
+ // NOTE - the ClassWizard will add and remove member functions here.\r
+ // DO NOT EDIT what you see in these blocks of generated code !\r
+ //}}AFX_MSG\r
+ DECLARE_MESSAGE_MAP()\r
+};\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+//{{AFX_INSERT_LOCATION}}\r
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.\r
+\r
+#endif // !defined(AFX_cximagemfcdll_H__E98F71A6_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_)\r
--- /dev/null
+//Microsoft Developer Studio generated resource script.\r
+//\r
+#include "resrc1.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "resource.h"\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Neutral resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifndef _MAC\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION 6,0,0,0\r
+ PRODUCTVERSION 6,0,0,0\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+ BLOCK "StringFileInfo"\r
+ BEGIN\r
+ BLOCK "000004b0"\r
+ BEGIN\r
+ VALUE "Comments", "CxImage 6.0.0.0 MFC DLL\0"\r
+ VALUE "CompanyName", "Pizzolato Davide - www.xdp.it\0"\r
+ VALUE "FileDescription", "cximage\0"\r
+ VALUE "FileVersion", "6, 0, 0, 0\0"\r
+ VALUE "InternalName", "cximage\0"\r
+ VALUE "LegalCopyright", "Copyright ยฉ 2001 - 2008\0"\r
+ VALUE "LegalTrademarks", "\0"\r
+ VALUE "OriginalFilename", "cximage.dll\0"\r
+ VALUE "PrivateBuild", "\0"\r
+ VALUE "ProductName", "cximage\0"\r
+ VALUE "ProductVersion", "6, 0, 0, 0\0"\r
+ VALUE "SpecialBuild", "\0"\r
+ END\r
+ END\r
+ BLOCK "VarFileInfo"\r
+ BEGIN\r
+ VALUE "Translation", 0x0, 1200\r
+ END\r
+END\r
+\r
+#endif // !_MAC\r
+\r
+#endif // Neutral resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Italian (Italy) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+ "resrc1.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+ "#include ""resource.h""\r\n"\r
+ "#include ""afxres.h""\r\n"\r
+ "\0"\r
+END\r
+\r
+3 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+ "\r\n"\r
+ "\0"\r
+END\r
+\r
+#endif // APSTUDIO_INVOKED\r
+\r
+#endif // Italian (Italy) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif // not APSTUDIO_INVOKED\r
+\r
--- /dev/null
+// stdafx.cpp : source file that includes just the standard includes\r
+// cximagemfcdll.pch will be the pre-compiled header\r
+// stdafx.obj will contain the pre-compiled type information\r
+\r
+#include "stdafx.h"\r
+\r
+\r
+\r
--- /dev/null
+// stdafx.h : include file for standard system include files,\r
+// or project specific include files that are used frequently, but\r
+// are changed infrequently\r
+//\r
+\r
+#if !defined(AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_)\r
+#define AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_\r
+\r
+#if _MSC_VER > 1000\r
+#pragma once\r
+#endif // _MSC_VER > 1000\r
+\r
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers\r
+\r
+#ifndef WINVER\r
+#define WINVER 0x0400\r
+#endif\r
+\r
+#include <afxwin.h> // MFC core and standard components\r
+#include <afxext.h> // MFC extensions\r
+\r
+#ifndef _AFX_NO_OLE_SUPPORT\r
+#include <afxole.h> // MFC OLE classes\r
+#include <afxodlgs.h> // MFC OLE dialog classes\r
+#include <afxdisp.h> // MFC Automation classes\r
+#endif // _AFX_NO_OLE_SUPPORT\r
+\r
+\r
+#ifndef _AFX_NO_DB_SUPPORT\r
+#include <afxdb.h> // MFC ODBC database classes\r
+#endif // _AFX_NO_DB_SUPPORT\r
+\r
+#ifndef _AFX_NO_DAO_SUPPORT\r
+#include <afxdao.h> // MFC DAO database classes\r
+#endif // _AFX_NO_DAO_SUPPORT\r
+\r
+#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls\r
+#ifndef _AFX_NO_AFXCMN_SUPPORT\r
+#include <afxcmn.h> // MFC support for Windows Common Controls\r
+#endif // _AFX_NO_AFXCMN_SUPPORT\r
+\r
+\r
+//{{AFX_INSERT_LOCATION}}\r
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.\r
+\r
+#endif // !defined(AFX_STDAFX_H__E98F71A8_B361_11D6_BB83_CAEE2E1CB77B__INCLUDED_)\r
--- /dev/null
+// stdafx.h : include file for standard system include files,\r
+// or project specific include files that are used frequently, but\r
+// are changed infrequently\r
+//\r
+\r
+#if !defined(AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_)\r
+#define AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_\r
+\r
+#if _MSC_VER > 1000\r
+#pragma once\r
+#endif // _MSC_VER > 1000\r
+\r
+\r
+// Insert your headers here\r
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers\r
+\r
+#include <windows.h>\r
+\r
+// TODO: reference additional headers your program requires here\r
+\r
+//{{AFX_INSERT_LOCATION}}\r
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.\r
+\r
+#endif // !defined(AFX_STDAFX_H__F30A8A60_284F_4DF6_9431_6283105686F6__INCLUDED_)\r
--- /dev/null
+# Microsoft Developer Studio Project File - Name="CxImageMfcDll" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=CxImageMfcDll - Win32 Unicode Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "cximagemfcdll.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "cximagemfcdll.mak" CFG="CxImageMfcDll - Win32 Unicode Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "CxImageMfcDll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "CxImageMfcDll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "CxImageMfcDll - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "CxImageMfcDll - Win32 Unicode Release" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF "$(CFG)" == "CxImageMfcDll - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 6\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 6\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL"\r
+# ADD RSC /l 0x809 /d "_DEBUG" /d "_AFXDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept\r
+# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximaged.dll" /pdbtype:sept\r
+\r
+!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 6\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 6\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL"\r
+# ADD RSC /l 0x809 /d "NDEBUG" /d "_AFXDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386\r
+# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximage.dll"\r
+\r
+!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Unicode Debug"\r
+\r
+# PROP BASE Use_MFC 6\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "CxImageMfcDll___Win32_Unicode_Debug"\r
+# PROP BASE Intermediate_Dir "CxImageMfcDll___Win32_Unicode_Debug"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 6\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Unicode_Debug"\r
+# PROP Intermediate_Dir "Unicode_Debug"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# SUBTRACT BASE CPP /YX /Yc /Yu\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL"\r
+# ADD RSC /l 0x809 /d "_DEBUG" /d "_AFXDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximaged.dll" /pdbtype:sept\r
+# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /out:"../../bin/cximagedu.dll" /pdbtype:sept\r
+\r
+!ELSEIF "$(CFG)" == "CxImageMfcDll - Win32 Unicode Release"\r
+\r
+# PROP BASE Use_MFC 6\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "CxImageMfcDll___Win32_Unicode_Release"\r
+# PROP BASE Intermediate_Dir "CxImageMfcDll___Win32_Unicode_Release"\r
+# PROP BASE Ignore_Export_Lib 0\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 6\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Unicode_Release"\r
+# PROP Intermediate_Dir "Unicode_Release"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# SUBTRACT BASE CPP /YX /Yc /Yu\r
+# 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\r
+# SUBTRACT CPP /YX /Yc /Yu\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL"\r
+# ADD RSC /l 0x809 /d "NDEBUG" /d "_AFXDLL"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximage.dll"\r
+# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/cximageu.dll"\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "CxImageMfcDll - Win32 Debug"\r
+# Name "CxImageMfcDll - Win32 Release"\r
+# Name "CxImageMfcDll - Win32 Unicode Debug"\r
+# Name "CxImageMfcDll - Win32 Unicode Release"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\cximagemfcdll.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\cximagemfcdll.rc\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\StdAfx.cpp\r
+# ADD CPP /Yc"stdafx.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\tif_xfile.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximabmp.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximadsp.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaenc.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaexif.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximage.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximagif.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximahist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaico.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximainfo.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaint.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajas.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajbg.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajpg.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximalpha.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximalyr.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximamng.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapal.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapcx.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapng.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaraw.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximasel.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaska.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatga.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximath.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatif.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatran.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawbmp.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawmf.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawnd.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xmemfile.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\cximagemfcdll.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\Resource.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\StdAfx.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xfile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximabmp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximadefs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximage.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximagif.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaico.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaiter.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajas.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximajpg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximamng.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapcx.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximapng.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximaska.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatga.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximath.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximatif.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawbmp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\ximawmf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xiofile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\xmemfile.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# End Target\r
+# End Project\r
--- /dev/null
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Developer Studio generated include file.\r
+// Used by CxImageMFCdll.rc\r
+//\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE 6000\r
+#define _APS_NEXT_COMMAND_VALUE 32771\r
+#define _APS_NEXT_CONTROL_VALUE 6000\r
+#define _APS_NEXT_SYMED_VALUE 6000\r
+#endif\r
+#endif\r
--- /dev/null
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Developer Studio generated include file.\r
+// Used by CxImageCrtDll.rc\r
+//\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE 6000\r
+#define _APS_NEXT_COMMAND_VALUE 32771\r
+#define _APS_NEXT_CONTROL_VALUE 6000\r
+#define _APS_NEXT_SYMED_VALUE 6000\r
+#endif\r
+#endif\r
--- /dev/null
+# Microsoft Developer Studio Project File - Name="CxImage" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=CxImage - Win32 Unicode Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "cximage.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "cximage.mak" CFG="CxImage - Win32 Unicode Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "CxImage - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "CxImage - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "CxImage - Win32 Unicode Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "CxImage - Win32 Unicode Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF "$(CFG)" == "CxImage - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 2\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# 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\r
+# SUBTRACT CPP /Fr /YX\r
+# ADD BASE RSC /l 0x410 /d "_DEBUG"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF "$(CFG)" == "CxImage - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 2\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# 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\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x410 /d "NDEBUG"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF "$(CFG)" == "CxImage - Win32 Unicode Debug"\r
+\r
+# PROP BASE Use_MFC 2\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "CxImage___Win32_Unicode_Debug"\r
+# PROP BASE Intermediate_Dir "CxImage___Win32_Unicode_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 2\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Unicode_Debug"\r
+# PROP Intermediate_Dir "Unicode_Debug"\r
+# PROP Target_Dir ""\r
+# 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\r
+# SUBTRACT BASE CPP /Fr /YX\r
+# 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\r
+# SUBTRACT CPP /Fr /YX\r
+# ADD BASE RSC /l 0x410 /d "_DEBUG" /d "_AFXDLL"\r
+# ADD RSC /l 0x809 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF "$(CFG)" == "CxImage - Win32 Unicode Release"\r
+\r
+# PROP BASE Use_MFC 2\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "CxImage___Win32_Unicode_Release"\r
+# PROP BASE Intermediate_Dir "CxImage___Win32_Unicode_Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 2\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Unicode_Release"\r
+# PROP Intermediate_Dir "Unicode_Release"\r
+# PROP Target_Dir ""\r
+# 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\r
+# SUBTRACT BASE CPP /YX\r
+# 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\r
+# SUBTRACT CPP /YX\r
+# ADD BASE RSC /l 0x410 /d "NDEBUG" /d "_AFXDLL"\r
+# ADD RSC /l 0x809 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "CxImage - Win32 Debug"\r
+# Name "CxImage - Win32 Release"\r
+# Name "CxImage - Win32 Unicode Debug"\r
+# Name "CxImage - Win32 Unicode Release"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=.\tif_xfile.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximabmp.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximadsp.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaenc.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaexif.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\xImage.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximagif.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximahist.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaico.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximainfo.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaint.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximajas.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximajbg.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximajpg.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximalpha.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximalyr.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximamng.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximapal.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximapcx.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximapng.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaraw.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximasel.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaska.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximatga.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximath.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximatif.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximatran.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximawbmp.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximawmf.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximawnd.cpp\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\xmemfile.cpp\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\xfile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximabmp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximacfg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximadef.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximage.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximagif.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaico.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaiter.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximajas.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximajbg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximajpg.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximamng.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximapcx.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximapng.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaraw.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximaska.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximatga.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximath.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximatif.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximawbmp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ximawmf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\xiofile.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\xmemfile.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 6.00\r
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
+\r
+###############################################################################\r
+\r
+Project: "CxImage"=.\CxImage.dsp - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Global:\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<3>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
--- /dev/null
+This copy of the CxImage notices is provided for your convenience. In case of\r
+any discrepancy between this copy and the notices in the file ximage.h that is\r
+included in the CxImage distribution, the latter shall prevail.\r
+\r
+If you modify CxImage you may insert additional notices immediately following\r
+this sentence.\r
+\r
+--------------------------------------------------------------------------------\r
+\r
+COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:\r
+\r
+CxImage version 6.0.0 02/Feb/2008\r
+\r
+CxImage : Copyright (C) 2001 - 2008, Davide Pizzolato\r
+\r
+Original CImage and CImageIterator implementation are:\r
+Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx)\r
+\r
+Covered code is provided under this license on an "as is" basis, without warranty\r
+of any kind, either expressed or implied, including, without limitation, warranties\r
+that the covered code is free of defects, merchantable, fit for a particular purpose\r
+or non-infringing. The entire risk as to the quality and performance of the covered\r
+code is with you. Should any covered code prove defective in any respect, you (not\r
+the initial developer or any other contributor) assume the cost of any necessary\r
+servicing, repair or correction. This disclaimer of warranty constitutes an essential\r
+part of this license. No use of any covered code is authorized hereunder except under\r
+this disclaimer.\r
+\r
+Permission is hereby granted to use, copy, modify, and distribute this\r
+source code, or portions hereof, for any purpose, including commercial applications,\r
+freely and without fee, subject to the following restrictions: \r
+\r
+1. The origin of this software must not be misrepresented; you must not\r
+claim that you wrote the original software. If you use this software\r
+in a product, an acknowledgment in the product documentation would be\r
+appreciated but is not required.\r
+\r
+2. Altered source versions must be plainly marked as such, and must not be\r
+misrepresented as being the original software.\r
+\r
+3. This notice may not be removed or altered from any source distribution.\r
+\r
+--------------------------------------------------------------------------------\r
+\r
+Other information: about CxImage, and the latest version, can be found at the\r
+CxImage home page: http://www.xdp.it\r
+\r
+--------------------------------------------------------------------------------\r
--- /dev/null
+/*\r
+ * TIFF file IO, using CxFile.\r
+ */\r
+\r
+#ifdef WIN32\r
+ #include <windows.h>\r
+#endif\r
+#include <stdio.h>\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_TIF\r
+\r
+#include "../tiff/tiffiop.h"\r
+\r
+#include "xfile.h"\r
+\r
+static tsize_t \r
+_tiffReadProcEx(thandle_t fd, tdata_t buf, tsize_t size)\r
+{\r
+ return (tsize_t)((CxFile*)fd)->Read(buf, 1, size);\r
+}\r
+\r
+static tsize_t\r
+_tiffWriteProcEx(thandle_t fd, tdata_t buf, tsize_t size)\r
+{\r
+ return (tsize_t)((CxFile*)fd)->Write(buf, 1, size);\r
+}\r
+\r
+static toff_t\r
+_tiffSeekProcEx(thandle_t fd, toff_t off, int whence)\r
+{\r
+ if ( off == 0xFFFFFFFF ) \r
+ return 0xFFFFFFFF;\r
+ if (!((CxFile*)fd)->Seek(off, whence))\r
+ return 0xFFFFFFFF;\r
+ if (whence == SEEK_SET)\r
+ return off;\r
+\r
+ return (toff_t)((CxFile*)fd)->Tell();\r
+}\r
+\r
+// Return nonzero if error\r
+static int\r
+_tiffCloseProcEx(thandle_t /*fd*/)\r
+{\r
+// return !((CxFile*)fd)->Close(); // "//" needed for memory files <DP>\r
+ return 0;\r
+}\r
+\r
+#include <sys/stat.h>\r
+\r
+static toff_t\r
+_tiffSizeProcEx(thandle_t fd)\r
+{\r
+ return ((CxFile*)fd)->Size();\r
+}\r
+\r
+static int\r
+_tiffMapProcEx(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/)\r
+{\r
+ return (0);\r
+}\r
+\r
+static void\r
+_tiffUnmapProcEx(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/)\r
+{\r
+}\r
+\r
+// Open a TIFF file descriptor for read/writing.\r
+/*\r
+TIFF*\r
+TIFFOpen(const char* name, const char* mode)\r
+{\r
+ static const char module[] = "TIFFOpen";\r
+ FILE* stream = fopen(name, mode);\r
+ if (stream == NULL) \r
+ {\r
+ TIFFError(module, "%s: Cannot open", name);\r
+ return NULL;\r
+ }\r
+ return (TIFFFdOpen((int)stream, name, mode));\r
+}\r
+*/\r
+\r
+TIFF*\r
+_TIFFFdOpen(void* fd, const char* name, const char* mode)\r
+{\r
+ TIFF* tif;\r
+\r
+ tif = TIFFClientOpen(name, mode,\r
+ (thandle_t) fd,\r
+ _tiffReadProcEx, _tiffWriteProcEx, _tiffSeekProcEx, _tiffCloseProcEx,\r
+ _tiffSizeProcEx, _tiffMapProcEx, _tiffUnmapProcEx);\r
+ if (tif)\r
+ tif->tif_fd = fd;\r
+ return (tif);\r
+}\r
+\r
+extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode)\r
+{\r
+ return (_TIFFFdOpen(stream, "TIFF IMAGE", mode));\r
+}\r
+\r
+#ifdef __GNUC__\r
+extern char* malloc();\r
+extern char* realloc();\r
+#else\r
+#include <malloc.h>\r
+#endif\r
+\r
+tdata_t\r
+_TIFFmalloc(tsize_t s)\r
+{\r
+ return (malloc((size_t) s));\r
+}\r
+\r
+void\r
+_TIFFfree(tdata_t p)\r
+{\r
+ free(p);\r
+}\r
+\r
+tdata_t\r
+_TIFFrealloc(tdata_t p, tsize_t s)\r
+{\r
+ return (realloc(p, (size_t) s));\r
+}\r
+\r
+void\r
+_TIFFmemset(tdata_t p, int v, tsize_t c)\r
+{\r
+ memset(p, v, (size_t) c);\r
+}\r
+\r
+void\r
+_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)\r
+{\r
+ memcpy(d, s, (size_t) c);\r
+}\r
+\r
+int\r
+_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)\r
+{\r
+ return (memcmp(p1, p2, (size_t) c));\r
+}\r
+\r
+#ifndef UNICODE\r
+#define DbgPrint wvsprintf\r
+#define DbgPrint2 wsprintf\r
+#define DbgMsgBox MessageBox\r
+#else\r
+#define DbgPrint wvsprintfA\r
+#define DbgPrint2 wsprintfA\r
+#define DbgMsgBox MessageBoxA\r
+#endif\r
+\r
+static void\r
+Win32WarningHandler(const char* module, const char* fmt, va_list ap)\r
+{\r
+#ifdef _DEBUG\r
+#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32))\r
+ LPSTR szTitle;\r
+ LPSTR szTmp;\r
+ LPCSTR szTitleText = "%s Warning";\r
+ LPCSTR szDefaultModule = "TIFFLIB";\r
+ szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module;\r
+ if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) +\r
+ strlen(szTitleText) + strlen(fmt) + 128))) == NULL)\r
+ return;\r
+ DbgPrint2(szTitle, szTitleText, szTmp);\r
+ szTmp = szTitle + (strlen(szTitle)+2);\r
+ DbgPrint(szTmp, fmt, ap);\r
+ DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION);\r
+ LocalFree(szTitle);\r
+ return;\r
+#else\r
+ if (module != NULL)\r
+ fprintf(stderr, "%s: ", module);\r
+ fprintf(stderr, "Warning, ");\r
+ vfprintf(stderr, fmt, ap);\r
+ fprintf(stderr, ".\n");\r
+#endif\r
+#endif\r
+}\r
+TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler;\r
+\r
+static void\r
+Win32ErrorHandler(const char* module, const char* fmt, va_list ap)\r
+{\r
+#ifdef _DEBUG\r
+#if (!defined(_CONSOLE) && !defined(_WIN32_WCE) && defined(WIN32))\r
+ LPSTR szTitle;\r
+ LPSTR szTmp;\r
+ LPCSTR szTitleText = "%s Error";\r
+ LPCSTR szDefaultModule = "TIFFLIB";\r
+ szTmp = (module == NULL) ? (LPSTR)szDefaultModule : (LPSTR)module;\r
+ if ((szTitle = (LPSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmp) +\r
+ strlen(szTitleText) + strlen(fmt) + 128))) == NULL)\r
+ return;\r
+ DbgPrint2(szTitle, szTitleText, szTmp);\r
+ szTmp = szTitle + (strlen(szTitle)+2);\r
+ DbgPrint(szTmp, fmt, ap);\r
+ DbgMsgBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION);\r
+ LocalFree(szTitle);\r
+ return;\r
+#else\r
+ if (module != NULL)\r
+ fprintf(stderr, "%s: ", module);\r
+ vfprintf(stderr, fmt, ap);\r
+ fprintf(stderr, ".\n");\r
+#endif\r
+#endif\r
+}\r
+TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler;\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ * File: xfile.h\r
+ * Purpose: General Purpose File Class \r
+ */\r
+/*\r
+ --------------------------------------------------------------------------------\r
+\r
+ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:\r
+\r
+ CxFile (c) 11/May/2002 Davide Pizzolato - www.xdp.it\r
+ CxFile version 2.00 23/Aug/2002\r
+ CxFile version 2.10 16/Dec/2007\r
+ \r
+ Special thanks to Chris Shearer Cooper for new features, enhancements and bugfixes\r
+\r
+ Covered code is provided under this license on an "as is" basis, without warranty\r
+ of any kind, either expressed or implied, including, without limitation, warranties\r
+ that the covered code is free of defects, merchantable, fit for a particular purpose\r
+ or non-infringing. The entire risk as to the quality and performance of the covered\r
+ code is with you. Should any covered code prove defective in any respect, you (not\r
+ the initial developer or any other contributor) assume the cost of any necessary\r
+ servicing, repair or correction. This disclaimer of warranty constitutes an essential\r
+ part of this license. No use of any covered code is authorized hereunder except under\r
+ this disclaimer.\r
+\r
+ Permission is hereby granted to use, copy, modify, and distribute this\r
+ source code, or portions hereof, for any purpose, including commercial applications,\r
+ freely and without fee, subject to the following restrictions: \r
+\r
+ 1. The origin of this software must not be misrepresented; you must not\r
+ claim that you wrote the original software. If you use this software\r
+ in a product, an acknowledgment in the product documentation would be\r
+ appreciated but is not required.\r
+\r
+ 2. Altered source versions must be plainly marked as such, and must not be\r
+ misrepresented as being the original software.\r
+\r
+ 3. This notice may not be removed or altered from any source distribution.\r
+ --------------------------------------------------------------------------------\r
+ */\r
+#if !defined(__xfile_h)\r
+#define __xfile_h\r
+\r
+#if defined (WIN32) || defined (_WIN32_WCE)\r
+ #include <windows.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include "ximadef.h"\r
+\r
+class DLL_EXP CxFile\r
+{\r
+public:\r
+ CxFile(void) { };\r
+ virtual ~CxFile() { };\r
+\r
+ virtual bool Close() = 0;\r
+ virtual size_t Read(void *buffer, size_t size, size_t count) = 0;\r
+ virtual size_t Write(const void *buffer, size_t size, size_t count) = 0;\r
+ virtual bool Seek(long offset, int origin) = 0;\r
+ virtual long Tell() = 0;\r
+ virtual long Size() = 0;\r
+ virtual bool Flush() = 0;\r
+ virtual bool Eof() = 0;\r
+ virtual long Error() = 0;\r
+ virtual bool PutC(unsigned char c)\r
+ {\r
+ // Default implementation\r
+ size_t nWrote = Write(&c, 1, 1);\r
+ return (bool)(nWrote == 1);\r
+ }\r
+ virtual long GetC() = 0;\r
+ virtual char * GetS(char *string, int n) = 0;\r
+ virtual long Scanf(const char *format, void* output) = 0;\r
+};\r
+\r
+#endif //__xfile_h\r
--- /dev/null
+/*\r
+ * File: ximabmp.cpp\r
+ * Purpose: Platform Independent BMP Image Class Loader and Writer\r
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximabmp.h"\r
+\r
+#if CXIMAGE_SUPPORT_BMP\r
+\r
+#include "ximaiter.h" \r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageBMP::Encode(CxFile * hFile)\r
+{\r
+\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ BITMAPFILEHEADER hdr;\r
+\r
+ hdr.bfType = 0x4d42; // 'BM' WINDOWS_BITMAP_SIGNATURE\r
+ hdr.bfSize = GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/;\r
+ hdr.bfReserved1 = hdr.bfReserved2 = 0;\r
+ hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + head.biSize + GetPaletteSize();\r
+\r
+ hdr.bfType = ntohs(hdr.bfType); \r
+ hdr.bfSize = ntohl(hdr.bfSize); \r
+ hdr.bfOffBits = ntohl(hdr.bfOffBits); \r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (GetNumColors()==0 && AlphaIsValid()){\r
+ \r
+ BITMAPINFOHEADER infohdr;\r
+ memcpy(&infohdr,&head,sizeof(BITMAPINFOHEADER));\r
+ infohdr.biCompression = BI_RGB;\r
+ infohdr.biBitCount = 32;\r
+ DWORD dwEffWidth = ((((infohdr.biBitCount * infohdr.biWidth) + 31) / 32) * 4);\r
+ infohdr.biSizeImage = dwEffWidth * infohdr.biHeight;\r
+\r
+ hdr.bfSize = infohdr.biSize + infohdr.biSizeImage + 14 /*sizeof(BITMAPFILEHEADER)*/;\r
+\r
+ hdr.bfSize = ntohl(hdr.bfSize);\r
+ bihtoh(&infohdr);\r
+\r
+ // Write the file header\r
+ hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);\r
+ hFile->Write(&infohdr,sizeof(BITMAPINFOHEADER),1);\r
+ //and DIB+ALPHA interlaced\r
+ BYTE *srcalpha = AlphaGetPointer();\r
+ for(long y = 0; y < infohdr.biHeight; ++y){\r
+ BYTE *srcdib = GetBits(y);\r
+ for(long x = 0; x < infohdr.biWidth; ++x){\r
+ hFile->Write(srcdib,3,1);\r
+ hFile->Write(srcalpha,1,1);\r
+ srcdib += 3;\r
+ ++srcalpha;\r
+ }\r
+ }\r
+\r
+ } else \r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ {\r
+ // Write the file header\r
+ hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);\r
+ //copy attributes\r
+ memcpy(pDib,&head,sizeof(BITMAPINFOHEADER));\r
+ bihtoh((BITMAPINFOHEADER*)pDib);\r
+ // Write the DIB header and the pixels\r
+ hFile->Write(pDib,GetSize(),1);\r
+ bihtoh((BITMAPINFOHEADER*)pDib);\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageBMP::Decode(CxFile * hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ BITMAPFILEHEADER bf;\r
+ DWORD off = hFile->Tell(); //<CSC>\r
+ cx_try {\r
+ if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) cx_throw("Not a BMP");\r
+\r
+ bf.bfSize = ntohl(bf.bfSize); \r
+ bf.bfOffBits = ntohl(bf.bfOffBits); \r
+\r
+ if (bf.bfType != BFT_BITMAP) { //do we have a RC HEADER?\r
+ bf.bfOffBits = 0L;\r
+ hFile->Seek(off,SEEK_SET);\r
+ }\r
+\r
+ BITMAPINFOHEADER bmpHeader;\r
+ if (!DibReadBitmapInfo(hFile,&bmpHeader)) cx_throw("Error reading BMP info");\r
+ DWORD dwCompression=bmpHeader.biCompression;\r
+ DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression <Thomas Ernst>\r
+ bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER);\r
+\r
+ bool bTopDownDib = bmpHeader.biHeight<0; //<Flanders> check if it's a top-down bitmap\r
+ if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight;\r
+\r
+ if (info.nEscape == -1) {\r
+ // Return output dimensions only\r
+ head.biWidth = bmpHeader.biWidth;\r
+ head.biHeight = bmpHeader.biHeight;\r
+ info.dwType = CXIMAGE_FORMAT_BMP;\r
+ cx_throw("output dimensions returned");\r
+ }\r
+\r
+ if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP))\r
+ cx_throw("");\r
+\r
+ SetXDPI((long) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5));\r
+ SetYDPI((long) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5));\r
+\r
+ if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
+\r
+ RGBQUAD *pRgb = GetPalette();\r
+ if (pRgb){\r
+ if (bIsOldBmp){\r
+ // convert a old color table (3 byte entries) to a new\r
+ // color table (4 byte entries)\r
+ hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1);\r
+ for (int i=DibNumColors(&head)-1; i>=0; i--){\r
+ pRgb[i].rgbRed = ((RGBTRIPLE *)pRgb)[i].rgbtRed;\r
+ pRgb[i].rgbBlue = ((RGBTRIPLE *)pRgb)[i].rgbtBlue;\r
+ pRgb[i].rgbGreen = ((RGBTRIPLE *)pRgb)[i].rgbtGreen;\r
+ pRgb[i].rgbReserved = (BYTE)0;\r
+ }\r
+ } else {\r
+ hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1);\r
+ //force rgbReserved=0, to avoid problems with some WinXp bitmaps\r
+ for (unsigned int i=0; i<head.biClrUsed; i++) pRgb[i].rgbReserved=0;\r
+ }\r
+ }\r
+\r
+ if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
+\r
+ switch (dwBitCount) {\r
+ case 32 :\r
+ DWORD bfmask[3];\r
+ if (dwCompression == BI_BITFIELDS)\r
+ {\r
+ hFile->Read(bfmask, 12, 1);\r
+ } else {\r
+ bfmask[0]=0x00FF0000;\r
+ bfmask[1]=0x0000FF00;\r
+ bfmask[2]=0x000000FF;\r
+ }\r
+ if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
+ if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){\r
+ long imagesize=4*head.biHeight*head.biWidth;\r
+ BYTE* buff32=(BYTE*)malloc(imagesize);\r
+ if (buff32){\r
+ hFile->Read(buff32, imagesize,1); // read in the pixels\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (dwCompression == BI_RGB){\r
+ AlphaCreate();\r
+ if (AlphaIsValid()){\r
+ bool bAlphaOk = false;\r
+ BYTE* p;\r
+ for (long y=0; y<head.biHeight; y++){\r
+ p = buff32 + 3 + head.biWidth * 4 * y;\r
+ for (long x=0; x<head.biWidth; x++){\r
+ if (*p) bAlphaOk = true;\r
+ AlphaSet(x,y,*p);\r
+ p+=4;\r
+ }\r
+ }\r
+ // fix if alpha pixels are all zero\r
+ if (!bAlphaOk) AlphaInvert();\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ Bitfield2RGB(buff32,bfmask[0],bfmask[1],bfmask[2],32);\r
+ free(buff32);\r
+ } else cx_throw("can't allocate memory");\r
+ } else cx_throw("unknown compression");\r
+ break;\r
+ case 24 :\r
+ if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
+ if (dwCompression == BI_RGB){\r
+ hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels\r
+ } else cx_throw("unknown compression");\r
+ break;\r
+ case 16 :\r
+ {\r
+ DWORD bfmask[3];\r
+ if (dwCompression == BI_BITFIELDS)\r
+ {\r
+ hFile->Read(bfmask, 12, 1);\r
+ } else {\r
+ bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555\r
+ }\r
+ // bf.bfOffBits required after the bitfield mask <Cui Ying Jie>\r
+ if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
+ // read in the pixels\r
+ hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1);\r
+ // transform into RGB\r
+ Bitfield2RGB(info.pImage,bfmask[0],bfmask[1],bfmask[2],16);\r
+ break;\r
+ }\r
+ case 8 :\r
+ case 4 :\r
+ case 1 :\r
+ if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);\r
+ switch (dwCompression) {\r
+ case BI_RGB :\r
+ hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels\r
+ break;\r
+ case BI_RLE4 :\r
+ {\r
+ BYTE status_byte = 0;\r
+ BYTE second_byte = 0;\r
+ int scanline = 0;\r
+ int bits = 0;\r
+ BOOL low_nibble = FALSE;\r
+ CImageIterator iter(this);\r
+\r
+ for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {\r
+ \r
+ switch (status_byte) {\r
+ case RLE_COMMAND :\r
+ hFile->Read(&status_byte, sizeof(BYTE), 1);\r
+ switch (status_byte) {\r
+ case RLE_ENDOFLINE :\r
+ bits = 0;\r
+ scanline++;\r
+ low_nibble = FALSE;\r
+ break;\r
+ case RLE_ENDOFBITMAP :\r
+ bContinue=FALSE;\r
+ break;\r
+ case RLE_DELTA :\r
+ {\r
+ // read the delta values\r
+ BYTE delta_x;\r
+ BYTE delta_y;\r
+ hFile->Read(&delta_x, sizeof(BYTE), 1);\r
+ hFile->Read(&delta_y, sizeof(BYTE), 1);\r
+ // apply them\r
+ bits += delta_x / 2;\r
+ scanline += delta_y;\r
+ break;\r
+ }\r
+ default :\r
+ hFile->Read(&second_byte, sizeof(BYTE), 1);\r
+ BYTE *sline = iter.GetRow(scanline);\r
+ for (int i = 0; i < status_byte; i++) {\r
+ if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){\r
+ if (low_nibble) {\r
+ if (i&1)\r
+ *(sline + bits) |= (second_byte & 0x0f);\r
+ else\r
+ *(sline + bits) |= (second_byte & 0xf0)>>4;\r
+ bits++;\r
+ } else {\r
+ if (i&1)\r
+ *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;\r
+ else\r
+ *(sline + bits) = (BYTE)(second_byte & 0xf0);\r
+ }\r
+ }\r
+\r
+ if ((i & 1) && (i != (status_byte - 1)))\r
+ hFile->Read(&second_byte, sizeof(BYTE), 1);\r
+\r
+ low_nibble = !low_nibble;\r
+ }\r
+ if ((((status_byte+1) >> 1) & 1 ) == 1)\r
+ hFile->Read(&second_byte, sizeof(BYTE), 1); \r
+ break;\r
+ };\r
+ break;\r
+ default :\r
+ {\r
+ BYTE *sline = iter.GetRow(scanline);\r
+ hFile->Read(&second_byte, sizeof(BYTE), 1);\r
+ for (unsigned i = 0; i < status_byte; i++) {\r
+ if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){\r
+ if (low_nibble) {\r
+ if (i&1)\r
+ *(sline + bits) |= (second_byte & 0x0f);\r
+ else\r
+ *(sline + bits) |= (second_byte & 0xf0)>>4;\r
+ bits++;\r
+ } else {\r
+ if (i&1)\r
+ *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;\r
+ else\r
+ *(sline + bits) = (BYTE)(second_byte & 0xf0);\r
+ }\r
+ }\r
+ low_nibble = !low_nibble;\r
+ }\r
+ }\r
+ break;\r
+ };\r
+ }\r
+ break;\r
+ }\r
+ case BI_RLE8 :\r
+ {\r
+ BYTE status_byte = 0;\r
+ BYTE second_byte = 0;\r
+ int scanline = 0;\r
+ int bits = 0;\r
+ CImageIterator iter(this);\r
+\r
+ for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {\r
+ switch (status_byte) {\r
+ case RLE_COMMAND :\r
+ hFile->Read(&status_byte, sizeof(BYTE), 1);\r
+ switch (status_byte) {\r
+ case RLE_ENDOFLINE :\r
+ bits = 0;\r
+ scanline++;\r
+ break;\r
+ case RLE_ENDOFBITMAP :\r
+ bContinue=FALSE;\r
+ break;\r
+ case RLE_DELTA :\r
+ {\r
+ // read the delta values\r
+ BYTE delta_x;\r
+ BYTE delta_y;\r
+ hFile->Read(&delta_x, sizeof(BYTE), 1);\r
+ hFile->Read(&delta_y, sizeof(BYTE), 1);\r
+ // apply them\r
+ bits += delta_x;\r
+ scanline += delta_y;\r
+ break;\r
+ }\r
+ default :\r
+ hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(BYTE) * status_byte, 1);\r
+ // align run length to even number of bytes \r
+ if ((status_byte & 1) == 1)\r
+ hFile->Read(&second_byte, sizeof(BYTE), 1); \r
+ bits += status_byte; \r
+ break; \r
+ };\r
+ break;\r
+ default :\r
+ BYTE *sline = iter.GetRow(scanline);\r
+ hFile->Read(&second_byte, sizeof(BYTE), 1);\r
+ for (unsigned i = 0; i < status_byte; i++) {\r
+ if ((DWORD)bits<info.dwEffWidth){\r
+ *(sline + bits) = second_byte;\r
+ bits++; \r
+ } else {\r
+ break;\r
+ }\r
+ }\r
+ break;\r
+ };\r
+ }\r
+ break;\r
+ }\r
+ default : \r
+ cx_throw("compression type not supported");\r
+ }\r
+ }\r
+\r
+ if (bTopDownDib) Flip(); //<Flanders>\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_BMP) return true;\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/* ReadDibBitmapInfo()\r
+ *\r
+ * Will read a file in DIB format and return a global HANDLE to its\r
+ * BITMAPINFO. This function will work with both "old" and "new"\r
+ * bitmap formats, but will always return a "new" BITMAPINFO.\r
+ */\r
+bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib)\r
+{\r
+ if ((fh==NULL)||(pdib==NULL)) return false;\r
+\r
+ if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false;\r
+\r
+ bihtoh(pdib);\r
+\r
+ switch (pdib->biSize) // what type of bitmap info is this?\r
+ {\r
+ case sizeof(BITMAPINFOHEADER):\r
+ break;\r
+\r
+ case 64: //sizeof(OS2_BMP_HEADER):\r
+ fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR);\r
+ break;\r
+\r
+ case sizeof(BITMAPCOREHEADER):\r
+ {\r
+ BITMAPCOREHEADER bc = *(BITMAPCOREHEADER*)pdib;\r
+ pdib->biSize = bc.bcSize;\r
+ pdib->biWidth = (DWORD)bc.bcWidth;\r
+ pdib->biHeight = (DWORD)bc.bcHeight;\r
+ pdib->biPlanes = bc.bcPlanes;\r
+ pdib->biBitCount = bc.bcBitCount;\r
+ pdib->biCompression = BI_RGB;\r
+ pdib->biSizeImage = 0;\r
+ pdib->biXPelsPerMeter = 0;\r
+ pdib->biYPelsPerMeter = 0;\r
+ pdib->biClrUsed = 0;\r
+ pdib->biClrImportant = 0;\r
+\r
+ fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR);\r
+ }\r
+ break;\r
+ default:\r
+ //give a last chance\r
+ if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&&\r
+ (pdib->biSizeImage>=(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&&\r
+ (pdib->biPlanes==1)&&(pdib->biClrUsed==0))\r
+ {\r
+ if (pdib->biCompression==BI_RGB)\r
+ fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR);\r
+ break;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ FixBitmapInfo(pdib);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_BMP\r
+////////////////////////////////////////////////////////////////////////////////\r
--- /dev/null
+/*\r
+ * File: ximabmp.h\r
+ * Purpose: BMP Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageBMP (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes\r
+ *\r
+ * original CImageBMP and CImageIterator implementation are:\r
+ * Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>\r
+ *\r
+ * ==========================================================\r
+ */\r
+\r
+#if !defined(__ximaBMP_h)\r
+#define __ximaBMP_h\r
+\r
+#include "ximage.h"\r
+\r
+const int RLE_COMMAND = 0;\r
+const int RLE_ENDOFLINE = 0;\r
+const int RLE_ENDOFBITMAP = 1;\r
+const int RLE_DELTA = 2;\r
+\r
+#if !defined(BI_RLE8)\r
+ #define BI_RLE8 1L\r
+#endif\r
+#if !defined(BI_RLE4)\r
+ #define BI_RLE4 2L\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_BMP\r
+\r
+class CxImageBMP: public CxImage\r
+{\r
+public:\r
+ CxImageBMP(): CxImage(CXIMAGE_FORMAT_BMP) {};\r
+\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+protected:\r
+ bool DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib);\r
+};\r
+\r
+#define BFT_ICON 0x4349 /* 'IC' */\r
+#define BFT_BITMAP 0x4d42 /* 'BM' */\r
+#define BFT_CURSOR 0x5450 /* 'PT' */\r
+\r
+#ifndef WIDTHBYTES\r
+#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */\r
+#endif\r
+\r
+#endif\r
+\r
+#define DibWidthBytesN(lpbi, n) (UINT)WIDTHBYTES((UINT)(lpbi)->biWidth * (UINT)(n))\r
+#define DibWidthBytes(lpbi) DibWidthBytesN(lpbi, (lpbi)->biBitCount)\r
+\r
+#define DibSizeImage(lpbi) ((lpbi)->biSizeImage == 0 \\r
+ ? ((DWORD)(UINT)DibWidthBytes(lpbi) * (DWORD)(UINT)(lpbi)->biHeight) \\r
+ : (lpbi)->biSizeImage)\r
+\r
+#define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \\r
+ ? (int)(1 << (int)(lpbi)->biBitCount) \\r
+ : (int)(lpbi)->biClrUsed)\r
+\r
+#define FixBitmapInfo(lpbi) if ((lpbi)->biSizeImage == 0) \\r
+ (lpbi)->biSizeImage = DibSizeImage(lpbi); \\r
+ if ((lpbi)->biClrUsed == 0) \\r
+ (lpbi)->biClrUsed = DibNumColors(lpbi); \\r
+\r
+#endif\r
--- /dev/null
+#if !defined(__ximaCFG_h)\r
+#define __ximaCFG_h\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CxImage supported features\r
+#define CXIMAGE_SUPPORT_ALPHA 1\r
+#define CXIMAGE_SUPPORT_SELECTION 1\r
+#define CXIMAGE_SUPPORT_TRANSFORMATION 1\r
+#define CXIMAGE_SUPPORT_DSP 1\r
+#define CXIMAGE_SUPPORT_LAYERS 1\r
+#define CXIMAGE_SUPPORT_INTERPOLATION 1\r
+\r
+#define CXIMAGE_SUPPORT_DECODE 1\r
+#define CXIMAGE_SUPPORT_ENCODE 1 //<vho><T.Peck>\r
+#define CXIMAGE_SUPPORT_WINDOWS 1\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CxImage supported formats\r
+#define CXIMAGE_SUPPORT_BMP 1\r
+#define CXIMAGE_SUPPORT_GIF 1\r
+#define CXIMAGE_SUPPORT_JPG 1\r
+#define CXIMAGE_SUPPORT_PNG 1\r
+#define CXIMAGE_SUPPORT_ICO 1\r
+#define CXIMAGE_SUPPORT_TIF 1\r
+#define CXIMAGE_SUPPORT_TGA 1\r
+#define CXIMAGE_SUPPORT_PCX 1\r
+#define CXIMAGE_SUPPORT_WBMP 1\r
+#define CXIMAGE_SUPPORT_WMF 1\r
+\r
+#define CXIMAGE_SUPPORT_JP2 1\r
+#define CXIMAGE_SUPPORT_JPC 1\r
+#define CXIMAGE_SUPPORT_PGX 1\r
+#define CXIMAGE_SUPPORT_PNM 1\r
+#define CXIMAGE_SUPPORT_RAS 1\r
+\r
+#define CXIMAGE_SUPPORT_JBG 0 // GPL'd see ../jbig/copying.txt & ../jbig/patents.htm\r
+\r
+#define CXIMAGE_SUPPORT_MNG 1\r
+#define CXIMAGE_SUPPORT_SKA 1\r
+#define CXIMAGE_SUPPORT_RAW 1\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#define CXIMAGE_MAX_MEMORY 268435456\r
+\r
+#define CXIMAGE_DEFAULT_DPI 96\r
+\r
+#define CXIMAGE_ERR_NOFILE "null file handler"\r
+#define CXIMAGE_ERR_NOIMAGE "null image!!!"\r
+\r
+#define CXIMAGE_SUPPORT_EXCEPTION_HANDLING 1\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//color to grey mapping <H. Muelner> <jurgene>\r
+//#define RGB2GRAY(r,g,b) (((b)*114 + (g)*587 + (r)*299)/1000)\r
+#define RGB2GRAY(r,g,b) (((b)*117 + (g)*601 + (r)*306) >> 10)\r
+\r
+#endif\r
--- /dev/null
+#if !defined(__ximadefs_h)\r
+#define __ximadefs_h\r
+\r
+#include "ximacfg.h"\r
+\r
+#if defined(_AFXDLL)||defined(_USRDLL)\r
+ #define DLL_EXP __declspec(dllexport)\r
+#elif defined(_MSC_VER)&&(_MSC_VER<1200)\r
+ #define DLL_EXP __declspec(dllimport)\r
+#else\r
+ #define DLL_EXP\r
+#endif\r
+\r
+\r
+#if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ #define cx_try try\r
+ #define cx_throw(message) throw(message)\r
+ #define cx_catch catch (const char *message)\r
+#else\r
+ #define cx_try bool cx_error=false;\r
+ #define cx_throw(message) {cx_error=true; if(strcmp(message,"")) strncpy(info.szLastError,message,255); goto cx_error_catch;}\r
+ #define cx_catch cx_error_catch: char message[]=""; if(cx_error)\r
+#endif\r
+\r
+\r
+#if CXIMAGE_SUPPORT_JP2 || CXIMAGE_SUPPORT_JPC || CXIMAGE_SUPPORT_PGX || CXIMAGE_SUPPORT_PNM || CXIMAGE_SUPPORT_RAS\r
+ #define CXIMAGE_SUPPORT_JASPER 1\r
+#else\r
+ #define CXIMAGE_SUPPORT_JASPER 0\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_DSP\r
+#undef CXIMAGE_SUPPORT_TRANSFORMATION\r
+ #define CXIMAGE_SUPPORT_TRANSFORMATION 1\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_TRANSFORMATION || CXIMAGE_SUPPORT_TIF || CXIMAGE_SUPPORT_TGA || CXIMAGE_SUPPORT_BMP || CXIMAGE_SUPPORT_WINDOWS\r
+ #define CXIMAGE_SUPPORT_BASICTRANSFORMATIONS 1\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_DSP || CXIMAGE_SUPPORT_TRANSFORMATION\r
+#undef CXIMAGE_SUPPORT_INTERPOLATION\r
+ #define CXIMAGE_SUPPORT_INTERPOLATION 1\r
+#endif\r
+\r
+#if defined (_WIN32_WCE)\r
+ #undef CXIMAGE_SUPPORT_WMF\r
+ #define CXIMAGE_SUPPORT_WMF 0\r
+#endif\r
+\r
+#if !defined(WIN32) && !defined(_WIN32_WCE)\r
+ #undef CXIMAGE_SUPPORT_WINDOWS\r
+ #define CXIMAGE_SUPPORT_WINDOWS 0\r
+#endif\r
+\r
+#ifndef min\r
+#define min(a,b) (((a)<(b))?(a):(b))\r
+#endif\r
+#ifndef max\r
+#define max(a,b) (((a)>(b))?(a):(b))\r
+#endif\r
+\r
+#ifndef PI\r
+ #define PI 3.141592653589793f\r
+#endif\r
+\r
+\r
+#if defined(WIN32) || defined(_WIN32_WCE)\r
+#include <windows.h>\r
+#include <tchar.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#include <math.h>\r
+\r
+#ifdef __BORLANDC__\r
+\r
+#ifndef _COMPLEX_DEFINED\r
+\r
+typedef struct tagcomplex {\r
+ double x,y;\r
+} _complex;\r
+\r
+#endif\r
+\r
+#define _cabs(c) sqrt(c.x*c.x+c.y*c.y)\r
+\r
+#endif\r
+\r
+\r
+#if !defined(WIN32) && !defined(_WIN32_WCE)\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+\r
+typedef unsigned char BYTE;\r
+typedef unsigned short WORD;\r
+typedef unsigned long DWORD;\r
+typedef unsigned int UINT;\r
+\r
+typedef DWORD COLORREF;\r
+typedef unsigned int HANDLE;\r
+typedef void* HRGN;\r
+\r
+#ifndef BOOL\r
+#define BOOL bool\r
+#endif\r
+\r
+#ifndef TRUE\r
+#define TRUE true\r
+#endif\r
+\r
+#ifndef FALSE\r
+#define FALSE false\r
+#endif\r
+\r
+#ifndef TCHAR\r
+#define TCHAR char\r
+#define _T\r
+#endif\r
+\r
+typedef struct tagRECT\r
+{\r
+ long left;\r
+ long top;\r
+ long right;\r
+ long bottom;\r
+} RECT;\r
+\r
+typedef struct tagPOINT\r
+{\r
+ long x;\r
+ long y;\r
+} POINT;\r
+\r
+typedef struct tagRGBQUAD {\r
+ BYTE rgbBlue;\r
+ BYTE rgbGreen;\r
+ BYTE rgbRed;\r
+ BYTE rgbReserved;\r
+} RGBQUAD;\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct tagBITMAPINFOHEADER{\r
+ DWORD biSize;\r
+ long biWidth;\r
+ long biHeight;\r
+ WORD biPlanes;\r
+ WORD biBitCount;\r
+ DWORD biCompression;\r
+ DWORD biSizeImage;\r
+ long biXPelsPerMeter;\r
+ long biYPelsPerMeter;\r
+ DWORD biClrUsed;\r
+ DWORD biClrImportant;\r
+} BITMAPINFOHEADER;\r
+\r
+typedef struct tagBITMAPFILEHEADER {\r
+ WORD bfType;\r
+ DWORD bfSize;\r
+ WORD bfReserved1;\r
+ WORD bfReserved2;\r
+ DWORD bfOffBits;\r
+} BITMAPFILEHEADER;\r
+\r
+typedef struct tagBITMAPCOREHEADER {\r
+ DWORD bcSize;\r
+ WORD bcWidth;\r
+ WORD bcHeight;\r
+ WORD bcPlanes;\r
+ WORD bcBitCount;\r
+} BITMAPCOREHEADER;\r
+\r
+typedef struct tagRGBTRIPLE {\r
+ BYTE rgbtBlue;\r
+ BYTE rgbtGreen;\r
+ BYTE rgbtRed;\r
+} RGBTRIPLE;\r
+\r
+#pragma pack()\r
+\r
+#define BI_RGB 0L\r
+#define BI_RLE8 1L\r
+#define BI_RLE4 2L\r
+#define BI_BITFIELDS 3L\r
+\r
+#define GetRValue(rgb) ((BYTE)(rgb))\r
+#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8))\r
+#define GetBValue(rgb) ((BYTE)((rgb)>>16))\r
+#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))\r
+\r
+#ifndef _COMPLEX_DEFINED\r
+\r
+typedef struct tagcomplex {\r
+ double x,y;\r
+} _complex;\r
+\r
+#endif\r
+\r
+#define _cabs(c) sqrt(c.x*c.x+c.y*c.y)\r
+\r
+#endif\r
+\r
+#endif //__ximadefs\r
--- /dev/null
+// xImaDsp.cpp : DSP functions\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+#include "ximaiter.h"\r
+\r
+#if CXIMAGE_SUPPORT_DSP\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Converts the image to B&W.\r
+ * The OptimalThreshold() function can be used for calculating the optimal threshold.\r
+ * \param level: the lightness threshold.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Threshold(BYTE level)\r
+{\r
+ if (!pDib) return false;\r
+ if (head.biBitCount == 1) return true;\r
+\r
+ GrayScale();\r
+\r
+ CxImage tmp(head.biWidth,head.biHeight,1);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ for (long y=0;y<head.biHeight;y++){\r
+ info.nProgress = (long)(100*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+ if (BlindGetPixelIndex(x,y)>level)\r
+ tmp.BlindSetPixelIndex(x,y,1);\r
+ else\r
+ tmp.BlindSetPixelIndex(x,y,0);\r
+ }\r
+ }\r
+ tmp.SetPaletteColor(0,0,0,0);\r
+ tmp.SetPaletteColor(1,255,255,255);\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Converts the image to B&W, using a threshold mask\r
+ * \param pThresholdMask: the lightness threshold mask.\r
+ * the pThresholdMask image must be grayscale with same with and height of the current image\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Threshold(CxImage* pThresholdMask)\r
+{\r
+ if (!pDib) return false;\r
+ if (head.biBitCount == 1) return true;\r
+\r
+ if (!pThresholdMask) return false;\r
+ \r
+ if (!pThresholdMask->IsValid() ||\r
+ !pThresholdMask->IsGrayScale() ||\r
+ pThresholdMask->GetWidth() != GetWidth() ||\r
+ pThresholdMask->GetHeight() != GetHeight()){\r
+ strcpy(info.szLastError,"invalid ThresholdMask");\r
+ return false;\r
+ }\r
+\r
+ GrayScale();\r
+\r
+ CxImage tmp(head.biWidth,head.biHeight,1);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ for (long y=0;y<head.biHeight;y++){\r
+ info.nProgress = (long)(100*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+ if (BlindGetPixelIndex(x,y)>pThresholdMask->BlindGetPixelIndex(x,y))\r
+ tmp.BlindSetPixelIndex(x,y,1);\r
+ else\r
+ tmp.BlindSetPixelIndex(x,y,0);\r
+ }\r
+ }\r
+ tmp.SetPaletteColor(0,0,0,0);\r
+ tmp.SetPaletteColor(1,255,255,255);\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Filters only the pixels with a lightness less (or more) than the threshold level,\r
+ * and preserves the colors for the unfiltered pixels.\r
+ * \param level = the lightness threshold.\r
+ * \param bDirection = false: filter dark pixels, true: filter light pixels\r
+ * \param nBkgndColor = filtered pixels are set to nBkgndColor color\r
+ * \param bSetAlpha = if true, sets also the alpha component for the filtered pixels, with nBkgndColor.rgbReserved\r
+ * \return true if everything is ok\r
+ * \author [DP], [wangsongtao]\r
+ */\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::Threshold2(BYTE level, bool bDirection, RGBQUAD nBkgndColor, bool bSetAlpha)\r
+{\r
+ if (!pDib) return false;\r
+ if (head.biBitCount == 1) return true;\r
+\r
+ CxImage tmp(*this, true, false, false);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ tmp.GrayScale();\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ BYTE i = tmp.BlindGetPixelIndex(x,y);\r
+ if (!bDirection && i<level) BlindSetPixelColor(x,y,nBkgndColor,bSetAlpha);\r
+ if (bDirection && i>=level) BlindSetPixelColor(x,y,nBkgndColor,bSetAlpha);\r
+ }\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Extract RGB channels from the image. Each channel is an 8 bit grayscale image. \r
+ * \param r,g,b: pointers to CxImage objects, to store the splited channels\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::SplitRGB(CxImage* r,CxImage* g,CxImage* b)\r
+{\r
+ if (!pDib) return false;\r
+ if (r==NULL && g==NULL && b==NULL) return false;\r
+\r
+ CxImage tmpr(head.biWidth,head.biHeight,8);\r
+ CxImage tmpg(head.biWidth,head.biHeight,8);\r
+ CxImage tmpb(head.biWidth,head.biHeight,8);\r
+\r
+ RGBQUAD color;\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ color = BlindGetPixelColor(x,y);\r
+ if (r) tmpr.BlindSetPixelIndex(x,y,color.rgbRed);\r
+ if (g) tmpg.BlindSetPixelIndex(x,y,color.rgbGreen);\r
+ if (b) tmpb.BlindSetPixelIndex(x,y,color.rgbBlue);\r
+ }\r
+ }\r
+\r
+ if (r) tmpr.SetGrayPalette();\r
+ if (g) tmpg.SetGrayPalette();\r
+ if (b) tmpb.SetGrayPalette();\r
+\r
+ /*for(long j=0; j<256; j++){\r
+ BYTE i=(BYTE)j;\r
+ if (r) tmpr.SetPaletteColor(i,i,0,0);\r
+ if (g) tmpg.SetPaletteColor(i,0,i,0);\r
+ if (b) tmpb.SetPaletteColor(i,0,0,i);\r
+ }*/\r
+\r
+ if (r) r->Transfer(tmpr);\r
+ if (g) g->Transfer(tmpg);\r
+ if (b) b->Transfer(tmpb);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Extract CMYK channels from the image. Each channel is an 8 bit grayscale image. \r
+ * \param c,m,y,k: pointers to CxImage objects, to store the splited channels\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::SplitCMYK(CxImage* c,CxImage* m,CxImage* y,CxImage* k)\r
+{\r
+ if (!pDib) return false;\r
+ if (c==NULL && m==NULL && y==NULL && k==NULL) return false;\r
+\r
+ CxImage tmpc(head.biWidth,head.biHeight,8);\r
+ CxImage tmpm(head.biWidth,head.biHeight,8);\r
+ CxImage tmpy(head.biWidth,head.biHeight,8);\r
+ CxImage tmpk(head.biWidth,head.biHeight,8);\r
+\r
+ RGBQUAD color;\r
+ for(long yy=0; yy<head.biHeight; yy++){\r
+ for(long xx=0; xx<head.biWidth; xx++){\r
+ color = BlindGetPixelColor(xx,yy);\r
+ if (c) tmpc.BlindSetPixelIndex(xx,yy,(BYTE)(255-color.rgbRed));\r
+ if (m) tmpm.BlindSetPixelIndex(xx,yy,(BYTE)(255-color.rgbGreen));\r
+ if (y) tmpy.BlindSetPixelIndex(xx,yy,(BYTE)(255-color.rgbBlue));\r
+ if (k) tmpk.BlindSetPixelIndex(xx,yy,(BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue));\r
+ }\r
+ }\r
+\r
+ if (c) tmpc.SetGrayPalette();\r
+ if (m) tmpm.SetGrayPalette();\r
+ if (y) tmpy.SetGrayPalette();\r
+ if (k) tmpk.SetGrayPalette();\r
+\r
+ if (c) c->Transfer(tmpc);\r
+ if (m) m->Transfer(tmpm);\r
+ if (y) y->Transfer(tmpy);\r
+ if (k) k->Transfer(tmpk);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Extract YUV channels from the image. Each channel is an 8 bit grayscale image. \r
+ * \param y,u,v: pointers to CxImage objects, to store the splited channels\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::SplitYUV(CxImage* y,CxImage* u,CxImage* v)\r
+{\r
+ if (!pDib) return false;\r
+ if (y==NULL && u==NULL && v==NULL) return false;\r
+\r
+ CxImage tmpy(head.biWidth,head.biHeight,8);\r
+ CxImage tmpu(head.biWidth,head.biHeight,8);\r
+ CxImage tmpv(head.biWidth,head.biHeight,8);\r
+\r
+ RGBQUAD color;\r
+ for(long yy=0; yy<head.biHeight; yy++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ color = RGBtoYUV(BlindGetPixelColor(x,yy));\r
+ if (y) tmpy.BlindSetPixelIndex(x,yy,color.rgbRed);\r
+ if (u) tmpu.BlindSetPixelIndex(x,yy,color.rgbGreen);\r
+ if (v) tmpv.BlindSetPixelIndex(x,yy,color.rgbBlue);\r
+ }\r
+ }\r
+\r
+ if (y) tmpy.SetGrayPalette();\r
+ if (u) tmpu.SetGrayPalette();\r
+ if (v) tmpv.SetGrayPalette();\r
+\r
+ if (y) y->Transfer(tmpy);\r
+ if (u) u->Transfer(tmpu);\r
+ if (v) v->Transfer(tmpv);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Extract YIQ channels from the image. Each channel is an 8 bit grayscale image. \r
+ * \param y,i,q: pointers to CxImage objects, to store the splited channels\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::SplitYIQ(CxImage* y,CxImage* i,CxImage* q)\r
+{\r
+ if (!pDib) return false;\r
+ if (y==NULL && i==NULL && q==NULL) return false;\r
+\r
+ CxImage tmpy(head.biWidth,head.biHeight,8);\r
+ CxImage tmpi(head.biWidth,head.biHeight,8);\r
+ CxImage tmpq(head.biWidth,head.biHeight,8);\r
+\r
+ RGBQUAD color;\r
+ for(long yy=0; yy<head.biHeight; yy++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ color = RGBtoYIQ(BlindGetPixelColor(x,yy));\r
+ if (y) tmpy.BlindSetPixelIndex(x,yy,color.rgbRed);\r
+ if (i) tmpi.BlindSetPixelIndex(x,yy,color.rgbGreen);\r
+ if (q) tmpq.BlindSetPixelIndex(x,yy,color.rgbBlue);\r
+ }\r
+ }\r
+\r
+ if (y) tmpy.SetGrayPalette();\r
+ if (i) tmpi.SetGrayPalette();\r
+ if (q) tmpq.SetGrayPalette();\r
+\r
+ if (y) y->Transfer(tmpy);\r
+ if (i) i->Transfer(tmpi);\r
+ if (q) q->Transfer(tmpq);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Extract XYZ channels from the image. Each channel is an 8 bit grayscale image. \r
+ * \param x,y,z: pointers to CxImage objects, to store the splited channels\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::SplitXYZ(CxImage* x,CxImage* y,CxImage* z)\r
+{\r
+ if (!pDib) return false;\r
+ if (x==NULL && y==NULL && z==NULL) return false;\r
+\r
+ CxImage tmpx(head.biWidth,head.biHeight,8);\r
+ CxImage tmpy(head.biWidth,head.biHeight,8);\r
+ CxImage tmpz(head.biWidth,head.biHeight,8);\r
+\r
+ RGBQUAD color;\r
+ for(long yy=0; yy<head.biHeight; yy++){\r
+ for(long xx=0; xx<head.biWidth; xx++){\r
+ color = RGBtoXYZ(BlindGetPixelColor(xx,yy));\r
+ if (x) tmpx.BlindSetPixelIndex(xx,yy,color.rgbRed);\r
+ if (y) tmpy.BlindSetPixelIndex(xx,yy,color.rgbGreen);\r
+ if (z) tmpz.BlindSetPixelIndex(xx,yy,color.rgbBlue);\r
+ }\r
+ }\r
+\r
+ if (x) tmpx.SetGrayPalette();\r
+ if (y) tmpy.SetGrayPalette();\r
+ if (z) tmpz.SetGrayPalette();\r
+\r
+ if (x) x->Transfer(tmpx);\r
+ if (y) y->Transfer(tmpy);\r
+ if (z) z->Transfer(tmpz);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Extract HSL channels from the image. Each channel is an 8 bit grayscale image. \r
+ * \param h,s,l: pointers to CxImage objects, to store the splited channels\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::SplitHSL(CxImage* h,CxImage* s,CxImage* l)\r
+{\r
+ if (!pDib) return false;\r
+ if (h==NULL && s==NULL && l==NULL) return false;\r
+\r
+ CxImage tmph(head.biWidth,head.biHeight,8);\r
+ CxImage tmps(head.biWidth,head.biHeight,8);\r
+ CxImage tmpl(head.biWidth,head.biHeight,8);\r
+\r
+ RGBQUAD color;\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ color = RGBtoHSL(BlindGetPixelColor(x,y));\r
+ if (h) tmph.BlindSetPixelIndex(x,y,color.rgbRed);\r
+ if (s) tmps.BlindSetPixelIndex(x,y,color.rgbGreen);\r
+ if (l) tmpl.BlindSetPixelIndex(x,y,color.rgbBlue);\r
+ }\r
+ }\r
+\r
+ if (h) tmph.SetGrayPalette();\r
+ if (s) tmps.SetGrayPalette();\r
+ if (l) tmpl.SetGrayPalette();\r
+\r
+ /* pseudo-color generator for hue channel (visual debug)\r
+ if (h) for(long j=0; j<256; j++){\r
+ BYTE i=(BYTE)j;\r
+ RGBQUAD hsl={120,240,i,0};\r
+ tmph.SetPaletteColor(i,HSLtoRGB(hsl));\r
+ }*/\r
+\r
+ if (h) h->Transfer(tmph);\r
+ if (s) s->Transfer(tmps);\r
+ if (l) l->Transfer(tmpl);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#define HSLMAX 255 /* H,L, and S vary over 0-HSLMAX */\r
+#define RGBMAX 255 /* R,G, and B vary over 0-RGBMAX */\r
+ /* HSLMAX BEST IF DIVISIBLE BY 6 */\r
+ /* RGBMAX, HSLMAX must each fit in a BYTE. */\r
+/* Hue is undefined if Saturation is 0 (grey-scale) */\r
+/* This value determines where the Hue scrollbar is */\r
+/* initially set for achromatic colors */\r
+#define HSLUNDEFINED (HSLMAX*2/3)\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::RGBtoHSL(RGBQUAD lRGBColor)\r
+{\r
+ BYTE R,G,B; /* input RGB values */\r
+ BYTE H,L,S; /* output HSL values */\r
+ BYTE cMax,cMin; /* max and min RGB values */\r
+ WORD Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max*/\r
+\r
+ R = lRGBColor.rgbRed; /* get R, G, and B out of DWORD */\r
+ G = lRGBColor.rgbGreen;\r
+ B = lRGBColor.rgbBlue;\r
+\r
+ cMax = max( max(R,G), B); /* calculate lightness */\r
+ cMin = min( min(R,G), B);\r
+ L = (BYTE)((((cMax+cMin)*HSLMAX)+RGBMAX)/(2*RGBMAX));\r
+\r
+ if (cMax==cMin){ /* r=g=b --> achromatic case */\r
+ S = 0; /* saturation */\r
+ H = HSLUNDEFINED; /* hue */\r
+ } else { /* chromatic case */\r
+ if (L <= (HSLMAX/2)) /* saturation */\r
+ S = (BYTE)((((cMax-cMin)*HSLMAX)+((cMax+cMin)/2))/(cMax+cMin));\r
+ else\r
+ S = (BYTE)((((cMax-cMin)*HSLMAX)+((2*RGBMAX-cMax-cMin)/2))/(2*RGBMAX-cMax-cMin));\r
+ /* hue */\r
+ Rdelta = (WORD)((((cMax-R)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin));\r
+ Gdelta = (WORD)((((cMax-G)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin));\r
+ Bdelta = (WORD)((((cMax-B)*(HSLMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin));\r
+\r
+ if (R == cMax)\r
+ H = (BYTE)(Bdelta - Gdelta);\r
+ else if (G == cMax)\r
+ H = (BYTE)((HSLMAX/3) + Rdelta - Bdelta);\r
+ else /* B == cMax */\r
+ H = (BYTE)(((2*HSLMAX)/3) + Gdelta - Rdelta);\r
+\r
+// if (H < 0) H += HSLMAX; //always false\r
+ if (H > HSLMAX) H -= HSLMAX;\r
+ }\r
+ RGBQUAD hsl={L,S,H,0};\r
+ return hsl;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::HueToRGB(float n1,float n2, float hue)\r
+{\r
+ //<F. Livraghi> fixed implementation for HSL2RGB routine\r
+ float rValue;\r
+\r
+ if (hue > 360)\r
+ hue = hue - 360;\r
+ else if (hue < 0)\r
+ hue = hue + 360;\r
+\r
+ if (hue < 60)\r
+ rValue = n1 + (n2-n1)*hue/60.0f;\r
+ else if (hue < 180)\r
+ rValue = n2;\r
+ else if (hue < 240)\r
+ rValue = n1+(n2-n1)*(240-hue)/60;\r
+ else\r
+ rValue = n1;\r
+\r
+ return rValue;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::HSLtoRGB(COLORREF cHSLColor)\r
+{\r
+ return HSLtoRGB(RGBtoRGBQUAD(cHSLColor));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::HSLtoRGB(RGBQUAD lHSLColor)\r
+{ \r
+ //<F. Livraghi> fixed implementation for HSL2RGB routine\r
+ float h,s,l;\r
+ float m1,m2;\r
+ BYTE r,g,b;\r
+\r
+ h = (float)lHSLColor.rgbRed * 360.0f/255.0f;\r
+ s = (float)lHSLColor.rgbGreen/255.0f;\r
+ l = (float)lHSLColor.rgbBlue/255.0f;\r
+\r
+ if (l <= 0.5) m2 = l * (1+s);\r
+ else m2 = l + s - l*s;\r
+\r
+ m1 = 2 * l - m2;\r
+\r
+ if (s == 0) {\r
+ r=g=b=(BYTE)(l*255.0f);\r
+ } else {\r
+ r = (BYTE)(HueToRGB(m1,m2,h+120) * 255.0f);\r
+ g = (BYTE)(HueToRGB(m1,m2,h) * 255.0f);\r
+ b = (BYTE)(HueToRGB(m1,m2,h-120) * 255.0f);\r
+ }\r
+\r
+ RGBQUAD rgb = {b,g,r,0};\r
+ return rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::YUVtoRGB(RGBQUAD lYUVColor)\r
+{\r
+ int U,V,R,G,B;\r
+ float Y = lYUVColor.rgbRed;\r
+ U = lYUVColor.rgbGreen - 128;\r
+ V = lYUVColor.rgbBlue - 128;\r
+\r
+// R = (int)(1.164 * Y + 2.018 * U);\r
+// G = (int)(1.164 * Y - 0.813 * V - 0.391 * U);\r
+// B = (int)(1.164 * Y + 1.596 * V);\r
+ R = (int)( Y + 1.403f * V);\r
+ G = (int)( Y - 0.344f * U - 0.714f * V);\r
+ B = (int)( Y + 1.770f * U);\r
+\r
+ R= min(255,max(0,R));\r
+ G= min(255,max(0,G));\r
+ B= min(255,max(0,B));\r
+ RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0};\r
+ return rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::RGBtoYUV(RGBQUAD lRGBColor)\r
+{\r
+ int Y,U,V,R,G,B;\r
+ R = lRGBColor.rgbRed;\r
+ G = lRGBColor.rgbGreen;\r
+ B = lRGBColor.rgbBlue;\r
+\r
+// Y = (int)( 0.257 * R + 0.504 * G + 0.098 * B);\r
+// U = (int)( 0.439 * R - 0.368 * G - 0.071 * B + 128);\r
+// V = (int)(-0.148 * R - 0.291 * G + 0.439 * B + 128);\r
+ Y = (int)(0.299f * R + 0.587f * G + 0.114f * B);\r
+ U = (int)((B-Y) * 0.565f + 128);\r
+ V = (int)((R-Y) * 0.713f + 128);\r
+\r
+ Y= min(255,max(0,Y));\r
+ U= min(255,max(0,U));\r
+ V= min(255,max(0,V));\r
+ RGBQUAD yuv={(BYTE)V,(BYTE)U,(BYTE)Y,0};\r
+ return yuv;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::YIQtoRGB(RGBQUAD lYIQColor)\r
+{\r
+ int I,Q,R,G,B;\r
+ float Y = lYIQColor.rgbRed;\r
+ I = lYIQColor.rgbGreen - 128;\r
+ Q = lYIQColor.rgbBlue - 128;\r
+\r
+ R = (int)( Y + 0.956f * I + 0.621f * Q);\r
+ G = (int)( Y - 0.273f * I - 0.647f * Q);\r
+ B = (int)( Y - 1.104f * I + 1.701f * Q);\r
+\r
+ R= min(255,max(0,R));\r
+ G= min(255,max(0,G));\r
+ B= min(255,max(0,B));\r
+ RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0};\r
+ return rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::RGBtoYIQ(RGBQUAD lRGBColor)\r
+{\r
+ int Y,I,Q,R,G,B;\r
+ R = lRGBColor.rgbRed;\r
+ G = lRGBColor.rgbGreen;\r
+ B = lRGBColor.rgbBlue;\r
+\r
+ Y = (int)( 0.2992f * R + 0.5868f * G + 0.1140f * B);\r
+ I = (int)( 0.5960f * R - 0.2742f * G - 0.3219f * B + 128);\r
+ Q = (int)( 0.2109f * R - 0.5229f * G + 0.3120f * B + 128);\r
+\r
+ Y= min(255,max(0,Y));\r
+ I= min(255,max(0,I));\r
+ Q= min(255,max(0,Q));\r
+ RGBQUAD yiq={(BYTE)Q,(BYTE)I,(BYTE)Y,0};\r
+ return yiq;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::XYZtoRGB(RGBQUAD lXYZColor)\r
+{\r
+ int X,Y,Z,R,G,B;\r
+ X = lXYZColor.rgbRed;\r
+ Y = lXYZColor.rgbGreen;\r
+ Z = lXYZColor.rgbBlue;\r
+ double k=1.088751;\r
+\r
+ R = (int)( 3.240479f * X - 1.537150f * Y - 0.498535f * Z * k);\r
+ G = (int)( -0.969256f * X + 1.875992f * Y + 0.041556f * Z * k);\r
+ B = (int)( 0.055648f * X - 0.204043f * Y + 1.057311f * Z * k);\r
+\r
+ R= min(255,max(0,R));\r
+ G= min(255,max(0,G));\r
+ B= min(255,max(0,B));\r
+ RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0};\r
+ return rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::RGBtoXYZ(RGBQUAD lRGBColor)\r
+{\r
+ int X,Y,Z,R,G,B;\r
+ R = lRGBColor.rgbRed;\r
+ G = lRGBColor.rgbGreen;\r
+ B = lRGBColor.rgbBlue;\r
+\r
+ X = (int)( 0.412453f * R + 0.357580f * G + 0.180423f * B);\r
+ Y = (int)( 0.212671f * R + 0.715160f * G + 0.072169f * B);\r
+ Z = (int)((0.019334f * R + 0.119193f * G + 0.950227f * B)*0.918483657f);\r
+\r
+ //X= min(255,max(0,X));\r
+ //Y= min(255,max(0,Y));\r
+ //Z= min(255,max(0,Z));\r
+ RGBQUAD xyz={(BYTE)Z,(BYTE)Y,(BYTE)X,0};\r
+ return xyz;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Generates a "rainbow" palette with saturated colors\r
+ * \param correction: 1 generates a single hue spectrum. 0.75 is nice for scientific applications.\r
+ */\r
+void CxImage::HuePalette(float correction)\r
+{\r
+ if (head.biClrUsed==0) return;\r
+\r
+ for(DWORD j=0; j<head.biClrUsed; j++){\r
+ BYTE i=(BYTE)(j*correction*(255/(head.biClrUsed-1)));\r
+ RGBQUAD hsl={120,240,i,0};\r
+ SetPaletteColor((BYTE)j,HSLtoRGB(hsl));\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Replaces the original hue and saturation values.\r
+ * \param hue: hue\r
+ * \param sat: saturation\r
+ * \param blend: can be from 0 (no effect) to 1 (full effect)\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Colorize(BYTE hue, BYTE sat, float blend)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ if (blend < 0.0f) blend = 0.0f;\r
+ if (blend > 1.0f) blend = 1.0f;\r
+ int a0 = (int)(256*blend);\r
+ int a1 = 256 - a0;\r
+\r
+ bool bFullBlend = false;\r
+ if (blend > 0.999f) bFullBlend = true;\r
+\r
+ RGBQUAD color,hsl;\r
+ if (head.biClrUsed==0){\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ if (bFullBlend){\r
+ color = RGBtoHSL(BlindGetPixelColor(x,y));\r
+ color.rgbRed=hue;\r
+ color.rgbGreen=sat;\r
+ BlindSetPixelColor(x,y,HSLtoRGB(color));\r
+ } else {\r
+ color = BlindGetPixelColor(x,y);\r
+ hsl.rgbRed=hue;\r
+ hsl.rgbGreen=sat;\r
+ hsl.rgbBlue = (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);\r
+ hsl = HSLtoRGB(hsl);\r
+ //BlendPixelColor(x,y,hsl,blend);\r
+ //color.rgbRed = (BYTE)(hsl.rgbRed * blend + color.rgbRed * (1.0f - blend));\r
+ //color.rgbBlue = (BYTE)(hsl.rgbBlue * blend + color.rgbBlue * (1.0f - blend));\r
+ //color.rgbGreen = (BYTE)(hsl.rgbGreen * blend + color.rgbGreen * (1.0f - blend));\r
+ color.rgbRed = (BYTE)((hsl.rgbRed * a0 + color.rgbRed * a1)>>8);\r
+ color.rgbBlue = (BYTE)((hsl.rgbBlue * a0 + color.rgbBlue * a1)>>8);\r
+ color.rgbGreen = (BYTE)((hsl.rgbGreen * a0 + color.rgbGreen * a1)>>8);\r
+ BlindSetPixelColor(x,y,color);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ for(DWORD j=0; j<head.biClrUsed; j++){\r
+ if (bFullBlend){\r
+ color = RGBtoHSL(GetPaletteColor((BYTE)j));\r
+ color.rgbRed=hue;\r
+ color.rgbGreen=sat;\r
+ SetPaletteColor((BYTE)j,HSLtoRGB(color));\r
+ } else {\r
+ color = GetPaletteColor((BYTE)j);\r
+ hsl.rgbRed=hue;\r
+ hsl.rgbGreen=sat;\r
+ hsl.rgbBlue = (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);\r
+ hsl = HSLtoRGB(hsl);\r
+ color.rgbRed = (BYTE)(hsl.rgbRed * blend + color.rgbRed * (1.0f - blend));\r
+ color.rgbBlue = (BYTE)(hsl.rgbBlue * blend + color.rgbBlue * (1.0f - blend));\r
+ color.rgbGreen = (BYTE)(hsl.rgbGreen * blend + color.rgbGreen * (1.0f - blend));\r
+ SetPaletteColor((BYTE)j,color);\r
+ }\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Changes the brightness and the contrast of the image. \r
+ * \param brightness: can be from -255 to 255, if brightness is negative, the image becomes dark.\r
+ * \param contrast: can be from -100 to 100, the neutral value is 0.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Light(long brightness, long contrast)\r
+{\r
+ if (!pDib) return false;\r
+ float c=(100 + contrast)/100.0f;\r
+ brightness+=128;\r
+\r
+ BYTE cTable[256]; //<nipper>\r
+ for (int i=0;i<256;i++) {\r
+ cTable[i] = (BYTE)max(0,min(255,(int)((i-128)*c + brightness + 0.5f)));\r
+ }\r
+\r
+ return Lut(cTable);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return mean lightness of the image. Useful with Threshold() and Light()\r
+ */\r
+float CxImage::Mean()\r
+{\r
+ if (!pDib) return 0;\r
+\r
+ CxImage tmp(*this,true);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ tmp.GrayScale();\r
+ float sum=0;\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+ if (xmin==xmax || ymin==ymax) return (float)0.0;\r
+\r
+ BYTE *iSrc=tmp.info.pImage;\r
+ iSrc += tmp.info.dwEffWidth*ymin; // necessary for selections <Admir Hodzic>\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin)); //<zhanghk><Anatoly Ivasyuk>\r
+ for(long x=xmin; x<xmax; x++){\r
+ sum+=iSrc[x];\r
+ }\r
+ iSrc+=tmp.info.dwEffWidth;\r
+ }\r
+ return sum/(xmax-xmin)/(ymax-ymin);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * 2D linear filter\r
+ * \param kernel: convolving matrix, in row format.\r
+ * \param Ksize: size of the kernel.\r
+ * \param Kfactor: normalization constant.\r
+ * \param Koffset: bias.\r
+ * \verbatim Example: the "soften" filter uses this kernel:\r
+ 1 1 1\r
+ 1 8 1\r
+ 1 1 1\r
+ the function needs: kernel={1,1,1,1,8,1,1,1,1}; Ksize=3; Kfactor=16; Koffset=0; \endverbatim\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Filter(long* kernel, long Ksize, long Kfactor, long Koffset)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long k2 = Ksize/2;\r
+ long kmax= Ksize-k2;\r
+ long r,g,b,i;\r
+ long ksumcur,ksumtot;\r
+ RGBQUAD c;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ ksumtot = 0;\r
+ for(long j=-k2;j<kmax;j++){\r
+ for(long k=-k2;k<kmax;k++){\r
+ ksumtot += kernel[(j+k2)+Ksize*(k+k2)];\r
+ }\r
+ }\r
+\r
+ if ((head.biBitCount==8) && IsGrayScale())\r
+ {\r
+ unsigned char* cPtr;\r
+ unsigned char* cPtr2; \r
+ int iCount;\r
+ int iY, iY2, iY1;\r
+ cPtr = info.pImage;\r
+ cPtr2 = (unsigned char *)tmp.info.pImage;\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ iY1 = y*info.dwEffWidth+xmin;\r
+ for(long x=xmin; x<xmax; x++, iY1++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ b=ksumcur=0;\r
+ iCount = 0;\r
+ iY2 = ((y-k2)*info.dwEffWidth);\r
+ for(long j=-k2;j<kmax;j++, iY2+=info.dwEffWidth)\r
+ {\r
+ if (0>(y+j) || (y+j)>=head.biHeight) continue;\r
+ iY = iY2+x;\r
+ for(long k=-k2;k<kmax;k++, iCount++)\r
+ {\r
+ if (0>(x+k) || (x+k)>=head.biWidth) continue;\r
+ i=kernel[iCount];\r
+ b += cPtr[iY+k] * i;\r
+ ksumcur += i;\r
+ }\r
+ }\r
+ if (Kfactor==0 || ksumcur==0){\r
+ cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b + Koffset)));\r
+ } else if (ksumtot == ksumcur) {\r
+ cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b/Kfactor + Koffset)));\r
+ } else {\r
+ cPtr2[iY1] = (BYTE)min(255, max(0,(int)((b*ksumtot)/(ksumcur*Kfactor) + Koffset)));\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+ #if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+ #endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ r=b=g=ksumcur=0;\r
+ for(long j=-k2;j<kmax;j++){\r
+ for(long k=-k2;k<kmax;k++){\r
+ if (!IsInside(x+j,y+k)) continue;\r
+ c = BlindGetPixelColor(x+j,y+k);\r
+ i = kernel[(j+k2)+Ksize*(k+k2)];\r
+ r += c.rgbRed * i;\r
+ g += c.rgbGreen * i;\r
+ b += c.rgbBlue * i;\r
+ ksumcur += i;\r
+ }\r
+ }\r
+ if (Kfactor==0 || ksumcur==0){\r
+ c.rgbRed = (BYTE)min(255, max(0,(int)(r + Koffset)));\r
+ c.rgbGreen = (BYTE)min(255, max(0,(int)(g + Koffset)));\r
+ c.rgbBlue = (BYTE)min(255, max(0,(int)(b + Koffset)));\r
+ } else if (ksumtot == ksumcur) {\r
+ c.rgbRed = (BYTE)min(255, max(0,(int)(r/Kfactor + Koffset)));\r
+ c.rgbGreen = (BYTE)min(255, max(0,(int)(g/Kfactor + Koffset)));\r
+ c.rgbBlue = (BYTE)min(255, max(0,(int)(b/Kfactor + Koffset)));\r
+ } else {\r
+ c.rgbRed = (BYTE)min(255, max(0,(int)((r*ksumtot)/(ksumcur*Kfactor) + Koffset)));\r
+ c.rgbGreen = (BYTE)min(255, max(0,(int)((g*ksumtot)/(ksumcur*Kfactor) + Koffset)));\r
+ c.rgbBlue = (BYTE)min(255, max(0,(int)((b*ksumtot)/(ksumcur*Kfactor) + Koffset)));\r
+ }\r
+ tmp.BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Enhance the dark areas of the image\r
+ * \param Ksize: size of the kernel.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Erode(long Ksize)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long k2 = Ksize/2;\r
+ long kmax= Ksize-k2;\r
+ BYTE r,g,b;\r
+ RGBQUAD c;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ r=b=g=255;\r
+ for(long j=-k2;j<kmax;j++){\r
+ for(long k=-k2;k<kmax;k++){\r
+ if (!IsInside(x+j,y+k)) continue;\r
+ c = BlindGetPixelColor(x+j,y+k);\r
+ if (c.rgbRed < r) r=c.rgbRed;\r
+ if (c.rgbGreen < g) g=c.rgbGreen;\r
+ if (c.rgbBlue < b) b=c.rgbBlue;\r
+ }\r
+ }\r
+ c.rgbRed = r;\r
+ c.rgbGreen = g;\r
+ c.rgbBlue = b;\r
+ tmp.BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Enhance the light areas of the image\r
+ * \param Ksize: size of the kernel.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Dilate(long Ksize)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long k2 = Ksize/2;\r
+ long kmax= Ksize-k2;\r
+ BYTE r,g,b;\r
+ RGBQUAD c;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ r=b=g=0;\r
+ for(long j=-k2;j<kmax;j++){\r
+ for(long k=-k2;k<kmax;k++){\r
+ if (!IsInside(x+j,y+k)) continue;\r
+ c = BlindGetPixelColor(x+j,y+k);\r
+ if (c.rgbRed > r) r=c.rgbRed;\r
+ if (c.rgbGreen > g) g=c.rgbGreen;\r
+ if (c.rgbBlue > b) b=c.rgbBlue;\r
+ }\r
+ }\r
+ c.rgbRed = r;\r
+ c.rgbGreen = g;\r
+ c.rgbBlue = b;\r
+ tmp.BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Enhance the variations between adjacent pixels.\r
+ * Similar results can be achieved using Filter(),\r
+ * but the algorithms are different both in Edge() and in Contour().\r
+ * \param Ksize: size of the kernel.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Edge(long Ksize)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long k2 = Ksize/2;\r
+ long kmax= Ksize-k2;\r
+ BYTE r,g,b,rr,gg,bb;\r
+ RGBQUAD c;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ r=b=g=0;\r
+ rr=bb=gg=255;\r
+ for(long j=-k2;j<kmax;j++){\r
+ for(long k=-k2;k<kmax;k++){\r
+ if (!IsInside(x+j,y+k)) continue;\r
+ c = BlindGetPixelColor(x+j,y+k);\r
+ if (c.rgbRed > r) r=c.rgbRed;\r
+ if (c.rgbGreen > g) g=c.rgbGreen;\r
+ if (c.rgbBlue > b) b=c.rgbBlue;\r
+\r
+ if (c.rgbRed < rr) rr=c.rgbRed;\r
+ if (c.rgbGreen < gg) gg=c.rgbGreen;\r
+ if (c.rgbBlue < bb) bb=c.rgbBlue;\r
+ }\r
+ }\r
+ c.rgbRed = (BYTE)(255-abs(r-rr));\r
+ c.rgbGreen = (BYTE)(255-abs(g-gg));\r
+ c.rgbBlue = (BYTE)(255-abs(b-bb));\r
+ tmp.BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Blends two images\r
+ * \param imgsrc2: image to be mixed with this\r
+ * \param op: blending method; see ImageOpType\r
+ * \param lXOffset, lYOffset: image displacement\r
+ * \param bMixAlpha: if true and imgsrc2 has a valid alpha layer, it will be mixed in the destination image.\r
+ * \return true if everything is ok\r
+ *\r
+ * thanks to Mwolski\r
+ */\r
+// \r
+void CxImage::Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset, long lYOffset, bool bMixAlpha)\r
+{\r
+ long lWide = min(GetWidth(),imgsrc2.GetWidth()-lXOffset);\r
+ long lHeight = min(GetHeight(),imgsrc2.GetHeight()-lYOffset);\r
+\r
+ bool bEditAlpha = imgsrc2.AlphaIsValid() & bMixAlpha;\r
+\r
+ if (bEditAlpha && AlphaIsValid()==false){\r
+ AlphaCreate();\r
+ }\r
+\r
+ RGBQUAD rgbBackgrnd1 = GetTransColor();\r
+ RGBQUAD rgb1, rgb2, rgbDest;\r
+\r
+ for(long lY=0;lY<lHeight;lY++)\r
+ {\r
+ info.nProgress = (long)(100*lY/head.biHeight);\r
+ if (info.nEscape) break;\r
+\r
+ for(long lX=0;lX<lWide;lX++)\r
+ {\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsInside(lX,lY) && imgsrc2.SelectionIsInside(lX+lXOffset,lY+lYOffset))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ rgb1 = GetPixelColor(lX,lY);\r
+ rgb2 = imgsrc2.GetPixelColor(lX+lXOffset,lY+lYOffset);\r
+ switch(op)\r
+ {\r
+ case OpAvg:\r
+ rgbDest.rgbBlue = (BYTE)((rgb1.rgbBlue+rgb2.rgbBlue)/2);\r
+ rgbDest.rgbGreen = (BYTE)((rgb1.rgbGreen+rgb2.rgbGreen)/2);\r
+ rgbDest.rgbRed = (BYTE)((rgb1.rgbRed+rgb2.rgbRed)/2);\r
+ if (bEditAlpha) rgbDest.rgbReserved = (BYTE)((rgb1.rgbReserved+rgb2.rgbReserved)/2);\r
+ break;\r
+ case OpAdd:\r
+ rgbDest.rgbBlue = (BYTE)max(0,min(255,rgb1.rgbBlue+rgb2.rgbBlue));\r
+ rgbDest.rgbGreen = (BYTE)max(0,min(255,rgb1.rgbGreen+rgb2.rgbGreen));\r
+ rgbDest.rgbRed = (BYTE)max(0,min(255,rgb1.rgbRed+rgb2.rgbRed));\r
+ if (bEditAlpha) rgbDest.rgbReserved = (BYTE)max(0,min(255,rgb1.rgbReserved+rgb2.rgbReserved));\r
+ break;\r
+ case OpSub:\r
+ rgbDest.rgbBlue = (BYTE)max(0,min(255,rgb1.rgbBlue-rgb2.rgbBlue));\r
+ rgbDest.rgbGreen = (BYTE)max(0,min(255,rgb1.rgbGreen-rgb2.rgbGreen));\r
+ rgbDest.rgbRed = (BYTE)max(0,min(255,rgb1.rgbRed-rgb2.rgbRed));\r
+ if (bEditAlpha) rgbDest.rgbReserved = (BYTE)max(0,min(255,rgb1.rgbReserved-rgb2.rgbReserved));\r
+ break;\r
+ case OpAnd:\r
+ rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue&rgb2.rgbBlue);\r
+ rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen&rgb2.rgbGreen);\r
+ rgbDest.rgbRed = (BYTE)(rgb1.rgbRed&rgb2.rgbRed);\r
+ if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved&rgb2.rgbReserved);\r
+ break;\r
+ case OpXor:\r
+ rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue^rgb2.rgbBlue);\r
+ rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen^rgb2.rgbGreen);\r
+ rgbDest.rgbRed = (BYTE)(rgb1.rgbRed^rgb2.rgbRed);\r
+ if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved^rgb2.rgbReserved);\r
+ break;\r
+ case OpOr:\r
+ rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue|rgb2.rgbBlue);\r
+ rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen|rgb2.rgbGreen);\r
+ rgbDest.rgbRed = (BYTE)(rgb1.rgbRed|rgb2.rgbRed);\r
+ if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved|rgb2.rgbReserved);\r
+ break;\r
+ case OpMask:\r
+ if(rgb2.rgbBlue==0 && rgb2.rgbGreen==0 && rgb2.rgbRed==0)\r
+ rgbDest = rgbBackgrnd1;\r
+ else\r
+ rgbDest = rgb1;\r
+ break;\r
+ case OpSrcCopy:\r
+ if(IsTransparent(lX,lY))\r
+ rgbDest = rgb2;\r
+ else // copy straight over\r
+ rgbDest = rgb1;\r
+ break;\r
+ case OpDstCopy:\r
+ if(imgsrc2.IsTransparent(lX+lXOffset,lY+lYOffset))\r
+ rgbDest = rgb1;\r
+ else // copy straight over\r
+ rgbDest = rgb2;\r
+ break;\r
+ case OpScreen:\r
+ { \r
+ BYTE a,a1; \r
+ \r
+ if (imgsrc2.IsTransparent(lX+lXOffset,lY+lYOffset)){\r
+ a=0;\r
+ } else if (imgsrc2.AlphaIsValid()){\r
+ a=imgsrc2.AlphaGet(lX+lXOffset,lY+lYOffset);\r
+ a =(BYTE)((a*imgsrc2.info.nAlphaMax)/255);\r
+ } else {\r
+ a=255;\r
+ }\r
+\r
+ if (a==0){ //transparent \r
+ rgbDest = rgb1; \r
+ } else if (a==255){ //opaque \r
+ rgbDest = rgb2; \r
+ } else { //blend \r
+ a1 = (BYTE)~a; \r
+ rgbDest.rgbBlue = (BYTE)((rgb1.rgbBlue*a1+rgb2.rgbBlue*a)/255); \r
+ rgbDest.rgbGreen = (BYTE)((rgb1.rgbGreen*a1+rgb2.rgbGreen*a)/255); \r
+ rgbDest.rgbRed = (BYTE)((rgb1.rgbRed*a1+rgb2.rgbRed*a)/255); \r
+ }\r
+\r
+ if (bEditAlpha) rgbDest.rgbReserved = (BYTE)((rgb1.rgbReserved*a)/255);\r
+ } \r
+ break; \r
+ case OpSrcBlend:\r
+ if(IsTransparent(lX,lY))\r
+ rgbDest = rgb2;\r
+ else\r
+ {\r
+ long lBDiff = abs(rgb1.rgbBlue - rgbBackgrnd1.rgbBlue);\r
+ long lGDiff = abs(rgb1.rgbGreen - rgbBackgrnd1.rgbGreen);\r
+ long lRDiff = abs(rgb1.rgbRed - rgbBackgrnd1.rgbRed);\r
+\r
+ double lAverage = (lBDiff+lGDiff+lRDiff)/3;\r
+ double lThresh = 16;\r
+ double dLarge = lAverage/lThresh;\r
+ double dSmall = (lThresh-lAverage)/lThresh;\r
+ double dSmallAmt = dSmall*((double)rgb2.rgbBlue);\r
+\r
+ if( lAverage < lThresh+1){\r
+ rgbDest.rgbBlue = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbBlue) +\r
+ dSmallAmt)));\r
+ rgbDest.rgbGreen = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbGreen) +\r
+ dSmallAmt)));\r
+ rgbDest.rgbRed = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbRed) +\r
+ dSmallAmt)));\r
+ }\r
+ else\r
+ rgbDest = rgb1;\r
+ }\r
+ break;\r
+ default:\r
+ return;\r
+ }\r
+ SetPixelColor(lX,lY,rgbDest,bEditAlpha);\r
+ }\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// thanks to Kenneth Ballard\r
+void CxImage::MixFrom(CxImage & imagesrc2, long lXOffset, long lYOffset)\r
+{\r
+ long width = imagesrc2.GetWidth();\r
+ long height = imagesrc2.GetHeight();\r
+\r
+ int x, y;\r
+\r
+ if (imagesrc2.IsTransparent()) {\r
+ for(x = 0; x < width; x++) {\r
+ for(y = 0; y < height; y++) {\r
+ if(!imagesrc2.IsTransparent(x,y)){\r
+ SetPixelColor(x + lXOffset, y + lYOffset, imagesrc2.BlindGetPixelColor(x, y));\r
+ }\r
+ }\r
+ }\r
+ } else { //no transparency so just set it <Matt>\r
+ for(x = 0; x < width; x++) {\r
+ for(y = 0; y < height; y++) {\r
+ SetPixelColor(x + lXOffset, y + lYOffset, imagesrc2.BlindGetPixelColor(x, y)); \r
+ }\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adjusts separately the red, green, and blue values in the image.\r
+ * \param r, g, b: can be from -255 to +255.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::ShiftRGB(long r, long g, long b)\r
+{\r
+ if (!pDib) return false;\r
+ RGBQUAD color;\r
+ if (head.biClrUsed==0){\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ color = BlindGetPixelColor(x,y);\r
+ color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + r)));\r
+ color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + g)));\r
+ color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + b)));\r
+ BlindSetPixelColor(x,y,color);\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ for(DWORD j=0; j<head.biClrUsed; j++){\r
+ color = GetPaletteColor((BYTE)j);\r
+ color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + r)));\r
+ color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + g)));\r
+ color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + b)));\r
+ SetPaletteColor((BYTE)j,color);\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adjusts the color balance of the image\r
+ * \param gamma can be from 0.1 to 5.\r
+ * \return true if everything is ok\r
+ * \sa GammaRGB\r
+ */\r
+bool CxImage::Gamma(float gamma)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ if (gamma <= 0.0f) return false;\r
+\r
+ double dinvgamma = 1/gamma;\r
+ double dMax = pow(255.0, dinvgamma) / 255.0;\r
+\r
+ BYTE cTable[256]; //<nipper>\r
+ for (int i=0;i<256;i++) {\r
+ cTable[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax)));\r
+ }\r
+\r
+ return Lut(cTable);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adjusts the color balance indipendent for each color channel\r
+ * \param gammaR, gammaG, gammaB can be from 0.1 to 5.\r
+ * \return true if everything is ok\r
+ * \sa Gamma\r
+ */\r
+bool CxImage::GammaRGB(float gammaR, float gammaG, float gammaB)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ if (gammaR <= 0.0f) return false;\r
+ if (gammaG <= 0.0f) return false;\r
+ if (gammaB <= 0.0f) return false;\r
+\r
+ double dinvgamma, dMax;\r
+ int i;\r
+\r
+ dinvgamma = 1/gammaR;\r
+ dMax = pow(255.0, dinvgamma) / 255.0;\r
+ BYTE cTableR[256];\r
+ for (i=0;i<256;i++) {\r
+ cTableR[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax)));\r
+ }\r
+\r
+ dinvgamma = 1/gammaG;\r
+ dMax = pow(255.0, dinvgamma) / 255.0;\r
+ BYTE cTableG[256];\r
+ for (i=0;i<256;i++) {\r
+ cTableG[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax)));\r
+ }\r
+\r
+ dinvgamma = 1/gammaB;\r
+ dMax = pow(255.0, dinvgamma) / 255.0;\r
+ BYTE cTableB[256];\r
+ for (i=0;i<256;i++) {\r
+ cTableB[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax)));\r
+ }\r
+\r
+ return Lut(cTableR, cTableG, cTableB);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+//#if !defined (_WIN32_WCE)\r
+/**\r
+ * Adjusts the intensity of each pixel to the median intensity of its surrounding pixels.\r
+ * \param Ksize: size of the kernel.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Median(long Ksize)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long k2 = Ksize/2;\r
+ long kmax= Ksize-k2;\r
+ long i,j,k;\r
+\r
+ RGBQUAD* kernel = (RGBQUAD*)malloc(Ksize*Ksize*sizeof(RGBQUAD));\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ for(j=-k2, i=0;j<kmax;j++)\r
+ for(k=-k2;k<kmax;k++)\r
+ if (IsInside(x+j,y+k))\r
+ kernel[i++]=BlindGetPixelColor(x+j,y+k);\r
+\r
+ qsort(kernel, i, sizeof(RGBQUAD), CompareColors);\r
+ tmp.SetPixelColor(x,y,kernel[i/2]);\r
+ }\r
+ }\r
+ }\r
+ free(kernel);\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+//#endif //_WIN32_WCE\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adds an uniform noise to the image\r
+ * \param level: can be from 0 (no noise) to 255 (lot of noise).\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Noise(long level)\r
+{\r
+ if (!pDib) return false;\r
+ RGBQUAD color;\r
+\r
+ long xmin,xmax,ymin,ymax,n;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin)); //<zhanghk><Anatoly Ivasyuk>\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ color = BlindGetPixelColor(x,y);\r
+ n=(long)((rand()/(float)RAND_MAX - 0.5)*level);\r
+ color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + n)));\r
+ n=(long)((rand()/(float)RAND_MAX - 0.5)*level);\r
+ color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + n)));\r
+ n=(long)((rand()/(float)RAND_MAX - 0.5)*level);\r
+ color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + n)));\r
+ BlindSetPixelColor(x,y,color);\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Computes the bidimensional FFT or DFT of the image.\r
+ * - The images are processed as grayscale\r
+ * - If the dimensions of the image are a power of, 2 the FFT is performed automatically.\r
+ * - If dstReal and/or dstImag are NULL, the resulting images replaces the original(s).\r
+ * - Note: with 8 bits there is a HUGE loss in the dynamics. The function tries\r
+ * to keep an acceptable SNR, but 8bit = 48dB...\r
+ *\r
+ * \param srcReal, srcImag: source images: One can be NULL, but not both\r
+ * \param dstReal, dstImag: destination images. Can be NULL.\r
+ * \param direction: 1 = forward, -1 = inverse.\r
+ * \param bForceFFT: if true, the images are resampled to make the dimensions a power of 2.\r
+ * \param bMagnitude: if true, the real part returns the magnitude, the imaginary part returns the phase\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::FFT2(CxImage* srcReal, CxImage* srcImag, CxImage* dstReal, CxImage* dstImag,\r
+ long direction, bool bForceFFT, bool bMagnitude)\r
+{\r
+ //check if there is something to convert\r
+ if (srcReal==NULL && srcImag==NULL) return false;\r
+\r
+ long w,h;\r
+ //get width and height\r
+ if (srcReal) {\r
+ w=srcReal->GetWidth();\r
+ h=srcReal->GetHeight();\r
+ } else {\r
+ w=srcImag->GetWidth();\r
+ h=srcImag->GetHeight();\r
+ }\r
+\r
+ bool bXpow2 = IsPowerof2(w);\r
+ bool bYpow2 = IsPowerof2(h);\r
+ //if bForceFFT, width AND height must be powers of 2\r
+ if (bForceFFT && !(bXpow2 && bYpow2)) {\r
+ long i;\r
+ \r
+ i=0;\r
+ while((1<<i)<w) i++;\r
+ w=1<<i;\r
+ bXpow2=true;\r
+\r
+ i=0;\r
+ while((1<<i)<h) i++;\r
+ h=1<<i;\r
+ bYpow2=true;\r
+ }\r
+\r
+ // I/O images for FFT\r
+ CxImage *tmpReal,*tmpImag;\r
+\r
+ // select output\r
+ tmpReal = (dstReal) ? dstReal : srcReal;\r
+ tmpImag = (dstImag) ? dstImag : srcImag;\r
+\r
+ // src!=dst -> copy the image\r
+ if (srcReal && dstReal) tmpReal->Copy(*srcReal,true,false,false);\r
+ if (srcImag && dstImag) tmpImag->Copy(*srcImag,true,false,false);\r
+\r
+ // dst&&src are empty -> create new one, else turn to GrayScale\r
+ if (srcReal==0 && dstReal==0){\r
+ tmpReal = new CxImage(w,h,8);\r
+ tmpReal->Clear(0);\r
+ tmpReal->SetGrayPalette();\r
+ } else {\r
+ if (!tmpReal->IsGrayScale()) tmpReal->GrayScale();\r
+ }\r
+ if (srcImag==0 && dstImag==0){\r
+ tmpImag = new CxImage(w,h,8);\r
+ tmpImag->Clear(0);\r
+ tmpImag->SetGrayPalette();\r
+ } else {\r
+ if (!tmpImag->IsGrayScale()) tmpImag->GrayScale();\r
+ }\r
+\r
+ if (!(tmpReal->IsValid() && tmpImag->IsValid())){\r
+ if (srcReal==0 && dstReal==0) delete tmpReal;\r
+ if (srcImag==0 && dstImag==0) delete tmpImag;\r
+ return false;\r
+ }\r
+\r
+ //resample for FFT, if necessary \r
+ tmpReal->Resample(w,h,0);\r
+ tmpImag->Resample(w,h,0);\r
+\r
+ //ok, here we have 2 (w x h), grayscale images ready for a FFT\r
+\r
+ double* real;\r
+ double* imag;\r
+ long j,k,m;\r
+\r
+ _complex **grid;\r
+ //double mean = tmpReal->Mean();\r
+ /* Allocate memory for the grid */\r
+ grid = (_complex **)malloc(w * sizeof(_complex));\r
+ for (k=0;k<w;k++) {\r
+ grid[k] = (_complex *)malloc(h * sizeof(_complex));\r
+ }\r
+ for (j=0;j<h;j++) {\r
+ for (k=0;k<w;k++) {\r
+ grid[k][j].x = tmpReal->GetPixelIndex(k,j)-128;\r
+ grid[k][j].y = tmpImag->GetPixelIndex(k,j)-128;\r
+ }\r
+ }\r
+\r
+ //DFT buffers\r
+ double *real2,*imag2;\r
+ real2 = (double*)malloc(max(w,h) * sizeof(double));\r
+ imag2 = (double*)malloc(max(w,h) * sizeof(double));\r
+\r
+ /* Transform the rows */\r
+ real = (double *)malloc(w * sizeof(double));\r
+ imag = (double *)malloc(w * sizeof(double));\r
+\r
+ m=0;\r
+ while((1<<m)<w) m++;\r
+\r
+ for (j=0;j<h;j++) {\r
+ for (k=0;k<w;k++) {\r
+ real[k] = grid[k][j].x;\r
+ imag[k] = grid[k][j].y;\r
+ }\r
+\r
+ if (bXpow2) FFT(direction,m,real,imag);\r
+ else DFT(direction,w,real,imag,real2,imag2);\r
+\r
+ for (k=0;k<w;k++) {\r
+ grid[k][j].x = real[k];\r
+ grid[k][j].y = imag[k];\r
+ }\r
+ }\r
+ free(real);\r
+ free(imag);\r
+\r
+ /* Transform the columns */\r
+ real = (double *)malloc(h * sizeof(double));\r
+ imag = (double *)malloc(h * sizeof(double));\r
+\r
+ m=0;\r
+ while((1<<m)<h) m++;\r
+\r
+ for (k=0;k<w;k++) {\r
+ for (j=0;j<h;j++) {\r
+ real[j] = grid[k][j].x;\r
+ imag[j] = grid[k][j].y;\r
+ }\r
+\r
+ if (bYpow2) FFT(direction,m,real,imag);\r
+ else DFT(direction,h,real,imag,real2,imag2);\r
+\r
+ for (j=0;j<h;j++) {\r
+ grid[k][j].x = real[j];\r
+ grid[k][j].y = imag[j];\r
+ }\r
+ }\r
+ free(real);\r
+ free(imag);\r
+\r
+ free(real2);\r
+ free(imag2);\r
+\r
+ /* converting from double to byte, there is a HUGE loss in the dynamics\r
+ "nn" tries to keep an acceptable SNR, but 8bit=48dB: don't ask more */\r
+ double nn=pow((double)2,(double)log((double)max(w,h))/(double)log((double)2)-4);\r
+ //reversed gain for reversed transform\r
+ if (direction==-1) nn=1/nn;\r
+ //bMagnitude : just to see it on the screen\r
+ if (bMagnitude) nn*=4;\r
+\r
+ for (j=0;j<h;j++) {\r
+ for (k=0;k<w;k++) {\r
+ if (bMagnitude){\r
+ tmpReal->SetPixelIndex(k,j,(BYTE)max(0,min(255,(nn*(3+log(_cabs(grid[k][j])))))));\r
+ if (grid[k][j].x==0){\r
+ tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/0.0000000001)*nn)))));\r
+ } else {\r
+ tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128+(atan(grid[k][j].y/grid[k][j].x)*nn)))));\r
+ }\r
+ } else {\r
+ tmpReal->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].x*nn))));\r
+ tmpImag->SetPixelIndex(k,j,(BYTE)max(0,min(255,(128 + grid[k][j].y*nn))));\r
+ }\r
+ }\r
+ }\r
+\r
+ for (k=0;k<w;k++) free (grid[k]);\r
+ free (grid);\r
+\r
+ if (srcReal==0 && dstReal==0) delete tmpReal;\r
+ if (srcImag==0 && dstImag==0) delete tmpImag;\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::IsPowerof2(long x)\r
+{\r
+ long i=0;\r
+ while ((1<<i)<x) i++;\r
+ if (x==(1<<i)) return true;\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ This computes an in-place complex-to-complex FFT \r
+ x and y are the real and imaginary arrays of n=2^m points.\r
+ o(n)=n*log2(n)\r
+ dir = 1 gives forward transform\r
+ dir = -1 gives reverse transform \r
+ Written by Paul Bourke, July 1998\r
+ FFT algorithm by Cooley and Tukey, 1965 \r
+*/\r
+bool CxImage::FFT(int dir,int m,double *x,double *y)\r
+{\r
+ long nn,i,i1,j,k,i2,l,l1,l2;\r
+ double c1,c2,tx,ty,t1,t2,u1,u2,z;\r
+\r
+ /* Calculate the number of points */\r
+ nn = 1<<m;\r
+\r
+ /* Do the bit reversal */\r
+ i2 = nn >> 1;\r
+ j = 0;\r
+ for (i=0;i<nn-1;i++) {\r
+ if (i < j) {\r
+ tx = x[i];\r
+ ty = y[i];\r
+ x[i] = x[j];\r
+ y[i] = y[j];\r
+ x[j] = tx;\r
+ y[j] = ty;\r
+ }\r
+ k = i2;\r
+ while (k <= j) {\r
+ j -= k;\r
+ k >>= 1;\r
+ }\r
+ j += k;\r
+ }\r
+\r
+ /* Compute the FFT */\r
+ c1 = -1.0;\r
+ c2 = 0.0;\r
+ l2 = 1;\r
+ for (l=0;l<m;l++) {\r
+ l1 = l2;\r
+ l2 <<= 1;\r
+ u1 = 1.0;\r
+ u2 = 0.0;\r
+ for (j=0;j<l1;j++) {\r
+ for (i=j;i<nn;i+=l2) {\r
+ i1 = i + l1;\r
+ t1 = u1 * x[i1] - u2 * y[i1];\r
+ t2 = u1 * y[i1] + u2 * x[i1];\r
+ x[i1] = x[i] - t1;\r
+ y[i1] = y[i] - t2;\r
+ x[i] += t1;\r
+ y[i] += t2;\r
+ }\r
+ z = u1 * c1 - u2 * c2;\r
+ u2 = u1 * c2 + u2 * c1;\r
+ u1 = z;\r
+ }\r
+ c2 = sqrt((1.0 - c1) / 2.0);\r
+ if (dir == 1)\r
+ c2 = -c2;\r
+ c1 = sqrt((1.0 + c1) / 2.0);\r
+ }\r
+\r
+ /* Scaling for forward transform */\r
+ if (dir == 1) {\r
+ for (i=0;i<nn;i++) {\r
+ x[i] /= (double)nn;\r
+ y[i] /= (double)nn;\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ Direct fourier transform o(n)=n^2\r
+ Written by Paul Bourke, July 1998 \r
+*/\r
+bool CxImage::DFT(int dir,long m,double *x1,double *y1,double *x2,double *y2)\r
+{\r
+ long i,k;\r
+ double arg;\r
+ double cosarg,sinarg;\r
+ \r
+ for (i=0;i<m;i++) {\r
+ x2[i] = 0;\r
+ y2[i] = 0;\r
+ arg = - dir * 2.0 * PI * i / (double)m;\r
+ for (k=0;k<m;k++) {\r
+ cosarg = cos(k * arg);\r
+ sinarg = sin(k * arg);\r
+ x2[i] += (x1[k] * cosarg - y1[k] * sinarg);\r
+ y2[i] += (x1[k] * sinarg + y1[k] * cosarg);\r
+ }\r
+ }\r
+ \r
+ /* Copy the data back */\r
+ if (dir == 1) {\r
+ for (i=0;i<m;i++) {\r
+ x1[i] = x2[i] / m;\r
+ y1[i] = y2[i] / m;\r
+ }\r
+ } else {\r
+ for (i=0;i<m;i++) {\r
+ x1[i] = x2[i];\r
+ y1[i] = y2[i];\r
+ }\r
+ }\r
+ \r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Combines different color components into a single image\r
+ * \param r,g,b: color channels\r
+ * \param a: alpha layer, can be NULL\r
+ * \param colorspace: 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ \r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Combine(CxImage* r,CxImage* g,CxImage* b,CxImage* a, long colorspace)\r
+{\r
+ if (r==0 || g==0 || b==0) return false;\r
+\r
+ long w = r->GetWidth();\r
+ long h = r->GetHeight();\r
+\r
+ Create(w,h,24);\r
+\r
+ g->Resample(w,h);\r
+ b->Resample(w,h);\r
+\r
+ if (a) {\r
+ a->Resample(w,h);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+\r
+ RGBQUAD c;\r
+ for (long y=0;y<h;y++){\r
+ info.nProgress = (long)(100*y/h); //<Anatoly Ivasyuk>\r
+ for (long x=0;x<w;x++){\r
+ c.rgbRed=r->GetPixelIndex(x,y);\r
+ c.rgbGreen=g->GetPixelIndex(x,y);\r
+ c.rgbBlue=b->GetPixelIndex(x,y);\r
+ switch (colorspace){\r
+ case 1:\r
+ BlindSetPixelColor(x,y,HSLtoRGB(c));\r
+ break;\r
+ case 2:\r
+ BlindSetPixelColor(x,y,YUVtoRGB(c));\r
+ break;\r
+ case 3:\r
+ BlindSetPixelColor(x,y,YIQtoRGB(c));\r
+ break;\r
+ case 4:\r
+ BlindSetPixelColor(x,y,XYZtoRGB(c));\r
+ break;\r
+ default:\r
+ BlindSetPixelColor(x,y,c);\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (a) AlphaSet(x,y,a->GetPixelIndex(x,y));\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Smart blurring to remove small defects, dithering or artifacts.\r
+ * \param radius: normally between 0.01 and 0.5\r
+ * \param niterations: should be trimmed with radius, to avoid blurring should be (radius*niterations)<1\r
+ * \param colorspace: 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ \r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Repair(float radius, long niterations, long colorspace)\r
+{\r
+ if (!IsValid()) return false;\r
+\r
+ long w = GetWidth();\r
+ long h = GetHeight();\r
+\r
+ CxImage r,g,b;\r
+\r
+ r.Create(w,h,8);\r
+ g.Create(w,h,8);\r
+ b.Create(w,h,8);\r
+\r
+ switch (colorspace){\r
+ case 1:\r
+ SplitHSL(&r,&g,&b);\r
+ break;\r
+ case 2:\r
+ SplitYUV(&r,&g,&b);\r
+ break;\r
+ case 3:\r
+ SplitYIQ(&r,&g,&b);\r
+ break;\r
+ case 4:\r
+ SplitXYZ(&r,&g,&b);\r
+ break;\r
+ default:\r
+ SplitRGB(&r,&g,&b);\r
+ }\r
+ \r
+ for (int i=0; i<niterations; i++){\r
+ RepairChannel(&r,radius);\r
+ RepairChannel(&g,radius);\r
+ RepairChannel(&b,radius);\r
+ }\r
+\r
+ CxImage* a=NULL;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()){\r
+ a = new CxImage();\r
+ AlphaSplit(a);\r
+ }\r
+#endif\r
+\r
+ Combine(&r,&g,&b,a,colorspace);\r
+\r
+ delete a;\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::RepairChannel(CxImage *ch, float radius)\r
+{\r
+ if (ch==NULL) return false;\r
+\r
+ CxImage tmp(*ch);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long w = ch->GetWidth()-1;\r
+ long h = ch->GetHeight()-1;\r
+\r
+ double correction,ix,iy,ixx,ixy,iyy;\r
+ int x,y,xy0,xp1,xm1,yp1,ym1;\r
+\r
+ for(x=1; x<w; x++){\r
+ for(y=1; y<h; y++){\r
+\r
+ xy0 = ch->BlindGetPixelIndex(x,y);\r
+ xm1 = ch->BlindGetPixelIndex(x-1,y);\r
+ xp1 = ch->BlindGetPixelIndex(x+1,y);\r
+ ym1 = ch->BlindGetPixelIndex(x,y-1);\r
+ yp1 = ch->BlindGetPixelIndex(x,y+1);\r
+\r
+ ix= (xp1-xm1)/2.0;\r
+ iy= (yp1-ym1)/2.0;\r
+ ixx= xp1 - 2.0 * xy0 + xm1;\r
+ iyy= yp1 - 2.0 * xy0 + ym1;\r
+ ixy=(ch->BlindGetPixelIndex(x+1,y+1) + ch->BlindGetPixelIndex(x-1,y-1) -\r
+ ch->BlindGetPixelIndex(x-1,y+1) - ch->BlindGetPixelIndex(x+1,y-1))/4.0;\r
+\r
+ correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy);\r
+\r
+ tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5))));\r
+ }\r
+ }\r
+\r
+ for (x=0;x<=w;x++){\r
+ for(y=0; y<=h; y+=h){\r
+ xy0 = ch->BlindGetPixelIndex(x,y);\r
+ xm1 = ch->GetPixelIndex(x-1,y);\r
+ xp1 = ch->GetPixelIndex(x+1,y);\r
+ ym1 = ch->GetPixelIndex(x,y-1);\r
+ yp1 = ch->GetPixelIndex(x,y+1);\r
+\r
+ ix= (xp1-xm1)/2.0;\r
+ iy= (yp1-ym1)/2.0;\r
+ ixx= xp1 - 2.0 * xy0 + xm1;\r
+ iyy= yp1 - 2.0 * xy0 + ym1;\r
+ ixy=(ch->GetPixelIndex(x+1,y+1) + ch->GetPixelIndex(x-1,y-1) -\r
+ ch->GetPixelIndex(x-1,y+1) - ch->GetPixelIndex(x+1,y-1))/4.0;\r
+\r
+ correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy);\r
+\r
+ tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5))));\r
+ }\r
+ }\r
+ for (x=0;x<=w;x+=w){\r
+ for (y=0;y<=h;y++){\r
+ xy0 = ch->BlindGetPixelIndex(x,y);\r
+ xm1 = ch->GetPixelIndex(x-1,y);\r
+ xp1 = ch->GetPixelIndex(x+1,y);\r
+ ym1 = ch->GetPixelIndex(x,y-1);\r
+ yp1 = ch->GetPixelIndex(x,y+1);\r
+\r
+ ix= (xp1-xm1)/2.0;\r
+ iy= (yp1-ym1)/2.0;\r
+ ixx= xp1 - 2.0 * xy0 + xm1;\r
+ iyy= yp1 - 2.0 * xy0 + ym1;\r
+ ixy=(ch->GetPixelIndex(x+1,y+1) + ch->GetPixelIndex(x-1,y-1) -\r
+ ch->GetPixelIndex(x-1,y+1) - ch->GetPixelIndex(x+1,y-1))/4.0;\r
+\r
+ correction = ((1.0+iy*iy)*ixx - ix*iy*ixy + (1.0+ix*ix)*iyy)/(1.0+ix*ix+iy*iy);\r
+\r
+ tmp.BlindSetPixelIndex(x,y,(BYTE)min(255,max(0,(xy0 + radius * correction + 0.5))));\r
+ }\r
+ }\r
+\r
+ ch->Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Enhance the variations between adjacent pixels.\r
+ * Similar results can be achieved using Filter(),\r
+ * but the algorithms are different both in Edge() and in Contour().\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Contour()\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long Ksize = 3;\r
+ long k2 = Ksize/2;\r
+ long kmax= Ksize-k2;\r
+ long i,j,k;\r
+ BYTE maxr,maxg,maxb;\r
+ RGBQUAD pix1,pix2;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ pix1 = BlindGetPixelColor(x,y);\r
+ maxr=maxg=maxb=0;\r
+ for(j=-k2, i=0;j<kmax;j++){\r
+ for(k=-k2;k<kmax;k++, i++){\r
+ if (!IsInside(x+j,y+k)) continue;\r
+ pix2 = BlindGetPixelColor(x+j,y+k);\r
+ if ((pix2.rgbBlue-pix1.rgbBlue)>maxb) maxb = pix2.rgbBlue;\r
+ if ((pix2.rgbGreen-pix1.rgbGreen)>maxg) maxg = pix2.rgbGreen;\r
+ if ((pix2.rgbRed-pix1.rgbRed)>maxr) maxr = pix2.rgbRed;\r
+ }\r
+ }\r
+ pix1.rgbBlue=(BYTE)(255-maxb);\r
+ pix1.rgbGreen=(BYTE)(255-maxg);\r
+ pix1.rgbRed=(BYTE)(255-maxr);\r
+ tmp.BlindSetPixelColor(x,y,pix1);\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adds a random offset to each pixel in the image\r
+ * \param radius: maximum pixel displacement\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Jitter(long radius)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long nx,ny;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ nx=x+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));\r
+ ny=y+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));\r
+ if (!IsInside(nx,ny)) {\r
+ nx=x;\r
+ ny=y;\r
+ }\r
+ if (head.biClrUsed==0){\r
+ tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(nx,ny));\r
+ } else {\r
+ tmp.BlindSetPixelIndex(x,y,BlindGetPixelIndex(nx,ny));\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaSet(x,y,AlphaGet(nx,ny));\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/** \r
+ * generates a 1-D convolution matrix to be used for each pass of \r
+ * a two-pass gaussian blur. Returns the length of the matrix.\r
+ * \author [nipper]\r
+ */\r
+int CxImage::gen_convolve_matrix (float radius, float **cmatrix_p)\r
+{\r
+ int matrix_length;\r
+ int matrix_midpoint;\r
+ float* cmatrix;\r
+ int i,j;\r
+ float std_dev;\r
+ float sum;\r
+ \r
+ /* we want to generate a matrix that goes out a certain radius\r
+ * from the center, so we have to go out ceil(rad-0.5) pixels,\r
+ * inlcuding the center pixel. Of course, that's only in one direction,\r
+ * so we have to go the same amount in the other direction, but not count\r
+ * the center pixel again. So we double the previous result and subtract\r
+ * one.\r
+ * The radius parameter that is passed to this function is used as\r
+ * the standard deviation, and the radius of effect is the\r
+ * standard deviation * 2. It's a little confusing.\r
+ * <DP> modified scaling, so that matrix_lenght = 1+2*radius parameter\r
+ */\r
+ radius = (float)fabs(0.5*radius) + 0.25f;\r
+ \r
+ std_dev = radius;\r
+ radius = std_dev * 2;\r
+ \r
+ /* go out 'radius' in each direction */\r
+ matrix_length = int (2 * ceil(radius-0.5) + 1);\r
+ if (matrix_length <= 0) matrix_length = 1;\r
+ matrix_midpoint = matrix_length/2 + 1;\r
+ *cmatrix_p = new float[matrix_length];\r
+ cmatrix = *cmatrix_p;\r
+ \r
+ /* Now we fill the matrix by doing a numeric integration approximation\r
+ * from -2*std_dev to 2*std_dev, sampling 50 points per pixel.\r
+ * We do the bottom half, mirror it to the top half, then compute the\r
+ * center point. Otherwise asymmetric quantization errors will occur.\r
+ * The formula to integrate is e^-(x^2/2s^2).\r
+ */\r
+ \r
+ /* first we do the top (right) half of matrix */\r
+ for (i = matrix_length/2 + 1; i < matrix_length; i++)\r
+ {\r
+ float base_x = i - (float)floor((float)(matrix_length/2)) - 0.5f;\r
+ sum = 0;\r
+ for (j = 1; j <= 50; j++)\r
+ {\r
+ if ( base_x+0.02*j <= radius ) \r
+ sum += (float)exp (-(base_x+0.02*j)*(base_x+0.02*j) / \r
+ (2*std_dev*std_dev));\r
+ }\r
+ cmatrix[i] = sum/50;\r
+ }\r
+ \r
+ /* mirror the thing to the bottom half */\r
+ for (i=0; i<=matrix_length/2; i++) {\r
+ cmatrix[i] = cmatrix[matrix_length-1-i];\r
+ }\r
+ \r
+ /* find center val -- calculate an odd number of quanta to make it symmetric,\r
+ * even if the center point is weighted slightly higher than others. */\r
+ sum = 0;\r
+ for (j=0; j<=50; j++)\r
+ {\r
+ sum += (float)exp (-(0.5+0.02*j)*(0.5+0.02*j) /\r
+ (2*std_dev*std_dev));\r
+ }\r
+ cmatrix[matrix_length/2] = sum/51;\r
+ \r
+ /* normalize the distribution by scaling the total sum to one */\r
+ sum=0;\r
+ for (i=0; i<matrix_length; i++) sum += cmatrix[i];\r
+ for (i=0; i<matrix_length; i++) cmatrix[i] = cmatrix[i] / sum;\r
+ \r
+ return matrix_length;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * generates a lookup table for every possible product of 0-255 and\r
+ * each value in the convolution matrix. The returned array is\r
+ * indexed first by matrix position, then by input multiplicand (?)\r
+ * value.\r
+ * \author [nipper]\r
+ */\r
+float* CxImage::gen_lookup_table (float *cmatrix, int cmatrix_length)\r
+{\r
+ float* lookup_table = new float[cmatrix_length * 256];\r
+ float* lookup_table_p = lookup_table;\r
+ float* cmatrix_p = cmatrix;\r
+ \r
+ for (int i=0; i<cmatrix_length; i++)\r
+ {\r
+ for (int j=0; j<256; j++)\r
+ {\r
+ *(lookup_table_p++) = *cmatrix_p * (float)j;\r
+ }\r
+ cmatrix_p++;\r
+ }\r
+ \r
+ return lookup_table;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * this function is written as if it is blurring a column at a time,\r
+ * even though it can operate on rows, too. There is no difference\r
+ * in the processing of the lines, at least to the blur_line function.\r
+ * \author [nipper]\r
+ */\r
+void CxImage::blur_line (float *ctable, float *cmatrix, int cmatrix_length, BYTE* cur_col, BYTE* dest_col, int y, long bytes)\r
+{\r
+ float scale;\r
+ float sum;\r
+ int i=0, j=0;\r
+ int row;\r
+ int cmatrix_middle = cmatrix_length/2;\r
+ \r
+ float *cmatrix_p;\r
+ BYTE *cur_col_p;\r
+ BYTE *cur_col_p1;\r
+ BYTE *dest_col_p;\r
+ float *ctable_p;\r
+ \r
+ /* this first block is the same as the non-optimized version --\r
+ * it is only used for very small pictures, so speed isn't a\r
+ * big concern.\r
+ */\r
+ if (cmatrix_length > y)\r
+ {\r
+ for (row = 0; row < y ; row++)\r
+ {\r
+ scale=0;\r
+ /* find the scale factor */\r
+ for (j = 0; j < y ; j++)\r
+ {\r
+ /* if the index is in bounds, add it to the scale counter */\r
+ if ((j + cmatrix_middle - row >= 0) &&\r
+ (j + cmatrix_middle - row < cmatrix_length))\r
+ scale += cmatrix[j + cmatrix_middle - row];\r
+ }\r
+ for (i = 0; i<bytes; i++)\r
+ {\r
+ sum = 0;\r
+ for (j = 0; j < y; j++)\r
+ {\r
+ if ((j >= row - cmatrix_middle) &&\r
+ (j <= row + cmatrix_middle))\r
+ sum += cur_col[j*bytes + i] * cmatrix[j];\r
+ }\r
+ dest_col[row*bytes + i] = (BYTE)(0.5f + sum / scale);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* for the edge condition, we only use available info and scale to one */\r
+ for (row = 0; row < cmatrix_middle; row++)\r
+ {\r
+ /* find scale factor */\r
+ scale=0;\r
+ for (j = cmatrix_middle - row; j<cmatrix_length; j++)\r
+ scale += cmatrix[j];\r
+ for (i = 0; i<bytes; i++)\r
+ {\r
+ sum = 0;\r
+ for (j = cmatrix_middle - row; j<cmatrix_length; j++)\r
+ {\r
+ sum += cur_col[(row + j-cmatrix_middle)*bytes + i] * cmatrix[j];\r
+ }\r
+ dest_col[row*bytes + i] = (BYTE)(0.5f + sum / scale);\r
+ }\r
+ }\r
+ /* go through each pixel in each col */\r
+ dest_col_p = dest_col + row*bytes;\r
+ for (; row < y-cmatrix_middle; row++)\r
+ {\r
+ cur_col_p = (row - cmatrix_middle) * bytes + cur_col;\r
+ for (i = 0; i<bytes; i++)\r
+ {\r
+ sum = 0;\r
+ cmatrix_p = cmatrix;\r
+ cur_col_p1 = cur_col_p;\r
+ ctable_p = ctable;\r
+ for (j = cmatrix_length; j>0; j--)\r
+ {\r
+ sum += *(ctable_p + *cur_col_p1);\r
+ cur_col_p1 += bytes;\r
+ ctable_p += 256;\r
+ }\r
+ cur_col_p++;\r
+ *(dest_col_p++) = (BYTE)(0.5f + sum);\r
+ }\r
+ }\r
+ \r
+ /* for the edge condition , we only use available info, and scale to one */\r
+ for (; row < y; row++)\r
+ {\r
+ /* find scale factor */\r
+ scale=0;\r
+ for (j = 0; j< y-row + cmatrix_middle; j++)\r
+ scale += cmatrix[j];\r
+ for (i = 0; i<bytes; i++)\r
+ {\r
+ sum = 0;\r
+ for (j = 0; j<y-row + cmatrix_middle; j++)\r
+ {\r
+ sum += cur_col[(row + j-cmatrix_middle)*bytes + i] * cmatrix[j];\r
+ }\r
+ dest_col[row*bytes + i] = (BYTE) (0.5f + sum / scale);\r
+ }\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \author [DP]\r
+ */\r
+void CxImage::blur_text (BYTE threshold, BYTE decay, BYTE max_depth, CxImage* iSrc, CxImage* iDst, BYTE bytes)\r
+{\r
+ long x,y,z,m;\r
+ BYTE *pSrc, *pSrc2, *pSrc3, *pDst;\r
+ BYTE step,n;\r
+ int pivot;\r
+\r
+ if (max_depth<1) max_depth = 1;\r
+\r
+ long nmin,nmax,xmin,xmax,ymin,ymax;\r
+ xmin = ymin = 0;\r
+ xmax = iSrc->head.biWidth;\r
+ ymax = iSrc->head.biHeight;\r
+\r
+ if (xmin==xmax || ymin==ymax) return;\r
+\r
+ nmin = xmin * bytes;\r
+ nmax = xmax * bytes;\r
+\r
+ CImageIterator itSrc(iSrc);\r
+ CImageIterator itTmp(iDst);\r
+\r
+ double dbScaler = 100.0f/(ymax-ymin)/bytes;\r
+\r
+ for (n=0; n<bytes; n++){\r
+ for (y=ymin+1;y<(ymax-1);y++)\r
+ {\r
+ if (info.nEscape) break;\r
+ info.nProgress = (long)((y-ymin)*dbScaler*(1+n));\r
+\r
+ pSrc = itSrc.GetRow(y);\r
+ pSrc2 = itSrc.GetRow(y+1);\r
+ pSrc3 = itSrc.GetRow(y-1);\r
+ pDst = itTmp.GetRow(y);\r
+\r
+ //scan left to right\r
+ for (x=n+nmin /*,i=xmin*/; x<(nmax-1); x+=bytes /*,i++*/)\r
+ {\r
+ z=x+bytes;\r
+ pivot = pSrc[z]-threshold;\r
+ //find upper corner\r
+ if (pSrc[x]<pivot && pSrc2[z]<pivot && pSrc3[x]>=pivot){\r
+ while (z<nmax && pSrc2[z]<pSrc[x+bytes] && pSrc[x+bytes]<=pSrc[z]){\r
+ z+=bytes;\r
+ }\r
+ m = z-x;\r
+ m = (decay>1) ? ((m/bytes)/decay+1) : m/bytes;\r
+ if (m>max_depth) m = max_depth;\r
+ step = (BYTE)((pSrc[x+bytes]-pSrc[x])/(m+1));\r
+ while (m-->1){\r
+ pDst[x+m*bytes] = (BYTE)(pDst[x]+(step*(m+1)));\r
+ }\r
+ }\r
+ //find lower corner\r
+ z=x+bytes;\r
+ if (pSrc[x]<pivot && pSrc3[z]<pivot && pSrc2[x]>=pivot){\r
+ while (z<nmax && pSrc3[z]<pSrc[x+bytes] && pSrc[x+bytes]<=pSrc[z]){\r
+ z+=bytes;\r
+ }\r
+ m = z-x;\r
+ m = (decay>1) ? ((m/bytes)/decay+1) : m/bytes;\r
+ if (m>max_depth) m = max_depth;\r
+ step = (BYTE)((pSrc[x+bytes]-pSrc[x])/(m+1));\r
+ while (m-->1){\r
+ pDst[x+m*bytes] = (BYTE)(pDst[x]+(step*(m+1)));\r
+ }\r
+ }\r
+ }\r
+ //scan right to left\r
+ for (x=nmax-1-n /*,i=(xmax-1)*/; x>0; x-=bytes /*,i--*/)\r
+ {\r
+ z=x-bytes;\r
+ pivot = pSrc[z]-threshold;\r
+ //find upper corner\r
+ if (pSrc[x]<pivot && pSrc2[z]<pivot && pSrc3[x]>=pivot){\r
+ while (z>n && pSrc2[z]<pSrc[x-bytes] && pSrc[x-bytes]<=pSrc[z]){\r
+ z-=bytes;\r
+ }\r
+ m = x-z;\r
+ m = (decay>1) ? ((m/bytes)/decay+1) : m/bytes;\r
+ if (m>max_depth) m = max_depth;\r
+ step = (BYTE)((pSrc[x-bytes]-pSrc[x])/(m+1));\r
+ while (m-->1){\r
+ pDst[x-m*bytes] = (BYTE)(pDst[x]+(step*(m+1)));\r
+ }\r
+ }\r
+ //find lower corner\r
+ z=x-bytes;\r
+ if (pSrc[x]<pivot && pSrc3[z]<pivot && pSrc2[x]>=pivot){\r
+ while (z>n && pSrc3[z]<pSrc[x-bytes] && pSrc[x-bytes]<=pSrc[z]){\r
+ z-=bytes;\r
+ }\r
+ m = x-z;\r
+ m = (decay>1) ? ((m/bytes)/decay+1) : m/bytes;\r
+ if (m>max_depth) m = max_depth;\r
+ step = (BYTE)((pSrc[x-bytes]-pSrc[x])/(m+1));\r
+ while (m-->1){\r
+ pDst[x-m*bytes] = (BYTE)(pDst[x]+(step*(m+1)));\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \author [DP]\r
+ */\r
+bool CxImage::TextBlur(BYTE threshold, BYTE decay, BYTE max_depth, bool bBlurHorizontal, bool bBlurVertical, CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ RGBQUAD* pPalette=NULL;\r
+ WORD bpp = GetBpp();\r
+\r
+ //the routine is optimized for RGB or GrayScale images\r
+ if (!(head.biBitCount == 24 || IsGrayScale())){\r
+ pPalette = new RGBQUAD[head.biClrUsed];\r
+ memcpy(pPalette, GetPalette(),GetPaletteSize());\r
+ if (!IncreaseBpp(24))\r
+ return false;\r
+ }\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ if (bBlurHorizontal)\r
+ blur_text(threshold, decay, max_depth, this, &tmp, head.biBitCount>>3);\r
+\r
+ if (bBlurVertical){\r
+ CxImage src2(*this);\r
+ src2.RotateLeft();\r
+ tmp.RotateLeft();\r
+ blur_text(threshold, decay, max_depth, &src2, &tmp, head.biBitCount>>3);\r
+ tmp.RotateRight();\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ //restore the non selected region\r
+ if (pSelection){\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ if (!BlindSelectionIsInside(x,y)){\r
+ tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y));\r
+ }\r
+ }\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+ //if necessary, restore the original BPP and palette\r
+ if (pPalette){\r
+ tmp.DecreaseBpp(bpp, true, pPalette);\r
+ delete [] pPalette;\r
+ }\r
+\r
+ if (iDst) iDst->Transfer(tmp);\r
+ else Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \author [nipper]; changes [DP]\r
+ */\r
+bool CxImage::GaussianBlur(float radius /*= 1.0f*/, CxImage* iDst /*= 0*/)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ RGBQUAD* pPalette=NULL;\r
+ WORD bpp = GetBpp();\r
+\r
+ //the routine is optimized for RGB or GrayScale images\r
+ if (!(head.biBitCount == 24 || IsGrayScale())){\r
+ pPalette = new RGBQUAD[head.biClrUsed];\r
+ memcpy(pPalette, GetPalette(),GetPaletteSize());\r
+ if (!IncreaseBpp(24))\r
+ return false;\r
+ }\r
+\r
+ CxImage tmp_x(*this, false, true, true);\r
+ if (!tmp_x.IsValid()){\r
+ strcpy(info.szLastError,tmp_x.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ // generate convolution matrix and make sure it's smaller than each dimension\r
+ float *cmatrix = NULL;\r
+ int cmatrix_length = gen_convolve_matrix(radius, &cmatrix);\r
+ // generate lookup table\r
+ float *ctable = gen_lookup_table(cmatrix, cmatrix_length);\r
+\r
+ long x,y;\r
+ int bypp = head.biBitCount>>3;\r
+\r
+ CImageIterator itSrc(this);\r
+ CImageIterator itTmp(&tmp_x);\r
+\r
+ double dbScaler = 50.0f/head.biHeight;\r
+\r
+ // blur the rows\r
+ for (y=0;y<head.biHeight;y++)\r
+ {\r
+ if (info.nEscape) break;\r
+ info.nProgress = (long)(y*dbScaler);\r
+\r
+ blur_line(ctable, cmatrix, cmatrix_length, itSrc.GetRow(y), itTmp.GetRow(y), head.biWidth, bypp);\r
+ }\r
+\r
+ CxImage tmp_y(tmp_x, false, true, true);\r
+ if (!tmp_y.IsValid()){\r
+ strcpy(info.szLastError,tmp_y.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ CImageIterator itDst(&tmp_y);\r
+\r
+ // blur the cols\r
+ BYTE* cur_col = (BYTE*)malloc(bypp*head.biHeight);\r
+ BYTE* dest_col = (BYTE*)malloc(bypp*head.biHeight);\r
+\r
+ dbScaler = 50.0f/head.biWidth;\r
+\r
+ for (x=0;x<head.biWidth;x++)\r
+ {\r
+ if (info.nEscape) break;\r
+ info.nProgress = (long)(50.0f+x*dbScaler);\r
+\r
+ itTmp.GetCol(cur_col, x);\r
+ itDst.GetCol(dest_col, x);\r
+ blur_line(ctable, cmatrix, cmatrix_length, cur_col, dest_col, head.biHeight, bypp);\r
+ itDst.SetCol(dest_col, x);\r
+ }\r
+\r
+ free(cur_col);\r
+ free(dest_col);\r
+\r
+ delete [] cmatrix;\r
+ delete [] ctable;\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ //restore the non selected region\r
+ if (pSelection){\r
+ for(y=0; y<head.biHeight; y++){\r
+ for(x=0; x<head.biWidth; x++){\r
+ if (!BlindSelectionIsInside(x,y)){\r
+ tmp_y.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y));\r
+ }\r
+ }\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+ //if necessary, restore the original BPP and palette\r
+ if (pPalette){\r
+ tmp_y.DecreaseBpp(bpp, false, pPalette);\r
+ if (iDst) DecreaseBpp(bpp, false, pPalette);\r
+ delete [] pPalette;\r
+ }\r
+\r
+ if (iDst) iDst->Transfer(tmp_y);\r
+ else Transfer(tmp_y);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \author [DP],[nipper]\r
+ */\r
+bool CxImage::SelectiveBlur(float radius, BYTE threshold, CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ RGBQUAD* pPalette=NULL;\r
+ WORD bpp = GetBpp();\r
+\r
+ CxImage Tmp(*this, true, true, true);\r
+ if (!Tmp.IsValid()){\r
+ strcpy(info.szLastError,Tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ //the routine is optimized for RGB or GrayScale images\r
+ if (!(head.biBitCount == 24 || IsGrayScale())){\r
+ pPalette = new RGBQUAD[head.biClrUsed];\r
+ memcpy(pPalette, GetPalette(),GetPaletteSize());\r
+ if (!Tmp.IncreaseBpp(24))\r
+ return false;\r
+ }\r
+\r
+ CxImage Dst(Tmp, true, true, true);\r
+ if (!Dst.IsValid()){\r
+ strcpy(info.szLastError,Dst.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ //build the difference mask\r
+ BYTE thresh_dw = (BYTE)max( 0 ,(int)(128 - threshold));\r
+ BYTE thresh_up = (BYTE)min(255,(int)(128 + threshold));\r
+ long kernel[]={-100,-100,-100,-100,801,-100,-100,-100,-100};\r
+ if (!Tmp.Filter(kernel,3,800,128)){\r
+ strcpy(info.szLastError,Tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ //if the image has no selection, build a selection for the whole image\r
+ if (!Tmp.SelectionIsValid()){\r
+ Tmp.SelectionCreate();\r
+ Tmp.SelectionClear(255);\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ xmin = Tmp.info.rSelectionBox.left;\r
+ xmax = Tmp.info.rSelectionBox.right;\r
+ ymin = Tmp.info.rSelectionBox.bottom;\r
+ ymax = Tmp.info.rSelectionBox.top;\r
+\r
+ //modify the selection where the difference mask is over the threshold\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+ if(Tmp.BlindSelectionIsInside(x,y)){\r
+ RGBQUAD c = Tmp.BlindGetPixelColor(x,y);\r
+ if ((c.rgbRed < thresh_dw || c.rgbRed > thresh_up) ||\r
+ (c.rgbGreen < thresh_dw || c.rgbGreen > thresh_up) ||\r
+ (c.rgbBlue < thresh_dw || c.rgbBlue > thresh_up))\r
+ {\r
+ Tmp.SelectionSet(x,y,0);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //blur the image (only in the selected pixels)\r
+ Dst.SelectionCopy(Tmp);\r
+ if (!Dst.GaussianBlur(radius)){\r
+ strcpy(info.szLastError,Dst.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ //restore the original selection\r
+ Dst.SelectionCopy(*this);\r
+\r
+ //if necessary, restore the original BPP and palette\r
+ if (pPalette){\r
+ Dst.DecreaseBpp(bpp, false, pPalette);\r
+ delete [] pPalette;\r
+ }\r
+\r
+ if (iDst) iDst->Transfer(Dst);\r
+ else Transfer(Dst);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * sharpen the image by subtracting a blurred copy from the original image.\r
+ * \param radius: width in pixels of the blurring effect. Range: >0; default = 5.\r
+ * \param amount: strength of the filter. Range: 0.0 (none) to 1.0 (max); default = 0.5\r
+ * \param threshold: difference, between blurred and original pixel, to trigger the filter\r
+ * Range: 0 (always triggered) to 255 (never triggered); default = 0.\r
+ * \return true if everything is ok\r
+ * \author [nipper]; changes [DP]\r
+ */\r
+bool CxImage::UnsharpMask(float radius /*= 5.0*/, float amount /*= 0.5*/, int threshold /*= 0*/)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ RGBQUAD* pPalette=NULL;\r
+ WORD bpp = GetBpp();\r
+\r
+ //the routine is optimized for RGB or GrayScale images\r
+ if (!(head.biBitCount == 24 || IsGrayScale())){\r
+ pPalette = new RGBQUAD[head.biClrUsed];\r
+ memcpy(pPalette, GetPalette(),GetPaletteSize());\r
+ if (!IncreaseBpp(24))\r
+ return false;\r
+ }\r
+\r
+ CxImage iDst;\r
+ if (!GaussianBlur(radius,&iDst))\r
+ return false;\r
+\r
+ CImageIterator itSrc(this);\r
+ CImageIterator itDst(&iDst);\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ if (xmin==xmax || ymin==ymax)\r
+ return false;\r
+\r
+ double dbScaler = 100.0/(ymax-ymin);\r
+ int bypp = head.biBitCount>>3;\r
+ \r
+ // merge the source and destination (which currently contains\r
+ // the blurred version) images\r
+ for (long y=ymin; y<ymax; y++)\r
+ {\r
+ if (info.nEscape) break;\r
+ info.nProgress = (long)((y-ymin)*dbScaler);\r
+\r
+ // get source row\r
+ BYTE* cur_row = itSrc.GetRow(y);\r
+ // get dest row\r
+ BYTE* dest_row = itDst.GetRow(y);\r
+ // combine the two\r
+ for (long x=xmin; x<xmax; x++) {\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ for (long b=0, z=x*bypp; b<bypp; b++, z++){\r
+ int diff = cur_row[z] - dest_row[z];\r
+\r
+ // do tresholding\r
+ if (abs(diff) < threshold){\r
+ dest_row[z] = cur_row[z];\r
+ } else {\r
+ dest_row[z] = (BYTE)min(255, max(0,(int)(cur_row[z] + amount * diff)));\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //if necessary, restore the original BPP and palette\r
+ if (pPalette){\r
+ iDst.DecreaseBpp(bpp, false, pPalette);\r
+ delete [] pPalette;\r
+ }\r
+\r
+ Transfer(iDst);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Apply a look up table to the image. \r
+ * \param pLut: BYTE[256] look up table\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Lut(BYTE* pLut)\r
+{\r
+ if (!pDib || !pLut) return false;\r
+ RGBQUAD color;\r
+\r
+ double dbScaler;\r
+ if (head.biClrUsed==0){\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ // faster loop for full image\r
+ BYTE *iSrc=info.pImage;\r
+ for(unsigned long i=0; i < head.biSizeImage ; i++){\r
+ *iSrc++ = pLut[*iSrc];\r
+ }\r
+ return true;\r
+ }\r
+\r
+ if (xmin==xmax || ymin==ymax)\r
+ return false;\r
+\r
+ dbScaler = 100.0/(ymax-ymin);\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)((y-ymin)*dbScaler); //<Anatoly Ivasyuk>\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ color = BlindGetPixelColor(x,y);\r
+ color.rgbRed = pLut[color.rgbRed];\r
+ color.rgbGreen = pLut[color.rgbGreen];\r
+ color.rgbBlue = pLut[color.rgbBlue];\r
+ BlindSetPixelColor(x,y,color);\r
+ }\r
+ }\r
+ }\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ } else if (pSelection && (head.biBitCount==8) && IsGrayScale()){\r
+ long xmin,xmax,ymin,ymax;\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+\r
+ if (xmin==xmax || ymin==ymax)\r
+ return false;\r
+\r
+ dbScaler = 100.0/(ymax-ymin);\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)((y-ymin)*dbScaler);\r
+ for(long x=xmin; x<xmax; x++){\r
+ if (BlindSelectionIsInside(x,y))\r
+ {\r
+ BlindSetPixelIndex(x,y,pLut[BlindGetPixelIndex(x,y)]);\r
+ }\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ } else {\r
+ bool bIsGrayScale = IsGrayScale();\r
+ for(DWORD j=0; j<head.biClrUsed; j++){\r
+ color = GetPaletteColor((BYTE)j);\r
+ color.rgbRed = pLut[color.rgbRed];\r
+ color.rgbGreen = pLut[color.rgbGreen];\r
+ color.rgbBlue = pLut[color.rgbBlue];\r
+ SetPaletteColor((BYTE)j,color);\r
+ }\r
+ if (bIsGrayScale) GrayScale();\r
+ }\r
+ return true;\r
+\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Apply an indipendent look up table for each channel\r
+ * \param pLutR, pLutG, pLutB, pLutA: BYTE[256] look up tables\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Lut(BYTE* pLutR, BYTE* pLutG, BYTE* pLutB, BYTE* pLutA)\r
+{\r
+ if (!pDib || !pLutR || !pLutG || !pLutB) return false;\r
+ RGBQUAD color;\r
+\r
+ double dbScaler;\r
+ if (head.biClrUsed==0){\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ if (xmin==xmax || ymin==ymax)\r
+ return false;\r
+\r
+ dbScaler = 100.0/(ymax-ymin);\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)((y-ymin)*dbScaler);\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ color = BlindGetPixelColor(x,y);\r
+ color.rgbRed = pLutR[color.rgbRed];\r
+ color.rgbGreen = pLutG[color.rgbGreen];\r
+ color.rgbBlue = pLutB[color.rgbBlue];\r
+ if (pLutA) color.rgbReserved=pLutA[color.rgbReserved];\r
+ BlindSetPixelColor(x,y,color,true);\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ bool bIsGrayScale = IsGrayScale();\r
+ for(DWORD j=0; j<head.biClrUsed; j++){\r
+ color = GetPaletteColor((BYTE)j);\r
+ color.rgbRed = pLutR[color.rgbRed];\r
+ color.rgbGreen = pLutG[color.rgbGreen];\r
+ color.rgbBlue = pLutB[color.rgbBlue];\r
+ SetPaletteColor((BYTE)j,color);\r
+ }\r
+ if (bIsGrayScale) GrayScale();\r
+ }\r
+\r
+ return true;\r
+\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Use the RedEyeRemove function to remove the red-eye effect that frequently\r
+ * occurs in photographs of humans and animals. You must select the region \r
+ * where the function will filter the red channel.\r
+ * \param strength: range from 0.0f (no effect) to 1.0f (full effect). Default = 0.8\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::RedEyeRemove(float strength)\r
+{\r
+ if (!pDib) return false;\r
+ RGBQUAD color;\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ if (xmin==xmax || ymin==ymax)\r
+ return false;\r
+\r
+ if (strength<0.0f) strength = 0.0f;\r
+ if (strength>1.0f) strength = 1.0f;\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ float a = 1.0f-5.0f*((float)((x-0.5f*(xmax+xmin))*(x-0.5f*(xmax+xmin))+(y-0.5f*(ymax+ymin))*(y-0.5f*(ymax+ymin))))/((float)((xmax-xmin)*(ymax-ymin)));\r
+ if (a<0) a=0;\r
+ color = BlindGetPixelColor(x,y);\r
+ color.rgbRed = (BYTE)(a*min(color.rgbGreen,color.rgbBlue)+(1.0f-a)*color.rgbRed);\r
+ BlindSetPixelColor(x,y,color);\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Changes the saturation of the image. \r
+ * \param saturation: can be from -100 to 100, positive values increase the saturation.\r
+ * \param colorspace: can be 1 (HSL) or 2 (YUV).\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Saturate(const long saturation, const long colorspace)\r
+{\r
+ if (!pDib)\r
+ return false;\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ if (xmin==xmax || ymin==ymax)\r
+ return false;\r
+\r
+ BYTE cTable[256];\r
+\r
+ switch(colorspace)\r
+ {\r
+ case 1:\r
+ {\r
+ for (int i=0;i<256;i++) {\r
+ cTable[i] = (BYTE)max(0,min(255,(int)(i + saturation)));\r
+ }\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ RGBQUAD c = RGBtoHSL(BlindGetPixelColor(x,y));\r
+ c.rgbGreen = cTable[c.rgbGreen];\r
+ c = HSLtoRGB(c);\r
+ BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ case 2:\r
+ {\r
+ for (int i=0;i<256;i++) {\r
+ cTable[i] = (BYTE)max(0,min(255,(int)((i-128)*(100 + saturation)/100.0f + 128.5f)));\r
+ }\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ RGBQUAD c = RGBtoYUV(BlindGetPixelColor(x,y));\r
+ c.rgbGreen = cTable[c.rgbGreen];\r
+ c.rgbBlue = cTable[c.rgbBlue];\r
+ c = YUVtoRGB(c);\r
+ BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ default:\r
+ strcpy(info.szLastError,"Saturate: wrong colorspace");\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Solarize: convert all colors above a given lightness level into their negative\r
+ * \param level : lightness threshold. Range = 0 to 255; default = 128.\r
+ * \param bLinkedChannels: true = compare with luminance, preserve colors (default)\r
+ * false = compare with independent R,G,B levels\r
+ * \return true if everything is ok\r
+ * \author [Priyank Bolia] (priyank_bolia(at)yahoo(dot)com); changes [DP]\r
+ */\r
+bool CxImage::Solarize(BYTE level, bool bLinkedChannels)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ if (head.biBitCount<=8){\r
+ if (IsGrayScale()){ //GRAYSCALE, selection\r
+ for(long y=ymin; y<ymax; y++){\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ BYTE index = BlindGetPixelIndex(x,y);\r
+ RGBQUAD color = GetPaletteColor(index);\r
+ if ((BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)>level){\r
+ BlindSetPixelIndex(x,y,255-index);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ } else { //PALETTE, full image\r
+ RGBQUAD* ppal=GetPalette();\r
+ for(DWORD i=0;i<head.biClrUsed;i++){\r
+ RGBQUAD color = GetPaletteColor((BYTE)i);\r
+ if (bLinkedChannels){\r
+ if ((BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)>level){\r
+ ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue);\r
+ ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen);\r
+ ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed);\r
+ }\r
+ } else {\r
+ if (color.rgbBlue>level) ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue);\r
+ if (color.rgbGreen>level) ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen);\r
+ if (color.rgbRed>level) ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed);\r
+ }\r
+ }\r
+ }\r
+ } else { //RGB, selection\r
+ for(long y=ymin; y<ymax; y++){\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ RGBQUAD color = BlindGetPixelColor(x,y);\r
+ if (bLinkedChannels){\r
+ if ((BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)>level){\r
+ color.rgbRed = (BYTE)(255-color.rgbRed);\r
+ color.rgbGreen = (BYTE)(255-color.rgbGreen);\r
+ color.rgbBlue = (BYTE)(255-color.rgbBlue);\r
+ }\r
+ } else {\r
+ if (color.rgbBlue>level) color.rgbBlue =(BYTE)(255-color.rgbBlue);\r
+ if (color.rgbGreen>level) color.rgbGreen =(BYTE)(255-color.rgbGreen);\r
+ if (color.rgbRed>level) color.rgbRed =(BYTE)(255-color.rgbRed);\r
+ }\r
+ BlindSetPixelColor(x,y,color);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //invert transparent color only in case of full image processing\r
+ if (pSelection==0 || (!IsGrayScale() && IsIndexed())){\r
+ if (bLinkedChannels){\r
+ if ((BYTE)RGB2GRAY(info.nBkgndColor.rgbRed,info.nBkgndColor.rgbGreen,info.nBkgndColor.rgbBlue)>level){\r
+ info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue);\r
+ info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen);\r
+ info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed);\r
+ } \r
+ } else {\r
+ if (info.nBkgndColor.rgbBlue>level) info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue);\r
+ if (info.nBkgndColor.rgbGreen>level) info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen);\r
+ if (info.nBkgndColor.rgbRed>level) info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed);\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Converts the RGB triplets to and from different colorspace\r
+ * \param dstColorSpace: destination colorspace; 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ \r
+ * \param srcColorSpace: source colorspace; 0 = RGB, 1 = HSL, 2 = YUV, 3 = YIQ, 4 = XYZ \r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::ConvertColorSpace(const long dstColorSpace, const long srcColorSpace)\r
+{\r
+ if (!pDib)\r
+ return false;\r
+\r
+ if (dstColorSpace == srcColorSpace)\r
+ return true;\r
+\r
+ long w = GetWidth();\r
+ long h = GetHeight();\r
+\r
+ for (long y=0;y<h;y++){\r
+ info.nProgress = (long)(100*y/h);\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<w;x++){\r
+ RGBQUAD c = BlindGetPixelColor(x,y);\r
+ switch (srcColorSpace){\r
+ case 0:\r
+ break;\r
+ case 1:\r
+ c = HSLtoRGB(c);\r
+ break;\r
+ case 2:\r
+ c = YUVtoRGB(c);\r
+ break;\r
+ case 3:\r
+ c = YIQtoRGB(c);\r
+ break;\r
+ case 4:\r
+ c = XYZtoRGB(c);\r
+ break;\r
+ default:\r
+ strcpy(info.szLastError,"ConvertColorSpace: unknown source colorspace");\r
+ return false;\r
+ }\r
+ switch (dstColorSpace){\r
+ case 0:\r
+ break;\r
+ case 1:\r
+ c = RGBtoHSL(c);\r
+ break;\r
+ case 2:\r
+ c = RGBtoYUV(c);\r
+ break;\r
+ case 3:\r
+ c = RGBtoYIQ(c);\r
+ break;\r
+ case 4:\r
+ c = RGBtoXYZ(c);\r
+ break;\r
+ default:\r
+ strcpy(info.szLastError,"ConvertColorSpace: unknown destination colorspace");\r
+ return false;\r
+ }\r
+ BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Finds the optimal (global or local) treshold for image binarization\r
+ * \param method: 0 = average all methods (default); 1 = Otsu; 2 = Kittler & Illingworth; 3 = max entropy; 4 = potential difference;\r
+ * \param pBox: region from where the threshold is computed; 0 = full image (default).\r
+ * \param pContrastMask: limit the computation only in regions with contrasted (!=0) pixels; default = 0.\r
+ * the pContrastMask image must be grayscale with same with and height of the current image,\r
+ * can be obtained from the current image with a filter:\r
+ * CxImage iContrastMask(*image,true,false,false);\r
+ * iContrastMask.GrayScale();\r
+ * long edge[]={-1,-1,-1,-1,8,-1,-1,-1,-1};\r
+ * iContrastMask.Filter(edge,3,1,0);\r
+ * long blur[]={1,1,1,1,1,1,1,1,1};\r
+ * iContrastMask.Filter(blur,3,9,0);\r
+ * \return optimal threshold; -1 = error.\r
+ * \sa AdaptiveThreshold\r
+ */\r
+int CxImage::OptimalThreshold(long method, RECT * pBox, CxImage* pContrastMask)\r
+{\r
+ if (!pDib)\r
+ return false;\r
+\r
+ if (head.biBitCount!=8){\r
+ strcpy(info.szLastError,"OptimalThreshold works only on 8 bit images");\r
+ return -1;\r
+ }\r
+\r
+ if (pContrastMask){\r
+ if (!pContrastMask->IsValid() ||\r
+ !pContrastMask->IsGrayScale() ||\r
+ pContrastMask->GetWidth() != GetWidth() ||\r
+ pContrastMask->GetHeight() != GetHeight()){\r
+ strcpy(info.szLastError,"OptimalThreshold invalid ContrastMask");\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pBox){\r
+ xmin = max(pBox->left,0);\r
+ xmax = min(pBox->right,head.biWidth);\r
+ ymin = max(pBox->bottom,0);\r
+ ymax = min(pBox->top,head.biHeight);\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+ \r
+ if (xmin>=xmax || ymin>=ymax)\r
+ return -1;\r
+\r
+ double p[256];\r
+ memset(p, 0, 256*sizeof(double));\r
+ //build histogram\r
+ for (long y = ymin; y<ymax; y++){\r
+ BYTE* pGray = GetBits(y) + xmin;\r
+ BYTE* pContr = 0;\r
+ if (pContrastMask) pContr = pContrastMask->GetBits(y) + xmin;\r
+ for (long x = xmin; x<xmax; x++){\r
+ BYTE n = *pGray++;\r
+ if (pContr){\r
+ if (*pContr) p[n]++;\r
+ pContr++;\r
+ } else {\r
+ p[n]++;\r
+ }\r
+ }\r
+ }\r
+\r
+ //find histogram limits\r
+ int gray_min = 0;\r
+ while (gray_min<255 && p[gray_min]==0) gray_min++;\r
+ int gray_max = 255;\r
+ while (gray_max>0 && p[gray_max]==0) gray_max--;\r
+ if (gray_min > gray_max)\r
+ return -1;\r
+ if (gray_min == gray_max){\r
+ if (gray_min == 0)\r
+ return 0;\r
+ else\r
+ return gray_max-1;\r
+ }\r
+\r
+ //compute total moments 0th,1st,2nd order\r
+ int i,k;\r
+ double w_tot = 0;\r
+ double m_tot = 0;\r
+ double q_tot = 0;\r
+ for (i = gray_min; i <= gray_max; i++){\r
+ w_tot += p[i];\r
+ m_tot += i*p[i];\r
+ q_tot += i*i*p[i];\r
+ }\r
+\r
+ double L, L1max, L2max, L3max, L4max; //objective functions\r
+ int th1,th2,th3,th4; //optimal thresholds\r
+ L1max = L2max = L3max = L4max = 0;\r
+ th1 = th2 = th3 = th4 = -1;\r
+\r
+ double w1, w2, m1, m2, q1, q2, s1, s2;\r
+ w1 = m1 = q1 = 0;\r
+ for (i = gray_min; i < gray_max; i++){\r
+ w1 += p[i];\r
+ w2 = w_tot - w1;\r
+ m1 += i*p[i];\r
+ m2 = m_tot - m1;\r
+ q1 += i*i*p[i];\r
+ q2 = q_tot - q1;\r
+ s1 = q1/w1-m1*m1/w1/w1; //s1 = q1/w1-pow(m1/w1,2);\r
+ s2 = q2/w2-m2*m2/w2/w2; //s2 = q2/w2-pow(m2/w2,2);\r
+\r
+ //Otsu\r
+ L = -(s1*w1 + s2*w2); //implemented as definition\r
+ //L = w1 * w2 * (m2/w2 - m1/w1)*(m2/w2 - m1/w1); //implementation that doesn't need s1 & s2\r
+ if (L1max < L || th1<0){\r
+ L1max = L;\r
+ th1 = i;\r
+ }\r
+\r
+ //Kittler and Illingworth\r
+ if (s1>0 && s2>0){\r
+ L = w1*log(w1/sqrt(s1))+w2*log(w2/sqrt(s2));\r
+ //L = w1*log(w1*w1/s1)+w2*log(w2*w2/s2);\r
+ if (L2max < L || th2<0){\r
+ L2max = L;\r
+ th2 = i;\r
+ }\r
+ }\r
+\r
+ //max entropy\r
+ L = 0;\r
+ for (k=gray_min;k<=i;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w1)/w1;\r
+ for (k;k<=gray_max;k++) if (p[k] > 0) L -= p[k]*log(p[k]/w2)/w2;\r
+ if (L3max < L || th3<0){\r
+ L3max = L;\r
+ th3 = i;\r
+ }\r
+\r
+ //potential difference (based on Electrostatic Binarization method by J. Acharya & G. Sreechakra)\r
+ // L=-fabs(vdiff/vsum); รจ molto selettivo, sembra che L=-fabs(vdiff) o L=-(vsum)\r
+ // abbiano lo stesso valore di soglia... il che semplificherebbe molto la routine\r
+ double vdiff = 0;\r
+ for (k=gray_min;k<=i;k++)\r
+ vdiff += p[k]*(i-k)*(i-k);\r
+ double vsum = vdiff;\r
+ for (k;k<=gray_max;k++){\r
+ double dv = p[k]*(k-i)*(k-i);\r
+ vdiff -= dv;\r
+ vsum += dv;\r
+ }\r
+ if (vsum>0) L = -fabs(vdiff/vsum); else L = 0;\r
+ if (L4max < L || th4<0){\r
+ L4max = L;\r
+ th4 = i;\r
+ }\r
+ }\r
+\r
+ int threshold;\r
+ switch (method){\r
+ case 1: //Otsu\r
+ threshold = th1;\r
+ break;\r
+ case 2: //Kittler and Illingworth\r
+ threshold = th2;\r
+ break;\r
+ case 3: //max entropy\r
+ threshold = th3;\r
+ break;\r
+ case 4: //potential difference\r
+ threshold = th4;\r
+ break;\r
+ default: //auto\r
+ {\r
+ int nt = 0;\r
+ threshold = 0;\r
+ if (th1>=0) { threshold += th1; nt++;}\r
+ if (th2>=0) { threshold += th2; nt++;}\r
+ if (th3>=0) { threshold += th3; nt++;}\r
+ if (th4>=0) { threshold += th4; nt++;}\r
+ if (nt)\r
+ threshold /= nt;\r
+ else\r
+ threshold = (gray_min+gray_max)/2;\r
+\r
+ /*better(?) but really expensive alternative:\r
+ n = 0:255;\r
+ 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));\r
+ 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));\r
+ ...\r
+ mse_th1 = sum((p-pth1).^2);\r
+ mse_th2 = sum((p-pth2).^2);\r
+ ...\r
+ select th# that gives minimum mse_th#\r
+ */\r
+\r
+ }\r
+ }\r
+\r
+ if (threshold <= gray_min || threshold >= gray_max)\r
+ threshold = (gray_min+gray_max)/2;\r
+ \r
+ return threshold;\r
+}\r
+///////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Converts the image to B&W, using an optimal threshold mask\r
+ * \param method: 0 = average all methods (default); 1 = Otsu; 2 = Kittler & Illingworth; 3 = max entropy; 4 = potential difference;\r
+ * \param nBoxSize: the image is divided into "nBoxSize x nBoxSize" blocks, from where the threshold is computed; min = 8; default = 64.\r
+ * \param pContrastMask: limit the computation only in regions with contrasted (!=0) pixels; default = 0.\r
+ * \param nBias: global offset added to the threshold mask; default = 0.\r
+ * \param fGlobalLocalBalance: balance between local and global threshold. default = 0.5\r
+ * fGlobalLocalBalance can be from 0.0 (use only local threshold) to 1.0 (use only global threshold)\r
+ * the pContrastMask image must be grayscale with same with and height of the current image,\r
+ * \return true if everything is ok.\r
+ * \sa OptimalThreshold\r
+ */\r
+bool CxImage::AdaptiveThreshold(long method, long nBoxSize, CxImage* pContrastMask, long nBias, float fGlobalLocalBalance)\r
+{\r
+ if (!pDib)\r
+ return false;\r
+\r
+ if (pContrastMask){\r
+ if (!pContrastMask->IsValid() ||\r
+ !pContrastMask->IsGrayScale() ||\r
+ pContrastMask->GetWidth() != GetWidth() ||\r
+ pContrastMask->GetHeight() != GetHeight()){\r
+ strcpy(info.szLastError,"AdaptiveThreshold invalid ContrastMask");\r
+ return false;\r
+ }\r
+ }\r
+\r
+ if (nBoxSize<8) nBoxSize = 8;\r
+ if (fGlobalLocalBalance<0.0f) fGlobalLocalBalance = 0.0f;\r
+ if (fGlobalLocalBalance>1.0f) fGlobalLocalBalance = 1.0f;\r
+\r
+ long mw = (head.biWidth + nBoxSize - 1)/nBoxSize;\r
+ long mh = (head.biHeight + nBoxSize - 1)/nBoxSize;\r
+\r
+ CxImage mask(mw,mh,8);\r
+ if(!mask.GrayScale())\r
+ return false;\r
+\r
+ if(!GrayScale())\r
+ return false;\r
+\r
+ int globalthreshold = OptimalThreshold(method, 0, pContrastMask);\r
+ if (globalthreshold <0)\r
+ return false;\r
+\r
+ for (long y=0; y<mh; y++){\r
+ for (long x=0; x<mw; x++){\r
+ info.nProgress = (long)(100*(x+y*mw)/(mw*mh));\r
+ if (info.nEscape) break;\r
+ RECT r;\r
+ r.left = x*nBoxSize;\r
+ r.right = r.left + nBoxSize;\r
+ r.bottom = y*nBoxSize;\r
+ r.top = r.bottom + nBoxSize;\r
+ int threshold = OptimalThreshold(method, &r, pContrastMask);\r
+ if (threshold <0) return false;\r
+ mask.SetPixelIndex(x,y,(BYTE)max(0,min(255,nBias+((1.0f-fGlobalLocalBalance)*threshold + fGlobalLocalBalance*globalthreshold))));\r
+ }\r
+ }\r
+\r
+ mask.Resample(mw*nBoxSize,mh*nBoxSize,0);\r
+ mask.Crop(0,head.biHeight,head.biWidth,0);\r
+\r
+ if(!Threshold(&mask))\r
+ return false;\r
+\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#include <queue>\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Flood Fill\r
+ * \param xStart, yStart: starting point\r
+ * \param cFillColor: filling color\r
+ * \param nTolerance: deviation from the starting point color\r
+ * \param nOpacity: can be from 0 (transparent) to 255 (opaque, default)\r
+ * \param bSelectFilledArea: if true, the pixels in the region are also set in the selection layer; default = false\r
+ * \param nSelectionLevel: if bSelectFilledArea is true, the selected pixels are set to nSelectionLevel; default = 255\r
+ * Note: nOpacity=0 && bSelectFilledArea=true act as a "magic wand"\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::FloodFill(const long xStart, const long yStart, const RGBQUAD cFillColor, const BYTE nTolerance,\r
+ BYTE nOpacity, const bool bSelectFilledArea, const BYTE nSelectionLevel)\r
+{\r
+ if (!pDib)\r
+ return false;\r
+\r
+ if (!IsInside(xStart,yStart))\r
+ return true;\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (!SelectionIsInside(xStart,yStart))\r
+ return true;\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+ RGBQUAD* pPalette=NULL;\r
+ WORD bpp = GetBpp();\r
+ //nTolerance or nOpacity implemented only for grayscale or 24bpp images\r
+ if ((nTolerance || nOpacity != 255) && !(head.biBitCount == 24 || IsGrayScale())){\r
+ pPalette = new RGBQUAD[head.biClrUsed];\r
+ memcpy(pPalette, GetPalette(),GetPaletteSize());\r
+ if (!IncreaseBpp(24))\r
+ return false;\r
+ }\r
+\r
+ BYTE* pFillMask = (BYTE*)calloc(head.biWidth * head.biHeight,1);\r
+ if (!pFillMask)\r
+ return false;\r
+\r
+//------------------------------------- Begin of Flood Fill\r
+ POINT offset[4] = {{-1,0},{0,-1},{1,0},{0,1}};\r
+ std::queue<POINT> q;\r
+ POINT point = {xStart,yStart};\r
+ q.push(point);\r
+\r
+ if (IsIndexed()){ //--- Generic indexed image, no tolerance OR Grayscale image with tolerance\r
+ BYTE idxRef = GetPixelIndex(xStart,yStart);\r
+ BYTE idxFill = GetNearestIndex(cFillColor);\r
+ BYTE idxMin = (BYTE)min(255, max(0,(int)(idxRef - nTolerance)));\r
+ BYTE idxMax = (BYTE)min(255, max(0,(int)(idxRef + nTolerance)));\r
+\r
+ while(!q.empty())\r
+ {\r
+ point = q.front();\r
+ q.pop();\r
+\r
+ for (int z=0; z<4; z++){\r
+ int x = point.x + offset[z].x;\r
+ int y = point.y + offset[z].y;\r
+ if(IsInside(x,y)){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ BYTE idx = BlindGetPixelIndex(x, y);\r
+ BYTE* pFill = pFillMask + x + y * head.biWidth;\r
+ if (*pFill==0 && idxMin <= idx && idx <= idxMax )\r
+ {\r
+ if (nOpacity>0){\r
+ if (nOpacity == 255)\r
+ BlindSetPixelIndex(x, y, idxFill);\r
+ else\r
+ BlindSetPixelIndex(x, y, (BYTE)((idxFill * nOpacity + idx * (255-nOpacity))>>8));\r
+ }\r
+ POINT pt = {x,y};\r
+ q.push(pt);\r
+ *pFill = 1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ } else { //--- RGB image\r
+ RGBQUAD cRef = GetPixelColor(xStart,yStart);\r
+ RGBQUAD cRefMin, cRefMax;\r
+ cRefMin.rgbRed = (BYTE)min(255, max(0,(int)(cRef.rgbRed - nTolerance)));\r
+ cRefMin.rgbGreen = (BYTE)min(255, max(0,(int)(cRef.rgbGreen - nTolerance)));\r
+ cRefMin.rgbBlue = (BYTE)min(255, max(0,(int)(cRef.rgbBlue - nTolerance)));\r
+ cRefMax.rgbRed = (BYTE)min(255, max(0,(int)(cRef.rgbRed + nTolerance)));\r
+ cRefMax.rgbGreen = (BYTE)min(255, max(0,(int)(cRef.rgbGreen + nTolerance)));\r
+ cRefMax.rgbBlue = (BYTE)min(255, max(0,(int)(cRef.rgbBlue + nTolerance)));\r
+\r
+ while(!q.empty())\r
+ {\r
+ point = q.front();\r
+ q.pop();\r
+\r
+ for (int z=0; z<4; z++){\r
+ int x = point.x + offset[z].x;\r
+ int y = point.y + offset[z].y;\r
+ if(IsInside(x,y)){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ RGBQUAD cc = BlindGetPixelColor(x, y);\r
+ BYTE* pFill = pFillMask + x + y * head.biWidth;\r
+ if (*pFill==0 &&\r
+ cRefMin.rgbRed <= cc.rgbRed && cc.rgbRed <= cRefMax.rgbRed &&\r
+ cRefMin.rgbGreen <= cc.rgbGreen && cc.rgbGreen <= cRefMax.rgbGreen &&\r
+ cRefMin.rgbBlue <= cc.rgbBlue && cc.rgbBlue <= cRefMax.rgbBlue )\r
+ {\r
+ if (nOpacity>0){\r
+ if (nOpacity == 255)\r
+ BlindSetPixelColor(x, y, cFillColor);\r
+ else\r
+ {\r
+ cc.rgbRed = (BYTE)((cFillColor.rgbRed * nOpacity + cc.rgbRed * (255-nOpacity))>>8);\r
+ cc.rgbGreen = (BYTE)((cFillColor.rgbGreen * nOpacity + cc.rgbGreen * (255-nOpacity))>>8);\r
+ cc.rgbBlue = (BYTE)((cFillColor.rgbBlue * nOpacity + cc.rgbBlue * (255-nOpacity))>>8);\r
+ BlindSetPixelColor(x, y, cc);\r
+ }\r
+ }\r
+ POINT pt = {x,y};\r
+ q.push(pt);\r
+ *pFill = 1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (pFillMask[xStart+yStart*head.biWidth] == 0 && nOpacity>0){\r
+ if (nOpacity == 255)\r
+ BlindSetPixelColor(xStart, yStart, cFillColor);\r
+ else\r
+ {\r
+ RGBQUAD cc = BlindGetPixelColor(xStart, yStart);\r
+ cc.rgbRed = (BYTE)((cFillColor.rgbRed * nOpacity + cc.rgbRed * (255-nOpacity))>>8);\r
+ cc.rgbGreen = (BYTE)((cFillColor.rgbGreen * nOpacity + cc.rgbGreen * (255-nOpacity))>>8);\r
+ cc.rgbBlue = (BYTE)((cFillColor.rgbBlue * nOpacity + cc.rgbBlue * (255-nOpacity))>>8);\r
+ BlindSetPixelColor(xStart, yStart, cc);\r
+ }\r
+ }\r
+ pFillMask[xStart+yStart*head.biWidth] = 1;\r
+//------------------------------------- End of Flood Fill\r
+\r
+ //if necessary, restore the original BPP and palette\r
+ if (pPalette){\r
+ DecreaseBpp(bpp, false, pPalette);\r
+ delete [] pPalette;\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (bSelectFilledArea){\r
+ if (!SelectionIsValid()){\r
+ if (!SelectionCreate()){\r
+ return false;\r
+ }\r
+ SelectionClear();\r
+ info.rSelectionBox.right = head.biWidth;\r
+ info.rSelectionBox.top = head.biHeight;\r
+ info.rSelectionBox.left = info.rSelectionBox.bottom = 0;\r
+ }\r
+ RECT r;\r
+ SelectionGetBox(r);\r
+ for (long y = r.bottom; y < r.top; y++){\r
+ BYTE* pFill = pFillMask + r.left + y * head.biWidth;\r
+ for (long x = r.left; x<r.right; x++){\r
+ if (*pFill) SelectionSet(x,y,nSelectionLevel);\r
+ pFill++;\r
+ }\r
+ }\r
+ SelectionRebuildBox();\r
+ }\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+ free(pFillMask);\r
+\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DSP\r
--- /dev/null
+// xImaCodec.cpp : Encode Decode functions\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_JPG\r
+#include "ximajpg.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_GIF\r
+#include "ximagif.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_PNG\r
+#include "ximapng.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_MNG\r
+#include "ximamng.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_BMP\r
+#include "ximabmp.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_ICO\r
+#include "ximaico.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_TIF\r
+#include "ximatif.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_TGA\r
+#include "ximatga.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_PCX\r
+#include "ximapcx.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_WBMP\r
+#include "ximawbmp.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_WMF\r
+#include "ximawmf.h" // <vho> - WMF/EMF support\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_JBG\r
+#include "ximajbg.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_JASPER\r
+#include "ximajas.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_SKA\r
+#include "ximaska.h"\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_RAW\r
+#include "ximaraw.h"\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::EncodeSafeCheck(CxFile *hFile)\r
+{\r
+ if (hFile==NULL) {\r
+ strcpy(info.szLastError,CXIMAGE_ERR_NOFILE);\r
+ return true;\r
+ }\r
+\r
+ if (pDib==NULL){\r
+ strcpy(info.szLastError,CXIMAGE_ERR_NOIMAGE);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+//#ifdef WIN32\r
+//bool CxImage::Save(LPCWSTR filename, DWORD imagetype)\r
+//{\r
+// FILE* hFile; //file handle to write the image\r
+// if ((hFile=_wfopen(filename,L"wb"))==NULL) return false;\r
+// bool bOK = Encode(hFile,imagetype);\r
+// fclose(hFile);\r
+// return bOK;\r
+//}\r
+//#endif //WIN32\r
+////////////////////////////////////////////////////////////////////////////////\r
+// For UNICODE support: char -> TCHAR\r
+/**\r
+ * Saves to disk the image in a specific format.\r
+ * \param filename: file name\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Save(const TCHAR * filename, DWORD imagetype)\r
+{\r
+ FILE* hFile; //file handle to write the image\r
+\r
+#ifdef WIN32\r
+ if ((hFile=_tfopen(filename,_T("wb")))==NULL) return false; // For UNICODE support\r
+#else\r
+ if ((hFile=fopen(filename,"wb"))==NULL) return false;\r
+#endif\r
+\r
+ bool bOK = Encode(hFile,imagetype);\r
+ fclose(hFile);\r
+ return bOK;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Saves to disk the image in a specific format.\r
+ * \param hFile: file handle, open and enabled for writing.\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Encode(FILE *hFile, DWORD imagetype)\r
+{\r
+ CxIOFile file(hFile);\r
+ return Encode(&file,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Saves to memory buffer the image in a specific format.\r
+ * \param buffer: output memory buffer pointer. Must be NULL,\r
+ * the function allocates and fill the memory,\r
+ * the application must free the buffer, see also FreeMemory().\r
+ * \param size: output memory buffer size.\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Encode(BYTE * &buffer, long &size, DWORD imagetype)\r
+{\r
+ if (buffer!=NULL){\r
+ strcpy(info.szLastError,"the buffer must be empty");\r
+ return false;\r
+ }\r
+ CxMemFile file;\r
+ file.Open();\r
+ if(Encode(&file,imagetype)){\r
+ buffer=file.GetBuffer();\r
+ size=file.Size();\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Saves to disk the image in a specific format.\r
+ * \param hFile: file handle (CxMemFile or CxIOFile), with write access.\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ * \sa ENUM_CXIMAGE_FORMATS\r
+ */\r
+bool CxImage::Encode(CxFile *hFile, DWORD imagetype)\r
+{\r
+\r
+#if CXIMAGE_SUPPORT_BMP\r
+\r
+ if (imagetype==CXIMAGE_FORMAT_BMP){\r
+ CxImageBMP newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ if (imagetype==CXIMAGE_FORMAT_ICO){\r
+ CxImageICO newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+ if (imagetype==CXIMAGE_FORMAT_TIF){\r
+ CxImageTIF newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+ if (imagetype==CXIMAGE_FORMAT_JPG){\r
+ CxImageJPG newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ if (imagetype==CXIMAGE_FORMAT_GIF){\r
+ CxImageGIF newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+ if (imagetype==CXIMAGE_FORMAT_PNG){\r
+ CxImagePNG newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+ if (imagetype==CXIMAGE_FORMAT_MNG){\r
+ CxImageMNG newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+ if (imagetype==CXIMAGE_FORMAT_TGA){\r
+ CxImageTGA newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+ if (imagetype==CXIMAGE_FORMAT_PCX){\r
+ CxImagePCX newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+ if (imagetype==CXIMAGE_FORMAT_WBMP){\r
+ CxImageWBMP newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS // <vho> - WMF/EMF support\r
+ if (imagetype==CXIMAGE_FORMAT_WMF){\r
+ CxImageWMF newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+ if (imagetype==CXIMAGE_FORMAT_JBG){\r
+ CxImageJBG newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JASPER\r
+ if (\r
+ #if CXIMAGE_SUPPORT_JP2\r
+ imagetype==CXIMAGE_FORMAT_JP2 || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_JPC\r
+ imagetype==CXIMAGE_FORMAT_JPC || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_PGX\r
+ imagetype==CXIMAGE_FORMAT_PGX || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_PNM\r
+ imagetype==CXIMAGE_FORMAT_PNM || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_RAS\r
+ imagetype==CXIMAGE_FORMAT_RAS || \r
+ #endif\r
+ false ){\r
+ CxImageJAS newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile,imagetype)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_SKA\r
+ if (imagetype==CXIMAGE_FORMAT_SKA){\r
+ CxImageSKA newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_RAW\r
+ if (imagetype==CXIMAGE_FORMAT_RAW){\r
+ CxImageRAW newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+\r
+ strcpy(info.szLastError,"Encode: Unknown format");\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Saves to disk or memory pagecount images, referenced by an array of CxImage pointers.\r
+ * \param hFile: file handle.\r
+ * \param pImages: array of CxImage pointers.\r
+ * \param pagecount: number of images.\r
+ * \param imagetype: can be CXIMAGE_FORMAT_TIF or CXIMAGE_FORMAT_GIF.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Encode(FILE * hFile, CxImage ** pImages, int pagecount, DWORD imagetype)\r
+{\r
+ CxIOFile file(hFile);\r
+ return Encode(&file, pImages, pagecount,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Saves to disk or memory pagecount images, referenced by an array of CxImage pointers.\r
+ * \param hFile: file handle (CxMemFile or CxIOFile), with write access.\r
+ * \param pImages: array of CxImage pointers.\r
+ * \param pagecount: number of images.\r
+ * \param imagetype: can be CXIMAGE_FORMAT_TIF, CXIMAGE_FORMAT_GIF or CXIMAGE_FORMAT_ICO.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Encode(CxFile * hFile, CxImage ** pImages, int pagecount, DWORD imagetype)\r
+{\r
+#if CXIMAGE_SUPPORT_TIF\r
+ if (imagetype==CXIMAGE_FORMAT_TIF){\r
+ CxImageTIF newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile,pImages,pagecount)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ if (imagetype==CXIMAGE_FORMAT_GIF){\r
+ CxImageGIF newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile,pImages,pagecount)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ if (imagetype==CXIMAGE_FORMAT_ICO){\r
+ CxImageICO newima;\r
+ newima.Ghost(this);\r
+ if (newima.Encode(hFile,pImages,pagecount)){\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+ strcpy(info.szLastError,"Multipage Encode, Unsupported operation for this format");\r
+ return false;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * exports the image into a RGBA buffer, Useful for OpenGL applications.\r
+ * \param buffer: output memory buffer pointer. Must be NULL,\r
+ * the function allocates and fill the memory,\r
+ * the application must free the buffer, see also FreeMemory().\r
+ * \param size: output memory buffer size.\r
+ * \param bFlipY: direction of Y axis. default = false.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Encode2RGBA(BYTE * &buffer, long &size, bool bFlipY)\r
+{\r
+ if (buffer!=NULL){\r
+ strcpy(info.szLastError,"the buffer must be empty");\r
+ return false;\r
+ }\r
+ CxMemFile file;\r
+ file.Open();\r
+ if(Encode2RGBA(&file,bFlipY)){\r
+ buffer=file.GetBuffer();\r
+ size=file.Size();\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * exports the image into a RGBA buffer, Useful for OpenGL applications.\r
+ * \param hFile: file handle (CxMemFile or CxIOFile), with write access.\r
+ * \param bFlipY: direction of Y axis. default = false.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Encode2RGBA(CxFile *hFile, bool bFlipY)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ for (long y1 = 0; y1 < head.biHeight; y1++) {\r
+ long y = bFlipY ? head.biHeight - 1 - y1 : y1;\r
+ for(long x = 0; x < head.biWidth; x++) {\r
+ RGBQUAD color = BlindGetPixelColor(x,y);\r
+ hFile->PutC(color.rgbRed);\r
+ hFile->PutC(color.rgbGreen);\r
+ hFile->PutC(color.rgbBlue);\r
+ hFile->PutC(color.rgbReserved);\r
+ }\r
+ }\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+// For UNICODE support: char -> TCHAR\r
+/**\r
+ * Reads from disk the image in a specific format.\r
+ * - If decoding fails using the specified image format,\r
+ * the function will try the automatic file format recognition.\r
+ *\r
+ * \param filename: file name\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Load(const TCHAR * filename, DWORD imagetype)\r
+//bool CxImage::Load(const char * filename, DWORD imagetype)\r
+{\r
+ /*FILE* hFile; //file handle to read the image\r
+ if ((hFile=fopen(filename,"rb"))==NULL) return false;\r
+ bool bOK = Decode(hFile,imagetype);\r
+ fclose(hFile);*/\r
+\r
+ /* automatic file type recognition */\r
+ bool bOK = false;\r
+ if ( GetTypeIndexFromId(imagetype) ){\r
+ FILE* hFile; //file handle to read the image\r
+\r
+#ifdef WIN32\r
+ if ((hFile=_tfopen(filename,_T("rb")))==NULL) return false; // For UNICODE support\r
+#else\r
+ if ((hFile=fopen(filename,"rb"))==NULL) return false;\r
+#endif\r
+\r
+ bOK = Decode(hFile,imagetype);\r
+ fclose(hFile);\r
+ if (bOK) return bOK;\r
+ }\r
+\r
+ char szError[256];\r
+ strcpy(szError,info.szLastError); //save the first error\r
+\r
+ // if failed, try automatic recognition of the file...\r
+ FILE* hFile;\r
+\r
+#ifdef WIN32\r
+ if ((hFile=_tfopen(filename,_T("rb")))==NULL) return false; // For UNICODE support\r
+#else\r
+ if ((hFile=fopen(filename,"rb"))==NULL) return false;\r
+#endif\r
+\r
+ bOK = Decode(hFile,CXIMAGE_FORMAT_UNKNOWN);\r
+ fclose(hFile);\r
+\r
+ if (!bOK && imagetype > 0) strcpy(info.szLastError,szError); //restore the first error\r
+\r
+ return bOK;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#ifdef WIN32\r
+//bool CxImage::Load(LPCWSTR filename, DWORD imagetype)\r
+//{\r
+// /*FILE* hFile; //file handle to read the image\r
+// if ((hFile=_wfopen(filename, L"rb"))==NULL) return false;\r
+// bool bOK = Decode(hFile,imagetype);\r
+// fclose(hFile);*/\r
+//\r
+// /* automatic file type recognition */\r
+// bool bOK = false;\r
+// if ( GetTypeIndexFromId(imagetype) ){\r
+// FILE* hFile; //file handle to read the image\r
+// if ((hFile=_wfopen(filename,L"rb"))==NULL) return false;\r
+// bOK = Decode(hFile,imagetype);\r
+// fclose(hFile);\r
+// if (bOK) return bOK;\r
+// }\r
+//\r
+// char szError[256];\r
+// strcpy(szError,info.szLastError); //save the first error\r
+//\r
+// // if failed, try automatic recognition of the file...\r
+// FILE* hFile; //file handle to read the image\r
+// if ((hFile=_wfopen(filename,L"rb"))==NULL) return false;\r
+// bOK = Decode(hFile,CXIMAGE_FORMAT_UNKNOWN);\r
+// fclose(hFile);\r
+//\r
+// if (!bOK && imagetype > 0) strcpy(info.szLastError,szError); //restore the first error\r
+//\r
+// return bOK;\r
+//}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Loads an image from the application resources.\r
+ * \param hRes: the resource handle returned by FindResource().\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS.\r
+ * \param hModule: NULL for internal resource, or external application/DLL hinstance returned by LoadLibray.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::LoadResource(HRSRC hRes, DWORD imagetype, HMODULE hModule)\r
+{\r
+ DWORD rsize=SizeofResource(hModule,hRes);\r
+ HGLOBAL hMem=::LoadResource(hModule,hRes);\r
+ if (hMem){\r
+ char* lpVoid=(char*)LockResource(hMem);\r
+ if (lpVoid){\r
+ // FILE* fTmp=tmpfile(); doesn't work with network\r
+ /*char tmpPath[MAX_PATH] = {0};\r
+ char tmpFile[MAX_PATH] = {0};\r
+ GetTempPath(MAX_PATH,tmpPath);\r
+ GetTempFileName(tmpPath,"IMG",0,tmpFile);\r
+ FILE* fTmp=fopen(tmpFile,"w+b");\r
+ if (fTmp){\r
+ fwrite(lpVoid,rsize,1,fTmp);\r
+ fseek(fTmp,0,SEEK_SET);\r
+ bool bOK = Decode(fTmp,imagetype);\r
+ fclose(fTmp);\r
+ DeleteFile(tmpFile);\r
+ return bOK;\r
+ }*/\r
+\r
+ CxMemFile fTmp((BYTE*)lpVoid,rsize);\r
+ return Decode(&fTmp,imagetype);\r
+ }\r
+ } else strcpy(info.szLastError,"Unable to load resource!");\r
+ return false;\r
+}\r
+#endif //WIN32\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Constructor from file name, see Load()\r
+ * \param filename: file name\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ */\r
+// \r
+// > filename: file name\r
+// > imagetype: specify the image format (CXIMAGE_FORMAT_BMP,...)\r
+// For UNICODE support: char -> TCHAR\r
+CxImage::CxImage(const TCHAR * filename, DWORD imagetype)\r
+//CxImage::CxImage(const char * filename, DWORD imagetype)\r
+{\r
+ Startup(imagetype);\r
+ Load(filename,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Constructor from file handle, see Decode()\r
+ * \param stream: file handle, with read access.\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ */\r
+CxImage::CxImage(FILE * stream, DWORD imagetype)\r
+{\r
+ Startup(imagetype);\r
+ Decode(stream,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Constructor from CxFile object, see Decode()\r
+ * \param stream: file handle (CxMemFile or CxIOFile), with read access.\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ */\r
+CxImage::CxImage(CxFile * stream, DWORD imagetype)\r
+{\r
+ Startup(imagetype);\r
+ Decode(stream,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Constructor from memory buffer, see Decode()\r
+ * \param buffer: memory buffer\r
+ * \param size: size of buffer\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ */\r
+CxImage::CxImage(BYTE * buffer, DWORD size, DWORD imagetype)\r
+{\r
+ Startup(imagetype);\r
+ CxMemFile stream(buffer,size);\r
+ Decode(&stream,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Loads an image from memory buffer\r
+ * \param buffer: memory buffer\r
+ * \param size: size of buffer\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Decode(BYTE * buffer, DWORD size, DWORD imagetype)\r
+{\r
+ CxMemFile file(buffer,size);\r
+ return Decode(&file,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Loads an image from file handle.\r
+ * \param hFile: file handle, with read access.\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Decode(FILE *hFile, DWORD imagetype)\r
+{\r
+ CxIOFile file(hFile);\r
+ return Decode(&file,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Loads an image from CxFile object\r
+ * \param hFile: file handle (CxMemFile or CxIOFile), with read access.\r
+ * \param imagetype: file format, see ENUM_CXIMAGE_FORMATS\r
+ * \return true if everything is ok\r
+ * \sa ENUM_CXIMAGE_FORMATS\r
+ */\r
+bool CxImage::Decode(CxFile *hFile, DWORD imagetype)\r
+{\r
+ if (hFile == NULL){\r
+ strcpy(info.szLastError,CXIMAGE_ERR_NOFILE);\r
+ return false;\r
+ }\r
+\r
+ if (imagetype==CXIMAGE_FORMAT_UNKNOWN){\r
+ DWORD pos = hFile->Tell();\r
+#if CXIMAGE_SUPPORT_BMP\r
+ { CxImageBMP newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+ { CxImageJPG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ { CxImageICO newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ { CxImageGIF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+ { CxImagePNG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+ { CxImageTIF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+ { CxImageMNG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+ { CxImageTGA newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+ { CxImagePCX newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+ { CxImageWBMP newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS\r
+ { CxImageWMF newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+ { CxImageJBG newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JASPER\r
+ { CxImageJAS newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_SKA\r
+ { CxImageSKA newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAW\r
+ { CxImageRAW newima; newima.CopyInfo(*this); if (newima.Decode(hFile)) { Transfer(newima); return true; } else hFile->Seek(pos,SEEK_SET); }\r
+#endif\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_BMP\r
+ if (imagetype==CXIMAGE_FORMAT_BMP){\r
+ CxImageBMP newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+ if (imagetype==CXIMAGE_FORMAT_JPG){\r
+ CxImageJPG newima;\r
+ newima.CopyInfo(*this); // <ignacio>\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ if (imagetype==CXIMAGE_FORMAT_ICO){\r
+ CxImageICO newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ info.nNumFrames = newima.info.nNumFrames;\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ if (imagetype==CXIMAGE_FORMAT_GIF){\r
+ CxImageGIF newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ info.nNumFrames = newima.info.nNumFrames;\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+ if (imagetype==CXIMAGE_FORMAT_PNG){\r
+ CxImagePNG newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+ if (imagetype==CXIMAGE_FORMAT_TIF){\r
+ CxImageTIF newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ info.nNumFrames = newima.info.nNumFrames;\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+ if (imagetype==CXIMAGE_FORMAT_MNG){\r
+ CxImageMNG newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ info.nNumFrames = newima.info.nNumFrames;\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+ if (imagetype==CXIMAGE_FORMAT_TGA){\r
+ CxImageTGA newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+ if (imagetype==CXIMAGE_FORMAT_PCX){\r
+ CxImagePCX newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+ if (imagetype==CXIMAGE_FORMAT_WBMP){\r
+ CxImageWBMP newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS // vho - WMF support\r
+ if (imagetype == CXIMAGE_FORMAT_WMF){\r
+ CxImageWMF newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+ if (imagetype==CXIMAGE_FORMAT_JBG){\r
+ CxImageJBG newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_JASPER\r
+ if (\r
+ #if CXIMAGE_SUPPORT_JP2\r
+ imagetype==CXIMAGE_FORMAT_JP2 || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_JPC\r
+ imagetype==CXIMAGE_FORMAT_JPC || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_PGX\r
+ imagetype==CXIMAGE_FORMAT_PGX || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_PNM\r
+ imagetype==CXIMAGE_FORMAT_PNM || \r
+ #endif\r
+ #if CXIMAGE_SUPPORT_RAS\r
+ imagetype==CXIMAGE_FORMAT_RAS || \r
+ #endif\r
+ false ){\r
+ CxImageJAS newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile,imagetype)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+#if CXIMAGE_SUPPORT_SKA\r
+ if (imagetype==CXIMAGE_FORMAT_SKA){\r
+ CxImageSKA newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_RAW\r
+ if (imagetype==CXIMAGE_FORMAT_RAW){\r
+ CxImageRAW newima;\r
+ newima.CopyInfo(*this);\r
+ if (newima.Decode(hFile)){\r
+ Transfer(newima);\r
+ return true;\r
+ } else {\r
+ strcpy(info.szLastError,newima.GetLastError());\r
+ return false;\r
+ }\r
+ }\r
+#endif\r
+\r
+ strcpy(info.szLastError,"Decode: Unknown or wrong format");\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Loads an image from CxFile object\r
+ * \param hFile: file handle (CxMemFile or CxIOFile), with read access.\r
+ * \param imagetype: file format, default = 0 (CXIMAGE_FORMAT_UNKNOWN)\r
+ * \return : if imagetype is not 0, the function returns true when imagetype\r
+ * matches the file image format. If imagetype is 0, the function returns true\r
+ * when the file image format is recognized as a supported format.\r
+ * If the returned value is true, use GetHeight(), GetWidth() or GetType()\r
+ * to retrieve the basic image information.\r
+ * \sa ENUM_CXIMAGE_FORMATS\r
+ */\r
+bool CxImage::CheckFormat(CxFile * hFile, DWORD imagetype)\r
+{\r
+ SetType(CXIMAGE_FORMAT_UNKNOWN);\r
+ SetEscape(-1);\r
+\r
+ if (!Decode(hFile,imagetype))\r
+ return false;\r
+\r
+ if (GetType() == CXIMAGE_FORMAT_UNKNOWN || GetType() != imagetype)\r
+ return false;\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::CheckFormat(BYTE * buffer, DWORD size, DWORD imagetype)\r
+{\r
+ if (buffer==NULL || size==NULL){\r
+ strcpy(info.szLastError,"invalid or empty buffer");\r
+ return false;\r
+ }\r
+ CxMemFile file(buffer,size);\r
+ return CheckFormat(&file,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
--- /dev/null
+/*\r
+ * File: ximaexif.cpp\r
+ * Purpose: EXIF reader\r
+ * 18/Aug/2002 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ * based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>\r
+ */\r
+\r
+#include "ximajpg.h"\r
+\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImageJPG::CxExifInfo::CxExifInfo(EXIFINFO* info)\r
+{\r
+ if (info) {\r
+ m_exifinfo = info;\r
+ freeinfo = false;\r
+ } else {\r
+ m_exifinfo = new EXIFINFO;\r
+ memset(m_exifinfo,0,sizeof(EXIFINFO));\r
+ freeinfo = true;\r
+ }\r
+\r
+ m_szLastError[0]='\0';\r
+ ExifImageWidth = MotorolaOrder = 0;\r
+ SectionsRead=0;\r
+ memset(&Sections, 0, MAX_SECTIONS * sizeof(Section_t));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImageJPG::CxExifInfo::~CxExifInfo()\r
+{\r
+ for(int i=0;i<MAX_SECTIONS;i++) if(Sections[i].Data) free(Sections[i].Data);\r
+ if (freeinfo) delete m_exifinfo;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageJPG::CxExifInfo::DecodeExif(CxFile * hFile, int nReadMode)\r
+{\r
+ int a;\r
+ int HaveCom = FALSE;\r
+\r
+ a = hFile->GetC();\r
+\r
+ if (a != 0xff || hFile->GetC() != M_SOI){\r
+ return FALSE;\r
+ }\r
+\r
+ for(;;){\r
+ int itemlen;\r
+ int marker = 0;\r
+ int ll,lh, got;\r
+ BYTE * Data;\r
+\r
+ if (SectionsRead >= MAX_SECTIONS){\r
+ strcpy(m_szLastError,"Too many sections in jpg file");\r
+ return false;\r
+ }\r
+\r
+ for (a=0;a<7;a++){\r
+ marker = hFile->GetC();\r
+ if (marker != 0xff) break;\r
+\r
+ if (a >= 6){\r
+ printf("too many padding bytes\n");\r
+ return false;\r
+ }\r
+ }\r
+\r
+ if (marker == 0xff){\r
+ // 0xff is legal padding, but if we get that many, something's wrong.\r
+ strcpy(m_szLastError,"too many padding bytes!");\r
+ return false;\r
+ }\r
+\r
+ Sections[SectionsRead].Type = marker;\r
+\r
+ // Read the length of the section.\r
+ lh = hFile->GetC();\r
+ ll = hFile->GetC();\r
+\r
+ itemlen = (lh << 8) | ll;\r
+\r
+ if (itemlen < 2){\r
+ strcpy(m_szLastError,"invalid marker");\r
+ return false;\r
+ }\r
+\r
+ Sections[SectionsRead].Size = itemlen;\r
+\r
+ Data = (BYTE *)malloc(itemlen);\r
+ if (Data == NULL){\r
+ strcpy(m_szLastError,"Could not allocate memory");\r
+ return false;\r
+ }\r
+ Sections[SectionsRead].Data = Data;\r
+\r
+ // Store first two pre-read bytes.\r
+ Data[0] = (BYTE)lh;\r
+ Data[1] = (BYTE)ll;\r
+\r
+ got = hFile->Read(Data+2, 1, itemlen-2); // Read the whole section.\r
+ if (got != itemlen-2){\r
+ strcpy(m_szLastError,"Premature end of file?");\r
+ return false;\r
+ }\r
+ SectionsRead += 1;\r
+\r
+ switch(marker){\r
+\r
+ case M_SOS: // stop before hitting compressed data \r
+ // If reading entire image is requested, read the rest of the data.\r
+ if (nReadMode & EXIF_READ_IMAGE){\r
+ int cp, ep, size;\r
+ // Determine how much file is left.\r
+ cp = hFile->Tell();\r
+ hFile->Seek(0, SEEK_END);\r
+ ep = hFile->Tell();\r
+ hFile->Seek(cp, SEEK_SET);\r
+\r
+ size = ep-cp;\r
+ Data = (BYTE *)malloc(size);\r
+ if (Data == NULL){\r
+ strcpy(m_szLastError,"could not allocate data for entire image");\r
+ return false;\r
+ }\r
+\r
+ got = hFile->Read(Data, 1, size);\r
+ if (got != size){\r
+ strcpy(m_szLastError,"could not read the rest of the image");\r
+ return false;\r
+ }\r
+\r
+ Sections[SectionsRead].Data = Data;\r
+ Sections[SectionsRead].Size = size;\r
+ Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;\r
+ SectionsRead ++;\r
+ }\r
+ return true;\r
+\r
+ case M_EOI: // in case it's a tables-only JPEG stream\r
+ printf("No image in jpeg!\n");\r
+ return FALSE;\r
+\r
+ case M_COM: // Comment section\r
+ if (HaveCom || ((nReadMode & EXIF_READ_EXIF) == 0)){\r
+ // Discard this section.\r
+ free(Sections[--SectionsRead].Data);\r
+ Sections[SectionsRead].Data=0;\r
+ }else{\r
+ process_COM(Data, itemlen);\r
+ HaveCom = TRUE;\r
+ }\r
+ break;\r
+\r
+ case M_JFIF:\r
+ // Regular jpegs always have this tag, exif images have the exif\r
+ // marker instead, althogh ACDsee will write images with both markers.\r
+ // this program will re-create this marker on absence of exif marker.\r
+ // hence no need to keep the copy from the file.\r
+ free(Sections[--SectionsRead].Data);\r
+ Sections[SectionsRead].Data=0;\r
+ break;\r
+\r
+ case M_EXIF:\r
+ // Seen files from some 'U-lead' software with Vivitar scanner\r
+ // that uses marker 31 for non exif stuff. Thus make sure \r
+ // it says 'Exif' in the section before treating it as exif.\r
+ if ((nReadMode & EXIF_READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){\r
+ m_exifinfo->IsExif = process_EXIF((BYTE *)Data+2, itemlen);\r
+ }else{\r
+ // Discard this section.\r
+ free(Sections[--SectionsRead].Data);\r
+ Sections[SectionsRead].Data=0;\r
+ }\r
+ break;\r
+\r
+ case M_SOF0: \r
+ case M_SOF1: \r
+ case M_SOF2: \r
+ case M_SOF3: \r
+ case M_SOF5: \r
+ case M_SOF6: \r
+ case M_SOF7: \r
+ case M_SOF9: \r
+ case M_SOF10:\r
+ case M_SOF11:\r
+ case M_SOF13:\r
+ case M_SOF14:\r
+ case M_SOF15:\r
+ process_SOFn(Data, marker);\r
+ break;\r
+ default:\r
+ // Skip any other sections.\r
+ //if (ShowTags) printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen);\r
+ break;\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/*--------------------------------------------------------------------------\r
+ Process a EXIF marker\r
+ Describes all the drivel that most digital cameras include...\r
+--------------------------------------------------------------------------*/\r
+bool CxImageJPG::CxExifInfo::process_EXIF(unsigned char * CharBuf, unsigned int length)\r
+{\r
+ m_exifinfo->FlashUsed = 0; \r
+ /* If it's from a digicam, and it used flash, it says so. */\r
+ m_exifinfo->Comments[0] = '\0'; /* Initial value - null string */\r
+\r
+ ExifImageWidth = 0;\r
+\r
+ { /* Check the EXIF header component */\r
+ static const unsigned char ExifHeader[] = "Exif\0\0";\r
+ if (memcmp(CharBuf+0, ExifHeader,6)){\r
+ strcpy(m_szLastError,"Incorrect Exif header");\r
+ return false;\r
+ }\r
+ }\r
+\r
+ if (memcmp(CharBuf+6,"II",2) == 0){\r
+ MotorolaOrder = 0;\r
+ }else{\r
+ if (memcmp(CharBuf+6,"MM",2) == 0){\r
+ MotorolaOrder = 1;\r
+ }else{\r
+ strcpy(m_szLastError,"Invalid Exif alignment marker.");\r
+ return false;\r
+ }\r
+ }\r
+\r
+ /* Check the next two values for correctness. */\r
+ if (Get16u(CharBuf+8) != 0x2a){\r
+ strcpy(m_szLastError,"Invalid Exif start (1)");\r
+ return false;\r
+ }\r
+\r
+ int FirstOffset = Get32u(CharBuf+10);\r
+ /* <Richard Collins> \r
+ if (FirstOffset < 8 || FirstOffset > 16){\r
+ // I used to ensure this was set to 8 (website I used indicated its 8)\r
+ // but PENTAX Optio 230 has it set differently, and uses it as offset. (Sept 11 2002)\r
+ strcpy(m_szLastError,"Suspicious offset of first IFD value");\r
+ return false;\r
+ }*/\r
+\r
+ unsigned char * LastExifRefd = CharBuf;\r
+\r
+ /* First directory starts 16 bytes in. Offsets start at 8 bytes in. */\r
+ if (!ProcessExifDir(CharBuf+14, CharBuf+6, length-6, m_exifinfo, &LastExifRefd))\r
+ return false;\r
+\r
+ /* <Richard Collins> give a chance for a second directory */\r
+ if (FirstOffset > 8) {\r
+ if (!ProcessExifDir(CharBuf+14+FirstOffset-8, CharBuf+6, length-6, m_exifinfo, &LastExifRefd))\r
+ return false;\r
+ }\r
+\r
+ /* This is how far the interesting (non thumbnail) part of the exif went. */\r
+ // int ExifSettingsLength = LastExifRefd - CharBuf;\r
+\r
+ /* Compute the CCD width, in milimeters. */\r
+ if (m_exifinfo->FocalplaneXRes != 0){\r
+ m_exifinfo->CCDWidth = (float)(ExifImageWidth * m_exifinfo->FocalplaneUnits / m_exifinfo->FocalplaneXRes);\r
+ }\r
+\r
+ return true;\r
+}\r
+//--------------------------------------------------------------------------\r
+// Get 16 bits motorola order (always) for jpeg header stuff.\r
+//--------------------------------------------------------------------------\r
+int CxImageJPG::CxExifInfo::Get16m(void * Short)\r
+{\r
+ return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/*--------------------------------------------------------------------------\r
+ Convert a 16 bit unsigned value from file's native byte order\r
+--------------------------------------------------------------------------*/\r
+int CxImageJPG::CxExifInfo::Get16u(void * Short)\r
+{\r
+ if (MotorolaOrder){\r
+ return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];\r
+ }else{\r
+ return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/*--------------------------------------------------------------------------\r
+ Convert a 32 bit signed value from file's native byte order\r
+--------------------------------------------------------------------------*/\r
+long CxImageJPG::CxExifInfo::Get32s(void * Long)\r
+{\r
+ if (MotorolaOrder){\r
+ return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)\r
+ | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );\r
+ }else{\r
+ return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)\r
+ | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/*--------------------------------------------------------------------------\r
+ Convert a 32 bit unsigned value from file's native byte order\r
+--------------------------------------------------------------------------*/\r
+unsigned long CxImageJPG::CxExifInfo::Get32u(void * Long)\r
+{\r
+ return (unsigned long)Get32s(Long) & 0xffffffff;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+/* Describes format descriptor */\r
+static const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};\r
+#define NUM_FORMATS 12\r
+\r
+#define FMT_BYTE 1 \r
+#define FMT_STRING 2\r
+#define FMT_USHORT 3\r
+#define FMT_ULONG 4\r
+#define FMT_URATIONAL 5\r
+#define FMT_SBYTE 6\r
+#define FMT_UNDEFINED 7\r
+#define FMT_SSHORT 8\r
+#define FMT_SLONG 9\r
+#define FMT_SRATIONAL 10\r
+#define FMT_SINGLE 11\r
+#define FMT_DOUBLE 12\r
+\r
+/* Describes tag values */\r
+\r
+#define TAG_EXIF_VERSION 0x9000\r
+#define TAG_EXIF_OFFSET 0x8769\r
+#define TAG_INTEROP_OFFSET 0xa005\r
+\r
+#define TAG_MAKE 0x010F\r
+#define TAG_MODEL 0x0110\r
+\r
+#define TAG_ORIENTATION 0x0112\r
+#define TAG_XRESOLUTION 0x011A\r
+#define TAG_YRESOLUTION 0x011B\r
+#define TAG_RESOLUTIONUNIT 0x0128\r
+\r
+#define TAG_EXPOSURETIME 0x829A\r
+#define TAG_FNUMBER 0x829D\r
+\r
+#define TAG_SHUTTERSPEED 0x9201\r
+#define TAG_APERTURE 0x9202\r
+#define TAG_BRIGHTNESS 0x9203\r
+#define TAG_MAXAPERTURE 0x9205\r
+#define TAG_FOCALLENGTH 0x920A\r
+\r
+#define TAG_DATETIME_ORIGINAL 0x9003\r
+#define TAG_USERCOMMENT 0x9286\r
+\r
+#define TAG_SUBJECT_DISTANCE 0x9206\r
+#define TAG_FLASH 0x9209\r
+\r
+#define TAG_FOCALPLANEXRES 0xa20E\r
+#define TAG_FOCALPLANEYRES 0xa20F\r
+#define TAG_FOCALPLANEUNITS 0xa210\r
+#define TAG_EXIF_IMAGEWIDTH 0xA002\r
+#define TAG_EXIF_IMAGELENGTH 0xA003\r
+\r
+/* the following is added 05-jan-2001 vcs */\r
+#define TAG_EXPOSURE_BIAS 0x9204\r
+#define TAG_WHITEBALANCE 0x9208\r
+#define TAG_METERING_MODE 0x9207\r
+#define TAG_EXPOSURE_PROGRAM 0x8822\r
+#define TAG_ISO_EQUIVALENT 0x8827\r
+#define TAG_COMPRESSION_LEVEL 0x9102\r
+\r
+#define TAG_THUMBNAIL_OFFSET 0x0201\r
+#define TAG_THUMBNAIL_LENGTH 0x0202\r
+\r
+\r
+/*--------------------------------------------------------------------------\r
+ Process one of the nested EXIF directories.\r
+--------------------------------------------------------------------------*/\r
+bool CxImageJPG::CxExifInfo::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,\r
+ EXIFINFO * const m_exifinfo, unsigned char ** const LastExifRefdP, int NestingLevel)\r
+{\r
+ int de;\r
+ int a;\r
+ int NumDirEntries;\r
+ unsigned ThumbnailOffset = 0;\r
+ unsigned ThumbnailSize = 0;\r
+\r
+ if (NestingLevel > 4){\r
+ strcpy(m_szLastError,"Maximum directory nesting exceeded (corrupt exif header)");\r
+ return false;\r
+ }\r
+\r
+ NumDirEntries = Get16u(DirStart);\r
+\r
+ if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)){\r
+ strcpy(m_szLastError,"Illegally sized directory");\r
+ return false;\r
+ }\r
+\r
+ for (de=0;de<NumDirEntries;de++){\r
+ int Tag, Format, Components;\r
+ unsigned char * ValuePtr;\r
+ /* This actually can point to a variety of things; it must be\r
+ cast to other types when used. But we use it as a byte-by-byte\r
+ cursor, so we declare it as a pointer to a generic byte here.\r
+ */\r
+ int ByteCount;\r
+ unsigned char * DirEntry;\r
+ DirEntry = DirStart+2+12*de;\r
+\r
+ Tag = Get16u(DirEntry);\r
+ Format = Get16u(DirEntry+2);\r
+ Components = Get32u(DirEntry+4);\r
+\r
+ if ((Format-1) >= NUM_FORMATS) {\r
+ /* (-1) catches illegal zero case as unsigned underflows to positive large */\r
+ strcpy(m_szLastError,"Illegal format code in EXIF dir");\r
+ return false;\r
+ }\r
+\r
+ ByteCount = Components * BytesPerFormat[Format];\r
+\r
+ if (ByteCount > 4){\r
+ unsigned OffsetVal;\r
+ OffsetVal = Get32u(DirEntry+8);\r
+ /* If its bigger than 4 bytes, the dir entry contains an offset.*/\r
+ if (OffsetVal+ByteCount > ExifLength){\r
+ /* Bogus pointer offset and / or bytecount value */\r
+ strcpy(m_szLastError,"Illegal pointer offset value in EXIF.");\r
+ return false;\r
+ }\r
+ ValuePtr = OffsetBase+OffsetVal;\r
+ }else{\r
+ /* 4 bytes or less and value is in the dir entry itself */\r
+ ValuePtr = DirEntry+8;\r
+ }\r
+\r
+ if (*LastExifRefdP < ValuePtr+ByteCount){\r
+ /* Keep track of last byte in the exif header that was\r
+ actually referenced. That way, we know where the\r
+ discardable thumbnail data begins.\r
+ */\r
+ *LastExifRefdP = ValuePtr+ByteCount;\r
+ }\r
+\r
+ /* Extract useful components of tag */\r
+ switch(Tag){\r
+\r
+ case TAG_MAKE:\r
+ strncpy(m_exifinfo->CameraMake, (char*)ValuePtr, 31);\r
+ break;\r
+\r
+ case TAG_MODEL:\r
+ strncpy(m_exifinfo->CameraModel, (char*)ValuePtr, 39);\r
+ break;\r
+\r
+ case TAG_EXIF_VERSION:\r
+ strncpy(m_exifinfo->Version,(char*)ValuePtr, 4);\r
+ break;\r
+\r
+ case TAG_DATETIME_ORIGINAL:\r
+ strncpy(m_exifinfo->DateTime, (char*)ValuePtr, 19);\r
+ break;\r
+\r
+ case TAG_USERCOMMENT:\r
+ // Olympus has this padded with trailing spaces. Remove these first. \r
+ for (a=ByteCount;;){\r
+ a--;\r
+ if (((char*)ValuePtr)[a] == ' '){\r
+ ((char*)ValuePtr)[a] = '\0';\r
+ }else{\r
+ break;\r
+ }\r
+ if (a == 0) break;\r
+ }\r
+\r
+ /* Copy the comment */\r
+ if (memcmp(ValuePtr, "ASCII",5) == 0){\r
+ for (a=5;a<10;a++){\r
+ char c;\r
+ c = ((char*)ValuePtr)[a];\r
+ if (c != '\0' && c != ' '){\r
+ strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, 199);\r
+ break;\r
+ }\r
+ }\r
+ \r
+ }else{\r
+ strncpy(m_exifinfo->Comments, (char*)ValuePtr, 199);\r
+ }\r
+ break;\r
+\r
+ case TAG_FNUMBER:\r
+ /* Simplest way of expressing aperture, so I trust it the most.\r
+ (overwrite previously computd value if there is one)\r
+ */\r
+ m_exifinfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_APERTURE:\r
+ case TAG_MAXAPERTURE:\r
+ /* More relevant info always comes earlier, so only\r
+ use this field if we don't have appropriate aperture\r
+ information yet. \r
+ */\r
+ if (m_exifinfo->ApertureFNumber == 0){\r
+ m_exifinfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)*0.5);\r
+ }\r
+ break;\r
+\r
+ case TAG_BRIGHTNESS:\r
+ m_exifinfo->Brightness = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_FOCALLENGTH:\r
+ /* Nice digital cameras actually save the focal length\r
+ as a function of how farthey are zoomed in. \r
+ */\r
+\r
+ m_exifinfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_SUBJECT_DISTANCE:\r
+ /* Inidcates the distacne the autofocus camera is focused to.\r
+ Tends to be less accurate as distance increases.\r
+ */\r
+ m_exifinfo->Distance = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_EXPOSURETIME:\r
+ /* Simplest way of expressing exposure time, so I\r
+ trust it most. (overwrite previously computd value\r
+ if there is one) \r
+ */\r
+ m_exifinfo->ExposureTime = \r
+ (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_SHUTTERSPEED:\r
+ /* More complicated way of expressing exposure time,\r
+ so only use this value if we don't already have it\r
+ from somewhere else. \r
+ */\r
+ if (m_exifinfo->ExposureTime == 0){\r
+ m_exifinfo->ExposureTime = (float)\r
+ (1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0f)));\r
+ }\r
+ break;\r
+\r
+ case TAG_FLASH:\r
+ if ((int)ConvertAnyFormat(ValuePtr, Format) & 7){\r
+ m_exifinfo->FlashUsed = 1;\r
+ }else{\r
+ m_exifinfo->FlashUsed = 0;\r
+ }\r
+ break;\r
+\r
+ case TAG_ORIENTATION:\r
+ m_exifinfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format);\r
+ if (m_exifinfo->Orientation < 1 || m_exifinfo->Orientation > 8){\r
+ strcpy(m_szLastError,"Undefined rotation value");\r
+ m_exifinfo->Orientation = 0;\r
+ }\r
+ break;\r
+\r
+ case TAG_EXIF_IMAGELENGTH:\r
+ case TAG_EXIF_IMAGEWIDTH:\r
+ /* Use largest of height and width to deal with images\r
+ that have been rotated to portrait format. \r
+ */\r
+ a = (int)ConvertAnyFormat(ValuePtr, Format);\r
+ if (ExifImageWidth < a) ExifImageWidth = a;\r
+ break;\r
+\r
+ case TAG_FOCALPLANEXRES:\r
+ m_exifinfo->FocalplaneXRes = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_FOCALPLANEYRES:\r
+ m_exifinfo->FocalplaneYRes = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_RESOLUTIONUNIT:\r
+ switch((int)ConvertAnyFormat(ValuePtr, Format)){\r
+ case 1: m_exifinfo->ResolutionUnit = 1.0f; break; /* 1 inch */\r
+ case 2: m_exifinfo->ResolutionUnit = 1.0f; break;\r
+ case 3: m_exifinfo->ResolutionUnit = 0.3937007874f; break; /* 1 centimeter*/\r
+ case 4: m_exifinfo->ResolutionUnit = 0.03937007874f; break; /* 1 millimeter*/\r
+ case 5: m_exifinfo->ResolutionUnit = 0.00003937007874f; /* 1 micrometer*/\r
+ }\r
+ break;\r
+\r
+ case TAG_FOCALPLANEUNITS:\r
+ switch((int)ConvertAnyFormat(ValuePtr, Format)){\r
+ case 1: m_exifinfo->FocalplaneUnits = 1.0f; break; /* 1 inch */\r
+ case 2: m_exifinfo->FocalplaneUnits = 1.0f; break;\r
+ case 3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; /* 1 centimeter*/\r
+ case 4: m_exifinfo->FocalplaneUnits = 0.03937007874f; break; /* 1 millimeter*/\r
+ case 5: m_exifinfo->FocalplaneUnits = 0.00003937007874f; /* 1 micrometer*/\r
+ }\r
+ break;\r
+\r
+ // Remaining cases contributed by: Volker C. Schoech <schoech(at)gmx(dot)de>\r
+\r
+ case TAG_EXPOSURE_BIAS:\r
+ m_exifinfo->ExposureBias = (float) ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_WHITEBALANCE:\r
+ m_exifinfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_METERING_MODE:\r
+ m_exifinfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_EXPOSURE_PROGRAM:\r
+ m_exifinfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_ISO_EQUIVALENT:\r
+ m_exifinfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);\r
+ if ( m_exifinfo->ISOequivalent < 50 ) m_exifinfo->ISOequivalent *= 200;\r
+ break;\r
+\r
+ case TAG_COMPRESSION_LEVEL:\r
+ m_exifinfo->CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_XRESOLUTION:\r
+ m_exifinfo->Xresolution = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+ case TAG_YRESOLUTION:\r
+ m_exifinfo->Yresolution = (float)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_THUMBNAIL_OFFSET:\r
+ ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ case TAG_THUMBNAIL_LENGTH:\r
+ ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);\r
+ break;\r
+\r
+ }\r
+\r
+ if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){\r
+ unsigned char * SubdirStart;\r
+ unsigned Offset = Get32u(ValuePtr);\r
+ if (Offset>8){\r
+ SubdirStart = OffsetBase + Offset;\r
+ if (SubdirStart < OffsetBase || \r
+ SubdirStart > OffsetBase+ExifLength){\r
+ strcpy(m_szLastError,"Illegal subdirectory link");\r
+ return false;\r
+ }\r
+ ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1);\r
+ }\r
+ continue;\r
+ }\r
+ }\r
+\r
+\r
+ {\r
+ /* In addition to linking to subdirectories via exif tags,\r
+ there's also a potential link to another directory at the end\r
+ of each directory. This has got to be the result of a\r
+ committee! \r
+ */\r
+ unsigned char * SubdirStart;\r
+ unsigned Offset;\r
+ Offset = Get16u(DirStart+2+12*NumDirEntries);\r
+ if (Offset){\r
+ SubdirStart = OffsetBase + Offset;\r
+ if (SubdirStart < OffsetBase \r
+ || SubdirStart > OffsetBase+ExifLength){\r
+ strcpy(m_szLastError,"Illegal subdirectory link");\r
+ return false;\r
+ }\r
+ ProcessExifDir(SubdirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP, NestingLevel+1);\r
+ }\r
+ }\r
+\r
+\r
+ if (ThumbnailSize && ThumbnailOffset){\r
+ if (ThumbnailSize + ThumbnailOffset <= ExifLength){\r
+ /* The thumbnail pointer appears to be valid. Store it. */\r
+ m_exifinfo->ThumbnailPointer = OffsetBase + ThumbnailOffset;\r
+ m_exifinfo->ThumbnailSize = ThumbnailSize;\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/*--------------------------------------------------------------------------\r
+ Evaluate number, be it int, rational, or float from directory.\r
+--------------------------------------------------------------------------*/\r
+double CxImageJPG::CxExifInfo::ConvertAnyFormat(void * ValuePtr, int Format)\r
+{\r
+ double Value;\r
+ Value = 0;\r
+\r
+ switch(Format){\r
+ case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;\r
+ case FMT_BYTE: Value = *(unsigned char *)ValuePtr; break;\r
+\r
+ case FMT_USHORT: Value = Get16u(ValuePtr); break;\r
+ case FMT_ULONG: Value = Get32u(ValuePtr); break;\r
+\r
+ case FMT_URATIONAL:\r
+ case FMT_SRATIONAL: \r
+ {\r
+ int Num,Den;\r
+ Num = Get32s(ValuePtr);\r
+ Den = Get32s(4+(char *)ValuePtr);\r
+ if (Den == 0){\r
+ Value = 0;\r
+ }else{\r
+ Value = (double)Num/Den;\r
+ }\r
+ break;\r
+ }\r
+\r
+ case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;\r
+ case FMT_SLONG: Value = Get32s(ValuePtr); break;\r
+\r
+ /* Not sure if this is correct (never seen float used in Exif format)\r
+ */\r
+ case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;\r
+ case FMT_DOUBLE: Value = *(double *)ValuePtr; break;\r
+ }\r
+ return Value;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageJPG::CxExifInfo::process_COM (const BYTE * Data, int length)\r
+{\r
+ int ch;\r
+ char Comment[MAX_COMMENT+1];\r
+ int nch;\r
+ int a;\r
+\r
+ nch = 0;\r
+\r
+ if (length > MAX_COMMENT) length = MAX_COMMENT; // Truncate if it won't fit in our structure.\r
+\r
+ for (a=2;a<length;a++){\r
+ ch = Data[a];\r
+\r
+ if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.\r
+\r
+ if (isprint(ch) || ch == '\n' || ch == '\t'){\r
+ Comment[nch++] = (char)ch;\r
+ }else{\r
+ Comment[nch++] = '?';\r
+ }\r
+ }\r
+\r
+ Comment[nch] = '\0'; // Null terminate\r
+\r
+ //if (ShowTags) printf("COM marker comment: %s\n",Comment);\r
+\r
+ strcpy(m_exifinfo->Comments,Comment);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageJPG::CxExifInfo::process_SOFn (const BYTE * Data, int marker)\r
+{\r
+ int data_precision, num_components;\r
+\r
+ data_precision = Data[2];\r
+ m_exifinfo->Height = Get16m((void*)(Data+3));\r
+ m_exifinfo->Width = Get16m((void*)(Data+5));\r
+ num_components = Data[7];\r
+\r
+ if (num_components == 3){\r
+ m_exifinfo->IsColor = 1;\r
+ }else{\r
+ m_exifinfo->IsColor = 0;\r
+ }\r
+\r
+ m_exifinfo->Process = marker;\r
+\r
+ //if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",\r
+ // ImageInfo.Width, ImageInfo.Height, num_components, data_precision);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * this will work only on a CxImageJPG object, if the image originally has valid EXIF data\r
+ \verbatim\r
+ CxImageJPG jpg;\r
+ CxIOFile in,out;\r
+ in.Open("D:\\exif_in.jpg","rb");\r
+ out.Open("D:\\exif_out.jpg","w+b");\r
+ jpg.Decode(&in);\r
+ if (jpg.IsValid()){\r
+ jpg.RotateLeft();\r
+ jpg.Encode(&out);\r
+ }\r
+ \endverbatim\r
+*/\r
+bool CxImageJPG::CxExifInfo::EncodeExif(CxFile * hFile)\r
+{\r
+ int a;\r
+\r
+ if (FindSection(M_SOS)==NULL){\r
+ strcpy(m_szLastError,"Can't write exif : didn't read all");\r
+ return false;\r
+ }\r
+\r
+ // Initial static jpeg marker.\r
+ hFile->PutC(0xff);\r
+ hFile->PutC(0xd8);\r
+ \r
+ if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){\r
+ // The image must start with an exif or jfif marker. If we threw those away, create one.\r
+ static BYTE JfifHead[18] = {\r
+ 0xff, M_JFIF,\r
+ 0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01, \r
+ 0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00 \r
+ };\r
+ hFile->Write(JfifHead, 18, 1);\r
+ }\r
+\r
+ // Write all the misc sections\r
+ for (a=0;a<SectionsRead-1;a++){\r
+ hFile->PutC(0xff);\r
+ hFile->PutC((unsigned char)(Sections[a].Type));\r
+ hFile->Write(Sections[a].Data, Sections[a].Size, 1);\r
+ }\r
+\r
+ // Write the remaining image data.\r
+ hFile->Write(Sections[a].Data, Sections[a].Size, 1);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageJPG::CxExifInfo::DiscardAllButExif()\r
+{\r
+ Section_t ExifKeeper;\r
+ Section_t CommentKeeper;\r
+ int a;\r
+\r
+ memset(&ExifKeeper, 0, sizeof(ExifKeeper));\r
+ memset(&CommentKeeper, 0, sizeof(ExifKeeper));\r
+\r
+ for (a=0;a<SectionsRead;a++){\r
+ if (Sections[a].Type == M_EXIF && ExifKeeper.Type == 0){\r
+ ExifKeeper = Sections[a];\r
+ }else if (Sections[a].Type == M_COM && CommentKeeper.Type == 0){\r
+ CommentKeeper = Sections[a];\r
+ }else{\r
+ free(Sections[a].Data);\r
+ Sections[a].Data = 0;\r
+ }\r
+ }\r
+ SectionsRead = 0;\r
+ if (ExifKeeper.Type){\r
+ Sections[SectionsRead++] = ExifKeeper;\r
+ }\r
+ if (CommentKeeper.Type){\r
+ Sections[SectionsRead++] = CommentKeeper;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void* CxImageJPG::CxExifInfo::FindSection(int SectionType)\r
+{\r
+ int a;\r
+ for (a=0;a<SectionsRead-1;a++){\r
+ if (Sections[a].Type == SectionType){\r
+ return &Sections[a];\r
+ }\r
+ }\r
+ // Could not be found.\r
+ return NULL;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGEJPG_SUPPORT_EXIF\r
+\r
--- /dev/null
+// ximage.cpp : main implementation file\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// CxImage \r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Initialize the internal structures\r
+ */\r
+void CxImage::Startup(DWORD imagetype)\r
+{\r
+ //init pointers\r
+ pDib = pSelection = pAlpha = NULL;\r
+ ppLayers = ppFrames = NULL;\r
+ //init structures\r
+ memset(&head,0,sizeof(BITMAPINFOHEADER));\r
+ memset(&info,0,sizeof(CXIMAGEINFO));\r
+ //init default attributes\r
+ info.dwType = imagetype;\r
+ info.fQuality = 90.0f;\r
+ info.nAlphaMax = 255;\r
+ info.nBkgndIndex = -1;\r
+ info.bEnabled = true;\r
+ SetXDPI(CXIMAGE_DEFAULT_DPI);\r
+ SetYDPI(CXIMAGE_DEFAULT_DPI);\r
+\r
+ short test = 1;\r
+ info.bLittleEndianHost = (*((char *) &test) == 1);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Empty image constructor\r
+ * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS\r
+ */\r
+CxImage::CxImage(DWORD imagetype)\r
+{\r
+ Startup(imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Call this function to destroy image pixels, alpha channel, selection and sub layers.\r
+ * - Attributes are not erased, but IsValid returns false.\r
+ *\r
+ * \return true if everything is freed, false if the image is a Ghost\r
+ */\r
+bool CxImage::Destroy()\r
+{\r
+ //free this only if it's valid and it's not a ghost\r
+ if (info.pGhost==NULL){\r
+ if (ppLayers) { \r
+ for(long n=0; n<info.nNumLayers;n++){ delete ppLayers[n]; }\r
+ delete [] ppLayers; ppLayers=0; info.nNumLayers = 0;\r
+ }\r
+ if (pSelection) {free(pSelection); pSelection=0;}\r
+ if (pAlpha) {free(pAlpha); pAlpha=0;}\r
+ if (pDib) {free(pDib); pDib=0;}\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::DestroyFrames()\r
+{\r
+ if (info.pGhost==NULL) {\r
+ if (ppFrames) {\r
+ for (long n=0; n<info.nNumFrames; n++) { delete ppFrames[n]; }\r
+ delete [] ppFrames; ppFrames = NULL; info.nNumFrames = 0;\r
+ }\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sized image constructor\r
+ * \param dwWidth: width\r
+ * \param dwHeight: height\r
+ * \param wBpp: bit per pixel, can be 1, 4, 8, 24\r
+ * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS\r
+ */\r
+CxImage::CxImage(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)\r
+{\r
+ Startup(imagetype);\r
+ Create(dwWidth,dwHeight,wBpp,imagetype);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * image constructor from existing source\r
+ * \param src: source image.\r
+ * \param copypixels: copy the pixels from the source image into the new image.\r
+ * \param copyselection: copy the selection from source\r
+ * \param copyalpha: copy the alpha channel from source\r
+ * \sa Copy\r
+ */\r
+CxImage::CxImage(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)\r
+{\r
+ Startup(src.GetType());\r
+ Copy(src,copypixels,copyselection,copyalpha);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Copies the image from an exsisting source\r
+ * \param src: source image.\r
+ * \param copypixels: copy the pixels from the source image into the new image.\r
+ * \param copyselection: copy the selection from source\r
+ * \param copyalpha: copy the alpha channel from source\r
+ */\r
+void CxImage::Copy(const CxImage &src, bool copypixels, bool copyselection, bool copyalpha)\r
+{\r
+ // if the source is a ghost, the copy is still a ghost\r
+ if (src.info.pGhost){\r
+ Ghost(&src);\r
+ return;\r
+ }\r
+ //copy the attributes\r
+ memcpy(&info,&src.info,sizeof(CXIMAGEINFO));\r
+ memcpy(&head,&src.head,sizeof(BITMAPINFOHEADER)); // [andy] - fix for bitmap header DPI\r
+ //rebuild the image\r
+ Create(src.GetWidth(),src.GetHeight(),src.GetBpp(),src.GetType());\r
+ //copy the pixels and the palette, or at least copy the palette only.\r
+ if (copypixels && pDib && src.pDib) memcpy(pDib,src.pDib,GetSize());\r
+ else SetPalette(src.GetPalette());\r
+ long nSize = head.biWidth * head.biHeight;\r
+ //copy the selection\r
+ if (copyselection && src.pSelection){\r
+ if (pSelection) free(pSelection);\r
+ pSelection = (BYTE*)malloc(nSize);\r
+ memcpy(pSelection,src.pSelection,nSize);\r
+ }\r
+ //copy the alpha channel\r
+ if (copyalpha && src.pAlpha){\r
+ if (pAlpha) free(pAlpha);\r
+ pAlpha = (BYTE*)malloc(nSize);\r
+ memcpy(pAlpha,src.pAlpha,nSize);\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Copies the image attributes from an existing image.\r
+ * - Works only on an empty image, and the image will be still empty.\r
+ * - <b> Use it before Create() </b>\r
+ */\r
+void CxImage::CopyInfo(const CxImage &src)\r
+{\r
+ if (pDib==NULL) memcpy(&info,&src.info,sizeof(CXIMAGEINFO));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa Copy\r
+ */\r
+CxImage& CxImage::operator = (const CxImage& isrc)\r
+{\r
+ if (this != &isrc) Copy(isrc);\r
+ return *this;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Initializes or rebuilds the image.\r
+ * \param dwWidth: width\r
+ * \param dwHeight: height\r
+ * \param wBpp: bit per pixel, can be 1, 4, 8, 24\r
+ * \param imagetype: (optional) set the image format, see ENUM_CXIMAGE_FORMATS\r
+ * \return pointer to the internal pDib object; NULL if an error occurs.\r
+ */\r
+void* CxImage::Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype)\r
+{\r
+ // destroy the existing image (if any)\r
+ if (!Destroy())\r
+ return NULL;\r
+\r
+ // prevent further actions if width or height are not vaild <Balabasnia>\r
+ if ((dwWidth == 0) || (dwHeight == 0)){\r
+ strcpy(info.szLastError,"CxImage::Create : width and height must be greater than zero");\r
+ return NULL;\r
+ }\r
+\r
+ // Make sure bits per pixel is valid\r
+ if (wBpp <= 1) wBpp = 1;\r
+ else if (wBpp <= 4) wBpp = 4;\r
+ else if (wBpp <= 8) wBpp = 8;\r
+ else wBpp = 24;\r
+\r
+ // limit memory requirements (and also a check for bad parameters)\r
+ if (((dwWidth*dwHeight*wBpp)>>3) > CXIMAGE_MAX_MEMORY ||\r
+ ((dwWidth*dwHeight*wBpp)/wBpp) != (dwWidth*dwHeight))\r
+ {\r
+ strcpy(info.szLastError,"CXIMAGE_MAX_MEMORY exceeded");\r
+ return NULL;\r
+ }\r
+\r
+ // set the correct bpp value\r
+ switch (wBpp){\r
+ case 1:\r
+ head.biClrUsed = 2; break;\r
+ case 4:\r
+ head.biClrUsed = 16; break;\r
+ case 8:\r
+ head.biClrUsed = 256; break;\r
+ default:\r
+ head.biClrUsed = 0;\r
+ }\r
+\r
+ //set the common image informations\r
+ info.dwEffWidth = ((((wBpp * dwWidth) + 31) / 32) * 4);\r
+ info.dwType = imagetype;\r
+\r
+ // initialize BITMAPINFOHEADER\r
+ head.biSize = sizeof(BITMAPINFOHEADER); //<ralphw>\r
+ head.biWidth = dwWidth; // fill in width from parameter\r
+ head.biHeight = dwHeight; // fill in height from parameter\r
+ head.biPlanes = 1; // must be 1\r
+ head.biBitCount = (WORD)wBpp; // from parameter\r
+ head.biCompression = BI_RGB; \r
+ head.biSizeImage = info.dwEffWidth * dwHeight;\r
+// head.biXPelsPerMeter = 0; See SetXDPI\r
+// head.biYPelsPerMeter = 0; See SetYDPI\r
+// head.biClrImportant = 0; See SetClrImportant\r
+\r
+ pDib = malloc(GetSize()); // alloc memory block to store our bitmap\r
+ if (!pDib){\r
+ strcpy(info.szLastError,"CxImage::Create can't allocate memory");\r
+ return NULL;\r
+ }\r
+\r
+ //clear the palette\r
+ RGBQUAD* pal=GetPalette();\r
+ if (pal) memset(pal,0,GetPaletteSize());\r
+ //Destroy the existing selection\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (pSelection) SelectionDelete();\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ //Destroy the existing alpha channel\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pAlpha) AlphaDelete();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ // use our bitmap info structure to fill in first part of\r
+ // our DIB with the BITMAPINFOHEADER\r
+ BITMAPINFOHEADER* lpbi;\r
+ lpbi = (BITMAPINFOHEADER*)(pDib);\r
+ *lpbi = head;\r
+\r
+ info.pImage=GetBits();\r
+\r
+ return pDib; //return handle to the DIB\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return pointer to the image pixels. <b> USE CAREFULLY </b>\r
+ */\r
+BYTE* CxImage::GetBits(DWORD row)\r
+{ \r
+ if (pDib){\r
+ if (row) {\r
+ if (row<(DWORD)head.biHeight){\r
+ return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize() + (info.dwEffWidth * row));\r
+ } else {\r
+ return NULL;\r
+ }\r
+ } else {\r
+ return ((BYTE*)pDib + *(DWORD*)pDib + GetPaletteSize());\r
+ }\r
+ }\r
+ return NULL;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return the size in bytes of the internal pDib object\r
+ */\r
+long CxImage::GetSize()\r
+{\r
+ return head.biSize + head.biSizeImage + GetPaletteSize();\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if the coordinates are inside the image\r
+ * \return true if x and y are both inside the image\r
+ */\r
+bool CxImage::IsInside(long x, long y)\r
+{\r
+ return (0<=y && y<head.biHeight && 0<=x && x<head.biWidth);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the image bits to the specified value\r
+ * - for indexed images, the output color is set by the palette entries.\r
+ * - for RGB images, the output color is a shade of gray.\r
+ */\r
+void CxImage::Clear(BYTE bval)\r
+{\r
+ if (pDib == 0) return;\r
+\r
+ if (GetBpp() == 1){\r
+ if (bval > 0) bval = 255;\r
+ }\r
+ if (GetBpp() == 4){\r
+ bval = (BYTE)(17*(0x0F & bval));\r
+ }\r
+\r
+ memset(info.pImage,bval,head.biSizeImage);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Transfers the image from an existing source image. The source becomes empty.\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::Transfer(CxImage &from, bool bTransferFrames /*=true*/)\r
+{\r
+ if (!Destroy())\r
+ return false;\r
+\r
+ memcpy(&head,&from.head,sizeof(BITMAPINFOHEADER));\r
+ memcpy(&info,&from.info,sizeof(CXIMAGEINFO));\r
+\r
+ pDib = from.pDib;\r
+ pSelection = from.pSelection;\r
+ pAlpha = from.pAlpha;\r
+ ppLayers = from.ppLayers;\r
+\r
+ memset(&from.head,0,sizeof(BITMAPINFOHEADER));\r
+ memset(&from.info,0,sizeof(CXIMAGEINFO));\r
+ from.pDib = from.pSelection = from.pAlpha = NULL;\r
+ from.ppLayers = NULL;\r
+\r
+ if (bTransferFrames){\r
+ DestroyFrames();\r
+ ppFrames = from.ppFrames;\r
+ from.ppFrames = NULL;\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * (this) points to the same pDib owned by (*from), the image remains in (*from)\r
+ * but (this) has the access to the pixels. <b>Use carefully !!!</b>\r
+ */\r
+void CxImage::Ghost(const CxImage *from)\r
+{\r
+ if (from){\r
+ memcpy(&head,&from->head,sizeof(BITMAPINFOHEADER));\r
+ memcpy(&info,&from->info,sizeof(CXIMAGEINFO));\r
+ pDib = from->pDib;\r
+ pSelection = from->pSelection;\r
+ pAlpha = from->pAlpha;\r
+ ppLayers = from->ppLayers;\r
+ ppFrames = from->ppFrames;\r
+ info.pGhost=(CxImage *)from;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * turns a 16 or 32 bit bitfield image into a RGB image\r
+ */\r
+void CxImage::Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp)\r
+{\r
+ switch (bpp){\r
+ case 16:\r
+ {\r
+ DWORD ns[3]={0,0,0};\r
+ // compute the number of shift for each mask\r
+ for (int i=0;i<16;i++){\r
+ if ((redmask>>i)&0x01) ns[0]++;\r
+ if ((greenmask>>i)&0x01) ns[1]++;\r
+ if ((bluemask>>i)&0x01) ns[2]++;\r
+ }\r
+ ns[1]+=ns[0]; ns[2]+=ns[1]; ns[0]=8-ns[0]; ns[1]-=8; ns[2]-=8;\r
+ // dword aligned width for 16 bit image\r
+ long effwidth2=(((head.biWidth + 1) / 2) * 4);\r
+ WORD w;\r
+ long y2,y3,x2,x3;\r
+ BYTE *p=info.pImage;\r
+ // scan the buffer in reverse direction to avoid reallocations\r
+ for (long y=head.biHeight-1; y>=0; y--){\r
+ y2=effwidth2*y;\r
+ y3=info.dwEffWidth*y;\r
+ for (long x=head.biWidth-1; x>=0; x--){\r
+ x2 = 2*x+y2;\r
+ x3 = 3*x+y3;\r
+ w = (WORD)(src[x2]+256*src[1+x2]);\r
+ p[ x3]=(BYTE)((w & bluemask)<<ns[0]);\r
+ p[1+x3]=(BYTE)((w & greenmask)>>ns[1]);\r
+ p[2+x3]=(BYTE)((w & redmask)>>ns[2]);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 32:\r
+ {\r
+ DWORD ns[3]={0,0,0};\r
+ // compute the number of shift for each mask\r
+ for (int i=8;i<32;i+=8){\r
+ if (redmask>>i) ns[0]++;\r
+ if (greenmask>>i) ns[1]++;\r
+ if (bluemask>>i) ns[2]++;\r
+ }\r
+ // dword aligned width for 32 bit image\r
+ long effwidth4 = head.biWidth * 4;\r
+ long y4,y3,x4,x3;\r
+ BYTE *p=info.pImage;\r
+ // scan the buffer in reverse direction to avoid reallocations\r
+ for (long y=head.biHeight-1; y>=0; y--){\r
+ y4=effwidth4*y;\r
+ y3=info.dwEffWidth*y;\r
+ for (long x=head.biWidth-1; x>=0; x--){\r
+ x4 = 4*x+y4;\r
+ x3 = 3*x+y3;\r
+ p[ x3]=src[ns[2]+x4];\r
+ p[1+x3]=src[ns[1]+x4];\r
+ p[2+x3]=src[ns[0]+x4];\r
+ }\r
+ }\r
+ }\r
+\r
+ }\r
+ return;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Creates an image from a generic buffer\r
+ * \param pArray: source memory buffer\r
+ * \param dwWidth: image width\r
+ * \param dwHeight: image height\r
+ * \param dwBitsperpixel: can be 1,4,8,24,32\r
+ * \param dwBytesperline: line alignment, in bytes, for a single row stored in pArray\r
+ * \param bFlipImage: tune this parameter if the image is upsidedown\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)\r
+{\r
+ if (pArray==NULL) return false;\r
+ if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||\r
+ (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;\r
+\r
+ if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;\r
+\r
+ if (dwBitsperpixel<24) SetGrayPalette();\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (dwBitsperpixel==32) AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ BYTE *dst,*src;\r
+\r
+ for (DWORD y = 0; y<dwHeight; y++) {\r
+ dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;\r
+ src = pArray + y * dwBytesperline;\r
+ if (dwBitsperpixel==32){\r
+ for(DWORD x=0;x<dwWidth;x++){\r
+ *dst++=src[0];\r
+ *dst++=src[1];\r
+ *dst++=src[2];\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ src+=4;\r
+ }\r
+ } else {\r
+ memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa CreateFromArray\r
+ */\r
+bool CxImage::CreateFromMatrix(BYTE** ppMatrix,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage)\r
+{\r
+ if (ppMatrix==NULL) return false;\r
+ if (!((dwBitsperpixel==1)||(dwBitsperpixel==4)||(dwBitsperpixel==8)||\r
+ (dwBitsperpixel==24)||(dwBitsperpixel==32))) return false;\r
+\r
+ if (!Create(dwWidth,dwHeight,dwBitsperpixel)) return false;\r
+\r
+ if (dwBitsperpixel<24) SetGrayPalette();\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (dwBitsperpixel==32) AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ BYTE *dst,*src;\r
+\r
+ for (DWORD y = 0; y<dwHeight; y++) {\r
+ dst = info.pImage + (bFlipImage?(dwHeight-1-y):y) * info.dwEffWidth;\r
+ src = ppMatrix[y];\r
+ if (src){\r
+ if (dwBitsperpixel==32){\r
+ for(DWORD x=0;x<dwWidth;x++){\r
+ *dst++=src[0];\r
+ *dst++=src[1];\r
+ *dst++=src[2];\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaSet(x,(bFlipImage?(dwHeight-1-y):y),src[3]);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ src+=4;\r
+ }\r
+ } else {\r
+ memcpy(dst,src,min(info.dwEffWidth,dwBytesperline));\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return lightness difference between elem1 and elem2\r
+ */\r
+int CxImage::CompareColors(const void *elem1, const void *elem2)\r
+{\r
+ RGBQUAD* c1 = (RGBQUAD*)elem1;\r
+ RGBQUAD* c2 = (RGBQUAD*)elem2;\r
+\r
+ int g1 = (int)RGB2GRAY(c1->rgbRed,c1->rgbGreen,c1->rgbBlue);\r
+ int g2 = (int)RGB2GRAY(c2->rgbRed,c2->rgbGreen,c2->rgbBlue);\r
+ \r
+ return (g1-g2);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * simply calls "if (memblock) free(memblock);".\r
+ * Useful when calling Encode for a memory buffer,\r
+ * from a DLL compiled with different memory management options.\r
+ * CxImage::FreeMemory will use the same memory environment used by Encode. \r
+ * \author [livecn]\r
+ */\r
+void CxImage::FreeMemory(void* memblock)\r
+{\r
+ if (memblock)\r
+ free(memblock);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+//EOF\r
--- /dev/null
+/*\r
+ * File: ximage.h\r
+ * Purpose: General Purpose Image Class \r
+ */\r
+/*\r
+ --------------------------------------------------------------------------------\r
+\r
+ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:\r
+\r
+ CxImage version 6.0.0 02/Feb/2008\r
+\r
+ CxImage : Copyright (C) 2001 - 2008, Davide Pizzolato\r
+\r
+ Original CImage and CImageIterator implementation are:\r
+ Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx)\r
+\r
+ Covered code is provided under this license on an "as is" basis, without warranty\r
+ of any kind, either expressed or implied, including, without limitation, warranties\r
+ that the covered code is free of defects, merchantable, fit for a particular purpose\r
+ or non-infringing. The entire risk as to the quality and performance of the covered\r
+ code is with you. Should any covered code prove defective in any respect, you (not\r
+ the initial developer or any other contributor) assume the cost of any necessary\r
+ servicing, repair or correction. This disclaimer of warranty constitutes an essential\r
+ part of this license. No use of any covered code is authorized hereunder except under\r
+ this disclaimer.\r
+\r
+ Permission is hereby granted to use, copy, modify, and distribute this\r
+ source code, or portions hereof, for any purpose, including commercial applications,\r
+ freely and without fee, subject to the following restrictions: \r
+\r
+ 1. The origin of this software must not be misrepresented; you must not\r
+ claim that you wrote the original software. If you use this software\r
+ in a product, an acknowledgment in the product documentation would be\r
+ appreciated but is not required.\r
+\r
+ 2. Altered source versions must be plainly marked as such, and must not be\r
+ misrepresented as being the original software.\r
+\r
+ 3. This notice may not be removed or altered from any source distribution.\r
+\r
+ --------------------------------------------------------------------------------\r
+\r
+ Other information about CxImage, and the latest version, can be found at the\r
+ CxImage home page: http://www.xdp.it/cximage/\r
+\r
+ --------------------------------------------------------------------------------\r
+ */\r
+#if !defined(__CXIMAGE_H)\r
+#define __CXIMAGE_H\r
+\r
+#if _MSC_VER > 1000\r
+#pragma once\r
+#endif \r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#include "xfile.h"\r
+#include "xiofile.h"\r
+#include "xmemfile.h"\r
+#include "ximadef.h" //<vho> adjust some #define\r
+\r
+/* see "ximacfg.h" for CxImage configuration options */\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CxImage formats enumerator\r
+enum ENUM_CXIMAGE_FORMATS{\r
+CXIMAGE_FORMAT_UNKNOWN = 0,\r
+#if CXIMAGE_SUPPORT_BMP\r
+CXIMAGE_FORMAT_BMP = 1,\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+CXIMAGE_FORMAT_GIF = 2,\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+CXIMAGE_FORMAT_JPG = 3,\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+CXIMAGE_FORMAT_PNG = 4,\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+CXIMAGE_FORMAT_ICO = 5,\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+CXIMAGE_FORMAT_TIF = 6,\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+CXIMAGE_FORMAT_TGA = 7,\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+CXIMAGE_FORMAT_PCX = 8,\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+CXIMAGE_FORMAT_WBMP = 9,\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF\r
+CXIMAGE_FORMAT_WMF = 10,\r
+#endif\r
+#if CXIMAGE_SUPPORT_JP2\r
+CXIMAGE_FORMAT_JP2 = 11,\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPC\r
+CXIMAGE_FORMAT_JPC = 12,\r
+#endif\r
+#if CXIMAGE_SUPPORT_PGX\r
+CXIMAGE_FORMAT_PGX = 13,\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNM\r
+CXIMAGE_FORMAT_PNM = 14,\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAS\r
+CXIMAGE_FORMAT_RAS = 15,\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+CXIMAGE_FORMAT_JBG = 16,\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+CXIMAGE_FORMAT_MNG = 17,\r
+#endif\r
+#if CXIMAGE_SUPPORT_SKA\r
+CXIMAGE_FORMAT_SKA = 18,\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAW\r
+CXIMAGE_FORMAT_RAW = 19,\r
+#endif\r
+CMAX_IMAGE_FORMATS = CXIMAGE_SUPPORT_BMP + CXIMAGE_SUPPORT_GIF + CXIMAGE_SUPPORT_JPG +\r
+ CXIMAGE_SUPPORT_PNG + CXIMAGE_SUPPORT_MNG + CXIMAGE_SUPPORT_ICO +\r
+ CXIMAGE_SUPPORT_TIF + CXIMAGE_SUPPORT_TGA + CXIMAGE_SUPPORT_PCX +\r
+ CXIMAGE_SUPPORT_WBMP+ CXIMAGE_SUPPORT_WMF +\r
+ CXIMAGE_SUPPORT_JBG + CXIMAGE_SUPPORT_JP2 + CXIMAGE_SUPPORT_JPC +\r
+ CXIMAGE_SUPPORT_PGX + CXIMAGE_SUPPORT_PNM + CXIMAGE_SUPPORT_RAS +\r
+ CXIMAGE_SUPPORT_SKA + CXIMAGE_SUPPORT_RAW + 1\r
+};\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CxImage class\r
+/////////////////////////////////////////////////////////////////////////////\r
+class DLL_EXP CxImage\r
+{\r
+//extensible information collector\r
+typedef struct tagCxImageInfo {\r
+ DWORD dwEffWidth; ///< DWORD aligned scan line width\r
+ BYTE* pImage; ///< THE IMAGE BITS\r
+ CxImage* pGhost; ///< if this is a ghost, pGhost points to the body\r
+ CxImage* pParent; ///< if this is a layer, pParent points to the body\r
+ DWORD dwType; ///< original image format\r
+ char szLastError[256]; ///< debugging\r
+ long nProgress; ///< monitor\r
+ long nEscape; ///< escape\r
+ long nBkgndIndex; ///< used for GIF, PNG, MNG\r
+ RGBQUAD nBkgndColor; ///< used for RGB transparency\r
+ float fQuality; ///< used for JPEG, JPEG2000 (0.0f ... 100.0f)\r
+ BYTE nJpegScale; ///< used for JPEG [ignacio]\r
+ long nFrame; ///< used for TIF, GIF, MNG : actual frame\r
+ long nNumFrames; ///< used for TIF, GIF, MNG : total number of frames\r
+ DWORD dwFrameDelay; ///< used for GIF, MNG\r
+ long xDPI; ///< horizontal resolution\r
+ long yDPI; ///< vertical resolution\r
+ RECT rSelectionBox; ///< bounding rectangle\r
+ BYTE nAlphaMax; ///< max opacity (fade)\r
+ bool bAlphaPaletteEnabled; ///< true if alpha values in the palette are enabled.\r
+ bool bEnabled; ///< enables the painting functions\r
+ long xOffset;\r
+ long yOffset;\r
+ DWORD dwCodecOpt[CMAX_IMAGE_FORMATS]; ///< for GIF, TIF : 0=def.1=unc,2=fax3,3=fax4,4=pack,5=jpg\r
+ RGBQUAD last_c; ///< for GetNearestIndex optimization\r
+ BYTE last_c_index;\r
+ bool last_c_isvalid;\r
+ long nNumLayers;\r
+ DWORD dwFlags; ///< 0x??00000 = reserved, 0x00??0000 = blend mode, 0x0000???? = layer id - user flags\r
+ BYTE dispmeth;\r
+ bool bGetAllFrames;\r
+ bool bLittleEndianHost;\r
+\r
+} CXIMAGEINFO;\r
+\r
+public:\r
+ //public structures\r
+struct rgb_color { BYTE r,g,b; };\r
+\r
+#if CXIMAGE_SUPPORT_WINDOWS\r
+// <VATI> text placement data\r
+// members must be initialized with the InitTextInfo(&this) function.\r
+typedef struct tagCxTextInfo\r
+{\r
+#if defined (_WIN32_WCE)\r
+ TCHAR text[256]; ///< text for windows CE\r
+#else\r
+ TCHAR text[4096]; ///< text (char -> TCHAR for UNICODE [Cesar M])\r
+#endif\r
+ LOGFONT lfont; ///< font and codepage data\r
+ COLORREF fcolor; ///< foreground color\r
+ long align; ///< DT_CENTER, DT_RIGHT, DT_LEFT aligment for multiline text\r
+ BYTE smooth; ///< text smoothing option. Default is false.\r
+ BYTE opaque; ///< text has background or hasn't. Default is true.\r
+ ///< data for background (ignored if .opaque==FALSE) \r
+ COLORREF bcolor; ///< background color\r
+ float b_opacity; ///< opacity value for background between 0.0-1.0 Default is 0. (opaque)\r
+ BYTE b_outline; ///< outline width for background (zero: no outline)\r
+ BYTE b_round; ///< rounding radius for background rectangle. % of the height, between 0-50. Default is 10.\r
+ ///< (backgr. always has a frame: width = 3 pixel + 10% of height by default.)\r
+} CXTEXTINFO;\r
+#endif\r
+\r
+public:\r
+/** \addtogroup Constructors */ //@{\r
+ CxImage(DWORD imagetype = 0);\r
+ CxImage(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype = 0);\r
+ CxImage(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true);\r
+ CxImage(const TCHAR * filename, DWORD imagetype); // For UNICODE support: char -> TCHAR\r
+ CxImage(FILE * stream, DWORD imagetype);\r
+ CxImage(CxFile * stream, DWORD imagetype);\r
+ CxImage(BYTE * buffer, DWORD size, DWORD imagetype);\r
+ virtual ~CxImage() { DestroyFrames(); Destroy(); };\r
+ CxImage& operator = (const CxImage&);\r
+//@}\r
+\r
+/** \addtogroup Initialization */ //@{\r
+ void* Create(DWORD dwWidth, DWORD dwHeight, DWORD wBpp, DWORD imagetype = 0);\r
+ bool Destroy();\r
+ bool DestroyFrames();\r
+ void Clear(BYTE bval=0);\r
+ void Copy(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true);\r
+ bool Transfer(CxImage &from, bool bTransferFrames = true);\r
+ bool CreateFromArray(BYTE* pArray,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage);\r
+ bool CreateFromMatrix(BYTE** ppMatrix,DWORD dwWidth,DWORD dwHeight,DWORD dwBitsperpixel, DWORD dwBytesperline, bool bFlipImage);\r
+ void FreeMemory(void* memblock);\r
+\r
+ DWORD Dump(BYTE * dst);\r
+ DWORD UnDump(const BYTE * src);\r
+ DWORD DumpSize();\r
+\r
+//@}\r
+\r
+/** \addtogroup Attributes */ //@{\r
+ long GetSize();\r
+ BYTE* GetBits(DWORD row = 0);\r
+ BYTE GetColorType();\r
+ void* GetDIB() const;\r
+ DWORD GetHeight() const;\r
+ DWORD GetWidth() const;\r
+ DWORD GetEffWidth() const;\r
+ DWORD GetNumColors() const;\r
+ WORD GetBpp() const;\r
+ DWORD GetType() const;\r
+ const char* GetLastError();\r
+ static const TCHAR* GetVersion();\r
+ static const float GetVersionNumber();\r
+\r
+ DWORD GetFrameDelay() const;\r
+ void SetFrameDelay(DWORD d);\r
+\r
+ void GetOffset(long *x,long *y);\r
+ void SetOffset(long x,long y);\r
+\r
+ BYTE GetJpegQuality() const;\r
+ void SetJpegQuality(BYTE q);\r
+ float GetJpegQualityF() const;\r
+ void SetJpegQualityF(float q);\r
+\r
+ BYTE GetJpegScale() const;\r
+ void SetJpegScale(BYTE q);\r
+\r
+ long GetXDPI() const;\r
+ long GetYDPI() const;\r
+ void SetXDPI(long dpi);\r
+ void SetYDPI(long dpi);\r
+\r
+ DWORD GetClrImportant() const;\r
+ void SetClrImportant(DWORD ncolors = 0);\r
+\r
+ long GetProgress() const;\r
+ long GetEscape() const;\r
+ void SetProgress(long p);\r
+ void SetEscape(long i);\r
+\r
+ long GetTransIndex() const;\r
+ RGBQUAD GetTransColor();\r
+ void SetTransIndex(long idx);\r
+ void SetTransColor(RGBQUAD rgb);\r
+ bool IsTransparent() const;\r
+\r
+ DWORD GetCodecOption(DWORD imagetype = 0);\r
+ bool SetCodecOption(DWORD opt, DWORD imagetype = 0);\r
+\r
+ DWORD GetFlags() const;\r
+ void SetFlags(DWORD flags, bool bLockReservedFlags = true);\r
+\r
+ BYTE GetDisposalMethod() const;\r
+ void SetDisposalMethod(BYTE dm);\r
+\r
+ bool SetType(DWORD type);\r
+\r
+ static DWORD GetNumTypes();\r
+ static DWORD GetTypeIdFromName(const TCHAR* ext);\r
+ static DWORD GetTypeIdFromIndex(const DWORD index);\r
+ static DWORD GetTypeIndexFromId(const DWORD id);\r
+\r
+ bool GetRetreiveAllFrames() const;\r
+ void SetRetreiveAllFrames(bool flag);\r
+ CxImage * GetFrame(long nFrame) const;\r
+\r
+ //void* GetUserData() const {return info.pUserData;}\r
+ //void SetUserData(void* pUserData) {info.pUserData = pUserData;}\r
+//@}\r
+\r
+/** \addtogroup Palette\r
+ * These functions have no effects on RGB images and in this case the returned value is always 0.\r
+ * @{ */\r
+ bool IsGrayScale();\r
+ bool IsIndexed() const;\r
+ bool IsSamePalette(CxImage &img, bool bCheckAlpha = true);\r
+ DWORD GetPaletteSize();\r
+ RGBQUAD* GetPalette() const;\r
+ RGBQUAD GetPaletteColor(BYTE idx);\r
+ bool GetPaletteColor(BYTE i, BYTE* r, BYTE* g, BYTE* b);\r
+ BYTE GetNearestIndex(RGBQUAD c);\r
+ void BlendPalette(COLORREF cr,long perc);\r
+ void SetGrayPalette();\r
+ void SetPalette(DWORD n, BYTE *r, BYTE *g, BYTE *b);\r
+ void SetPalette(RGBQUAD* pPal,DWORD nColors=256);\r
+ void SetPalette(rgb_color *rgb,DWORD nColors=256);\r
+ void SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha=0);\r
+ void SetPaletteColor(BYTE idx, RGBQUAD c);\r
+ void SetPaletteColor(BYTE idx, COLORREF cr);\r
+ void SwapIndex(BYTE idx1, BYTE idx2);\r
+ void SwapRGB2BGR();\r
+ void SetStdPalette();\r
+//@}\r
+\r
+/** \addtogroup Pixel */ //@{\r
+ bool IsInside(long x, long y);\r
+ bool IsTransparent(long x,long y);\r
+ bool GetTransparentMask(CxImage* iDst = 0);\r
+ RGBQUAD GetPixelColor(long x,long y, bool bGetAlpha = true);\r
+ BYTE GetPixelIndex(long x,long y);\r
+ BYTE GetPixelGray(long x, long y);\r
+ void SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha = false);\r
+ void SetPixelColor(long x,long y,COLORREF cr);\r
+ void SetPixelIndex(long x,long y,BYTE i);\r
+ void DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha=false);\r
+ void DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr);\r
+ void BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha = false);\r
+//@}\r
+\r
+protected:\r
+/** \addtogroup Protected */ //@{\r
+ BYTE BlindGetPixelIndex(const long x,const long y);\r
+ RGBQUAD BlindGetPixelColor(const long x,const long y, bool bGetAlpha = true);\r
+ void *BlindGetPixelPointer(const long x,const long y);\r
+ void BlindSetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha = false);\r
+ void BlindSetPixelIndex(long x,long y,BYTE i);\r
+//@}\r
+\r
+public:\r
+\r
+#if CXIMAGE_SUPPORT_INTERPOLATION\r
+/** \addtogroup Interpolation */ //@{\r
+ //overflow methods:\r
+ enum OverflowMethod {\r
+ OM_COLOR=1,\r
+ OM_BACKGROUND=2,\r
+ OM_TRANSPARENT=3,\r
+ OM_WRAP=4,\r
+ OM_REPEAT=5,\r
+ OM_MIRROR=6\r
+ };\r
+ void OverflowCoordinates(float &x, float &y, OverflowMethod const ofMethod);\r
+ void OverflowCoordinates(long &x, long &y, OverflowMethod const ofMethod);\r
+ RGBQUAD GetPixelColorWithOverflow(long x, long y, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0);\r
+ //interpolation methods:\r
+ enum InterpolationMethod {\r
+ IM_NEAREST_NEIGHBOUR=1,\r
+ IM_BILINEAR =2,\r
+ IM_BSPLINE =3,\r
+ IM_BICUBIC =4,\r
+ IM_BICUBIC2 =5,\r
+ IM_LANCZOS =6,\r
+ IM_BOX =7,\r
+ IM_HERMITE =8,\r
+ IM_HAMMING =9,\r
+ IM_SINC =10,\r
+ IM_BLACKMAN =11,\r
+ IM_BESSEL =12,\r
+ IM_GAUSSIAN =13,\r
+ IM_QUADRATIC =14,\r
+ IM_MITCHELL =15,\r
+ IM_CATROM =16,\r
+ IM_HANNING =17,\r
+ IM_POWER =18\r
+ };\r
+ RGBQUAD GetPixelColorInterpolated(float x,float y, InterpolationMethod const inMethod=IM_BILINEAR, OverflowMethod const ofMethod=OM_BACKGROUND, RGBQUAD* const rplColor=0);\r
+ 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);\r
+//@}\r
+\r
+protected:\r
+/** \addtogroup Protected */ //@{\r
+ void AddAveragingCont(RGBQUAD const &color, float const surf, float &rr, float &gg, float &bb, float &aa);\r
+//@}\r
+\r
+/** \addtogroup Kernels */ //@{\r
+public:\r
+ static float KernelBSpline(const float x);\r
+ static float KernelLinear(const float t);\r
+ static float KernelCubic(const float t);\r
+ static float KernelGeneralizedCubic(const float t, const float a=-1);\r
+ static float KernelLanczosSinc(const float t, const float r = 3);\r
+ static float KernelBox(const float x);\r
+ static float KernelHermite(const float x);\r
+ static float KernelHamming(const float x);\r
+ static float KernelSinc(const float x);\r
+ static float KernelBlackman(const float x);\r
+ static float KernelBessel_J1(const float x);\r
+ static float KernelBessel_P1(const float x);\r
+ static float KernelBessel_Q1(const float x);\r
+ static float KernelBessel_Order1(float x);\r
+ static float KernelBessel(const float x);\r
+ static float KernelGaussian(const float x);\r
+ static float KernelQuadratic(const float x);\r
+ static float KernelMitchell(const float x);\r
+ static float KernelCatrom(const float x);\r
+ static float KernelHanning(const float x);\r
+ static float KernelPower(const float x, const float a = 2);\r
+//@}\r
+#endif //CXIMAGE_SUPPORT_INTERPOLATION\r
+ \r
+/** \addtogroup Painting */ //@{\r
+#if CXIMAGE_SUPPORT_WINDOWS\r
+ long Blt(HDC pDC, long x=0, long y=0);\r
+ HBITMAP MakeBitmap(HDC hdc = NULL);\r
+ HANDLE CopyToHandle();\r
+ bool CreateFromHANDLE(HANDLE hMem); //Windows objects (clipboard)\r
+ bool CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal=0); //Windows resource\r
+ bool CreateFromHICON(HICON hico);\r
+ long Draw(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1, RECT* pClipRect = 0, bool bSmooth = false);\r
+ long Draw(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false);\r
+ long Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop = SRCCOPY);\r
+ long Stretch(HDC hdc, const RECT& rect, DWORD dwRop = SRCCOPY);\r
+ long Tile(HDC hdc, RECT *rc);\r
+ long Draw2(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1);\r
+ long Draw2(HDC hdc, const RECT& rect);\r
+ //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);\r
+ 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);\r
+ // <VATI> extensions\r
+ long DrawStringEx(HDC hdc, long x, long y, CXTEXTINFO *pTextType, bool bSetAlpha=false );\r
+ void InitTextInfo( CXTEXTINFO *txt );\r
+#endif //CXIMAGE_SUPPORT_WINDOWS\r
+//@}\r
+\r
+ // file operations\r
+#if CXIMAGE_SUPPORT_DECODE\r
+/** \addtogroup Decode */ //@{\r
+#ifdef WIN32\r
+ //bool Load(LPCWSTR filename, DWORD imagetype=0);\r
+ bool LoadResource(HRSRC hRes, DWORD imagetype, HMODULE hModule=NULL);\r
+#endif\r
+ // For UNICODE support: char -> TCHAR\r
+ bool Load(const TCHAR* filename, DWORD imagetype=0);\r
+ //bool Load(const char * filename, DWORD imagetype=0);\r
+ bool Decode(FILE * hFile, DWORD imagetype);\r
+ bool Decode(CxFile * hFile, DWORD imagetype);\r
+ bool Decode(BYTE * buffer, DWORD size, DWORD imagetype);\r
+\r
+ bool CheckFormat(CxFile * hFile, DWORD imagetype = 0);\r
+ bool CheckFormat(BYTE * buffer, DWORD size, DWORD imagetype = 0);\r
+//@}\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+protected:\r
+/** \addtogroup Protected */ //@{\r
+ bool EncodeSafeCheck(CxFile *hFile);\r
+//@}\r
+\r
+public:\r
+/** \addtogroup Encode */ //@{\r
+#ifdef WIN32\r
+ //bool Save(LPCWSTR filename, DWORD imagetype=0);\r
+#endif\r
+ // For UNICODE support: char -> TCHAR\r
+ bool Save(const TCHAR* filename, DWORD imagetype);\r
+ //bool Save(const char * filename, DWORD imagetype=0);\r
+ bool Encode(FILE * hFile, DWORD imagetype);\r
+ bool Encode(CxFile * hFile, DWORD imagetype);\r
+ bool Encode(CxFile * hFile, CxImage ** pImages, int pagecount, DWORD imagetype);\r
+ bool Encode(FILE *hFile, CxImage ** pImages, int pagecount, DWORD imagetype);\r
+ bool Encode(BYTE * &buffer, long &size, DWORD imagetype);\r
+\r
+ bool Encode2RGBA(CxFile *hFile, bool bFlipY = false);\r
+ bool Encode2RGBA(BYTE * &buffer, long &size, bool bFlipY = false);\r
+//@}\r
+#endif //CXIMAGE_SUPPORT_ENCODE\r
+\r
+/** \addtogroup Attributes */ //@{\r
+ //misc.\r
+ bool IsValid() const;\r
+ bool IsEnabled() const;\r
+ void Enable(bool enable=true);\r
+\r
+ // frame operations\r
+ long GetNumFrames() const;\r
+ long GetFrame() const;\r
+ void SetFrame(long nFrame);\r
+//@}\r
+\r
+#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS\r
+/** \addtogroup BasicTransformations */ //@{\r
+ bool GrayScale();\r
+ bool Flip(bool bFlipSelection = false, bool bFlipAlpha = true);\r
+ bool Mirror(bool bMirrorSelection = false, bool bMirrorAlpha = true);\r
+ bool Negative();\r
+ bool RotateLeft(CxImage* iDst = NULL);\r
+ bool RotateRight(CxImage* iDst = NULL);\r
+//@}\r
+#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS\r
+\r
+#if CXIMAGE_SUPPORT_TRANSFORMATION\r
+/** \addtogroup Transformations */ //@{\r
+ // image operations\r
+ bool Rotate(float angle, CxImage* iDst = NULL);\r
+ bool Rotate2(float angle, CxImage *iDst = NULL, InterpolationMethod inMethod=IM_BILINEAR,\r
+ OverflowMethod ofMethod=OM_BACKGROUND, RGBQUAD *replColor=0,\r
+ bool const optimizeRightAngles=true, bool const bKeepOriginalSize=false);\r
+ bool Rotate180(CxImage* iDst = NULL);\r
+ bool Resample(long newx, long newy, int mode = 1, CxImage* iDst = NULL);\r
+ bool Resample2(long newx, long newy, InterpolationMethod const inMethod=IM_BICUBIC2,\r
+ OverflowMethod const ofMethod=OM_REPEAT, CxImage* const iDst = NULL,\r
+ bool const disableAveraging=false);\r
+ bool DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal = 0, DWORD clrimportant = 0);\r
+ bool IncreaseBpp(DWORD nbit);\r
+ bool Dither(long method = 0);\r
+ bool Crop(long left, long top, long right, long bottom, CxImage* iDst = NULL);\r
+ bool Crop(const RECT& rect, CxImage* iDst = NULL);\r
+ bool CropRotatedRectangle( long topx, long topy, long width, long height, float angle, CxImage* iDst = NULL);\r
+ bool Skew(float xgain, float ygain, long xpivot=0, long ypivot=0, bool bEnableInterpolation = false);\r
+ bool Expand(long left, long top, long right, long bottom, RGBQUAD canvascolor, CxImage* iDst = 0);\r
+ bool Expand(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst = 0);\r
+ bool Thumbnail(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst = 0);\r
+ bool CircleTransform(int type,long rmax=0,float Koeff=1.0f);\r
+ bool RedEyeRemove(float strength = 0.8f);\r
+ bool QIShrink(long newx, long newy, CxImage* const iDst = NULL, bool bChangeBpp = false);\r
+\r
+//@}\r
+#endif //CXIMAGE_SUPPORT_TRANSFORMATION\r
+\r
+#if CXIMAGE_SUPPORT_DSP\r
+/** \addtogroup DSP */ //@{\r
+ bool Contour();\r
+ bool HistogramStretch(long method = 0, double threshold = 0);\r
+ bool HistogramEqualize();\r
+ bool HistogramNormalize();\r
+ bool HistogramRoot();\r
+ bool HistogramLog();\r
+ long Histogram(long* red, long* green = 0, long* blue = 0, long* gray = 0, long colorspace = 0);\r
+ bool Jitter(long radius=2);\r
+ bool Repair(float radius = 0.25f, long niterations = 1, long colorspace = 0);\r
+ bool Combine(CxImage* r,CxImage* g,CxImage* b,CxImage* a, long colorspace = 0);\r
+ bool FFT2(CxImage* srcReal, CxImage* srcImag, CxImage* dstReal, CxImage* dstImag, long direction = 1, bool bForceFFT = true, bool bMagnitude = true);\r
+ bool Noise(long level);\r
+ bool Median(long Ksize=3);\r
+ bool Gamma(float gamma);\r
+ bool GammaRGB(float gammaR, float gammaG, float gammaB);\r
+ bool ShiftRGB(long r, long g, long b);\r
+ bool Threshold(BYTE level);\r
+ bool Threshold(CxImage* pThresholdMask);\r
+ bool Threshold2(BYTE level, bool bDirection, RGBQUAD nBkgndColor, bool bSetAlpha = false);\r
+ bool Colorize(BYTE hue, BYTE sat, float blend = 1.0f);\r
+ bool Light(long brightness, long contrast = 0);\r
+ float Mean();\r
+ bool Filter(long* kernel, long Ksize, long Kfactor, long Koffset);\r
+ bool Erode(long Ksize=2);\r
+ bool Dilate(long Ksize=2);\r
+ bool Edge(long Ksize=2);\r
+ void HuePalette(float correction=1);\r
+ enum ImageOpType { OpAdd, OpAnd, OpXor, OpOr, OpMask, OpSrcCopy, OpDstCopy, OpSub, OpSrcBlend, OpScreen, OpAvg };\r
+ void Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset = 0, long lYOffset = 0, bool bMixAlpha = false);\r
+ void MixFrom(CxImage & imagesrc2, long lXOffset, long lYOffset);\r
+ bool UnsharpMask(float radius = 5.0f, float amount = 0.5f, int threshold = 0);\r
+ bool Lut(BYTE* pLut);\r
+ bool Lut(BYTE* pLutR, BYTE* pLutG, BYTE* pLutB, BYTE* pLutA = 0);\r
+ bool GaussianBlur(float radius = 1.0f, CxImage* iDst = 0);\r
+ bool TextBlur(BYTE threshold = 100, BYTE decay = 2, BYTE max_depth = 5, bool bBlurHorizontal = true, bool bBlurVertical = true, CxImage* iDst = 0);\r
+ bool SelectiveBlur(float radius = 1.0f, BYTE threshold = 25, CxImage* iDst = 0);\r
+ bool Solarize(BYTE level = 128, bool bLinkedChannels = true);\r
+ bool FloodFill(const long xStart, const long yStart, const RGBQUAD cFillColor, const BYTE tolerance = 0,\r
+ BYTE nOpacity = 255, const bool bSelectFilledArea = false, const BYTE nSelectionLevel = 255);\r
+ bool Saturate(const long saturation, const long colorspace = 1);\r
+ bool ConvertColorSpace(const long dstColorSpace, const long srcColorSpace);\r
+ int OptimalThreshold(long method = 0, RECT * pBox = 0, CxImage* pContrastMask = 0);\r
+ bool AdaptiveThreshold(long method = 0, long nBoxSize = 64, CxImage* pContrastMask = 0, long nBias = 0, float fGlobalLocalBalance = 0.5f);\r
+\r
+//@}\r
+\r
+protected:\r
+/** \addtogroup Protected */ //@{\r
+ bool IsPowerof2(long x);\r
+ bool FFT(int dir,int m,double *x,double *y);\r
+ bool DFT(int dir,long m,double *x1,double *y1,double *x2,double *y2);\r
+ bool RepairChannel(CxImage *ch, float radius);\r
+ // <nipper>\r
+ int gen_convolve_matrix (float radius, float **cmatrix_p);\r
+ float* gen_lookup_table (float *cmatrix, int cmatrix_length);\r
+ void blur_line (float *ctable, float *cmatrix, int cmatrix_length, BYTE* cur_col, BYTE* dest_col, int y, long bytes);\r
+ void blur_text (BYTE threshold, BYTE decay, BYTE max_depth, CxImage* iSrc, CxImage* iDst, BYTE bytes);\r
+//@}\r
+\r
+public:\r
+/** \addtogroup ColorSpace */ //@{\r
+ bool SplitRGB(CxImage* r,CxImage* g,CxImage* b);\r
+ bool SplitYUV(CxImage* y,CxImage* u,CxImage* v);\r
+ bool SplitHSL(CxImage* h,CxImage* s,CxImage* l);\r
+ bool SplitYIQ(CxImage* y,CxImage* i,CxImage* q);\r
+ bool SplitXYZ(CxImage* x,CxImage* y,CxImage* z);\r
+ bool SplitCMYK(CxImage* c,CxImage* m,CxImage* y,CxImage* k);\r
+ static RGBQUAD HSLtoRGB(COLORREF cHSLColor);\r
+ static RGBQUAD RGBtoHSL(RGBQUAD lRGBColor);\r
+ static RGBQUAD HSLtoRGB(RGBQUAD lHSLColor);\r
+ static RGBQUAD YUVtoRGB(RGBQUAD lYUVColor);\r
+ static RGBQUAD RGBtoYUV(RGBQUAD lRGBColor);\r
+ static RGBQUAD YIQtoRGB(RGBQUAD lYIQColor);\r
+ static RGBQUAD RGBtoYIQ(RGBQUAD lRGBColor);\r
+ static RGBQUAD XYZtoRGB(RGBQUAD lXYZColor);\r
+ static RGBQUAD RGBtoXYZ(RGBQUAD lRGBColor);\r
+#endif //CXIMAGE_SUPPORT_DSP\r
+ static RGBQUAD RGBtoRGBQUAD(COLORREF cr);\r
+ static COLORREF RGBQUADtoRGB (RGBQUAD c);\r
+//@}\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+/** \addtogroup Selection */ //@{\r
+ bool SelectionClear(BYTE level = 0);\r
+ bool SelectionCreate();\r
+ bool SelectionDelete();\r
+ bool SelectionInvert();\r
+ bool SelectionMirror();\r
+ bool SelectionFlip();\r
+ bool SelectionAddRect(RECT r, BYTE level = 255);\r
+ bool SelectionAddEllipse(RECT r, BYTE level = 255);\r
+ bool SelectionAddPolygon(POINT *points, long npoints, BYTE level = 255);\r
+ bool SelectionAddColor(RGBQUAD c, BYTE level = 255);\r
+ bool SelectionAddPixel(long x, long y, BYTE level = 255);\r
+ bool SelectionCopy(CxImage &from);\r
+ bool SelectionIsInside(long x, long y);\r
+ bool SelectionIsValid();\r
+ void SelectionGetBox(RECT& r);\r
+ bool SelectionToHRGN(HRGN& region);\r
+ bool SelectionSplit(CxImage *dest);\r
+ BYTE SelectionGet(const long x,const long y);\r
+ bool SelectionSet(CxImage &from);\r
+ void SelectionRebuildBox();\r
+ BYTE* SelectionGetPointer(const long x = 0,const long y = 0);\r
+//@}\r
+\r
+protected:\r
+/** \addtogroup Protected */ //@{\r
+ bool BlindSelectionIsInside(long x, long y);\r
+ BYTE BlindSelectionGet(const long x,const long y);\r
+ void SelectionSet(const long x,const long y,const BYTE level);\r
+//@}\r
+\r
+public:\r
+\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+/** \addtogroup Alpha */ //@{\r
+ void AlphaClear();\r
+ bool AlphaCreate();\r
+ void AlphaDelete();\r
+ void AlphaInvert();\r
+ bool AlphaMirror();\r
+ bool AlphaFlip();\r
+ bool AlphaCopy(CxImage &from);\r
+ bool AlphaSplit(CxImage *dest);\r
+ void AlphaStrip();\r
+ void AlphaSet(BYTE level);\r
+ bool AlphaSet(CxImage &from);\r
+ void AlphaSet(const long x,const long y,const BYTE level);\r
+ BYTE AlphaGet(const long x,const long y);\r
+ BYTE AlphaGetMax() const;\r
+ void AlphaSetMax(BYTE nAlphaMax);\r
+ bool AlphaIsValid();\r
+ BYTE* AlphaGetPointer(const long x = 0,const long y = 0);\r
+ bool AlphaFromTransparency();\r
+\r
+ void AlphaPaletteClear();\r
+ void AlphaPaletteEnable(bool enable=true);\r
+ bool AlphaPaletteIsEnabled();\r
+ bool AlphaPaletteIsValid();\r
+ bool AlphaPaletteSplit(CxImage *dest);\r
+//@}\r
+\r
+protected:\r
+/** \addtogroup Protected */ //@{\r
+ BYTE BlindAlphaGet(const long x,const long y);\r
+//@}\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+public:\r
+#if CXIMAGE_SUPPORT_LAYERS\r
+/** \addtogroup Layers */ //@{\r
+ bool LayerCreate(long position = -1);\r
+ bool LayerDelete(long position = -1);\r
+ void LayerDeleteAll();\r
+ CxImage* GetLayer(long position);\r
+ CxImage* GetParent() const;\r
+ long GetNumLayers() const;\r
+ long LayerDrawAll(HDC hdc, long x=0, long y=0, long cx = -1, long cy = -1, RECT* pClipRect = 0, bool bSmooth = false);\r
+ long LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false);\r
+//@}\r
+#endif //CXIMAGE_SUPPORT_LAYERS\r
+\r
+protected:\r
+/** \addtogroup Protected */ //@{\r
+ void Startup(DWORD imagetype = 0);\r
+ void CopyInfo(const CxImage &src);\r
+ void Ghost(const CxImage *src);\r
+ void RGBtoBGR(BYTE *buffer, int length);\r
+ static float HueToRGB(float n1,float n2, float hue);\r
+ void Bitfield2RGB(BYTE *src, DWORD redmask, DWORD greenmask, DWORD bluemask, BYTE bpp);\r
+ static int CompareColors(const void *elem1, const void *elem2);\r
+ short ntohs(const short word);\r
+ long ntohl(const long dword);\r
+ void bihtoh(BITMAPINFOHEADER* bih);\r
+\r
+ void* pDib; //contains the header, the palette, the pixels\r
+ BITMAPINFOHEADER head; //standard header\r
+ CXIMAGEINFO info; //extended information\r
+ BYTE* pSelection; //selected region\r
+ BYTE* pAlpha; //alpha channel\r
+ CxImage** ppLayers; //generic layers\r
+ CxImage** ppFrames;\r
+//@}\r
+};\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+#endif // !defined(__CXIMAGE_H)\r
--- /dev/null
+/*\r
+ * File: ximagif.cpp\r
+ * Purpose: Platform Independent GIF Image Class Loader and Writer\r
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximagif.h"\r
+\r
+#if CXIMAGE_SUPPORT_GIF\r
+\r
+#include "ximaiter.h"\r
+\r
+#if defined (_WIN32_WCE)\r
+ #define assert(s)\r
+#else\r
+ #include <assert.h>\r
+#endif\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageGIF::Decode(CxFile *fp)\r
+{\r
+ /* AD - for transparency */\r
+ struct_dscgif dscgif;\r
+ struct_image image;\r
+ struct_TabCol TabCol;\r
+\r
+ if (fp == NULL) return false;\r
+\r
+ fp->Read(&dscgif,/*sizeof(dscgif)*/13,1);\r
+ //if (strncmp(dscgif.header,"GIF8",3)!=0) {\r
+ if (strncmp(dscgif.header,"GIF8",4)!=0) return FALSE;\r
+\r
+ // Avoid Byte order problem with Mac <AMSN>\r
+ dscgif.scrheight = ntohs(dscgif.scrheight);\r
+ dscgif.scrwidth = ntohs(dscgif.scrwidth);\r
+\r
+ if (info.nEscape == -1) {\r
+ // Return output dimensions only\r
+ head.biWidth = dscgif.scrwidth;\r
+ head.biHeight = dscgif.scrheight;\r
+ info.dwType = CXIMAGE_FORMAT_GIF;\r
+ return true;\r
+ }\r
+\r
+ /* AD - for interlace */\r
+ TabCol.sogct = (short)(1 << ((dscgif.pflds & 0x07)+1));\r
+ TabCol.colres = (short)(((dscgif.pflds & 0x70) >> 4) + 1);\r
+\r
+ // assume that the image is a truecolor-gif if\r
+ // 1) no global color map found\r
+ // 2) (image.w, image.h) of the 1st image != (dscgif.scrwidth, dscgif.scrheight)\r
+ long bTrueColor=0;\r
+ CxImage* imaRGB=NULL;\r
+\r
+ // Global colour map?\r
+ if (dscgif.pflds & 0x80)\r
+ fp->Read(TabCol.paleta,sizeof(struct rgb_color)*TabCol.sogct,1);\r
+ else \r
+ bTrueColor++; //first chance for a truecolor gif\r
+\r
+ long first_transparent_index = 0;\r
+\r
+ int iImage = 0;\r
+ info.nNumFrames=get_num_frames(fp,&TabCol,&dscgif);\r
+\r
+ if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)) return false;\r
+\r
+ //it cannot be a true color GIF with only one frame\r
+ if (info.nNumFrames == 1)\r
+ bTrueColor=0;\r
+\r
+ char ch;\r
+ bool bPreviousWasNull = true;\r
+ int prevdispmeth = 0;\r
+ CxImage *previousFrame = NULL;\r
+\r
+ for (BOOL bContinue = TRUE; bContinue; )\r
+ {\r
+ if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}\r
+\r
+ if (info.nEscape > 0) return false; // <vho> - cancel decoding\r
+ if (bPreviousWasNull || ch==0)\r
+ {\r
+ switch (ch)\r
+ {\r
+ case '!': // extension\r
+ {\r
+ bContinue = DecodeExtension(fp);\r
+ break;\r
+ }\r
+ case ',': // image\r
+ {\r
+ assert(sizeof(image) == 9);\r
+ fp->Read(&image,sizeof(image),1);\r
+ //avoid byte order problems with Solaris <candan> <AMSN>\r
+ image.l = ntohs(image.l);\r
+ image.t = ntohs(image.t);\r
+ image.w = ntohs(image.w);\r
+ image.h = ntohs(image.h);\r
+\r
+ if (((image.l + image.w) > dscgif.scrwidth)||((image.t + image.h) > dscgif.scrheight))\r
+ break;\r
+\r
+ // check if it could be a truecolor gif\r
+ if ((iImage==0) && (image.w != dscgif.scrwidth) && (image.h != dscgif.scrheight))\r
+ bTrueColor++;\r
+\r
+ rgb_color locpal[256]; //Local Palette \r
+ rgb_color* pcurpal = TabCol.paleta; //Current Palette \r
+ short palcount = TabCol.sogct; //Current Palette color count \r
+\r
+ // Local colour map?\r
+ if (image.pf & 0x80) {\r
+ palcount = (short)(1 << ((image.pf & 0x07) +1));\r
+ assert(3 == sizeof(struct rgb_color));\r
+ fp->Read(locpal,sizeof(struct rgb_color)*palcount,1);\r
+ pcurpal = locpal;\r
+ }\r
+\r
+ int bpp; //<DP> select the correct bit per pixel value\r
+ if (palcount <= 2) bpp = 1;\r
+ else if (palcount <= 16) bpp = 4;\r
+ else bpp = 8;\r
+\r
+ CxImageGIF backimage;\r
+ backimage.CopyInfo(*this);\r
+ if (iImage==0){\r
+ //first frame: build image background\r
+ backimage.Create(dscgif.scrwidth, dscgif.scrheight, bpp, CXIMAGE_FORMAT_GIF);\r
+ first_transparent_index = info.nBkgndIndex;\r
+ backimage.Clear((BYTE)gifgce.transpcolindex);\r
+ previousFrame = new CxImage(backimage);\r
+ previousFrame->SetRetreiveAllFrames(false);\r
+ } else {\r
+ //generic frame: handle disposal method from previous one\r
+ /*Values : 0 - No disposal specified. The decoder is\r
+ not required to take any action.\r
+ 1 - Do not dispose. The graphic is to be left\r
+ in place.\r
+ 2 - Restore to background color. The area used by the\r
+ graphic must be restored to the background color.\r
+ 3 - Restore to previous. The decoder is required to\r
+ restore the area overwritten by the graphic with\r
+ what was there prior to rendering the graphic.\r
+ */\r
+ /* backimage.Copy(*this);\r
+ if (prevdispmeth==2){\r
+ backimage.Clear((BYTE)first_transparent_index);\r
+ }*/\r
+ if (prevdispmeth==2){\r
+ backimage.Copy(*this,false,false,false);\r
+ backimage.Clear((BYTE)first_transparent_index);\r
+ } else if (prevdispmeth==3) {\r
+ backimage.Copy(*this,false,false,false);\r
+ backimage.Create(previousFrame->GetWidth(),\r
+ previousFrame->GetHeight(),\r
+ previousFrame->GetBpp(),CXIMAGE_FORMAT_GIF);\r
+ memcpy(backimage.GetDIB(),previousFrame->GetDIB(),\r
+ backimage.GetSize());\r
+ backimage.AlphaSet(*previousFrame);\r
+ } else {\r
+ backimage.Copy(*this);\r
+ }\r
+ }\r
+\r
+ //active frame\r
+ Create(image.w, image.h, bpp, CXIMAGE_FORMAT_GIF);\r
+\r
+ if ((image.pf & 0x80) || (dscgif.pflds & 0x80)) {\r
+ unsigned char r[256], g[256], b[256];\r
+ int i, has_white = 0;\r
+\r
+ for (i=0; i < palcount; i++) {\r
+ r[i] = pcurpal[i].r;\r
+ g[i] = pcurpal[i].g;\r
+ b[i] = pcurpal[i].b;\r
+ if (RGB(r[i],g[i],b[i]) == 0xFFFFFF) has_white = 1;\r
+ }\r
+\r
+ // Force transparency colour white...\r
+ //if (0) if (info.nBkgndIndex >= 0)\r
+ // r[info.nBkgndIndex] = g[info.nBkgndIndex] = b[info.nBkgndIndex] = 255;\r
+ // Fill in with white // AD\r
+ if (info.nBkgndIndex >= 0) {\r
+ while (i < 256) {\r
+ has_white = 1;\r
+ r[i] = g[i] = b[i] = 255;\r
+ i++;\r
+ }\r
+ }\r
+\r
+ // Force last colour to white... // AD\r
+ //if ((info.nBkgndIndex >= 0) && !has_white) {\r
+ // r[255] = g[255] = b[255] = 255;\r
+ //}\r
+\r
+ SetPalette((info.nBkgndIndex >= 0 ? 256 : palcount), r, g, b);\r
+ }\r
+\r
+ CImageIterator* iter = new CImageIterator(this);\r
+ iter->Upset();\r
+ int badcode=0;\r
+ ibf = GIFBUFTAM+1;\r
+\r
+ interlaced = image.pf & 0x40;\r
+ iheight = image.h;\r
+ istep = 8;\r
+ iypos = 0;\r
+ ipass = 0;\r
+\r
+ long pos_start = fp->Tell();\r
+ //if (interlaced) log << "Interlaced" << endl;\r
+ decoder(fp, iter, image.w, badcode);\r
+ delete iter;\r
+\r
+ if (info.nEscape) return false; // <vho> - cancel decoding\r
+\r
+ if (bTrueColor<2 ){ //standard GIF: mix frame with background\r
+ backimage.GifMix(*this,image);\r
+ backimage.SetTransIndex(first_transparent_index);\r
+ backimage.SetPalette(GetPalette());\r
+ Transfer(backimage,false);\r
+ } else { //it's a truecolor gif!\r
+ //force full image decoding\r
+ info.nFrame=info.nNumFrames-1;\r
+ //build the RGB image\r
+ if (imaRGB==NULL) imaRGB = new CxImage(dscgif.scrwidth,dscgif.scrheight,24,CXIMAGE_FORMAT_GIF);\r
+ //copy the partial image into the full RGB image\r
+ for(long y=0;y<image.h;y++){\r
+ for (long x=0;x<image.w;x++){\r
+ imaRGB->SetPixelColor(x+image.l,dscgif.scrheight-1-image.t-y,GetPixelColor(x,image.h-y-1));\r
+ }\r
+ }\r
+ }\r
+\r
+ prevdispmeth = (gifgce.flags >> 2) & 0x7;\r
+\r
+ //restore the correct position in the file for the next image\r
+ if (badcode){\r
+ seek_next_image(fp,pos_start);\r
+ } else {\r
+ fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);\r
+ }\r
+\r
+ if (info.bGetAllFrames && imaRGB == NULL) {\r
+ if (iImage == 0) {\r
+ DestroyFrames();\r
+ ppFrames = new CxImage*[info.nNumFrames];\r
+ for(int frameIdx = 0; frameIdx < info.nNumFrames; frameIdx++){\r
+ ppFrames[frameIdx] = NULL;\r
+ }\r
+ }\r
+ ppFrames[iImage] = new CxImage(*this);\r
+ ppFrames[iImage]->SetRetreiveAllFrames(false);\r
+ }\r
+ if (prevdispmeth <= 1) {\r
+ delete previousFrame;\r
+ previousFrame = new CxImage(*this);\r
+ previousFrame->SetRetreiveAllFrames(false);\r
+ }\r
+\r
+ if (info.nFrame==iImage) bContinue=false; else iImage++;\r
+\r
+ break;\r
+ }\r
+ case ';': //terminator\r
+ bContinue=false;\r
+ break;\r
+ default:\r
+ bPreviousWasNull = (ch==0);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (bTrueColor>=2 && imaRGB){\r
+ if (gifgce.flags & 0x1){\r
+ imaRGB->SetTransColor(GetPaletteColor((BYTE)info.nBkgndIndex));\r
+ imaRGB->SetTransIndex(0);\r
+ }\r
+ Transfer(*imaRGB);\r
+ }\r
+ delete imaRGB;\r
+\r
+ delete previousFrame;\r
+\r
+ return true;\r
+\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageGIF::DecodeExtension(CxFile *fp)\r
+{\r
+ bool bContinue;\r
+ unsigned char count;\r
+ unsigned char fc;\r
+\r
+ bContinue = (1 == fp->Read(&fc, sizeof(fc), 1));\r
+ if (bContinue) {\r
+ /* AD - for transparency */\r
+ if (fc == 0xF9) {\r
+ bContinue = (1 == fp->Read(&count, sizeof(count), 1));\r
+ if (bContinue) {\r
+ assert(sizeof(gifgce) == 4);\r
+ bContinue = (count == fp->Read(&gifgce, 1, sizeof(gifgce)));\r
+ gifgce.delaytime = ntohs(gifgce.delaytime); // Avoid Byte order problem with Mac <AMSN>\r
+ if (bContinue) {\r
+ info.nBkgndIndex = (gifgce.flags & 0x1) ? gifgce.transpcolindex : -1;\r
+ info.dwFrameDelay = gifgce.delaytime;\r
+ SetDisposalMethod((gifgce.flags >> 2) & 0x7);\r
+ } } }\r
+\r
+ if (fc == 0xFE) { //<DP> Comment block\r
+ bContinue = (1 == fp->Read(&count, sizeof(count), 1));\r
+ if (bContinue) {\r
+ bContinue = (1 == fp->Read(m_comment, count, 1));\r
+ m_comment[count]='\0';\r
+ } }\r
+\r
+ if (fc == 0xFF) { //<DP> Application Extension block\r
+ bContinue = (1 == fp->Read(&count, sizeof(count), 1));\r
+ if (bContinue) {\r
+ bContinue = (count==11);\r
+ if (bContinue){\r
+ char AppID[11];\r
+ bContinue = (1 == fp->Read(AppID, count, 1));\r
+ if (bContinue) {\r
+ bContinue = (1 == fp->Read(&count, sizeof(count), 1));\r
+ if (bContinue) {\r
+ BYTE* dati = (BYTE*)malloc(count);\r
+ bContinue = (dati!=NULL);\r
+ if (bContinue){\r
+ bContinue = (1 == fp->Read(dati, count, 1));\r
+ if (count>2){\r
+ m_loops = dati[1]+256*dati[2];\r
+ }\r
+ }\r
+ free(dati);\r
+ } } } } }\r
+\r
+ while (bContinue && fp->Read(&count, sizeof(count), 1) && count) {\r
+ //log << "Skipping " << count << " bytes" << endl;\r
+ fp->Seek(count, SEEK_CUR);\r
+ }\r
+ }\r
+ return bContinue;\r
+\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+// - This external (machine specific) function is expected to return\r
+// either the next BYTE from the GIF file, or a negative error number.\r
+int CxImageGIF::get_byte(CxFile* file)\r
+{\r
+ if (ibf>=GIFBUFTAM){\r
+ // FW 06/02/98 >>>\r
+ ibfmax = (int)file->Read( buf , 1 , GIFBUFTAM) ;\r
+ if( ibfmax < GIFBUFTAM ) buf[ ibfmax ] = 255 ;\r
+ // FW 06/02/98 <<<\r
+ ibf = 0;\r
+ }\r
+ if (ibf>=ibfmax) return -1; //<DP> avoid overflows\r
+ return buf[ibf++];\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/* - This function takes a full line of pixels (one BYTE per pixel) and\r
+ * displays them (or does whatever your program wants with them...). It\r
+ * should return zero, or negative if an error or some other event occurs\r
+ * which would require aborting the decode process... Note that the length\r
+ * passed will almost always be equal to the line length passed to the\r
+ * decoder function, with the sole exception occurring when an ending code\r
+ * occurs in an odd place in the GIF file... In any case, linelen will be\r
+ * equal to the number of pixels passed...\r
+*/\r
+int CxImageGIF::out_line(CImageIterator* iter, unsigned char *pixels, int linelen)\r
+{\r
+ if (iter == NULL || pixels == NULL)\r
+ return -1;\r
+\r
+ //<DP> for 1 & 4 bpp images, the pixels are compressed\r
+ if (head.biBitCount < 8){\r
+ for(long x=0;x<head.biWidth;x++){\r
+ BYTE pos;\r
+ BYTE* iDst= pixels + (x*head.biBitCount >> 3);\r
+ if (head.biBitCount==4){\r
+ pos = (BYTE)(4*(1-x%2));\r
+ *iDst &= ~(0x0F<<pos);\r
+ *iDst |= ((pixels[x] & 0x0F)<<pos);\r
+ } else if (head.biBitCount==1){\r
+ pos = (BYTE)(7-x%8);\r
+ *iDst &= ~(0x01<<pos);\r
+ *iDst |= ((pixels[x] & 0x01)<<pos);\r
+ }\r
+ }\r
+ }\r
+\r
+ /* AD - for interlace */\r
+ if (interlaced) {\r
+ iter->SetY(iheight-iypos-1);\r
+ iter->SetRow(pixels, linelen);\r
+\r
+ if ((iypos += istep) >= iheight) {\r
+ do {\r
+ if (ipass++ > 0) istep /= 2;\r
+ iypos = istep / 2;\r
+ }\r
+ while (iypos > iheight);\r
+ }\r
+ return 0;\r
+ } else {\r
+ if (iter->ItOK()) {\r
+ iter->SetRow(pixels, linelen);\r
+ (void)iter->PrevRow();\r
+ return 0;\r
+ } else {\r
+ // puts("chafeo");\r
+ return -1;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+// SaveFile - writes GIF87a gif file\r
+// Randy Spann 6/15/97\r
+// R.Spann@ConnRiver.net\r
+bool CxImageGIF::Encode(CxFile * fp)\r
+{\r
+ if (EncodeSafeCheck(fp)) return false;\r
+\r
+ if(head.biBitCount > 8) {\r
+ //strcpy(info.szLastError,"GIF Images must be 8 bit or less");\r
+ //return FALSE;\r
+ return EncodeRGB(fp);\r
+ }\r
+\r
+ if ( GetNumFrames()>1 && ppFrames ) {\r
+ return Encode(fp, ppFrames, GetNumFrames() );\r
+ }\r
+\r
+ EncodeHeader(fp);\r
+\r
+ EncodeExtension(fp);\r
+\r
+ EncodeComment(fp);\r
+\r
+ EncodeBody(fp);\r
+\r
+ fp->PutC(';'); // Write the GIF file terminator\r
+\r
+ return true; // done!\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageGIF::Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap, bool bLocalDispMeth)\r
+{\r
+ cx_try {\r
+ if (fp==NULL) cx_throw("invalid file pointer");\r
+ if (pImages==NULL || pagecount<=0 || pImages[0]==NULL) cx_throw("multipage GIF, no images!");\r
+\r
+ int i;\r
+ for (i=0; i<pagecount; i++){\r
+ if (pImages[i]==NULL)\r
+ cx_throw("Bad image pointer");\r
+ if (!(pImages[i]->IsValid()))\r
+ cx_throw("Empty image");\r
+ if (pImages[i]->GetNumColors()==0)\r
+ cx_throw("CxImageGIF::Encode cannot create animated GIFs with a true color frame. Use DecreaseBpp before");\r
+ }\r
+\r
+ CxImageGIF ghost;\r
+\r
+ //write the first image\r
+ ghost.Ghost(pImages[0]);\r
+ ghost.EncodeHeader(fp);\r
+\r
+ if (m_loops!=1){\r
+ ghost.SetLoops(max(0,m_loops-1));\r
+ ghost.EncodeLoopExtension(fp);\r
+ }\r
+\r
+ if (bLocalDispMeth) {\r
+ ghost.EncodeExtension(fp);\r
+ } else {\r
+ BYTE dm = ghost.GetDisposalMethod();\r
+ ghost.SetDisposalMethod(GetDisposalMethod());\r
+ ghost.EncodeExtension(fp);\r
+ ghost.SetDisposalMethod(dm);\r
+ }\r
+\r
+ EncodeComment(fp);\r
+\r
+ ghost.EncodeBody(fp);\r
+\r
+ for (i=1; i<pagecount; i++){\r
+ ghost.Ghost(pImages[i]);\r
+\r
+ if (bLocalDispMeth) {\r
+ ghost.EncodeExtension(fp);\r
+ } else {\r
+ BYTE dm = ghost.GetDisposalMethod();\r
+ ghost.SetDisposalMethod(GetDisposalMethod());\r
+ ghost.EncodeExtension(fp);\r
+ ghost.SetDisposalMethod(dm);\r
+ }\r
+\r
+ ghost.EncodeBody(fp,bLocalColorMap);\r
+ }\r
+\r
+ fp->PutC(';'); // Write the GIF file terminator\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::EncodeHeader(CxFile *fp)\r
+{\r
+ fp->Write("GIF89a",1,6); //GIF Header\r
+\r
+ Putword(head.biWidth,fp); //Logical screen descriptor\r
+ Putword(head.biHeight,fp);\r
+\r
+ BYTE Flags;\r
+ if (head.biClrUsed==0){\r
+ Flags=0x11;\r
+ } else {\r
+ Flags = 0x80;\r
+ Flags |=(head.biBitCount - 1) << 5;\r
+ Flags |=(head.biBitCount - 1);\r
+ }\r
+\r
+ fp->PutC(Flags); //GIF "packed fields"\r
+ fp->PutC(0); //GIF "BackGround"\r
+ fp->PutC(0); //GIF "pixel aspect ratio"\r
+\r
+ if (head.biClrUsed!=0){\r
+ RGBQUAD* pPal = GetPalette();\r
+ for(DWORD i=0; i<head.biClrUsed; ++i) \r
+ {\r
+ fp->PutC(pPal[i].rgbRed);\r
+ fp->PutC(pPal[i].rgbGreen);\r
+ fp->PutC(pPal[i].rgbBlue);\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::EncodeExtension(CxFile *fp)\r
+{\r
+ // TRK BEGIN : transparency\r
+ fp->PutC('!');\r
+ fp->PutC(TRANSPARENCY_CODE);\r
+\r
+ gifgce.flags = 0;\r
+ gifgce.flags |= ((info.nBkgndIndex != -1) ? 1 : 0);\r
+ gifgce.flags |= ((GetDisposalMethod() & 0x7) << 2);\r
+ gifgce.delaytime = (WORD)info.dwFrameDelay;\r
+ gifgce.transpcolindex = (BYTE)info.nBkgndIndex; \r
+\r
+ //Invert byte order in case we use a byte order arch, then set it back <AMSN>\r
+ gifgce.delaytime = ntohs(gifgce.delaytime);\r
+ fp->PutC(sizeof(gifgce));\r
+ fp->Write(&gifgce, sizeof(gifgce), 1);\r
+ gifgce.delaytime = ntohs(gifgce.delaytime);\r
+\r
+ fp->PutC(0);\r
+ // TRK END\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::EncodeLoopExtension(CxFile *fp)\r
+{\r
+ fp->PutC('!'); //byte 1 : 33 (hex 0x21) GIF Extension code\r
+ fp->PutC(255); //byte 2 : 255 (hex 0xFF) Application Extension Label\r
+ fp->PutC(11); //byte 3 : 11 (hex (0x0B) Length of Application Block (eleven bytes of data to follow)\r
+ fp->Write("NETSCAPE2.0",11,1);\r
+ fp->PutC(3); //byte 15 : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow)\r
+ fp->PutC(1); //byte 16 : 1 (hex 0x01)\r
+ Putword(m_loops,fp); //bytes 17 to 18 : 0 to 65535, an unsigned integer in lo-hi byte format. \r
+ //This indicate the number of iterations the loop should be executed.\r
+ fp->PutC(0); //bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator. \r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::EncodeBody(CxFile *fp, bool bLocalColorMap)\r
+{\r
+ curx = 0;\r
+ cury = head.biHeight - 1; //because we read the image bottom to top\r
+ CountDown = (long)head.biWidth * (long)head.biHeight;\r
+\r
+ fp->PutC(',');\r
+\r
+ Putword(info.xOffset,fp);\r
+ Putword(info.yOffset,fp);\r
+ Putword(head.biWidth,fp);\r
+ Putword(head.biHeight,fp);\r
+\r
+ BYTE Flags=0x00; //non-interlaced (0x40 = interlaced) (0x80 = LocalColorMap)\r
+ if (bLocalColorMap) { Flags|=0x80; Flags|=head.biBitCount-1; }\r
+ fp->PutC(Flags);\r
+\r
+ if (bLocalColorMap){\r
+ Flags|=0x87;\r
+ RGBQUAD* pPal = GetPalette();\r
+ for(DWORD i=0; i<head.biClrUsed; ++i) \r
+ {\r
+ fp->PutC(pPal[i].rgbRed);\r
+ fp->PutC(pPal[i].rgbGreen);\r
+ fp->PutC(pPal[i].rgbBlue);\r
+ }\r
+ }\r
+\r
+ int InitCodeSize = head.biBitCount <=1 ? 2 : head.biBitCount;\r
+ // Write out the initial code size\r
+ fp->PutC((BYTE)InitCodeSize);\r
+\r
+ // Go and actually compress the data\r
+ switch (GetCodecOption(CXIMAGE_FORMAT_GIF))\r
+ {\r
+ case 1: //uncompressed\r
+ compressNONE(InitCodeSize+1, fp);\r
+ break;\r
+ case 2: //RLE\r
+ compressRLE(InitCodeSize+1, fp);\r
+ break;\r
+ default: //LZW\r
+ compressLZW(InitCodeSize+1, fp);\r
+ }\r
+\r
+ // Write out a Zero-length packet (to end the series)\r
+ fp->PutC(0);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::EncodeComment(CxFile *fp)\r
+{\r
+ unsigned long n = (unsigned long) strlen(m_comment);\r
+ if (n>255) n=255;\r
+ if (n) {\r
+ fp->PutC('!'); //extension code:\r
+ fp->PutC(254); //comment extension\r
+ fp->PutC((BYTE)n); //size of comment\r
+ fp->Write(m_comment,n,1);\r
+ fp->PutC(0); //block terminator\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageGIF::EncodeRGB(CxFile *fp)\r
+{\r
+ EncodeHeader(fp);\r
+\r
+// EncodeLoopExtension(fp);\r
+\r
+ EncodeComment(fp);\r
+\r
+ unsigned long w,h;\r
+ w=h=0;\r
+ const long cellw = 17;\r
+ const long cellh = 15;\r
+ CxImageGIF tmp;\r
+ for (long y=0;y<head.biHeight;y+=cellh){\r
+ for (long x=0;x<head.biWidth;x+=cellw){\r
+ if ((head.biWidth -x)<cellw) w=head.biWidth -x; else w=cellw;\r
+ if ((head.biHeight-y)<cellh) h=head.biHeight-y; else h=cellh;\r
+\r
+ if (w!=tmp.GetWidth() || h!=tmp.GetHeight()) tmp.Create(w,h,8);\r
+\r
+ if (IsTransparent()){\r
+ tmp.SetTransIndex(0);\r
+ tmp.SetPaletteColor(0,GetTransColor());\r
+ }\r
+\r
+ BYTE i;\r
+ for (unsigned long j=0;j<h;j++){\r
+ for (unsigned long k=0;k<w;k++){\r
+ i=(BYTE)(1+k+cellw*j);\r
+ tmp.SetPaletteColor(i,GetPixelColor(x+k,head.biHeight-y-h+j));\r
+ tmp.SetPixelIndex(k,j,tmp.GetNearestIndex(tmp.GetPaletteColor(i)));\r
+ }\r
+ }\r
+\r
+ tmp.SetOffset(x,y);\r
+ tmp.EncodeExtension(fp);\r
+ tmp.EncodeBody(fp,true);\r
+ }\r
+ }\r
+\r
+ fp->PutC(';'); // Write the GIF file terminator\r
+\r
+ return true; // done!\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Return the next pixel from the image\r
+// <DP> fix for 1 & 4 bpp images\r
+int CxImageGIF::GifNextPixel( )\r
+{\r
+ if( CountDown == 0 ) return EOF;\r
+ --CountDown;\r
+ int r = GetPixelIndex(curx,cury);\r
+ // Bump the current X position\r
+ ++curx;\r
+ if( curx == head.biWidth ){\r
+ curx = 0;\r
+ cury--; //bottom to top\r
+ }\r
+ return r;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::Putword(int w, CxFile *fp )\r
+{\r
+ fp->PutC((BYTE)(w & 0xff));\r
+ fp->PutC((BYTE)((w >> 8) & 0xff));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::compressNONE( int init_bits, CxFile* outfile)\r
+{\r
+ register long c;\r
+ register long ent;\r
+\r
+ // g_init_bits - initial number of bits\r
+ // g_outfile - pointer to output file\r
+ g_init_bits = init_bits;\r
+ g_outfile = outfile;\r
+\r
+ // Set up the necessary values\r
+ cur_accum = cur_bits = clear_flg = 0;\r
+ maxcode = (short)MAXCODE(n_bits = g_init_bits);\r
+ code_int maxmaxcode = (code_int)1 << MAXBITSCODES;\r
+\r
+ ClearCode = (1 << (init_bits - 1));\r
+ EOFCode = ClearCode + 1;\r
+ free_ent = (short)(ClearCode + 2);\r
+\r
+ a_count=0;\r
+ ent = GifNextPixel( );\r
+\r
+ output( (code_int)ClearCode );\r
+\r
+ while ( ent != EOF ) { \r
+ c = GifNextPixel();\r
+\r
+ output ( (code_int) ent );\r
+ ent = c;\r
+ if ( free_ent < maxmaxcode ) { \r
+ free_ent++;\r
+ } else {\r
+ free_ent=(short)(ClearCode+2);\r
+ clear_flg=1;\r
+ output((code_int)ClearCode);\r
+ }\r
+ }\r
+ // Put out the final code.\r
+ output( (code_int) EOFCode );\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+/***************************************************************************\r
+ *\r
+ * GIFCOMPR.C - LZW GIF Image compression routines\r
+ *\r
+ ***************************************************************************/\r
+\r
+void CxImageGIF::compressLZW( int init_bits, CxFile* outfile)\r
+{\r
+ register long fcode;\r
+ register long c;\r
+ register long ent;\r
+ register long hshift;\r
+ register long disp;\r
+ register long i;\r
+\r
+ // g_init_bits - initial number of bits\r
+ // g_outfile - pointer to output file\r
+ g_init_bits = init_bits;\r
+ g_outfile = outfile;\r
+\r
+ // Set up the necessary values\r
+ cur_accum = cur_bits = clear_flg = 0;\r
+ maxcode = (short)MAXCODE(n_bits = g_init_bits);\r
+ code_int maxmaxcode = (code_int)1 << MAXBITSCODES;\r
+\r
+ ClearCode = (1 << (init_bits - 1));\r
+ EOFCode = ClearCode + 1;\r
+ free_ent = (short)(ClearCode + 2);\r
+\r
+ a_count=0;\r
+ ent = GifNextPixel( );\r
+\r
+ hshift = 0;\r
+ for ( fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L ) ++hshift;\r
+ hshift = 8 - hshift; /* set hash code range bound */\r
+ cl_hash((long)HSIZE); /* clear hash table */\r
+ output( (code_int)ClearCode );\r
+\r
+ while ( (c = GifNextPixel( )) != EOF ) { \r
+\r
+ fcode = (long) (((long) c << MAXBITSCODES) + ent);\r
+ i = (((code_int)c << hshift) ^ ent); /* xor hashing */\r
+\r
+ if ( HashTabOf (i) == fcode ) {\r
+ ent = CodeTabOf (i);\r
+ continue;\r
+ } else if ( (long)HashTabOf (i) < 0 ) /* empty slot */\r
+ goto nomatch;\r
+ disp = HSIZE - i; /* secondary hash (after G. Knott) */\r
+ if ( i == 0 ) disp = 1;\r
+probe:\r
+ if ( (i -= disp) < 0 ) i += HSIZE;\r
+ if ( HashTabOf (i) == fcode ) { ent = CodeTabOf (i); continue; }\r
+ if ( (long)HashTabOf (i) > 0 ) goto probe;\r
+nomatch:\r
+ output ( (code_int) ent );\r
+ ent = c;\r
+ if ( free_ent < maxmaxcode ) { \r
+ CodeTabOf (i) = free_ent++; /* code -> hashtable */\r
+ HashTabOf (i) = fcode;\r
+ } else {\r
+ cl_hash((long)HSIZE);\r
+ free_ent=(short)(ClearCode+2);\r
+ clear_flg=1;\r
+ output((code_int)ClearCode);\r
+ }\r
+ }\r
+ // Put out the final code.\r
+ output( (code_int)ent );\r
+ output( (code_int) EOFCode );\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+static const unsigned long code_mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,\r
+ 0x001F, 0x003F, 0x007F, 0x00FF,\r
+ 0x01FF, 0x03FF, 0x07FF, 0x0FFF,\r
+ 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::output( code_int code)\r
+{\r
+ cur_accum &= code_mask[ cur_bits ];\r
+\r
+ if( cur_bits > 0 )\r
+ cur_accum |= ((long)code << cur_bits);\r
+ else\r
+ cur_accum = code;\r
+\r
+ cur_bits += n_bits;\r
+\r
+ while( cur_bits >= 8 ) {\r
+ char_out( (unsigned int)(cur_accum & 0xff) );\r
+ cur_accum >>= 8;\r
+ cur_bits -= 8;\r
+ }\r
+\r
+ /*\r
+ * If the next entry is going to be too big for the code size,\r
+ * then increase it, if possible.\r
+ */\r
+\r
+ if ( free_ent > maxcode || clear_flg ) {\r
+ if( clear_flg ) {\r
+ maxcode = (short)MAXCODE(n_bits = g_init_bits);\r
+ clear_flg = 0;\r
+ } else {\r
+ ++n_bits;\r
+ if ( n_bits == MAXBITSCODES )\r
+ maxcode = (code_int)1 << MAXBITSCODES; /* should NEVER generate this code */\r
+ else\r
+ maxcode = (short)MAXCODE(n_bits);\r
+ }\r
+ }\r
+ \r
+ if( code == EOFCode ) {\r
+ // At EOF, write the rest of the buffer.\r
+ while( cur_bits > 0 ) {\r
+ char_out( (unsigned int)(cur_accum & 0xff) );\r
+ cur_accum >>= 8;\r
+ cur_bits -= 8;\r
+ }\r
+ \r
+ flush_char();\r
+ g_outfile->Flush();\r
+\r
+ if(g_outfile->Error()) strcpy(info.szLastError,"Write Error in GIF file");\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+void CxImageGIF::cl_hash(long hsize)\r
+\r
+{\r
+ register long *htab_p = htab+hsize;\r
+\r
+ register long i;\r
+ register long m1 = -1L;\r
+\r
+ i = hsize - 16;\r
+\r
+ do {\r
+ *(htab_p-16)=m1;\r
+ *(htab_p-15)=m1;\r
+ *(htab_p-14)=m1;\r
+ *(htab_p-13)=m1;\r
+ *(htab_p-12)=m1;\r
+ *(htab_p-11)=m1;\r
+ *(htab_p-10)=m1;\r
+ *(htab_p-9)=m1;\r
+ *(htab_p-8)=m1;\r
+ *(htab_p-7)=m1;\r
+ *(htab_p-6)=m1;\r
+ *(htab_p-5)=m1;\r
+ *(htab_p-4)=m1;\r
+ *(htab_p-3)=m1;\r
+ *(htab_p-2)=m1;\r
+ *(htab_p-1)=m1;\r
+ \r
+ htab_p-=16;\r
+ } while ((i-=16) >=0);\r
+\r
+ for (i+=16;i>0;--i)\r
+ *--htab_p=m1;\r
+}\r
+\r
+/*******************************************************************************\r
+* GIF specific\r
+*******************************************************************************/\r
+\r
+void CxImageGIF::char_out(int c)\r
+{\r
+ accum[a_count++]=(char)c;\r
+ if (a_count >=254)\r
+ flush_char();\r
+}\r
+\r
+void CxImageGIF::flush_char()\r
+{\r
+ if (a_count > 0) {\r
+ g_outfile->PutC((BYTE)a_count);\r
+ g_outfile->Write(accum,1,a_count);\r
+ a_count=0;\r
+ }\r
+}\r
+\r
+/*******************************************************************************\r
+* GIF decoder\r
+*******************************************************************************/\r
+/* DECODE.C - An LZW decoder for GIF\r
+ * Copyright (C) 1987, by Steven A. Bennett\r
+ * Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra\r
+*\r
+ * Permission is given by the author to freely redistribute and include\r
+ * this code in any program as long as this credit is given where due.\r
+ *\r
+ * In accordance with the above, I want to credit Steve Wilhite who wrote\r
+ * the code which this is heavily inspired by...\r
+ *\r
+ * GIF and 'Graphics Interchange Format' are trademarks (tm) of\r
+ * Compuserve, Incorporated, an H&R Block Company.\r
+ *\r
+ * Release Notes: This file contains a decoder routine for GIF images\r
+ * which is similar, structurally, to the original routine by Steve Wilhite.\r
+ * It is, however, somewhat noticably faster in most cases.\r
+ *\r
+ */\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+short CxImageGIF::init_exp(short size)\r
+{\r
+ curr_size = (short)(size + 1);\r
+ top_slot = (short)(1 << curr_size);\r
+ clear = (short)(1 << size);\r
+ ending = (short)(clear + 1);\r
+ slot = newcodes = (short)(ending + 1);\r
+ navail_bytes = nbits_left = 0;\r
+\r
+ memset(stack,0,MAX_CODES + 1);\r
+ memset(prefix,0,MAX_CODES + 1);\r
+ memset(suffix,0,MAX_CODES + 1);\r
+ return(0);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+/* get_next_code()\r
+ * - gets the next code from the GIF file. Returns the code, or else\r
+ * a negative number in case of file errors...\r
+ */\r
+short CxImageGIF::get_next_code(CxFile* file)\r
+{\r
+ short i, x;\r
+ DWORD ret;\r
+\r
+ if (nbits_left == 0) {\r
+ if (navail_bytes <= 0) {\r
+ /* Out of bytes in current block, so read next block */\r
+ pbytes = byte_buff;\r
+ if ((navail_bytes = (short)get_byte(file)) < 0)\r
+ return(navail_bytes);\r
+ else if (navail_bytes) {\r
+ for (i = 0; i < navail_bytes; ++i) {\r
+ if ((x = (short)get_byte(file)) < 0) return(x);\r
+ byte_buff[i] = (BYTE)x;\r
+ }\r
+ }\r
+ }\r
+ b1 = *pbytes++;\r
+ nbits_left = 8;\r
+ --navail_bytes;\r
+ }\r
+\r
+ if (navail_bytes<0) return ending; // prevent deadlocks (thanks to Mike Melnikov)\r
+\r
+ ret = b1 >> (8 - nbits_left);\r
+ while (curr_size > nbits_left){\r
+ if (navail_bytes <= 0){\r
+ /* Out of bytes in current block, so read next block*/\r
+ pbytes = byte_buff;\r
+ if ((navail_bytes = (short)get_byte(file)) < 0)\r
+ return(navail_bytes);\r
+ else if (navail_bytes){\r
+ for (i = 0; i < navail_bytes; ++i){\r
+ if ((x = (short)get_byte(file)) < 0) return(x);\r
+ byte_buff[i] = (BYTE)x;\r
+ }\r
+ }\r
+ }\r
+ b1 = *pbytes++;\r
+ ret |= b1 << nbits_left;\r
+ nbits_left += 8;\r
+ --navail_bytes;\r
+ }\r
+ nbits_left = (short)(nbits_left-curr_size);\r
+ ret &= code_mask[curr_size];\r
+ return((short)(ret));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+/* short decoder(linewidth)\r
+ * short linewidth; * Pixels per line of image *\r
+ *\r
+ * - This function decodes an LZW image, according to the method used\r
+ * in the GIF spec. Every *linewidth* "characters" (ie. pixels) decoded\r
+ * will generate a call to out_line(), which is a user specific function\r
+ * to display a line of pixels. The function gets it's codes from\r
+ * get_next_code() which is responsible for reading blocks of data and\r
+ * seperating them into the proper size codes. Finally, get_byte() is\r
+ * the global routine to read the next BYTE from the GIF file.\r
+ *\r
+ * It is generally a good idea to have linewidth correspond to the actual\r
+ * width of a line (as specified in the Image header) to make your own\r
+ * code a bit simpler, but it isn't absolutely necessary.\r
+ *\r
+ * Returns: 0 if successful, else negative. (See ERRS.H)\r
+ *\r
+ */\r
+/* bad_code_count is incremented each time an out of range code is read.\r
+ * When this value is non-zero after a decode, your GIF file is probably\r
+ * corrupt in some way...\r
+ */\r
+short CxImageGIF::decoder(CxFile* file, CImageIterator* iter, short linewidth, int &bad_code_count)\r
+{\r
+ register BYTE *sp, *bufptr;\r
+ BYTE *buf;\r
+ register short code, fc, oc, bufcnt;\r
+ short c, size, ret;\r
+\r
+ /* Initialize for decoding a new image... */\r
+ bad_code_count = 0;\r
+ if ((size = (short)get_byte(file)) < 0) return(size);\r
+ if (size < 2 || 9 < size) return(BAD_CODE_SIZE);\r
+ // out_line = outline;\r
+ init_exp(size);\r
+ //printf("L %d %x\n",linewidth,size);\r
+\r
+ /* Initialize in case they forgot to put in a clear code.\r
+ * (This shouldn't happen, but we'll try and decode it anyway...)\r
+ */\r
+ oc = fc = 0;\r
+\r
+ /* Allocate space for the decode buffer */\r
+ if ((buf = new BYTE[linewidth + 1]) == NULL) return(OUT_OF_MEMORY);\r
+\r
+ /* Set up the stack pointer and decode buffer pointer */\r
+ sp = stack;\r
+ bufptr = buf;\r
+ bufcnt = linewidth;\r
+\r
+ /* This is the main loop. For each code we get we pass through the\r
+ * linked list of prefix codes, pushing the corresponding "character" for\r
+ * each code onto the stack. When the list reaches a single "character"\r
+ * we push that on the stack too, and then start unstacking each\r
+ * character for output in the correct order. Special handling is\r
+ * included for the clear code, and the whole thing ends when we get\r
+ * an ending code.\r
+ */\r
+ while ((c = get_next_code(file)) != ending) {\r
+ /* If we had a file error, return without completing the decode*/\r
+ if (c < 0){\r
+ delete [] buf;\r
+ return(0);\r
+ }\r
+ /* If the code is a clear code, reinitialize all necessary items.*/\r
+ if (c == clear){\r
+ curr_size = (short)(size + 1);\r
+ slot = newcodes;\r
+ top_slot = (short)(1 << curr_size);\r
+\r
+ /* Continue reading codes until we get a non-clear code\r
+ * (Another unlikely, but possible case...)\r
+ */\r
+ while ((c = get_next_code(file)) == clear);\r
+\r
+ /* If we get an ending code immediately after a clear code\r
+ * (Yet another unlikely case), then break out of the loop.\r
+ */\r
+ if (c == ending) break;\r
+\r
+ /* Finally, if the code is beyond the range of already set codes,\r
+ * (This one had better NOT happen... I have no idea what will\r
+ * result from this, but I doubt it will look good...) then set it\r
+ * to color zero.\r
+ */\r
+ if (c >= slot) c = 0;\r
+ oc = fc = c;\r
+\r
+ /* And let us not forget to put the char into the buffer... And\r
+ * if, on the off chance, we were exactly one pixel from the end\r
+ * of the line, we have to send the buffer to the out_line()\r
+ * routine...\r
+ */\r
+ *bufptr++ = (BYTE)c;\r
+ if (--bufcnt == 0) {\r
+ if (iter) {\r
+ if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {\r
+ delete [] buf;\r
+ return(ret);\r
+ }\r
+ }\r
+ bufptr = buf;\r
+ bufcnt = linewidth;\r
+ }\r
+ } else {\r
+ /* In this case, it's not a clear code or an ending code, so\r
+ * it must be a code code... So we can now decode the code into\r
+ * a stack of character codes. (Clear as mud, right?)\r
+ */\r
+ code = c;\r
+\r
+ /* Here we go again with one of those off chances... If, on the\r
+ * off chance, the code we got is beyond the range of those already\r
+ * set up (Another thing which had better NOT happen...) we trick\r
+ * the decoder into thinking it actually got the last code read.\r
+ * (Hmmn... I'm not sure why this works... But it does...)\r
+ */\r
+ if (code >= slot && sp<(stack+MAX_CODES-1)) {\r
+ if (code > slot)\r
+ ++bad_code_count;\r
+ code = oc;\r
+ *sp++ = (BYTE)fc;\r
+ }\r
+\r
+ /* Here we scan back along the linked list of prefixes, pushing\r
+ * helpless characters (ie. suffixes) onto the stack as we do so.\r
+ */\r
+ while (code >= newcodes && sp<(stack+MAX_CODES-1)) {\r
+ *sp++ = suffix[code];\r
+ code = prefix[code];\r
+ }\r
+\r
+ /* Push the last character on the stack, and set up the new\r
+ * prefix and suffix, and if the required slot number is greater\r
+ * than that allowed by the current bit size, increase the bit\r
+ * size. (NOTE - If we are all full, we *don't* save the new\r
+ * suffix and prefix... I'm not certain if this is correct...\r
+ * it might be more proper to overwrite the last code...\r
+ */\r
+ *sp++ = (BYTE)code;\r
+ if (slot < top_slot){\r
+ suffix[slot] = (BYTE)(fc = (BYTE)code);\r
+ prefix[slot++] = oc;\r
+ oc = c;\r
+ }\r
+ if (slot >= top_slot){\r
+ if (curr_size < 12) {\r
+ top_slot <<= 1;\r
+ ++curr_size;\r
+ }\r
+ }\r
+\r
+ /* Now that we've pushed the decoded string (in reverse order)\r
+ * onto the stack, lets pop it off and put it into our decode\r
+ * buffer... And when the decode buffer is full, write another\r
+ * line...\r
+ */\r
+ while (sp > stack) {\r
+ *bufptr++ = *(--sp);\r
+ if (--bufcnt == 0) {\r
+ if (iter) {\r
+ if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {\r
+ delete [] buf;\r
+ return(ret);\r
+ }\r
+ }\r
+ bufptr = buf;\r
+ bufcnt = linewidth;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ ret = 0;\r
+ if (bufcnt != linewidth && iter)\r
+ ret = (short)out_line(iter, buf, (linewidth - bufcnt));\r
+ delete [] buf;\r
+ return(ret);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+int CxImageGIF::get_num_frames(CxFile *fp,struct_TabCol* TabColSrc,struct_dscgif* dscgif)\r
+{\r
+ struct_image image;\r
+\r
+ long pos=fp->Tell();\r
+ int nframes=0;\r
+\r
+ struct_TabCol TempTabCol;\r
+ memcpy(&TempTabCol,TabColSrc,sizeof(struct_TabCol));\r
+\r
+ char ch;\r
+ bool bPreviousWasNull = true;\r
+\r
+ for (BOOL bContinue = TRUE; bContinue; )\r
+ {\r
+ if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}\r
+\r
+ if (bPreviousWasNull || ch==0)\r
+ {\r
+ switch (ch)\r
+ {\r
+ case '!': // extension\r
+ {\r
+ DecodeExtension(fp);\r
+ break;\r
+ }\r
+ case ',': // image\r
+ {\r
+\r
+ assert(sizeof(image) == 9);\r
+ //log << "Image header" << endl;\r
+ fp->Read(&image,sizeof(image),1);\r
+\r
+ //avoid byte order problems with Solaris <candan> <AMSN>\r
+ image.l = ntohs(image.l);\r
+ image.t = ntohs(image.t);\r
+ image.w = ntohs(image.w);\r
+ image.h = ntohs(image.h);\r
+\r
+ // in case of images with empty screen descriptor, give a last chance\r
+ if (dscgif->scrwidth==0 && dscgif->scrheight==0){\r
+ dscgif->scrwidth = image.w;\r
+ dscgif->scrheight = image.h;\r
+ }\r
+\r
+ if (((image.l + image.w) > dscgif->scrwidth)||((image.t + image.h) > dscgif->scrheight))\r
+ break;\r
+\r
+ nframes++;\r
+\r
+ // Local colour map?\r
+ if (image.pf & 0x80) {\r
+ TempTabCol.sogct = (short)(1 << ((image.pf & 0x07) +1));\r
+ assert(3 == sizeof(struct rgb_color));\r
+ fp->Read(TempTabCol.paleta,sizeof(struct rgb_color)*TempTabCol.sogct,1);\r
+ //log << "Local colour map" << endl;\r
+ }\r
+\r
+ int badcode=0;\r
+ ibf = GIFBUFTAM+1;\r
+\r
+ interlaced = image.pf & 0x40;\r
+ iheight = image.h;\r
+ istep = 8;\r
+ iypos = 0;\r
+ ipass = 0;\r
+\r
+ long pos_start = fp->Tell();\r
+\r
+ //if (interlaced) log << "Interlaced" << endl;\r
+ decoder(fp, 0, image.w, badcode);\r
+\r
+ if (badcode){\r
+ seek_next_image(fp,pos_start);\r
+ } else {\r
+ fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);\r
+ }\r
+ \r
+ break;\r
+ }\r
+ case ';': //terminator\r
+ bContinue=false;\r
+ break;\r
+ default:\r
+ bPreviousWasNull = (ch==0);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ fp->Seek(pos,SEEK_SET);\r
+ return nframes;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImageGIF::seek_next_image(CxFile* fp, long position)\r
+{\r
+ fp->Seek(position, SEEK_SET);\r
+ char ch1,ch2;\r
+ ch1=ch2=0;\r
+ while(fp->Read(&ch2,sizeof(char),1)>0){\r
+ if (ch1 == 0 && ch2 == ','){\r
+ fp->Seek(-1,SEEK_CUR);\r
+ return fp->Tell();\r
+ } else {\r
+ ch1 = ch2;\r
+ }\r
+ }\r
+ return -1;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::SetLoops(int loops)\r
+{ m_loops=loops; }\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImageGIF::GetLoops()\r
+{ return m_loops; }\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::SetComment(const char* sz_comment_in)\r
+{ if (sz_comment_in) strncpy(m_comment,sz_comment_in,255); }\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::GetComment(char* sz_comment_out)\r
+{ if (sz_comment_out) strncpy(sz_comment_out,m_comment,255); }\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::GifMix(CxImage & imgsrc2, struct_image & imgdesc)\r
+{\r
+ long ymin = max(0,(long)(GetHeight()-imgdesc.t - imgdesc.h));\r
+ long ymax = GetHeight()-imgdesc.t;\r
+ long xmin = imgdesc.l;\r
+ long xmax = min(GetWidth(), (DWORD)(imgdesc.l + imgdesc.w));\r
+\r
+ long ibg2= imgsrc2.GetTransIndex();\r
+ BYTE i2;\r
+\r
+ for(long y = ymin; y < ymax; y++){\r
+ for(long x = xmin; x < xmax; x++){\r
+ i2 = imgsrc2.GetPixelIndex(x-xmin,y-ymin);\r
+ if(i2!=ibg2) SetPixelIndex(x,y,i2);\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/*-----------------------------------------------------------------------\r
+ *\r
+ * miGIF Compression - mouse and ivo's GIF-compatible compression\r
+ *\r
+ * -run length encoding compression routines-\r
+ *\r
+ * Copyright (C) 1998 Hutchison Avenue Software Corporation\r
+ * http://www.hasc.com\r
+ * info@hasc.com\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software and its\r
+ * documentation for any purpose and without fee is hereby granted, provided\r
+ * that the above copyright notice appear in all copies and that both that\r
+ * copyright notice and this permission notice appear in supporting\r
+ * documentation. This software is provided "AS IS." The Hutchison Avenue \r
+ * Software Corporation disclaims all warranties, either express or implied, \r
+ * including but not limited to implied warranties of merchantability and \r
+ * fitness for a particular purpose, with respect to this code and accompanying\r
+ * documentation. \r
+ * \r
+ * The miGIF compression routines do not, strictly speaking, generate files \r
+ * conforming to the GIF spec, since the image data is not LZW-compressed \r
+ * (this is the point: in order to avoid transgression of the Unisys patent \r
+ * on the LZW algorithm.) However, miGIF generates data streams that any \r
+ * reasonably sane LZW decompresser will decompress to what we want.\r
+ *\r
+ * miGIF compression uses run length encoding. It compresses horizontal runs \r
+ * of pixels of the same color. This type of compression gives good results\r
+ * on images with many runs, for example images with lines, text and solid \r
+ * shapes on a solid-colored background. It gives little or no compression \r
+ * on images with few runs, for example digital or scanned photos.\r
+ *\r
+ * der Mouse\r
+ * mouse@rodents.montreal.qc.ca\r
+ * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B\r
+ *\r
+ * ivo@hasc.com\r
+ *\r
+ * The Graphics Interchange Format(c) is the Copyright property of\r
+ * CompuServe Incorporated. GIF(sm) is a Service Mark property of\r
+ * CompuServe Incorporated.\r
+ *\r
+ */\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_clear(struct_RLE* rle)\r
+{\r
+ rle->out_bits = rle->out_bits_init;\r
+ rle->out_bump = rle->out_bump_init;\r
+ rle->out_clear = rle->out_clear_init;\r
+ rle->out_count = 0;\r
+ rle->rl_table_max = 0;\r
+ rle->just_cleared = 1;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_flush(struct_RLE* rle)\r
+{\r
+ if (rle->rl_count == 1){\r
+ rle_output_plain(rle->rl_pixel,rle);\r
+ rle->rl_count = 0;\r
+ return;\r
+ }\r
+ if (rle->just_cleared){\r
+ rle_flush_fromclear(rle->rl_count,rle);\r
+ } else if ((rle->rl_table_max < 2) || (rle->rl_table_pixel != rle->rl_pixel)) {\r
+ rle_flush_clearorrep(rle->rl_count,rle);\r
+ } else {\r
+ rle_flush_withtable(rle->rl_count,rle);\r
+ }\r
+ rle->rl_count = 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_output_plain(int c,struct_RLE* rle)\r
+{\r
+ rle->just_cleared = 0;\r
+ rle_output(c,rle);\r
+ rle->out_count++;\r
+ if (rle->out_count >= rle->out_bump){\r
+ rle->out_bits ++;\r
+ rle->out_bump += 1 << (rle->out_bits - 1);\r
+ }\r
+ if (rle->out_count >= rle->out_clear){\r
+ rle_output(rle->code_clear,rle);\r
+ rle_clear(rle);\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_flush_fromclear(int count,struct_RLE* rle)\r
+{\r
+ int n;\r
+\r
+ rle->out_clear = rle->max_ocodes;\r
+ rle->rl_table_pixel = rle->rl_pixel;\r
+ n = 1;\r
+ while (count > 0){\r
+ if (n == 1){\r
+ rle->rl_table_max = 1;\r
+ rle_output_plain(rle->rl_pixel,rle);\r
+ count --;\r
+ } else if (count >= n){\r
+ rle->rl_table_max = n;\r
+ rle_output_plain(rle->rl_basecode+n-2,rle);\r
+ count -= n;\r
+ } else if (count == 1){\r
+ rle->rl_table_max ++;\r
+ rle_output_plain(rle->rl_pixel,rle);\r
+ count = 0;\r
+ } else {\r
+ rle->rl_table_max ++;\r
+ rle_output_plain(rle->rl_basecode+count-2,rle);\r
+ count = 0;\r
+ }\r
+ if (rle->out_count == 0) n = 1; else n ++;\r
+ }\r
+ rle_reset_out_clear(rle);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_reset_out_clear(struct_RLE* rle)\r
+{\r
+ rle->out_clear = rle->out_clear_init;\r
+ if (rle->out_count >= rle->out_clear){\r
+ rle_output(rle->code_clear,rle);\r
+ rle_clear(rle);\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_flush_withtable(int count, struct_RLE* rle)\r
+{\r
+ int repmax;\r
+ int repleft;\r
+ int leftover;\r
+\r
+ repmax = count / rle->rl_table_max;\r
+ leftover = count % rle->rl_table_max;\r
+ repleft = (leftover ? 1 : 0);\r
+ if (rle->out_count+repmax+repleft > rle->max_ocodes){\r
+ repmax = rle->max_ocodes - rle->out_count;\r
+ leftover = count - (repmax * rle->rl_table_max);\r
+ repleft = 1 + rle_compute_triangle_count(leftover,rle->max_ocodes);\r
+ }\r
+ if (1+rle_compute_triangle_count(count,rle->max_ocodes) < (unsigned int)(repmax+repleft)){\r
+ rle_output(rle->code_clear,rle);\r
+ rle_clear(rle);\r
+ rle_flush_fromclear(count,rle);\r
+ return;\r
+ }\r
+ rle->out_clear = rle->max_ocodes;\r
+ for (;repmax>0;repmax--) rle_output_plain(rle->rl_basecode+rle->rl_table_max-2,rle);\r
+ if (leftover){\r
+ if (rle->just_cleared){\r
+ rle_flush_fromclear(leftover,rle);\r
+ } else if (leftover == 1){\r
+ rle_output_plain(rle->rl_pixel,rle);\r
+ } else {\r
+ rle_output_plain(rle->rl_basecode+leftover-2,rle);\r
+ }\r
+ }\r
+ rle_reset_out_clear(rle);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+unsigned int CxImageGIF::rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes)\r
+{\r
+ unsigned int perrep;\r
+ unsigned int cost;\r
+\r
+ cost = 0;\r
+ perrep = (nrepcodes * (nrepcodes+1)) / 2;\r
+ while (count >= perrep){\r
+ cost += nrepcodes;\r
+ count -= perrep;\r
+ }\r
+ if (count > 0){\r
+ unsigned int n;\r
+ n = rle_isqrt(count);\r
+ while ((n*(n+1)) >= 2*count) n --;\r
+ while ((n*(n+1)) < 2*count) n ++;\r
+ cost += n;\r
+ }\r
+ return(cost);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+unsigned int CxImageGIF::rle_isqrt(unsigned int x)\r
+{\r
+ unsigned int r;\r
+ unsigned int v;\r
+\r
+ if (x < 2) return(x);\r
+ for (v=x,r=1;v;v>>=2,r<<=1) ;\r
+ for( ;; )\r
+ {\r
+ v = ((x / r) + r) / 2;\r
+ if ((v == r) || (v == r+1)) return(r);\r
+ r = v;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_flush_clearorrep(int count, struct_RLE* rle)\r
+{\r
+ int withclr;\r
+ withclr = 1 + rle_compute_triangle_count(count,rle->max_ocodes);\r
+ if (withclr < count) {\r
+ rle_output(rle->code_clear,rle);\r
+ rle_clear(rle);\r
+ rle_flush_fromclear(count,rle);\r
+ } else {\r
+ for (;count>0;count--) rle_output_plain(rle->rl_pixel,rle);\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_write_block(struct_RLE* rle)\r
+{\r
+ g_outfile->PutC((BYTE)rle->oblen);\r
+ g_outfile->Write(rle->oblock,1,rle->oblen);\r
+ rle->oblen = 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_block_out(unsigned char c, struct_RLE* rle)\r
+{\r
+ rle->oblock[rle->oblen++] = c;\r
+ if (rle->oblen >= 255) rle_write_block(rle);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_block_flush(struct_RLE* rle)\r
+{\r
+ if (rle->oblen > 0) rle_write_block(rle);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_output(int val, struct_RLE* rle)\r
+{\r
+ rle->obuf |= val << rle->obits;\r
+ rle->obits += rle->out_bits;\r
+ while (rle->obits >= 8){\r
+ rle_block_out((unsigned char)(rle->obuf&0xff),rle);\r
+ rle->obuf >>= 8;\r
+ rle->obits -= 8;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::rle_output_flush(struct_RLE* rle)\r
+{\r
+ if (rle->obits > 0) rle_block_out((unsigned char)(rle->obuf),rle);\r
+ rle_block_flush(rle);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageGIF::compressRLE( int init_bits, CxFile* outfile)\r
+{\r
+ g_init_bits = init_bits;\r
+ g_outfile = outfile;\r
+\r
+ struct_RLE rle;\r
+ rle.code_clear = 1 << (init_bits - 1);\r
+ rle.code_eof = rle.code_clear + 1;\r
+ rle.rl_basecode = rle.code_eof + 1;\r
+ rle.out_bump_init = (1 << (init_bits - 1)) - 1;\r
+ rle.out_clear_init = (init_bits <= 3) ? 9 : (rle.out_bump_init-1);\r
+ rle.out_bits_init = init_bits;\r
+ rle.max_ocodes = (1 << MAXBITSCODES) - ((1 << (rle.out_bits_init - 1)) + 3);\r
+ rle.rl_count = 0;\r
+ rle_clear(&rle);\r
+ rle.obuf = 0;\r
+ rle.obits = 0;\r
+ rle.oblen = 0;\r
+\r
+ rle_output(rle.code_clear,&rle);\r
+\r
+ int c;\r
+ for( ;; )\r
+ {\r
+ c = GifNextPixel();\r
+ if ((rle.rl_count > 0) && (c != rle.rl_pixel)) rle_flush(&rle);\r
+ if (c == EOF) break;\r
+ if (rle.rl_pixel == c){\r
+ rle.rl_count++;\r
+ } else {\r
+ rle.rl_pixel = c;\r
+ rle.rl_count = 1;\r
+ }\r
+ }\r
+ rle_output(rle.code_eof,&rle);\r
+ rle_output_flush(&rle);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_GIF\r
--- /dev/null
+/*\r
+ * File: ximagif.h\r
+ * Purpose: GIF Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageGIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes\r
+ *\r
+ * original CImageGIF and CImageIterator implementation are:\r
+ * Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>\r
+ *\r
+ * 6/15/97 Randy Spann: Added GIF87a writing support\r
+ * R.Spann@ConnRiver.net\r
+ *\r
+ * DECODE.C - An LZW decoder for GIF\r
+ * Copyright (C) 1987, by Steven A. Bennett\r
+ * Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra\r
+ *\r
+ * In accordance with the above, I want to credit Steve Wilhite who wrote\r
+ * the code which this is heavily inspired by...\r
+ *\r
+ * GIF and 'Graphics Interchange Format' are trademarks (tm) of\r
+ * Compuserve, Incorporated, an H&R Block Company.\r
+ *\r
+ * Release Notes: This file contains a decoder routine for GIF images\r
+ * which is similar, structurally, to the original routine by Steve Wilhite.\r
+ * It is, however, somewhat noticably faster in most cases.\r
+ *\r
+ * ==========================================================\r
+ */\r
+\r
+#if !defined(__ximaGIF_h)\r
+#define __ximaGIF_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_GIF\r
+\r
+typedef short int code_int; \r
+\r
+/* Various error codes used by decoder */\r
+#define OUT_OF_MEMORY -10\r
+#define BAD_CODE_SIZE -20\r
+#define READ_ERROR -1\r
+#define WRITE_ERROR -2\r
+#define OPEN_ERROR -3\r
+#define CREATE_ERROR -4\r
+#define MAX_CODES 4095\r
+#define GIFBUFTAM 16383\r
+#define TRANSPARENCY_CODE 0xF9\r
+\r
+//LZW GIF Image compression\r
+#define MAXBITSCODES 12\r
+#define HSIZE 5003 /* 80% occupancy */\r
+#define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)\r
+#define HashTabOf(i) htab[i]\r
+#define CodeTabOf(i) codetab[i]\r
+\r
+\r
+class CImageIterator;\r
+class DLL_EXP CxImageGIF: public CxImage\r
+{\r
+#pragma pack(1)\r
+\r
+typedef struct tag_gifgce{\r
+ BYTE flags; /*res:3|dispmeth:3|userinputflag:1|transpcolflag:1*/\r
+ WORD delaytime;\r
+ BYTE transpcolindex;\r
+} struct_gifgce;\r
+\r
+typedef struct tag_dscgif{ /* Logic Screen Descriptor */\r
+ char header[6]; /* Firma and version */\r
+ WORD scrwidth;\r
+ WORD scrheight;\r
+ char pflds;\r
+ char bcindx;\r
+ char pxasrat;\r
+} struct_dscgif;\r
+\r
+typedef struct tag_image{ /* Image Descriptor */\r
+ WORD l;\r
+ WORD t;\r
+ WORD w;\r
+ WORD h;\r
+ BYTE pf;\r
+} struct_image;\r
+\r
+typedef struct tag_TabCol{ /* Tabla de colores */\r
+ short colres; /* color resolution */\r
+ short sogct; /* size of global color table */\r
+ rgb_color paleta[256]; /* paleta */\r
+} struct_TabCol;\r
+\r
+typedef struct tag_RLE{\r
+ int rl_pixel;\r
+ int rl_basecode;\r
+ int rl_count;\r
+ int rl_table_pixel;\r
+ int rl_table_max;\r
+ int just_cleared;\r
+ int out_bits;\r
+ int out_bits_init;\r
+ int out_count;\r
+ int out_bump;\r
+ int out_bump_init;\r
+ int out_clear;\r
+ int out_clear_init;\r
+ int max_ocodes;\r
+ int code_clear;\r
+ int code_eof;\r
+ unsigned int obuf;\r
+ int obits;\r
+ unsigned char oblock[256];\r
+ int oblen;\r
+} struct_RLE;\r
+#pragma pack()\r
+\r
+public:\r
+ CxImageGIF(): CxImage(CXIMAGE_FORMAT_GIF) {m_loops=0; info.dispmeth=0; m_comment[0]='\0';}\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_GIF);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_GIF);}\r
+ \r
+ bool Decode(CxFile * fp);\r
+ bool Decode(FILE *fp) { CxIOFile file(fp); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * fp);\r
+ bool Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap = false, bool bLocalDispMeth = false);\r
+ bool Encode(FILE *fp) { CxIOFile file(fp); return Encode(&file); }\r
+ bool Encode(FILE *fp, CxImage ** pImages, int pagecount, bool bLocalColorMap = false)\r
+ { CxIOFile file(fp); return Encode(&file, pImages, pagecount, bLocalColorMap); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+ void SetLoops(int loops);\r
+ long GetLoops();\r
+ void SetComment(const char* sz_comment_in);\r
+ void GetComment(char* sz_comment_out);\r
+\r
+protected:\r
+ bool DecodeExtension(CxFile *fp);\r
+ void EncodeHeader(CxFile *fp);\r
+ void EncodeLoopExtension(CxFile *fp);\r
+ void EncodeExtension(CxFile *fp);\r
+ void EncodeBody(CxFile *fp, bool bLocalColorMap = false);\r
+ void EncodeComment(CxFile *fp);\r
+ bool EncodeRGB(CxFile *fp);\r
+ void GifMix(CxImage & imgsrc2, struct_image & imgdesc);\r
+ \r
+ struct_gifgce gifgce;\r
+\r
+ int curx, cury;\r
+ long CountDown;\r
+ unsigned long cur_accum;\r
+ int cur_bits;\r
+ int interlaced, iypos, istep, iheight, ipass;\r
+ int ibf;\r
+ int ibfmax;\r
+ BYTE buf[GIFBUFTAM + 1];\r
+// Implementation\r
+ int GifNextPixel ();\r
+ void Putword (int w, CxFile* fp );\r
+ void compressNONE (int init_bits, CxFile* outfile);\r
+ void compressLZW (int init_bits, CxFile* outfile);\r
+ void output (code_int code );\r
+ void cl_hash (long hsize);\r
+ void char_out (int c);\r
+ void flush_char ();\r
+ short init_exp(short size);\r
+ short get_next_code(CxFile*);\r
+ short decoder(CxFile*, CImageIterator* iter, short linewidth, int &bad_code_count);\r
+ int get_byte(CxFile*);\r
+ int out_line(CImageIterator* iter, unsigned char *pixels, int linelen);\r
+ int get_num_frames(CxFile *f,struct_TabCol* TabColSrc,struct_dscgif* dscgif);\r
+ long seek_next_image(CxFile* fp, long position);\r
+\r
+ short curr_size; /* The current code size */\r
+ short clear; /* Value for a clear code */\r
+ short ending; /* Value for a ending code */\r
+ short newcodes; /* First available code */\r
+ short top_slot; /* Highest code for current size */\r
+ short slot; /* Last read code */\r
+\r
+ /* The following static variables are used\r
+ * for seperating out codes */\r
+ short navail_bytes; /* # bytes left in block */\r
+ short nbits_left; /* # bits left in current BYTE */\r
+ BYTE b1; /* Current BYTE */\r
+ BYTE byte_buff[257]; /* Current block */\r
+ BYTE *pbytes; /* Pointer to next BYTE in block */\r
+ /* The reason we have these seperated like this instead of using\r
+ * a structure like the original Wilhite code did, is because this\r
+ * stuff generally produces significantly faster code when compiled...\r
+ * This code is full of similar speedups... (For a good book on writing\r
+ * C for speed or for space optomisation, see Efficient C by Tom Plum,\r
+ * published by Plum-Hall Associates...)\r
+ */\r
+ BYTE stack[MAX_CODES + 1]; /* Stack for storing pixels */\r
+ BYTE suffix[MAX_CODES + 1]; /* Suffix table */\r
+ WORD prefix[MAX_CODES + 1]; /* Prefix linked list */\r
+\r
+//LZW GIF Image compression routines\r
+ long htab [HSIZE];\r
+ unsigned short codetab [HSIZE];\r
+ int n_bits; /* number of bits/code */\r
+ code_int maxcode; /* maximum code, given n_bits */\r
+ code_int free_ent; /* first unused entry */\r
+ int clear_flg;\r
+ int g_init_bits;\r
+ CxFile* g_outfile;\r
+ int ClearCode;\r
+ int EOFCode;\r
+\r
+ int a_count;\r
+ char accum[256];\r
+\r
+ char m_comment[256];\r
+ int m_loops;\r
+\r
+//RLE compression routines\r
+ void compressRLE( int init_bits, CxFile* outfile);\r
+ void rle_clear(struct_RLE* rle);\r
+ void rle_flush(struct_RLE* rle);\r
+ void rle_flush_withtable(int count, struct_RLE* rle);\r
+ void rle_flush_clearorrep(int count, struct_RLE* rle);\r
+ void rle_flush_fromclear(int count,struct_RLE* rle);\r
+ void rle_output_plain(int c,struct_RLE* rle);\r
+ void rle_reset_out_clear(struct_RLE* rle);\r
+ unsigned int rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes);\r
+ unsigned int rle_isqrt(unsigned int x);\r
+ void rle_write_block(struct_RLE* rle);\r
+ void rle_block_out(unsigned char c, struct_RLE* rle);\r
+ void rle_block_flush(struct_RLE* rle);\r
+ void rle_output(int val, struct_RLE* rle);\r
+ void rle_output_flush(struct_RLE* rle);\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+// xImaHist.cpp : histogram functions\r
+/* 28/01/2004 v1.00 - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_DSP\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace)\r
+{\r
+ if (!pDib) return 0;\r
+ RGBQUAD color;\r
+\r
+ if (red) memset(red,0,256*sizeof(long));\r
+ if (green) memset(green,0,256*sizeof(long));\r
+ if (blue) memset(blue,0,256*sizeof(long));\r
+ if (gray) memset(gray,0,256*sizeof(long));\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ switch (colorspace){\r
+ case 1:\r
+ color = HSLtoRGB(BlindGetPixelColor(x,y));\r
+ break;\r
+ case 2:\r
+ color = YUVtoRGB(BlindGetPixelColor(x,y));\r
+ break;\r
+ case 3:\r
+ color = YIQtoRGB(BlindGetPixelColor(x,y));\r
+ break;\r
+ case 4:\r
+ color = XYZtoRGB(BlindGetPixelColor(x,y));\r
+ break;\r
+ default:\r
+ color = BlindGetPixelColor(x,y);\r
+ }\r
+\r
+ if (red) red[color.rgbRed]++;\r
+ if (green) green[color.rgbGreen]++;\r
+ if (blue) blue[color.rgbBlue]++;\r
+ if (gray) gray[(BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)]++;\r
+ }\r
+ }\r
+ }\r
+\r
+ long n=0;\r
+ for (int i=0; i<256; i++){\r
+ if (red && red[i]>n) n=red[i];\r
+ if (green && green[i]>n) n=green[i];\r
+ if (blue && blue[i]>n) n=blue[i];\r
+ if (gray && gray[i]>n) n=gray[i];\r
+ }\r
+\r
+ return n;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * HistogramStretch\r
+ * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels.\r
+ * \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%);\r
+ * \return true if everything is ok\r
+ * \author [dave] and [nipper]; changes [DP]\r
+ */\r
+bool CxImage::HistogramStretch(long method, double threshold)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ double dbScaler = 50.0/head.biHeight;\r
+ long x,y;\r
+\r
+ if ((head.biBitCount==8) && IsGrayScale()){\r
+\r
+ double p[256];\r
+ memset(p, 0, 256*sizeof(double));\r
+ for (y=0; y<head.biHeight; y++)\r
+ {\r
+ info.nProgress = (long)(y*dbScaler);\r
+ if (info.nEscape) break;\r
+ for (x=0; x<head.biWidth; x++) {\r
+ p[BlindGetPixelIndex(x, y)]++;\r
+ }\r
+ }\r
+\r
+ double maxh = 0;\r
+ for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];\r
+ threshold *= maxh;\r
+ int minc = 0;\r
+ while (minc<255 && p[minc]<=threshold) minc++;\r
+ int maxc = 255;\r
+ while (maxc>0 && p[maxc]<=threshold) maxc--;\r
+\r
+ if (minc == 0 && maxc == 255) return true;\r
+ if (minc >= maxc) return true;\r
+\r
+ // calculate LUT\r
+ BYTE lut[256];\r
+ for (x = 0; x <256; x++){\r
+ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));\r
+ }\r
+\r
+ for (y=0; y<head.biHeight; y++) {\r
+ if (info.nEscape) break;\r
+ info.nProgress = (long)(50.0+y*dbScaler);\r
+ for (x=0; x<head.biWidth; x++)\r
+ {\r
+ BlindSetPixelIndex(x, y, lut[BlindGetPixelIndex(x, y)]);\r
+ }\r
+ }\r
+ } else {\r
+ switch(method){\r
+ case 1:\r
+ { // <nipper>\r
+ double p[256];\r
+ memset(p, 0, 256*sizeof(double));\r
+ for (y=0; y<head.biHeight; y++)\r
+ {\r
+ info.nProgress = (long)(y*dbScaler);\r
+ if (info.nEscape) break;\r
+ for (x=0; x<head.biWidth; x++) {\r
+ RGBQUAD color = BlindGetPixelColor(x, y);\r
+ p[color.rgbRed]++;\r
+ p[color.rgbBlue]++;\r
+ p[color.rgbGreen]++;\r
+ }\r
+ }\r
+ double maxh = 0;\r
+ for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];\r
+ threshold *= maxh;\r
+ int minc = 0;\r
+ while (minc<255 && p[minc]<=threshold) minc++;\r
+ int maxc = 255;\r
+ while (maxc>0 && p[maxc]<=threshold) maxc--;\r
+\r
+ if (minc == 0 && maxc == 255) return true;\r
+ if (minc >= maxc) return true;\r
+\r
+ // calculate LUT\r
+ BYTE lut[256];\r
+ for (x = 0; x <256; x++){\r
+ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));\r
+ }\r
+\r
+ // normalize image\r
+ for (y=0; y<head.biHeight; y++) {\r
+ if (info.nEscape) break;\r
+ info.nProgress = (long)(50.0+y*dbScaler);\r
+\r
+ for (x=0; x<head.biWidth; x++)\r
+ {\r
+ RGBQUAD color = BlindGetPixelColor(x, y);\r
+\r
+ color.rgbRed = lut[color.rgbRed];\r
+ color.rgbBlue = lut[color.rgbBlue];\r
+ color.rgbGreen = lut[color.rgbGreen];\r
+\r
+ BlindSetPixelColor(x, y, color);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ case 2:\r
+ { // <nipper>\r
+ double pR[256];\r
+ memset(pR, 0, 256*sizeof(double));\r
+ double pG[256];\r
+ memset(pG, 0, 256*sizeof(double));\r
+ double pB[256];\r
+ memset(pB, 0, 256*sizeof(double));\r
+ for (y=0; y<head.biHeight; y++)\r
+ {\r
+ info.nProgress = (long)(y*dbScaler);\r
+ if (info.nEscape) break;\r
+ for (long x=0; x<head.biWidth; x++) {\r
+ RGBQUAD color = BlindGetPixelColor(x, y);\r
+ pR[color.rgbRed]++;\r
+ pB[color.rgbBlue]++;\r
+ pG[color.rgbGreen]++;\r
+ }\r
+ }\r
+\r
+ double maxh = 0;\r
+ for (y=0; y<255; y++) if (maxh < pR[y]) maxh = pR[y];\r
+ double threshold2 = threshold*maxh;\r
+ int minR = 0;\r
+ while (minR<255 && pR[minR]<=threshold2) minR++;\r
+ int maxR = 255;\r
+ while (maxR>0 && pR[maxR]<=threshold2) maxR--;\r
+\r
+ maxh = 0;\r
+ for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y];\r
+ threshold2 = threshold*maxh;\r
+ int minG = 0;\r
+ while (minG<255 && pG[minG]<=threshold2) minG++;\r
+ int maxG = 255;\r
+ while (maxG>0 && pG[maxG]<=threshold2) maxG--;\r
+\r
+ maxh = 0;\r
+ for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y];\r
+ threshold2 = threshold*maxh;\r
+ int minB = 0;\r
+ while (minB<255 && pB[minB]<=threshold2) minB++;\r
+ int maxB = 255;\r
+ while (maxB>0 && pB[maxB]<=threshold2) maxB--;\r
+\r
+ if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255)\r
+ return true;\r
+\r
+ // calculate LUT\r
+ BYTE lutR[256];\r
+ BYTE range = maxR - minR;\r
+ if (range != 0) {\r
+ for (x = 0; x <256; x++){\r
+ lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range)));\r
+ }\r
+ } else lutR[minR] = minR;\r
+\r
+ BYTE lutG[256];\r
+ range = maxG - minG;\r
+ if (range != 0) {\r
+ for (x = 0; x <256; x++){\r
+ lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range)));\r
+ }\r
+ } else lutG[minG] = minG;\r
+ \r
+ BYTE lutB[256];\r
+ range = maxB - minB;\r
+ if (range != 0) {\r
+ for (x = 0; x <256; x++){\r
+ lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range)));\r
+ }\r
+ } else lutB[minB] = minB;\r
+\r
+ // normalize image\r
+ for (y=0; y<head.biHeight; y++)\r
+ {\r
+ info.nProgress = (long)(50.0+y*dbScaler);\r
+ if (info.nEscape) break;\r
+\r
+ for (x=0; x<head.biWidth; x++)\r
+ {\r
+ RGBQUAD color = BlindGetPixelColor(x, y);\r
+\r
+ color.rgbRed = lutR[color.rgbRed];\r
+ color.rgbBlue = lutB[color.rgbBlue];\r
+ color.rgbGreen = lutG[color.rgbGreen];\r
+\r
+ BlindSetPixelColor(x, y, color);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ default:\r
+ { // <dave>\r
+ double p[256];\r
+ memset(p, 0, 256*sizeof(double));\r
+ for (y=0; y<head.biHeight; y++)\r
+ {\r
+ info.nProgress = (long)(y*dbScaler);\r
+ if (info.nEscape) break;\r
+ for (x=0; x<head.biWidth; x++) {\r
+ RGBQUAD color = BlindGetPixelColor(x, y);\r
+ p[RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue)]++;\r
+ }\r
+ }\r
+\r
+ double maxh = 0;\r
+ for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];\r
+ threshold *= maxh;\r
+ int minc = 0;\r
+ while (minc<255 && p[minc]<=threshold) minc++;\r
+ int maxc = 255;\r
+ while (maxc>0 && p[maxc]<=threshold) maxc--;\r
+\r
+ if (minc == 0 && maxc == 255) return true;\r
+ if (minc >= maxc) return true;\r
+\r
+ // calculate LUT\r
+ BYTE lut[256];\r
+ for (x = 0; x <256; x++){\r
+ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));\r
+ }\r
+\r
+ for(y=0; y<head.biHeight; y++){\r
+ info.nProgress = (long)(50.0+y*dbScaler);\r
+ if (info.nEscape) break;\r
+ for(x=0; x<head.biWidth; x++){\r
+\r
+ RGBQUAD color = BlindGetPixelColor( x, y );\r
+ RGBQUAD yuvClr = RGBtoYUV(color);\r
+ yuvClr.rgbRed = lut[yuvClr.rgbRed];\r
+ color = YUVtoRGB(yuvClr);\r
+ BlindSetPixelColor( x, y, color );\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// HistogramEqualize function by <dave> : dave(at)posortho(dot)com\r
+bool CxImage::HistogramEqualize()\r
+{\r
+ if (!pDib) return false;\r
+\r
+ int histogram[256];\r
+ int map[256];\r
+ int equalize_map[256];\r
+ int x, y, i, j;\r
+ RGBQUAD color;\r
+ RGBQUAD yuvClr;\r
+ unsigned int YVal, high, low;\r
+\r
+ memset( &histogram, 0, sizeof(int) * 256 );\r
+ memset( &map, 0, sizeof(int) * 256 );\r
+ memset( &equalize_map, 0, sizeof(int) * 256 );\r
+ \r
+ // form histogram\r
+ for(y=0; y < head.biHeight; y++){\r
+ info.nProgress = (long)(50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for(x=0; x < head.biWidth; x++){\r
+ color = BlindGetPixelColor( x, y );\r
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
+ histogram[YVal]++;\r
+ }\r
+ }\r
+\r
+ // integrate the histogram to get the equalization map.\r
+ j = 0;\r
+ for(i=0; i <= 255; i++){\r
+ j += histogram[i];\r
+ map[i] = j; \r
+ }\r
+\r
+ // equalize\r
+ low = map[0];\r
+ high = map[255];\r
+ if (low == high) return false;\r
+ for( i = 0; i <= 255; i++ ){\r
+ equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) );\r
+ }\r
+\r
+ // stretch the histogram\r
+ if(head.biClrUsed == 0){ // No Palette\r
+ for( y = 0; y < head.biHeight; y++ ){\r
+ info.nProgress = (long)(50+50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for( x = 0; x < head.biWidth; x++ ){\r
+\r
+ color = BlindGetPixelColor( x, y );\r
+ yuvClr = RGBtoYUV(color);\r
+\r
+ yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];\r
+\r
+ color = YUVtoRGB(yuvClr);\r
+ BlindSetPixelColor( x, y, color );\r
+ }\r
+ }\r
+ } else { // Palette\r
+ for( i = 0; i < (int)head.biClrUsed; i++ ){\r
+\r
+ color = GetPaletteColor((BYTE)i);\r
+ yuvClr = RGBtoYUV(color);\r
+\r
+ yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];\r
+\r
+ color = YUVtoRGB(yuvClr);\r
+ SetPaletteColor( (BYTE)i, color );\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// HistogramNormalize function by <dave> : dave(at)posortho(dot)com\r
+bool CxImage::HistogramNormalize()\r
+{\r
+ if (!pDib) return false;\r
+\r
+ int histogram[256];\r
+ int threshold_intensity, intense;\r
+ int x, y, i;\r
+ unsigned int normalize_map[256];\r
+ unsigned int high, low, YVal;\r
+\r
+ RGBQUAD color;\r
+ RGBQUAD yuvClr;\r
+\r
+ memset( &histogram, 0, sizeof( int ) * 256 );\r
+ memset( &normalize_map, 0, sizeof( unsigned int ) * 256 );\r
+ \r
+ // form histogram\r
+ for(y=0; y < head.biHeight; y++){\r
+ info.nProgress = (long)(50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for(x=0; x < head.biWidth; x++){\r
+ color = BlindGetPixelColor( x, y );\r
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
+ histogram[YVal]++;\r
+ }\r
+ }\r
+\r
+ // find histogram boundaries by locating the 1 percent levels\r
+ threshold_intensity = ( head.biWidth * head.biHeight) / 100;\r
+\r
+ intense = 0;\r
+ for( low = 0; low < 255; low++ ){\r
+ intense += histogram[low];\r
+ if( intense > threshold_intensity ) break;\r
+ }\r
+\r
+ intense = 0;\r
+ for( high = 255; high != 0; high--){\r
+ intense += histogram[ high ];\r
+ if( intense > threshold_intensity ) break;\r
+ }\r
+\r
+ if ( low == high ){\r
+ // Unreasonable contrast; use zero threshold to determine boundaries.\r
+ threshold_intensity = 0;\r
+ intense = 0;\r
+ for( low = 0; low < 255; low++){\r
+ intense += histogram[low];\r
+ if( intense > threshold_intensity ) break;\r
+ }\r
+ intense = 0;\r
+ for( high = 255; high != 0; high-- ){\r
+ intense += histogram [high ];\r
+ if( intense > threshold_intensity ) break;\r
+ }\r
+ }\r
+ if( low == high ) return false; // zero span bound\r
+\r
+ // Stretch the histogram to create the normalized image mapping.\r
+ for(i = 0; i <= 255; i++){\r
+ if ( i < (int) low ){\r
+ normalize_map[i] = 0;\r
+ } else {\r
+ if(i > (int) high)\r
+ normalize_map[i] = 255;\r
+ else\r
+ normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low );\r
+ }\r
+ }\r
+\r
+ // Normalize\r
+ if( head.biClrUsed == 0 ){\r
+ for( y = 0; y < head.biHeight; y++ ){\r
+ info.nProgress = (long)(50+50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for( x = 0; x < head.biWidth; x++ ){\r
+\r
+ color = BlindGetPixelColor( x, y );\r
+ yuvClr = RGBtoYUV( color );\r
+\r
+ yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];\r
+\r
+ color = YUVtoRGB( yuvClr );\r
+ BlindSetPixelColor( x, y, color );\r
+ }\r
+ }\r
+ } else {\r
+ for(i = 0; i < (int)head.biClrUsed; i++){\r
+\r
+ color = GetPaletteColor( (BYTE)i );\r
+ yuvClr = RGBtoYUV( color );\r
+\r
+ yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];\r
+\r
+ color = YUVtoRGB( yuvClr );\r
+ SetPaletteColor( (BYTE)i, color );\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// HistogramLog function by <dave> : dave(at)posortho(dot)com\r
+bool CxImage::HistogramLog()\r
+{\r
+ if (!pDib) return false;\r
+\r
+ //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|);\r
+ int x, y, i;\r
+ RGBQUAD color;\r
+ RGBQUAD yuvClr;\r
+\r
+ unsigned int YVal, high = 1;\r
+\r
+ // Find Highest Luminance Value in the Image\r
+ if( head.biClrUsed == 0 ){ // No Palette\r
+ for(y=0; y < head.biHeight; y++){\r
+ info.nProgress = (long)(50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for(x=0; x < head.biWidth; x++){\r
+ color = BlindGetPixelColor( x, y );\r
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
+ if (YVal > high ) high = YVal;\r
+ }\r
+ }\r
+ } else { // Palette\r
+ for(i = 0; i < (int)head.biClrUsed; i++){\r
+ color = GetPaletteColor((BYTE)i);\r
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
+ if (YVal > high ) high = YVal;\r
+ }\r
+ }\r
+\r
+ // Logarithm Operator\r
+ double k = 255.0 / ::log( 1.0 + (double)high );\r
+ if( head.biClrUsed == 0 ){\r
+ for( y = 0; y < head.biHeight; y++ ){\r
+ info.nProgress = (long)(50+50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for( x = 0; x < head.biWidth; x++ ){\r
+\r
+ color = BlindGetPixelColor( x, y );\r
+ yuvClr = RGBtoYUV( color );\r
+ \r
+ yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );\r
+\r
+ color = YUVtoRGB( yuvClr );\r
+ BlindSetPixelColor( x, y, color );\r
+ }\r
+ }\r
+ } else {\r
+ for(i = 0; i < (int)head.biClrUsed; i++){\r
+\r
+ color = GetPaletteColor( (BYTE)i );\r
+ yuvClr = RGBtoYUV( color );\r
+\r
+ yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );\r
+ \r
+ color = YUVtoRGB( yuvClr );\r
+ SetPaletteColor( (BYTE)i, color );\r
+ }\r
+ }\r
+ \r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// HistogramRoot function by <dave> : dave(at)posortho(dot)com\r
+bool CxImage::HistogramRoot()\r
+{\r
+ if (!pDib) return false;\r
+ //q(i,j) = sqrt(|p(i,j)|);\r
+\r
+ int x, y, i;\r
+ RGBQUAD color;\r
+ RGBQUAD yuvClr;\r
+ double dtmp;\r
+ unsigned int YVal, high = 1;\r
+\r
+ // Find Highest Luminance Value in the Image\r
+ if( head.biClrUsed == 0 ){ // No Palette\r
+ for(y=0; y < head.biHeight; y++){\r
+ info.nProgress = (long)(50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for(x=0; x < head.biWidth; x++){\r
+ color = BlindGetPixelColor( x, y );\r
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
+ if (YVal > high ) high = YVal;\r
+ }\r
+ }\r
+ } else { // Palette\r
+ for(i = 0; i < (int)head.biClrUsed; i++){\r
+ color = GetPaletteColor((BYTE)i);\r
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
+ if (YVal > high ) high = YVal;\r
+ }\r
+ }\r
+\r
+ // Root Operator\r
+ double k = 128.0 / ::log( 1.0 + (double)high );\r
+ if( head.biClrUsed == 0 ){\r
+ for( y = 0; y < head.biHeight; y++ ){\r
+ info.nProgress = (long)(50+50*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for( x = 0; x < head.biWidth; x++ ){\r
+\r
+ color = BlindGetPixelColor( x, y );\r
+ yuvClr = RGBtoYUV( color );\r
+\r
+ dtmp = k * ::sqrt( (double)yuvClr.rgbRed );\r
+ if ( dtmp > 255.0 ) dtmp = 255.0;\r
+ if ( dtmp < 0 ) dtmp = 0;\r
+ yuvClr.rgbRed = (BYTE)dtmp;\r
+\r
+ color = YUVtoRGB( yuvClr );\r
+ BlindSetPixelColor( x, y, color );\r
+ }\r
+ }\r
+ } else {\r
+ for(i = 0; i < (int)head.biClrUsed; i++){\r
+\r
+ color = GetPaletteColor( (BYTE)i );\r
+ yuvClr = RGBtoYUV( color );\r
+\r
+ dtmp = k * ::sqrt( (double)yuvClr.rgbRed );\r
+ if ( dtmp > 255.0 ) dtmp = 255.0;\r
+ if ( dtmp < 0 ) dtmp = 0;\r
+ yuvClr.rgbRed = (BYTE)dtmp;\r
+\r
+ color = YUVtoRGB( yuvClr );\r
+ SetPaletteColor( (BYTE)i, color );\r
+ }\r
+ }\r
+ \r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximaico.cpp\r
+ * Purpose: Platform Independent ICON Image Class Loader and Writer (MS version)\r
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximaico.h"\r
+\r
+#if CXIMAGE_SUPPORT_ICO\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageICO::Decode(CxFile *hFile)\r
+{\r
+ if (hFile==NULL) return false;\r
+\r
+ DWORD off = hFile->Tell(); //<yuandi>\r
+ int page=info.nFrame; //internal icon structure indexes\r
+\r
+ // read the first part of the header\r
+ ICONHEADER icon_header;\r
+ hFile->Read(&icon_header,sizeof(ICONHEADER),1);\r
+\r
+ icon_header.idType = ntohs(icon_header.idType);\r
+ icon_header.idCount = ntohs(icon_header.idCount);\r
+\r
+ // check if it's an icon or a cursor\r
+ if ((icon_header.idReserved == 0) && ((icon_header.idType == 1)||(icon_header.idType == 2))) {\r
+\r
+ info.nNumFrames = icon_header.idCount;\r
+\r
+ // load the icon descriptions\r
+ ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY));\r
+ int c;\r
+ for (c = 0; c < icon_header.idCount; c++) {\r
+ hFile->Read(icon_list + c, sizeof(ICONDIRENTRY), 1);\r
+\r
+ icon_list[c].wPlanes = ntohs(icon_list[c].wPlanes);\r
+ icon_list[c].wBitCount = ntohs(icon_list[c].wBitCount);\r
+ icon_list[c].dwBytesInRes = ntohl(icon_list[c].dwBytesInRes);\r
+ icon_list[c].dwImageOffset = ntohl(icon_list[c].dwImageOffset);\r
+ }\r
+ \r
+ if ((page>=0)&&(page<icon_header.idCount)){\r
+\r
+ if (info.nEscape == -1) {\r
+ // Return output dimensions only\r
+ head.biWidth = icon_list[page].bWidth;\r
+ head.biHeight = icon_list[page].bHeight;\r
+#if CXIMAGE_SUPPORT_PNG\r
+ if (head.biWidth==0 && head.biHeight==0)\r
+ { // Vista icon support\r
+ hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);\r
+ CxImage png;\r
+ png.SetEscape(-1);\r
+ if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){\r
+ Transfer(png);\r
+ info.nNumFrames = icon_header.idCount;\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_PNG\r
+ free(icon_list);\r
+ info.dwType = CXIMAGE_FORMAT_ICO;\r
+ return true;\r
+ }\r
+\r
+ // get the bit count for the colors in the icon <CoreyRLucier>\r
+ BITMAPINFOHEADER bih;\r
+ hFile->Seek(off + icon_list[page].dwImageOffset, SEEK_SET);\r
+\r
+ if (icon_list[page].bWidth==0 && icon_list[page].bHeight==0)\r
+ { // Vista icon support\r
+#if CXIMAGE_SUPPORT_PNG\r
+ CxImage png;\r
+ if (png.Decode(hFile,CXIMAGE_FORMAT_PNG)){\r
+ Transfer(png);\r
+ info.nNumFrames = icon_header.idCount;\r
+ }\r
+ SetType(CXIMAGE_FORMAT_ICO);\r
+#endif //CXIMAGE_SUPPORT_PNG\r
+ }\r
+ else\r
+ { // standard icon\r
+ hFile->Read(&bih,sizeof(BITMAPINFOHEADER),1);\r
+\r
+ bihtoh(&bih);\r
+\r
+ c = bih.biBitCount;\r
+\r
+ // allocate memory for one icon\r
+ Create(icon_list[page].bWidth,icon_list[page].bHeight, c, CXIMAGE_FORMAT_ICO); //image creation\r
+\r
+ // read the palette\r
+ RGBQUAD pal[256];\r
+ if (bih.biClrUsed)\r
+ hFile->Read(pal,bih.biClrUsed*sizeof(RGBQUAD), 1);\r
+ else\r
+ hFile->Read(pal,head.biClrUsed*sizeof(RGBQUAD), 1);\r
+\r
+ SetPalette(pal,head.biClrUsed); //palette assign\r
+\r
+ //read the icon\r
+ if (c<=24){\r
+ hFile->Read(info.pImage, head.biSizeImage, 1);\r
+ } else { // 32 bit icon\r
+ BYTE* buf=(BYTE*)malloc(4*head.biHeight*head.biWidth);\r
+ BYTE* src = buf;\r
+ hFile->Read(buf, 4*head.biHeight*head.biWidth, 1);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (!AlphaIsValid()) AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ for (long y = 0; y < head.biHeight; y++) {\r
+ BYTE* dst = GetBits(y);\r
+ for(long x=0;x<head.biWidth;x++){\r
+ *dst++=src[0];\r
+ *dst++=src[1];\r
+ *dst++=src[2];\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaSet(x,y,src[3]);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ src+=4;\r
+ }\r
+ }\r
+ free(buf);\r
+ }\r
+ // apply the AND and XOR masks\r
+ int maskwdt = ((head.biWidth+31) / 32) * 4; //line width of AND mask (always 1 Bpp)\r
+ int masksize = head.biHeight * maskwdt; //size of mask\r
+ BYTE *mask = (BYTE *)malloc(masksize);\r
+ if (hFile->Read(mask, masksize, 1)){\r
+\r
+ bool bGoodMask=false;\r
+ for (int im=0;im<masksize;im++){\r
+ if (mask[im]!=255){\r
+ bGoodMask=true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (bGoodMask){\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ bool bNeedAlpha = false;\r
+ if (!AlphaIsValid()){\r
+ AlphaCreate();\r
+ } else { \r
+ bNeedAlpha=true; //32bit icon\r
+ }\r
+ int x,y;\r
+ for (y = 0; y < head.biHeight; y++) {\r
+ for (x = 0; x < head.biWidth; x++) {\r
+ if (((mask[y*maskwdt+(x>>3)]>>(7-x%8))&0x01)){\r
+ AlphaSet(x,y,0);\r
+ bNeedAlpha=true;\r
+ }\r
+ }\r
+ }\r
+ if (!bNeedAlpha) AlphaDelete();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ //check if there is only one transparent color\r
+ RGBQUAD cc,ct;\r
+ long* pcc = (long*)&cc;\r
+ long* pct = (long*)&ct;\r
+ int nTransColors=0;\r
+ int nTransIndex=0;\r
+ for (y = 0; y < head.biHeight; y++){\r
+ for (x = 0; x < head.biWidth; x++){\r
+ if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){\r
+ cc = GetPixelColor(x,y,false);\r
+ if (nTransColors==0){\r
+ nTransIndex = GetPixelIndex(x,y);\r
+ nTransColors++;\r
+ ct = cc;\r
+ } else {\r
+ if (*pct!=*pcc){\r
+ nTransColors++;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (nTransColors==1){\r
+ SetTransColor(ct);\r
+ SetTransIndex(nTransIndex);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaDelete(); //because we have a unique transparent color in the image\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+\r
+ // <vho> - Transparency support w/o Alpha support\r
+ if (c <= 8){ // only for icons with less than 256 colors (XP icons need alpha).\r
+ \r
+ // find a color index, which is not used in the image\r
+ // it is almost sure to find one, bcs. nobody uses all possible colors for an icon\r
+\r
+ BYTE colorsUsed[256];\r
+ memset(colorsUsed, 0, sizeof(colorsUsed));\r
+\r
+ for (y = 0; y < head.biHeight; y++){\r
+ for (x = 0; x < head.biWidth; x++){\r
+ colorsUsed[BlindGetPixelIndex(x,y)] = 1;\r
+ }\r
+ }\r
+\r
+ int iTransIdx = -1;\r
+ for (x = (int)(head.biClrUsed-1); x>=0 ; x--){\r
+ if (colorsUsed[x] == 0){\r
+ iTransIdx = x; // this one is not in use. we may use it as transparent color\r
+ break;\r
+ }\r
+ }\r
+\r
+ // Go thru image and set unused color as transparent index if needed\r
+ if (iTransIdx >= 0){\r
+ bool bNeedTrans = false;\r
+ for (y = 0; y < head.biHeight; y++){\r
+ for (x = 0; x < head.biWidth; x++){\r
+ // AND mask (Each Byte represents 8 Pixels)\r
+ if (((mask[y*maskwdt+(x>>3)] >> (7-x%8)) & 0x01)){\r
+ // AND mask is set (!=0). This is a transparent part\r
+ SetPixelIndex(x, y, (BYTE)iTransIdx);\r
+ bNeedTrans = true;\r
+ }\r
+ }\r
+ }\r
+ // set transparent index if needed\r
+ if (bNeedTrans) SetTransIndex(iTransIdx);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaDelete(); //because we have a transparent color in the palette\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ }\r
+ } else {\r
+ SetTransIndex(0); //empty mask, set black as transparent color\r
+ Negative();\r
+ }\r
+ } \r
+ free(mask);\r
+ }\r
+ free(icon_list);\r
+ // icon has been loaded successfully!\r
+ return true;\r
+ }\r
+ free(icon_list);\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Thanks to <Alas>\r
+bool CxImageICO::Encode(CxFile * hFile, CxImage ** pImages, int nPageCount)\r
+{\r
+ cx_try\r
+ {\r
+ if (hFile==NULL) cx_throw("invalid file pointer");\r
+ if (pImages==NULL || nPageCount<=0) cx_throw("multipage ICO, no images!");\r
+\r
+ int i;\r
+ for (i=0; i<nPageCount; i++){\r
+ if (pImages[i]==NULL)\r
+ cx_throw("Bad image pointer");\r
+ if (!(pImages[i]->IsValid()))\r
+ cx_throw("Empty image");\r
+ }\r
+\r
+ CxImageICO ghost;\r
+ for (i=0; i<nPageCount; i++){ //write headers\r
+ ghost.Ghost(pImages[i]);\r
+ ghost.info.nNumFrames = nPageCount;\r
+ if (i==0) {\r
+ if (!ghost.Encode(hFile,false,nPageCount))\r
+ cx_throw("Error writing ICO file header");\r
+ }\r
+ if (!ghost.Encode(hFile,true,nPageCount)) \r
+ cx_throw("Error saving ICO image header");\r
+ }\r
+ for (i=0; i<nPageCount; i++){ //write bodies\r
+ ghost.Ghost(pImages[i]);\r
+ ghost.info.nNumFrames = nPageCount;\r
+ if (!ghost.Encode(hFile,true,i)) \r
+ cx_throw("Error saving ICO body");\r
+ }\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageICO::Encode(CxFile * hFile, bool bAppend, int nPageCount)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+#if CXIMAGE_SUPPORT_PNG == 0\r
+ //check format limits\r
+ if ((head.biWidth>255)||(head.biHeight>255)){\r
+ strcpy(info.szLastError,"Can't save this image as icon");\r
+ return false;\r
+ }\r
+#endif\r
+\r
+ //prepare the palette struct\r
+ RGBQUAD* pal=GetPalette();\r
+ if (head.biBitCount<=8 && pal==NULL) return false;\r
+\r
+ int maskwdt=((head.biWidth+31)/32)*4; //mask line width\r
+ int masksize=head.biHeight * maskwdt; //size of mask\r
+ int bitcount=head.biBitCount;\r
+ int imagesize=head.biSizeImage;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid() && head.biClrUsed==0){\r
+ bitcount=32;\r
+ imagesize=4*head.biHeight*head.biWidth;\r
+ }\r
+#endif\r
+\r
+ //fill the icon headers\r
+ int nPages = nPageCount;\r
+ if (nPages<1) nPages = 1;\r
+\r
+ ICONHEADER icon_header={0,1,nPages};\r
+\r
+ if (!bAppend)\r
+ m_dwImageOffset = sizeof(ICONHEADER) + nPages * sizeof(ICONDIRENTRY);\r
+\r
+ DWORD dwBytesInRes = sizeof(BITMAPINFOHEADER)+head.biClrUsed*sizeof(RGBQUAD)+imagesize+masksize;\r
+\r
+ ICONDIRENTRY icon_list={\r
+ (BYTE)head.biWidth,\r
+ (BYTE)head.biHeight,\r
+ (BYTE)head.biClrUsed,\r
+ 0, 0,\r
+ (WORD)bitcount,\r
+ dwBytesInRes,\r
+ m_dwImageOffset\r
+ };\r
+\r
+ BITMAPINFOHEADER bi={\r
+ sizeof(BITMAPINFOHEADER),\r
+ head.biWidth,\r
+ 2*head.biHeight,\r
+ 1,\r
+ (WORD)bitcount,\r
+ 0, imagesize,\r
+ 0, 0, 0, 0\r
+ };\r
+\r
+#if CXIMAGE_SUPPORT_PNG // Vista icon support\r
+ CxImage png(*this);\r
+ CxMemFile memfile;\r
+ if (head.biWidth>255 || head.biHeight>255){\r
+ icon_list.bWidth = icon_list.bHeight = 0;\r
+ memfile.Open();\r
+ png.Encode(&memfile,CXIMAGE_FORMAT_PNG);\r
+ icon_list.dwBytesInRes = dwBytesInRes = memfile.Size();\r
+ }\r
+#endif //CXIMAGE_SUPPORT_PNG\r
+\r
+ if (!bAppend){\r
+ icon_header.idType = ntohs(icon_header.idType);\r
+ icon_header.idCount = ntohs(icon_header.idCount);\r
+ hFile->Write(&icon_header,sizeof(ICONHEADER),1); //write the file header\r
+ icon_header.idType = ntohs(icon_header.idType);\r
+ icon_header.idCount = ntohs(icon_header.idCount);\r
+ }\r
+\r
+\r
+ if ((bAppend && nPageCount==info.nNumFrames) || (!bAppend && nPageCount==0)){\r
+ icon_list.wPlanes = ntohs(icon_list.wPlanes);\r
+ icon_list.wBitCount = ntohs(icon_list.wBitCount);\r
+ icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);\r
+ icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);\r
+ hFile->Write(&icon_list,sizeof(ICONDIRENTRY),1); //write the image entry\r
+ icon_list.wPlanes = ntohs(icon_list.wPlanes);\r
+ icon_list.wBitCount = ntohs(icon_list.wBitCount);\r
+ icon_list.dwBytesInRes = ntohl(icon_list.dwBytesInRes);\r
+ icon_list.dwImageOffset = ntohl(icon_list.dwImageOffset);\r
+\r
+ m_dwImageOffset += dwBytesInRes; //update offset for next header\r
+ }\r
+\r
+ if ((bAppend && nPageCount<info.nNumFrames) || (!bAppend && nPageCount==0))\r
+ {\r
+#if CXIMAGE_SUPPORT_PNG\r
+ if (icon_list.bWidth==0 && icon_list.bHeight==0) { // Vista icon support\r
+ hFile->Write(memfile.GetBuffer(false),dwBytesInRes,1);\r
+ } else\r
+#endif //CXIMAGE_SUPPORT_PNG\r
+ { // standard icon\r
+ bihtoh(&bi);\r
+ hFile->Write(&bi,sizeof(BITMAPINFOHEADER),1); //write the image header\r
+ bihtoh(&bi);\r
+\r
+ bool bTransparent = info.nBkgndIndex >= 0;\r
+ RGBQUAD ct = GetTransColor();\r
+ if (pal){\r
+ if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,0,0,0,0);\r
+ hFile->Write(pal,head.biClrUsed*sizeof(RGBQUAD),1); //write palette\r
+ if (bTransparent) SetPaletteColor((BYTE)info.nBkgndIndex,ct);\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid() && head.biClrUsed==0){\r
+ BYTE* buf=(BYTE*)malloc(imagesize);\r
+ BYTE* dst = buf;\r
+ for (long y = 0; y < head.biHeight; y++) {\r
+ BYTE* src = GetBits(y);\r
+ for(long x=0;x<head.biWidth;x++){\r
+ *dst++=*src++;\r
+ *dst++=*src++;\r
+ *dst++=*src++;\r
+ *dst++=AlphaGet(x,y);\r
+ }\r
+ }\r
+ hFile->Write(buf,imagesize, 1);\r
+ free(buf);\r
+ } else {\r
+ hFile->Write(info.pImage,imagesize,1); //write image\r
+ }\r
+#else\r
+ hFile->Write(info.pImage,imagesize,1); //write image\r
+#endif\r
+\r
+ //save transparency mask\r
+ BYTE* mask=(BYTE*)calloc(masksize,1); //create empty AND/XOR masks\r
+ if (!mask) return false;\r
+\r
+ //prepare the variables to build the mask\r
+ BYTE* iDst;\r
+ int pos,i;\r
+ RGBQUAD c={0,0,0,0};\r
+ long* pc = (long*)&c;\r
+ long* pct= (long*)&ct;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ bool bAlphaPaletteIsValid = AlphaPaletteIsValid();\r
+ bool bAlphaIsValid = AlphaIsValid();\r
+#endif\r
+ //build the mask\r
+ for (int y = 0; y < head.biHeight; y++) {\r
+ for (int x = 0; x < head.biWidth; x++) {\r
+ i=0;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (bAlphaIsValid && AlphaGet(x,y)==0) i=1;\r
+ if (bAlphaPaletteIsValid && BlindGetPixelColor(x,y).rgbReserved==0) i=1;\r
+#endif\r
+ c=GetPixelColor(x,y,false);\r
+ if (bTransparent && *pc==*pct) i=1;\r
+ iDst = mask + y*maskwdt + (x>>3);\r
+ pos = 7-x%8;\r
+ *iDst &= ~(0x01<<pos);\r
+ *iDst |= ((i & 0x01)<<pos);\r
+ }\r
+ }\r
+ //write AND/XOR masks\r
+ hFile->Write(mask,masksize,1);\r
+ free(mask);\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ICO\r
+\r
--- /dev/null
+/*\r
+ * File: ximaico.h\r
+ * Purpose: ICON Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageICO (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaICO_h)\r
+#define __ximaICO_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_ICO\r
+\r
+class CxImageICO: public CxImage\r
+{\r
+typedef struct tagIconDirectoryEntry {\r
+ BYTE bWidth;\r
+ BYTE bHeight;\r
+ BYTE bColorCount;\r
+ BYTE bReserved;\r
+ WORD wPlanes;\r
+ WORD wBitCount;\r
+ DWORD dwBytesInRes;\r
+ DWORD dwImageOffset;\r
+} ICONDIRENTRY;\r
+\r
+typedef struct tagIconDir {\r
+ WORD idReserved;\r
+ WORD idType;\r
+ WORD idCount;\r
+} ICONHEADER;\r
+\r
+public:\r
+ CxImageICO(): CxImage(CXIMAGE_FORMAT_ICO) {m_dwImageOffset=0;}\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile, bool bAppend=false, int nPageCount=0);\r
+ bool Encode(CxFile * hFile, CxImage ** pImages, int nPageCount);\r
+ bool Encode(FILE *hFile, bool bAppend=false, int nPageCount=0)\r
+ { CxIOFile file(hFile); return Encode(&file,bAppend,nPageCount); }\r
+ bool Encode(FILE *hFile, CxImage ** pImages, int nPageCount)\r
+ { CxIOFile file(hFile); return Encode(&file, pImages, nPageCount); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+protected:\r
+ DWORD m_dwImageOffset;\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+// ximainfo.cpp : main attributes\r
+/* 03/10/2004 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return the color used for transparency, and/or for background color\r
+ */\r
+RGBQUAD CxImage::GetTransColor()\r
+{\r
+ if (head.biBitCount<24 && info.nBkgndIndex>=0) return GetPaletteColor((BYTE)info.nBkgndIndex);\r
+ return info.nBkgndColor;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Gets the index used for transparency. Returns -1 for no transparancy.\r
+ */\r
+long CxImage::GetTransIndex() const\r
+{\r
+ return info.nBkgndIndex;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the index used for transparency with 1, 4 and 8 bpp images. Set to -1 to remove the effect.\r
+ */\r
+void CxImage::SetTransIndex(long idx)\r
+{\r
+ if (idx<(long)head.biClrUsed)\r
+ info.nBkgndIndex = idx;\r
+ else \r
+ info.nBkgndIndex = 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the color used for transparency with 24 bpp images.\r
+ * You must call SetTransIndex(0) to enable the effect, SetTransIndex(-1) to disable it.\r
+ */\r
+void CxImage::SetTransColor(RGBQUAD rgb)\r
+{\r
+ rgb.rgbReserved=0;\r
+ info.nBkgndColor = rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::IsTransparent() const\r
+{\r
+ return info.nBkgndIndex>=0; // <vho>\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns true if the image has 256 colors or less.\r
+ */\r
+bool CxImage::IsIndexed() const\r
+{\r
+ return head.biClrUsed!=0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return 1 = indexed, 2 = RGB, 4 = RGBA\r
+ */\r
+BYTE CxImage::GetColorType()\r
+{\r
+ BYTE b = (BYTE)((head.biBitCount>8) ? 2 /*COLORTYPE_COLOR*/ : 1 /*COLORTYPE_PALETTE*/);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) b = 4 /*COLORTYPE_ALPHA*/;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ return b;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return Resolution for TIFF, JPEG, PNG and BMP formats.\r
+ */\r
+long CxImage::GetXDPI() const\r
+{\r
+ return info.xDPI;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return Resolution for TIFF, JPEG, PNG and BMP formats.\r
+ */\r
+long CxImage::GetYDPI() const\r
+{\r
+ return info.yDPI;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Set resolution for TIFF, JPEG, PNG and BMP formats.\r
+ */\r
+void CxImage::SetXDPI(long dpi)\r
+{\r
+ if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI;\r
+ info.xDPI = dpi;\r
+ head.biXPelsPerMeter = (long) floor(dpi * 10000.0 / 254.0 + 0.5);\r
+ if (pDib) ((BITMAPINFOHEADER*)pDib)->biXPelsPerMeter = head.biXPelsPerMeter;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Set resolution for TIFF, JPEG, PNG and BMP formats.\r
+ */\r
+void CxImage::SetYDPI(long dpi)\r
+{\r
+ if (dpi<=0) dpi = CXIMAGE_DEFAULT_DPI;\r
+ info.yDPI = dpi;\r
+ head.biYPelsPerMeter = (long) floor(dpi * 10000.0 / 254.0 + 0.5);\r
+ if (pDib) ((BITMAPINFOHEADER*)pDib)->biYPelsPerMeter = head.biYPelsPerMeter;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa SetFlags\r
+ */\r
+DWORD CxImage::GetFlags() const\r
+{\r
+ return info.dwFlags;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Image flags, for future use\r
+ * \param flags\r
+ * - 0x??00000 = reserved for 16 bit, CMYK, multilayer\r
+ * - 0x00??0000 = blend modes\r
+ * - 0x0000???? = layer id or user flags\r
+ *\r
+ * \param bLockReservedFlags protects the "reserved" and "blend modes" flags \r
+ */\r
+void CxImage::SetFlags(DWORD flags, bool bLockReservedFlags)\r
+{\r
+ if (bLockReservedFlags) info.dwFlags = flags & 0x0000ffff;\r
+ else info.dwFlags = flags;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa SetCodecOption\r
+ */\r
+DWORD CxImage::GetCodecOption(DWORD imagetype)\r
+{\r
+ imagetype = GetTypeIndexFromId(imagetype);\r
+ if (imagetype==0){\r
+ imagetype = GetTypeIndexFromId(GetType());\r
+ }\r
+ return info.dwCodecOpt[imagetype];\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Encode option for GIF, TIF and JPG.\r
+ * - GIF : 0 = LZW (default), 1 = none, 2 = RLE.\r
+ * - TIF : 0 = automatic (default), or a valid compression code as defined in "tiff.h" (COMPRESSION_NONE = 1, COMPRESSION_CCITTRLE = 2, ...)\r
+ * - JPG : valid values stored in enum CODEC_OPTION ( ENCODE_BASELINE = 0x01, ENCODE_PROGRESSIVE = 0x10, ...)\r
+ * - RAW : valid values stored in enum CODEC_OPTION ( DECODE_QUALITY_LIN = 0x00, DECODE_QUALITY_VNG = 0x01, ...)\r
+ *\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::SetCodecOption(DWORD opt, DWORD imagetype)\r
+{\r
+ imagetype = GetTypeIndexFromId(imagetype);\r
+ if (imagetype==0){\r
+ imagetype = GetTypeIndexFromId(GetType());\r
+ }\r
+ info.dwCodecOpt[imagetype] = opt;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return internal hDib object..\r
+ */\r
+void* CxImage::GetDIB() const\r
+{\r
+ return pDib;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::GetHeight() const\r
+{\r
+ return head.biHeight;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::GetWidth() const\r
+{\r
+ return head.biWidth;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return DWORD aligned width of the image.\r
+ */\r
+DWORD CxImage::GetEffWidth() const\r
+{\r
+ return info.dwEffWidth;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return 2, 16, 256; 0 for RGB images.\r
+ */\r
+DWORD CxImage::GetNumColors() const\r
+{\r
+ return head.biClrUsed;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return: 1, 4, 8, 24.\r
+ */\r
+WORD CxImage::GetBpp() const\r
+{\r
+ return head.biBitCount;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return original image format\r
+ * \sa ENUM_CXIMAGE_FORMATS.\r
+ */\r
+DWORD CxImage::GetType() const\r
+{\r
+ return info.dwType;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * change image format identifier\r
+ * \sa ENUM_CXIMAGE_FORMATS.\r
+ */\r
+bool CxImage::SetType(DWORD type)\r
+{\r
+ switch (type){\r
+#if CXIMAGE_SUPPORT_BMP\r
+ case CXIMAGE_FORMAT_BMP:\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ case CXIMAGE_FORMAT_GIF:\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+ case CXIMAGE_FORMAT_JPG:\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+ case CXIMAGE_FORMAT_PNG:\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+ case CXIMAGE_FORMAT_MNG:\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ case CXIMAGE_FORMAT_ICO:\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+ case CXIMAGE_FORMAT_TIF:\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+ case CXIMAGE_FORMAT_TGA:\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+ case CXIMAGE_FORMAT_PCX:\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+ case CXIMAGE_FORMAT_WBMP:\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF\r
+ case CXIMAGE_FORMAT_WMF:\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+ case CXIMAGE_FORMAT_JBG:\r
+#endif\r
+#if CXIMAGE_SUPPORT_JP2\r
+ case CXIMAGE_FORMAT_JP2:\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPC\r
+ case CXIMAGE_FORMAT_JPC:\r
+#endif\r
+#if CXIMAGE_SUPPORT_PGX\r
+ case CXIMAGE_FORMAT_PGX:\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNM\r
+ case CXIMAGE_FORMAT_PNM:\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAS\r
+ case CXIMAGE_FORMAT_RAS:\r
+#endif\r
+#if CXIMAGE_SUPPORT_SKA\r
+ case CXIMAGE_FORMAT_SKA:\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAW\r
+ case CXIMAGE_FORMAT_RAW:\r
+#endif\r
+ info.dwType = type;\r
+ return true;\r
+ }\r
+ info.dwType = CXIMAGE_FORMAT_UNKNOWN;\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::GetNumTypes()\r
+{\r
+ return CMAX_IMAGE_FORMATS-1;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::GetTypeIdFromName(const TCHAR* ext)\r
+{\r
+#if CXIMAGE_SUPPORT_BMP\r
+ if (_tcsnicmp(ext,_T("bmp"),3)==0 ) return CXIMAGE_FORMAT_BMP;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+ if (_tcsnicmp(ext,_T("jpg"),3)==0 ||\r
+ _tcsnicmp(ext,_T("jpe"),3)==0 ||\r
+ _tcsnicmp(ext,_T("jfi"),3)==0 ) return CXIMAGE_FORMAT_JPG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ if (_tcsnicmp(ext,_T("gif"),3)==0 ) return CXIMAGE_FORMAT_GIF;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+ if (_tcsnicmp(ext,_T("png"),3)==0 ) return CXIMAGE_FORMAT_PNG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ if (_tcsnicmp(ext,_T("ico"),3)==0 ||\r
+ _tcsnicmp(ext,_T("cur"),3)==0 ) return CXIMAGE_FORMAT_ICO;\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+ if (_tcsnicmp(ext,_T("tif"),3)==0 ) return CXIMAGE_FORMAT_TIF;\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+ if (_tcsnicmp(ext,_T("tga"),3)==0 ) return CXIMAGE_FORMAT_TGA;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+ if (_tcsnicmp(ext,_T("pcx"),3)==0 ) return CXIMAGE_FORMAT_PCX;\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+ if (_tcsnicmp(ext,_T("wbm"),3)==0 ) return CXIMAGE_FORMAT_WBMP;\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF\r
+ if (_tcsnicmp(ext,_T("wmf"),3)==0 ||\r
+ _tcsnicmp(ext,_T("emf"),3)==0 ) return CXIMAGE_FORMAT_WMF;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JP2\r
+ if (_tcsnicmp(ext,_T("jp2"),3)==0 ||\r
+ _tcsnicmp(ext,_T("j2k"),3)==0 ) return CXIMAGE_FORMAT_JP2;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPC\r
+ if (_tcsnicmp(ext,_T("jpc"),3)==0 ||\r
+ _tcsnicmp(ext,_T("j2c"),3)==0 ) return CXIMAGE_FORMAT_JPC;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PGX\r
+ if (_tcsnicmp(ext,_T("pgx"),3)==0 ) return CXIMAGE_FORMAT_PGX;\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAS\r
+ if (_tcsnicmp(ext,_T("ras"),3)==0 ) return CXIMAGE_FORMAT_RAS;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNM\r
+ if (_tcsnicmp(ext,_T("pnm"),3)==0 ||\r
+ _tcsnicmp(ext,_T("pgm"),3)==0 ||\r
+ _tcsnicmp(ext,_T("ppm"),3)==0 ) return CXIMAGE_FORMAT_PNM;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+ if (_tcsnicmp(ext,_T("jbg"),3)==0 ) return CXIMAGE_FORMAT_JBG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+ if (_tcsnicmp(ext,_T("mng"),3)==0 ||\r
+ _tcsnicmp(ext,_T("jng"),3)==0 ) return CXIMAGE_FORMAT_MNG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_SKA\r
+ if (_tcsnicmp(ext,_T("ska"),3)==0 ) return CXIMAGE_FORMAT_SKA;\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAW\r
+ if (_tcsnicmp(ext,_T("nef"),3)==0 ||\r
+ _tcsnicmp(ext,_T("crw"),3)==0 ||\r
+ _tcsnicmp(ext,_T("cr2"),3)==0 ||\r
+ _tcsnicmp(ext,_T("dng"),3)==0 ||\r
+ _tcsnicmp(ext,_T("arw"),3)==0 ||\r
+ _tcsnicmp(ext,_T("erf"),3)==0 ||\r
+ _tcsnicmp(ext,_T("3fr"),3)==0 ||\r
+ _tcsnicmp(ext,_T("dcr"),3)==0 ||\r
+ _tcsnicmp(ext,_T("raw"),3)==0 ||\r
+ _tcsnicmp(ext,_T("x3f"),3)==0 ||\r
+ _tcsnicmp(ext,_T("mef"),3)==0 ||\r
+ _tcsnicmp(ext,_T("raf"),3)==0 ||\r
+ _tcsnicmp(ext,_T("mrw"),3)==0 ||\r
+ _tcsnicmp(ext,_T("pef"),3)==0 ||\r
+ _tcsnicmp(ext,_T("sr2"),3)==0 ||\r
+ _tcsnicmp(ext,_T("orf"),3)==0 ) return CXIMAGE_FORMAT_RAW;\r
+#endif\r
+\r
+ return CXIMAGE_FORMAT_UNKNOWN;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::GetTypeIdFromIndex(const DWORD index)\r
+{\r
+ DWORD n;\r
+\r
+ n=0; if (index == n) return CXIMAGE_FORMAT_UNKNOWN;\r
+#if CXIMAGE_SUPPORT_BMP\r
+ n++; if (index == n) return CXIMAGE_FORMAT_BMP;\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ n++; if (index == n) return CXIMAGE_FORMAT_GIF;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+ n++; if (index == n) return CXIMAGE_FORMAT_JPG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+ n++; if (index == n) return CXIMAGE_FORMAT_PNG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ n++; if (index == n) return CXIMAGE_FORMAT_ICO;\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+ n++; if (index == n) return CXIMAGE_FORMAT_TIF;\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+ n++; if (index == n) return CXIMAGE_FORMAT_TGA;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+ n++; if (index == n) return CXIMAGE_FORMAT_PCX;\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+ n++; if (index == n) return CXIMAGE_FORMAT_WBMP;\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF\r
+ n++; if (index == n) return CXIMAGE_FORMAT_WMF;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JP2\r
+ n++; if (index == n) return CXIMAGE_FORMAT_JP2;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPC\r
+ n++; if (index == n) return CXIMAGE_FORMAT_JPC;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PGX\r
+ n++; if (index == n) return CXIMAGE_FORMAT_PGX;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNM\r
+ n++; if (index == n) return CXIMAGE_FORMAT_PNM;\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAS\r
+ n++; if (index == n) return CXIMAGE_FORMAT_RAS;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+ n++; if (index == n) return CXIMAGE_FORMAT_JBG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+ n++; if (index == n) return CXIMAGE_FORMAT_MNG;\r
+#endif\r
+#if CXIMAGE_SUPPORT_SKA\r
+ n++; if (index == n) return CXIMAGE_FORMAT_SKA;\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAW\r
+ n++; if (index == n) return CXIMAGE_FORMAT_RAW;\r
+#endif\r
+\r
+ return CXIMAGE_FORMAT_UNKNOWN;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::GetTypeIndexFromId(const DWORD id)\r
+{\r
+ DWORD n;\r
+\r
+ n=0; if (id == CXIMAGE_FORMAT_UNKNOWN) return n;\r
+#if CXIMAGE_SUPPORT_BMP\r
+ n++; if (id == CXIMAGE_FORMAT_BMP) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_GIF\r
+ n++; if (id == CXIMAGE_FORMAT_GIF) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPG\r
+ n++; if (id == CXIMAGE_FORMAT_JPG) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNG\r
+ n++; if (id == CXIMAGE_FORMAT_PNG) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_ICO\r
+ n++; if (id == CXIMAGE_FORMAT_ICO) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_TIF\r
+ n++; if (id == CXIMAGE_FORMAT_TIF) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_TGA\r
+ n++; if (id == CXIMAGE_FORMAT_TGA) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PCX\r
+ n++; if (id == CXIMAGE_FORMAT_PCX) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_WBMP\r
+ n++; if (id == CXIMAGE_FORMAT_WBMP) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_WMF\r
+ n++; if (id == CXIMAGE_FORMAT_WMF) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JP2\r
+ n++; if (id == CXIMAGE_FORMAT_JP2) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPC\r
+ n++; if (id == CXIMAGE_FORMAT_JPC) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PGX\r
+ n++; if (id == CXIMAGE_FORMAT_PGX) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNM\r
+ n++; if (id == CXIMAGE_FORMAT_PNM) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAS\r
+ n++; if (id == CXIMAGE_FORMAT_RAS) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JBG\r
+ n++; if (id == CXIMAGE_FORMAT_JBG) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_MNG\r
+ n++; if (id == CXIMAGE_FORMAT_MNG) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_SKA\r
+ n++; if (id == CXIMAGE_FORMAT_SKA) return n;\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAW\r
+ n++; if (id == CXIMAGE_FORMAT_RAW) return n;\r
+#endif\r
+\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return current frame delay in milliseconds. Only for GIF and MNG formats.\r
+ */\r
+DWORD CxImage::GetFrameDelay() const\r
+{\r
+ return info.dwFrameDelay;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets current frame delay. Only for GIF format.\r
+ * \param d = delay in milliseconds\r
+ */\r
+void CxImage::SetFrameDelay(DWORD d)\r
+{\r
+ info.dwFrameDelay=d;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::GetOffset(long *x,long *y)\r
+{\r
+ *x=info.xOffset;\r
+ *y=info.yOffset;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetOffset(long x,long y)\r
+{\r
+ info.xOffset=x;\r
+ info.yOffset=y;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa SetJpegQuality, GetJpegQualityF\r
+ * \author [DP]; changes [Stefan Schรผrmans]\r
+ */\r
+BYTE CxImage::GetJpegQuality() const\r
+{\r
+ return (BYTE)(info.fQuality + 0.5f);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa SetJpegQuality, GetJpegQuality\r
+ * \author [Stefan Schรผrmans]\r
+ */\r
+float CxImage::GetJpegQualityF() const\r
+{\r
+ return info.fQuality;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * quality level for JPEG and JPEG2000\r
+ * \param q: can be from 0 to 100\r
+ * \author [DP]; changes [Stefan Schรผrmans]\r
+ */\r
+void CxImage::SetJpegQuality(BYTE q){\r
+ info.fQuality = (float)q;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * quality level for JPEG and JPEG2000\r
+ * necessary for JPEG2000 when quality is between 0.0 and 1.0\r
+ * \param q: can be from 0.0 to 100.0\r
+ * \author [Stefan Schรผrmans]\r
+ */\r
+void CxImage::SetJpegQualityF(float q){\r
+ if (q>0) info.fQuality = q;\r
+ else info.fQuality = 0.0f;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa SetJpegScale\r
+ */\r
+BYTE CxImage::GetJpegScale() const\r
+{\r
+ return info.nJpegScale;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * scaling down during JPEG decoding valid numbers are 1, 2, 4, 8\r
+ * \author [ignacio]\r
+ */\r
+void CxImage::SetJpegScale(BYTE q){\r
+ info.nJpegScale = q;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Used to monitor the slow loops.\r
+ * \return value is from 0 to 100.\r
+ * \sa SetProgress\r
+ */\r
+long CxImage::GetProgress() const\r
+{\r
+ return info.nProgress;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return the escape code.\r
+ * \sa SetEscape\r
+ */\r
+long CxImage::GetEscape() const\r
+{\r
+ return info.nEscape;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Forces the value of the internal progress variable.\r
+ * \param p should be from 0 to 100.\r
+ * \sa GetProgress\r
+ */\r
+void CxImage::SetProgress(long p)\r
+{\r
+ info.nProgress = p;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Used to quit the slow loops or the codecs.\r
+ * - SetEscape(-1) before Decode forces the function to exit, right after \r
+ * the image width and height are available ( for bmp, jpg, gif, tif )\r
+ */\r
+void CxImage::SetEscape(long i)\r
+{\r
+ info.nEscape = i;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if the image is correctly initializated.\r
+ */\r
+bool CxImage::IsValid() const\r
+{\r
+ return pDib!=0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * True if the image is enabled for painting.\r
+ */\r
+bool CxImage::IsEnabled() const\r
+{\r
+ return info.bEnabled;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Enables/disables the image.\r
+ */\r
+void CxImage::Enable(bool enable)\r
+{\r
+ info.bEnabled=enable;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * This function must be used after a Decode() / Load() call.\r
+ * Use the sequence SetFrame(-1); Load(...); GetNumFrames();\r
+ * to get the number of images without loading the first image.\r
+ * \return the number of images in the file.\r
+ */\r
+long CxImage::GetNumFrames() const\r
+{\r
+ return info.nNumFrames;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return the current selected image (zero-based index).\r
+ */\r
+long CxImage::GetFrame() const\r
+{\r
+ return info.nFrame;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the image number that the next Decode() / Load() call will load\r
+ */\r
+void CxImage::SetFrame(long nFrame){\r
+ info.nFrame=nFrame;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the method for drawing the frame related to others\r
+ * \sa GetDisposalMethod\r
+ */\r
+void CxImage::SetDisposalMethod(BYTE dm)\r
+{ info.dispmeth=dm; }\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Gets the method for drawing the frame related to others\r
+ * Values : 0 - No disposal specified. The decoder is\r
+ * not required to take any action.\r
+ * 1 - Do not dispose. The graphic is to be left\r
+ * in place.\r
+ * 2 - Restore to background color. The area used by the\r
+ * graphic must be restored to the background color.\r
+ * 3 - Restore to previous. The decoder is required to\r
+ * restore the area overwritten by the graphic with\r
+ * what was there prior to rendering the graphic.\r
+ * 4-7 - To be defined.\r
+ */\r
+BYTE CxImage::GetDisposalMethod() const\r
+{ return info.dispmeth; }\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::GetRetreiveAllFrames() const\r
+{ return info.bGetAllFrames; }\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetRetreiveAllFrames(bool flag)\r
+{ info.bGetAllFrames = flag; }\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImage * CxImage::GetFrame(long nFrame) const\r
+{\r
+ if ( ppFrames == NULL) return NULL;\r
+ if ( info.nNumFrames == 0) return NULL;\r
+ if ( nFrame >= info.nNumFrames ) return NULL;\r
+ if ( nFrame < 0) nFrame = info.nNumFrames - 1;\r
+ return ppFrames[nFrame];\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+short CxImage::ntohs(const short word)\r
+{\r
+ if (info.bLittleEndianHost) return word;\r
+ return ( (word & 0xff) << 8 ) | ( (word >> 8) & 0xff );\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::ntohl(const long dword)\r
+{\r
+ if (info.bLittleEndianHost) return dword;\r
+ return ((dword & 0xff) << 24 ) | ((dword & 0xff00) << 8 ) |\r
+ ((dword >> 8) & 0xff00) | ((dword >> 24) & 0xff);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::bihtoh(BITMAPINFOHEADER* bih)\r
+{\r
+ bih->biSize = ntohl(bih->biSize);\r
+ bih->biWidth = ntohl(bih->biWidth);\r
+ bih->biHeight = ntohl(bih->biHeight);\r
+ bih->biPlanes = ntohs(bih->biPlanes);\r
+ bih->biBitCount = ntohs(bih->biBitCount);\r
+ bih->biCompression = ntohl(bih->biCompression);\r
+ bih->biSizeImage = ntohl(bih->biSizeImage);\r
+ bih->biXPelsPerMeter = ntohl(bih->biXPelsPerMeter);\r
+ bih->biYPelsPerMeter = ntohl(bih->biYPelsPerMeter);\r
+ bih->biClrUsed = ntohl(bih->biClrUsed);\r
+ bih->biClrImportant = ntohl(bih->biClrImportant);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns the last reported error.\r
+ */\r
+const char* CxImage::GetLastError()\r
+{\r
+ return info.szLastError;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::DumpSize()\r
+{\r
+ DWORD n;\r
+ n = sizeof(BITMAPINFOHEADER) + sizeof(CXIMAGEINFO) + GetSize();\r
+\r
+ if (pAlpha){\r
+ n += 1 + head.biWidth * head.biHeight;\r
+ } else n++;\r
+\r
+ if (pSelection){\r
+ n += 1 + head.biWidth * head.biHeight;\r
+ } else n++;\r
+\r
+ if (ppLayers){\r
+ for (long m=0; m<GetNumLayers(); m++){\r
+ if (GetLayer(m)){\r
+ n += 1 + GetLayer(m)->DumpSize();\r
+ }\r
+ }\r
+ } else n++;\r
+\r
+ if (ppFrames){\r
+ for (long m=0; m<GetNumFrames(); m++){\r
+ if (GetFrame(m)){\r
+ n += 1 + GetFrame(m)->DumpSize();\r
+ }\r
+ }\r
+ } else n++;\r
+\r
+ return n;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::Dump(BYTE * dst)\r
+{\r
+ if (!dst) return 0;\r
+\r
+ memcpy(dst,&head,sizeof(BITMAPINFOHEADER));\r
+ dst += sizeof(BITMAPINFOHEADER);\r
+\r
+ memcpy(dst,&info,sizeof(CXIMAGEINFO));\r
+ dst += sizeof(CXIMAGEINFO);\r
+\r
+ memcpy(dst,pDib,GetSize());\r
+ dst += GetSize();\r
+\r
+ if (pAlpha){\r
+ memset(dst++, 1, 1);\r
+ memcpy(dst,pAlpha,head.biWidth * head.biHeight);\r
+ dst += head.biWidth * head.biHeight;\r
+ } else {\r
+ memset(dst++, 0, 1);\r
+ }\r
+\r
+ if (pSelection){\r
+ memset(dst++, 1, 1);\r
+ memcpy(dst,pSelection,head.biWidth * head.biHeight);\r
+ dst += head.biWidth * head.biHeight;\r
+ } else {\r
+ memset(dst++, 0, 1);\r
+ }\r
+\r
+ if (ppLayers){\r
+ memset(dst++, 1, 1);\r
+ for (long m=0; m<GetNumLayers(); m++){\r
+ if (GetLayer(m)){\r
+ dst += GetLayer(m)->Dump(dst);\r
+ }\r
+ }\r
+ } else {\r
+ memset(dst++, 0, 1);\r
+ }\r
+\r
+ if (ppFrames){\r
+ memset(dst++, 1, 1);\r
+ for (long m=0; m<GetNumFrames(); m++){\r
+ if (GetFrame(m)){\r
+ dst += GetFrame(m)->Dump(dst);\r
+ }\r
+ }\r
+ } else {\r
+ memset(dst++, 0, 1);\r
+ }\r
+\r
+ return DumpSize();\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+DWORD CxImage::UnDump(const BYTE * src)\r
+{\r
+ if (!src)\r
+ return 0;\r
+ if (!Destroy())\r
+ return 0;\r
+ if (!DestroyFrames())\r
+ return 0;\r
+\r
+ DWORD n = 0;\r
+\r
+ memcpy(&head,src,sizeof(BITMAPINFOHEADER));\r
+ n += sizeof(BITMAPINFOHEADER);\r
+\r
+ memcpy(&info,&src[n],sizeof(CXIMAGEINFO));\r
+ n += sizeof(CXIMAGEINFO);\r
+\r
+ if (!Create(head.biWidth, head.biHeight, head.biBitCount, info.dwType))\r
+ return 0;\r
+\r
+ memcpy(pDib,&src[n],GetSize());\r
+ n += GetSize();\r
+\r
+ if (src[n++]){\r
+ if (AlphaCreate()){\r
+ memcpy(pAlpha, &src[n], head.biWidth * head.biHeight);\r
+ }\r
+ n += head.biWidth * head.biHeight;\r
+ }\r
+\r
+ if (src[n++]){\r
+ RECT box = info.rSelectionBox;\r
+ if (SelectionCreate()){\r
+ info.rSelectionBox = box;\r
+ memcpy(pSelection, &src[n], head.biWidth * head.biHeight);\r
+ }\r
+ n += head.biWidth * head.biHeight;\r
+ }\r
+\r
+ if (src[n++]){\r
+ ppLayers = new CxImage*[info.nNumLayers];\r
+ for (long m=0; m<GetNumLayers(); m++){\r
+ ppLayers[m] = new CxImage();\r
+ n += ppLayers[m]->UnDump(&src[n]);\r
+ }\r
+ }\r
+\r
+ if (src[n++]){\r
+ ppFrames = new CxImage*[info.nNumFrames];\r
+ for (long m=0; m<GetNumFrames(); m++){\r
+ ppFrames[m] = new CxImage();\r
+ n += ppFrames[m]->UnDump(&src[n]);\r
+ }\r
+ }\r
+\r
+ return n;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \return A.BBCCCDDDD\r
+ * - A = main version\r
+ * - BB = main revision\r
+ * - CCC = minor revision (letter)\r
+ * - DDDD = experimental revision\r
+ */\r
+const float CxImage::GetVersionNumber()\r
+{\r
+ return 6.000000015f;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+const TCHAR* CxImage::GetVersion()\r
+{\r
+ static const TCHAR CxImageVersion[] = _T("CxImage 6.0.0");\r
+ return (CxImageVersion);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
--- /dev/null
+// xImaInt.cpp : interpolation functions\r
+/* 02/2004 - Branko Brevensek \r
+ * CxImage version 6.0.0 02/Feb/2008 - Davide Pizzolato - www.xdp.it\r
+ */\r
+\r
+#include "ximage.h"\r
+#include "ximath.h"\r
+\r
+#if CXIMAGE_SUPPORT_INTERPOLATION\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Recalculates coordinates according to specified overflow method.\r
+ * If pixel (x,y) lies within image, nothing changes.\r
+ *\r
+ * \param x, y - coordinates of pixel\r
+ * \param ofMethod - overflow method\r
+ * \r
+ * \return x, y - new coordinates (pixel (x,y) now lies inside image)\r
+ *\r
+ * \author ***bd*** 2.2004\r
+ */\r
+void CxImage::OverflowCoordinates(long &x, long &y, OverflowMethod const ofMethod)\r
+{\r
+ if (IsInside(x,y)) return; //if pixel is within bounds, no change\r
+ switch (ofMethod) {\r
+ case OM_REPEAT:\r
+ //clip coordinates\r
+ x=max(x,0); x=min(x, head.biWidth-1);\r
+ y=max(y,0); y=min(y, head.biHeight-1);\r
+ break;\r
+ case OM_WRAP:\r
+ //wrap coordinates\r
+ x = x % head.biWidth;\r
+ y = y % head.biHeight;\r
+ if (x<0) x = head.biWidth + x;\r
+ if (y<0) y = head.biHeight + y;\r
+ break;\r
+ case OM_MIRROR:\r
+ //mirror pixels near border\r
+ if (x<0) x=((-x) % head.biWidth);\r
+ else if (x>=head.biWidth) x=head.biWidth-(x % head.biWidth + 1);\r
+ if (y<0) y=((-y) % head.biHeight);\r
+ else if (y>=head.biHeight) y=head.biHeight-(y % head.biHeight + 1);\r
+ break;\r
+ default:\r
+ return;\r
+ }//switch\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * See OverflowCoordinates for integer version \r
+ * \author ***bd*** 2.2004\r
+ */\r
+void CxImage::OverflowCoordinates(float &x, float &y, OverflowMethod const ofMethod)\r
+{\r
+ if (x>=0 && x<head.biWidth && y>=0 && y<head.biHeight) return; //if pixel is within bounds, no change\r
+ switch (ofMethod) {\r
+ case OM_REPEAT:\r
+ //clip coordinates\r
+ x=max(x,0); x=min(x, head.biWidth-1);\r
+ y=max(y,0); y=min(y, head.biHeight-1);\r
+ break;\r
+ case OM_WRAP:\r
+ //wrap coordinates\r
+ x = (float)fmod(x, (float) head.biWidth);\r
+ y = (float)fmod(y, (float) head.biHeight);\r
+ if (x<0) x = head.biWidth + x;\r
+ if (y<0) y = head.biHeight + y;\r
+ break;\r
+ case OM_MIRROR:\r
+ //mirror pixels near border\r
+ if (x<0) x=(float)fmod(-x, (float) head.biWidth);\r
+ else if (x>=head.biWidth) x=head.biWidth-((float)fmod(x, (float) head.biWidth) + 1);\r
+ if (y<0) y=(float)fmod(-y, (float) head.biHeight);\r
+ else if (y>=head.biHeight) y=head.biHeight-((float)fmod(y, (float) head.biHeight) + 1);\r
+ break;\r
+ default:\r
+ return;\r
+ }//switch\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Method return pixel color. Different methods are implemented for out of bounds pixels.\r
+ * If an image has alpha channel, alpha value is returned in .RGBReserved.\r
+ *\r
+ * \param x,y : pixel coordinates\r
+ * \param ofMethod : out-of-bounds method:\r
+ * - OF_WRAP - wrap over to pixels on other side of the image\r
+ * - OF_REPEAT - repeat last pixel on the edge\r
+ * - OF_COLOR - return input value of color\r
+ * - OF_BACKGROUND - return background color (if not set, return input color)\r
+ * - OF_TRANSPARENT - return transparent pixel\r
+ *\r
+ * \param rplColor : input color (returned for out-of-bound coordinates in OF_COLOR mode and if other mode is not applicable)\r
+ *\r
+ * \return color : color of pixel\r
+ * \author ***bd*** 2.2004\r
+ */\r
+RGBQUAD CxImage::GetPixelColorWithOverflow(long x, long y, OverflowMethod const ofMethod, RGBQUAD* const rplColor)\r
+{\r
+ RGBQUAD color; //color to return\r
+ if ((!IsInside(x,y)) || pDib==NULL) { //is pixel within bouns?:\r
+ //pixel is out of bounds or no DIB\r
+ if (rplColor!=NULL)\r
+ color=*rplColor;\r
+ else {\r
+ color.rgbRed=color.rgbGreen=color.rgbBlue=255; color.rgbReserved=0; //default replacement colour: white transparent\r
+ }//if\r
+ if (pDib==NULL) return color;\r
+ //pixel is out of bounds:\r
+ switch (ofMethod) {\r
+ case OM_TRANSPARENT:\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ //alpha transparency is supported and image has alpha layer\r
+ color.rgbReserved=0;\r
+ } else {\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ //no alpha transparency\r
+ if (GetTransIndex()>=0) {\r
+ color=GetTransColor(); //single color transparency enabled (return transparent color)\r
+ }//if\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ }//if\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ return color;\r
+ case OM_BACKGROUND:\r
+ //return background color (if it exists, otherwise input value)\r
+ if (info.nBkgndIndex >= 0) {\r
+ if (head.biBitCount<24) color = GetPaletteColor((BYTE)info.nBkgndIndex);\r
+ else color = info.nBkgndColor;\r
+ }//if\r
+ return color;\r
+ case OM_REPEAT:\r
+ case OM_WRAP:\r
+ case OM_MIRROR:\r
+ OverflowCoordinates(x,y,ofMethod);\r
+ break;\r
+ default:\r
+ //simply return replacement color (OM_COLOR and others)\r
+ return color;\r
+ }//switch\r
+ }//if\r
+ //just return specified pixel (it's within bounds)\r
+ return BlindGetPixelColor(x,y);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * This method reconstructs image according to chosen interpolation method and then returns pixel (x,y).\r
+ * (x,y) can lie between actual image pixels. If (x,y) lies outside of image, method returns value\r
+ * according to overflow method.\r
+ * This method is very useful for geometrical image transformations, where destination pixel\r
+ * can often assume color value lying between source pixels.\r
+ *\r
+ * \param (x,y) - coordinates of pixel to return\r
+ * GPCI method recreates "analogue" image back from digital data, so x and y\r
+ * are float values and color value of point (1.1,1) will generally not be same\r
+ * as (1,1). Center of first pixel is at (0,0) and center of pixel right to it is (1,0).\r
+ * (0.5,0) is half way between these two pixels.\r
+ * \param inMethod - interpolation (reconstruction) method (kernel) to use:\r
+ * - IM_NEAREST_NEIGHBOUR - returns colour of nearest lying pixel (causes stairy look of \r
+ * processed images)\r
+ * - IM_BILINEAR - interpolates colour from four neighbouring pixels (softens image a bit)\r
+ * - IM_BICUBIC - interpolates from 16 neighbouring pixels (can produce "halo" artifacts)\r
+ * - IM_BICUBIC2 - interpolates from 16 neighbouring pixels (perhaps a bit less halo artifacts \r
+ than IM_BICUBIC)\r
+ * - IM_BSPLINE - interpolates from 16 neighbouring pixels (softens image, washes colours)\r
+ * (As far as I know, image should be prefiltered for this method to give \r
+ * good results... some other time :) )\r
+ * This method uses bicubic interpolation kernel from CXImage 5.99a and older\r
+ * versions.\r
+ * - IM_LANCZOS - interpolates from 12*12 pixels (slow, ringing artifacts)\r
+ *\r
+ * \param ofMethod - overflow method (see comments at GetPixelColorWithOverflow)\r
+ * \param rplColor - pointer to color used for out of borders pixels in OM_COLOR mode\r
+ * (and other modes if colour can't calculated in a specified way)\r
+ *\r
+ * \return interpolated color value (including interpolated alpha value, if image has alpha layer)\r
+ * \r
+ * \author ***bd*** 2.2004\r
+ */\r
+RGBQUAD CxImage::GetPixelColorInterpolated(\r
+ float x,float y, \r
+ InterpolationMethod const inMethod, \r
+ OverflowMethod const ofMethod, \r
+ RGBQUAD* const rplColor)\r
+{\r
+ //calculate nearest pixel\r
+ int xi=(int)(x); if (x<0) xi--; //these replace (incredibly slow) floor (Visual c++ 2003, AMD Athlon)\r
+ int yi=(int)(y); if (y<0) yi--;\r
+ RGBQUAD color; //calculated colour\r
+\r
+ switch (inMethod) {\r
+ case IM_NEAREST_NEIGHBOUR:\r
+ return GetPixelColorWithOverflow((long)(x+0.5f), (long)(y+0.5f), ofMethod, rplColor);\r
+ default: {\r
+ //IM_BILINEAR: bilinear interpolation\r
+ if (xi<-1 || xi>=head.biWidth || yi<-1 || yi>=head.biHeight) { //all 4 points are outside bounds?:\r
+ switch (ofMethod) {\r
+ case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND:\r
+ //we don't need to interpolate anything with all points outside in this case\r
+ return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor);\r
+ default:\r
+ //recalculate coordinates and use faster method later on\r
+ OverflowCoordinates(x,y,ofMethod);\r
+ xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi\r
+ yi=(int)(y); if (y<0) yi--;\r
+ }//switch\r
+ }//if\r
+ //get four neighbouring pixels\r
+ if ((xi+1)<head.biWidth && xi>=0 && (yi+1)<head.biHeight && yi>=0 && head.biClrUsed==0) {\r
+ //all pixels are inside RGB24 image... optimize reading (and use fixed point arithmetic)\r
+ WORD wt1=(WORD)((x-xi)*256.0f), wt2=(WORD)((y-yi)*256.0f);\r
+ WORD wd=wt1*wt2>>8;\r
+ WORD wb=wt1-wd;\r
+ WORD wc=wt2-wd;\r
+ WORD wa=256-wt1-wc;\r
+ WORD wrr,wgg,wbb;\r
+ BYTE *pxptr=(BYTE*)info.pImage+yi*info.dwEffWidth+xi*3;\r
+ wbb=wa*(*pxptr++); wgg=wa*(*pxptr++); wrr=wa*(*pxptr++);\r
+ wbb+=wb*(*pxptr++); wgg+=wb*(*pxptr++); wrr+=wb*(*pxptr);\r
+ pxptr+=(info.dwEffWidth-5); //move to next row\r
+ wbb+=wc*(*pxptr++); wgg+=wc*(*pxptr++); wrr+=wc*(*pxptr++); \r
+ wbb+=wd*(*pxptr++); wgg+=wd*(*pxptr++); wrr+=wd*(*pxptr); \r
+ color.rgbRed=(BYTE) (wrr>>8); color.rgbGreen=(BYTE) (wgg>>8); color.rgbBlue=(BYTE) (wbb>>8);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pAlpha) {\r
+ WORD waa;\r
+ //image has alpha layer... we have to do the same for alpha data\r
+ pxptr=AlphaGetPointer(xi,yi); //pointer to first byte\r
+ waa=wa*(*pxptr++); waa+=wb*(*pxptr); //first two pixels\r
+ pxptr+=(head.biWidth-1); //move to next row\r
+ waa+=wc*(*pxptr++); waa+=wd*(*pxptr); //and second row pixels\r
+ color.rgbReserved=(BYTE) (waa>>8);\r
+ } else\r
+#endif\r
+ { //Alpha not supported or no alpha at all\r
+ color.rgbReserved = 0;\r
+ }\r
+ return color;\r
+ } else {\r
+ //default (slower) way to get pixels (not RGB24 or some pixels out of borders)\r
+ float t1=x-xi, t2=y-yi;\r
+ float d=t1*t2;\r
+ float b=t1-d;\r
+ float c=t2-d;\r
+ float a=1-t1-c;\r
+ RGBQUAD rgb11,rgb21,rgb12,rgb22;\r
+ rgb11=GetPixelColorWithOverflow(xi, yi, ofMethod, rplColor);\r
+ rgb21=GetPixelColorWithOverflow(xi+1, yi, ofMethod, rplColor);\r
+ rgb12=GetPixelColorWithOverflow(xi, yi+1, ofMethod, rplColor);\r
+ rgb22=GetPixelColorWithOverflow(xi+1, yi+1, ofMethod, rplColor);\r
+ //calculate linear interpolation\r
+ color.rgbRed=(BYTE) (a*rgb11.rgbRed+b*rgb21.rgbRed+c*rgb12.rgbRed+d*rgb22.rgbRed);\r
+ color.rgbGreen=(BYTE) (a*rgb11.rgbGreen+b*rgb21.rgbGreen+c*rgb12.rgbGreen+d*rgb22.rgbGreen);\r
+ color.rgbBlue=(BYTE) (a*rgb11.rgbBlue+b*rgb21.rgbBlue+c*rgb12.rgbBlue+d*rgb22.rgbBlue);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid())\r
+ color.rgbReserved=(BYTE) (a*rgb11.rgbReserved+b*rgb21.rgbReserved+c*rgb12.rgbReserved+d*rgb22.rgbReserved);\r
+ else\r
+#endif\r
+ { //Alpha not supported or no alpha at all\r
+ color.rgbReserved = 0;\r
+ }\r
+ return color;\r
+ }//if\r
+ }//default\r
+ case IM_BICUBIC: \r
+ case IM_BICUBIC2:\r
+ case IM_BSPLINE:\r
+ case IM_BOX:\r
+ case IM_HERMITE:\r
+ case IM_HAMMING:\r
+ case IM_SINC:\r
+ case IM_BLACKMAN:\r
+ case IM_BESSEL:\r
+ case IM_GAUSSIAN:\r
+ case IM_QUADRATIC:\r
+ case IM_MITCHELL:\r
+ case IM_CATROM:\r
+ case IM_HANNING:\r
+ case IM_POWER:\r
+ //bicubic interpolation(s)\r
+ if (((xi+2)<0) || ((xi-1)>=head.biWidth) || ((yi+2)<0) || ((yi-1)>=head.biHeight)) { //all points are outside bounds?:\r
+ switch (ofMethod) {\r
+ case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND:\r
+ //we don't need to interpolate anything with all points outside in this case\r
+ return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor);\r
+ break;\r
+ default:\r
+ //recalculate coordinates and use faster method later on\r
+ OverflowCoordinates(x,y,ofMethod);\r
+ xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi\r
+ yi=(int)(y); if (y<0) yi--;\r
+ }//switch\r
+ }//if\r
+\r
+ //some variables needed from here on\r
+ int xii,yii; //x any y integer indexes for loops\r
+ float kernel, kernelyc; //kernel cache\r
+ float kernelx[12], kernely[4]; //precalculated kernel values\r
+ float rr,gg,bb,aa; //accumulated color values\r
+ //calculate multiplication factors for all pixels\r
+ int i;\r
+ switch (inMethod) {\r
+ case IM_BICUBIC:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelCubic((float)(xi+i-1-x));\r
+ kernely[i]=KernelCubic((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_BICUBIC2:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelGeneralizedCubic((float)(xi+i-1-x), -0.5);\r
+ kernely[i]=KernelGeneralizedCubic((float)(yi+i-1-y), -0.5);\r
+ }//for i\r
+ break;\r
+ case IM_BSPLINE:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelBSpline((float)(xi+i-1-x));\r
+ kernely[i]=KernelBSpline((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_BOX:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelBox((float)(xi+i-1-x));\r
+ kernely[i]=KernelBox((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_HERMITE:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelHermite((float)(xi+i-1-x));\r
+ kernely[i]=KernelHermite((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_HAMMING:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelHamming((float)(xi+i-1-x));\r
+ kernely[i]=KernelHamming((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_SINC:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelSinc((float)(xi+i-1-x));\r
+ kernely[i]=KernelSinc((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_BLACKMAN:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelBlackman((float)(xi+i-1-x));\r
+ kernely[i]=KernelBlackman((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_BESSEL:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelBessel((float)(xi+i-1-x));\r
+ kernely[i]=KernelBessel((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_GAUSSIAN:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelGaussian((float)(xi+i-1-x));\r
+ kernely[i]=KernelGaussian((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_QUADRATIC:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelQuadratic((float)(xi+i-1-x));\r
+ kernely[i]=KernelQuadratic((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_MITCHELL:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelMitchell((float)(xi+i-1-x));\r
+ kernely[i]=KernelMitchell((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_CATROM:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelCatrom((float)(xi+i-1-x));\r
+ kernely[i]=KernelCatrom((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_HANNING:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelHanning((float)(xi+i-1-x));\r
+ kernely[i]=KernelHanning((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ case IM_POWER:\r
+ for (i=0; i<4; i++) {\r
+ kernelx[i]=KernelPower((float)(xi+i-1-x));\r
+ kernely[i]=KernelPower((float)(yi+i-1-y));\r
+ }//for i\r
+ break;\r
+ }//switch\r
+ rr=gg=bb=aa=0;\r
+ if (((xi+2)<head.biWidth) && xi>=1 && ((yi+2)<head.biHeight) && (yi>=1) && !IsIndexed()) {\r
+ //optimized interpolation (faster pixel reads) for RGB24 images with all pixels inside bounds\r
+ BYTE *pxptr, *pxptra;\r
+ for (yii=yi-1; yii<yi+3; yii++) {\r
+ pxptr=(BYTE *)BlindGetPixelPointer(xi-1, yii); //calculate pointer to first byte in row\r
+ kernelyc=kernely[yii-(yi-1)];\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ //alpha is supported and valid (optimized bicubic int. for image with alpha)\r
+ pxptra=AlphaGetPointer(xi-1, yii);\r
+ kernel=kernelyc*kernelx[0];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++); aa+=kernel*(*pxptra++);\r
+ kernel=kernelyc*kernelx[1];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++); aa+=kernel*(*pxptra++);\r
+ kernel=kernelyc*kernelx[2];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++); aa+=kernel*(*pxptra++);\r
+ kernel=kernelyc*kernelx[3];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr); aa+=kernel*(*pxptra);\r
+ } else\r
+#endif\r
+ //alpha not supported or valid (optimized bicubic int. for no alpha channel)\r
+ {\r
+ kernel=kernelyc*kernelx[0];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++);\r
+ kernel=kernelyc*kernelx[1];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++);\r
+ kernel=kernelyc*kernelx[2];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++);\r
+ kernel=kernelyc*kernelx[3];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr);\r
+ }\r
+ }//yii\r
+ } else {\r
+ //slower more flexible interpolation for border pixels and paletted images\r
+ RGBQUAD rgbs;\r
+ for (yii=yi-1; yii<yi+3; yii++) {\r
+ kernelyc=kernely[yii-(yi-1)];\r
+ for (xii=xi-1; xii<xi+3; xii++) {\r
+ kernel=kernelyc*kernelx[xii-(xi-1)];\r
+ rgbs=GetPixelColorWithOverflow(xii, yii, ofMethod, rplColor);\r
+ rr+=kernel*rgbs.rgbRed;\r
+ gg+=kernel*rgbs.rgbGreen;\r
+ bb+=kernel*rgbs.rgbBlue;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ aa+=kernel*rgbs.rgbReserved;\r
+#endif\r
+ }//xii\r
+ }//yii\r
+ }//if\r
+ //for all colors, clip to 0..255 and assign to RGBQUAD\r
+ if (rr>255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr;\r
+ if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg;\r
+ if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa;\r
+ } else\r
+#endif\r
+ { //Alpha not supported or no alpha at all\r
+ color.rgbReserved = 0;\r
+ }\r
+ return color;\r
+ case IM_LANCZOS:\r
+ //lanczos window (16*16) sinc interpolation\r
+ if (((xi+6)<0) || ((xi-5)>=head.biWidth) || ((yi+6)<0) || ((yi-5)>=head.biHeight)) {\r
+ //all points are outside bounds\r
+ switch (ofMethod) {\r
+ case OM_COLOR: case OM_TRANSPARENT: case OM_BACKGROUND:\r
+ //we don't need to interpolate anything with all points outside in this case\r
+ return GetPixelColorWithOverflow(-999, -999, ofMethod, rplColor);\r
+ break;\r
+ default:\r
+ //recalculate coordinates and use faster method later on\r
+ OverflowCoordinates(x,y,ofMethod);\r
+ xi=(int)(x); if (x<0) xi--; //x and/or y have changed ... recalculate xi and yi\r
+ yi=(int)(y); if (y<0) yi--;\r
+ }//switch\r
+ }//if\r
+\r
+ for (xii=xi-5; xii<xi+7; xii++) kernelx[xii-(xi-5)]=KernelLanczosSinc((float)(xii-x), 6.0f);\r
+ rr=gg=bb=aa=0;\r
+\r
+ if (((xi+6)<head.biWidth) && ((xi-5)>=0) && ((yi+6)<head.biHeight) && ((yi-5)>=0) && !IsIndexed()) {\r
+ //optimized interpolation (faster pixel reads) for RGB24 images with all pixels inside bounds\r
+ BYTE *pxptr, *pxptra;\r
+ for (yii=yi-5; yii<yi+7; yii++) {\r
+ pxptr=(BYTE *)BlindGetPixelPointer(xi-5, yii); //calculate pointer to first byte in row\r
+ kernelyc=KernelLanczosSinc((float)(yii-y),6.0f);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ //alpha is supported and valid\r
+ pxptra=AlphaGetPointer(xi-1, yii);\r
+ for (xii=0; xii<12; xii++) {\r
+ kernel=kernelyc*kernelx[xii];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++); aa+=kernel*(*pxptra++);\r
+ }//for xii\r
+ } else\r
+#endif\r
+ //alpha not supported or valid\r
+ {\r
+ for (xii=0; xii<12; xii++) {\r
+ kernel=kernelyc*kernelx[xii];\r
+ bb+=kernel*(*pxptr++); gg+=kernel*(*pxptr++); rr+=kernel*(*pxptr++);\r
+ }//for xii\r
+ }\r
+ }//yii\r
+ } else {\r
+ //slower more flexible interpolation for border pixels and paletted images\r
+ RGBQUAD rgbs;\r
+ for (yii=yi-5; yii<yi+7; yii++) {\r
+ kernelyc=KernelLanczosSinc((float)(yii-y),6.0f);\r
+ for (xii=xi-5; xii<xi+7; xii++) {\r
+ kernel=kernelyc*kernelx[xii-(xi-5)];\r
+ rgbs=GetPixelColorWithOverflow(xii, yii, ofMethod, rplColor);\r
+ rr+=kernel*rgbs.rgbRed;\r
+ gg+=kernel*rgbs.rgbGreen;\r
+ bb+=kernel*rgbs.rgbBlue;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ aa+=kernel*rgbs.rgbReserved;\r
+#endif\r
+ }//xii\r
+ }//yii\r
+ }//if\r
+ //for all colors, clip to 0..255 and assign to RGBQUAD\r
+ if (rr>255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr;\r
+ if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg;\r
+ if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa; \r
+ } else\r
+#endif\r
+ { //Alpha not supported or no alpha at all\r
+ color.rgbReserved = 0;\r
+ }\r
+ return color;\r
+ }//switch\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Helper function for GetAreaColorInterpolated.\r
+ * Adds 'surf' portion of image pixel with color 'color' to (rr,gg,bb,aa).\r
+ */\r
+void CxImage::AddAveragingCont(RGBQUAD const &color, float const surf, float &rr, float &gg, float &bb, float &aa)\r
+{\r
+ rr+=color.rgbRed*surf;\r
+ gg+=color.rgbGreen*surf;\r
+ bb+=color.rgbBlue*surf;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ aa+=color.rgbReserved*surf;\r
+#endif\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * This method is similar to GetPixelColorInterpolated, but this method also properly handles \r
+ * subsampling.\r
+ * If you need to sample original image with interval of more than 1 pixel (as when shrinking an image), \r
+ * you should use this method instead of GetPixelColorInterpolated or aliasing will occur.\r
+ * When area width and height are both less than pixel, this method gets pixel color by interpolating\r
+ * color of frame center with selected (inMethod) interpolation by calling GetPixelColorInterpolated. \r
+ * If width and height are more than 1, method calculates color by averaging color of pixels within area.\r
+ * Interpolation method is not used in this case. Pixel color is interpolated by averaging instead.\r
+ * If only one of both is more than 1, method uses combination of interpolation and averaging.\r
+ * Chosen interpolation method is used, but since it is averaged later on, there is little difference\r
+ * between IM_BILINEAR (perhaps best for this case) and better methods. IM_NEAREST_NEIGHBOUR again\r
+ * leads to aliasing artifacts.\r
+ * This method is a bit slower than GetPixelColorInterpolated and when aliasing is not a problem, you should\r
+ * simply use the later. \r
+ *\r
+ * \param xc, yc - center of (rectangular) area\r
+ * \param w, h - width and height of area\r
+ * \param inMethod - interpolation method that is used, when interpolation is used (see above)\r
+ * \param ofMethod - overflow method used when retrieving individual pixel colors\r
+ * \param rplColor - replacement colour to use, in OM_COLOR\r
+ *\r
+ * \author ***bd*** 2.2004\r
+ */\r
+RGBQUAD CxImage::GetAreaColorInterpolated(\r
+ float const xc, float const yc, float const w, float const h, \r
+ InterpolationMethod const inMethod, \r
+ OverflowMethod const ofMethod, \r
+ RGBQUAD* const rplColor)\r
+{\r
+ RGBQUAD color; //calculated colour\r
+ \r
+ if (h<=1 && w<=1) {\r
+ //both width and height are less than one... we will use interpolation of center point\r
+ return GetPixelColorInterpolated(xc, yc, inMethod, ofMethod, rplColor);\r
+ } else {\r
+ //area is wider and/or taller than one pixel:\r
+ CxRect2 area(xc-w/2.0f, yc-h/2.0f, xc+w/2.0f, yc+h/2.0f); //area\r
+ int xi1=(int)(area.botLeft.x+0.49999999f); //low x\r
+ int yi1=(int)(area.botLeft.y+0.49999999f); //low y\r
+ \r
+ \r
+ int xi2=(int)(area.topRight.x+0.5f); //top x\r
+ int yi2=(int)(area.topRight.y+0.5f); //top y (for loops)\r
+ \r
+ float rr,gg,bb,aa; //red, green, blue and alpha components\r
+ rr=gg=bb=aa=0;\r
+ int x,y; //loop counters\r
+ float s=0; //surface of all pixels\r
+ float cps; //surface of current crosssection\r
+ if (h>1 && w>1) {\r
+ //width and height of area are greater than one pixel, so we can employ "ordinary" averaging\r
+ CxRect2 intBL, intTR; //bottom left and top right intersection\r
+ intBL=area.CrossSection(CxRect2(((float)xi1)-0.5f, ((float)yi1)-0.5f, ((float)xi1)+0.5f, ((float)yi1)+0.5f));\r
+ intTR=area.CrossSection(CxRect2(((float)xi2)-0.5f, ((float)yi2)-0.5f, ((float)xi2)+0.5f, ((float)yi2)+0.5f));\r
+ float wBL, wTR, hBL, hTR;\r
+ wBL=intBL.Width(); //width of bottom left pixel-area intersection\r
+ hBL=intBL.Height(); //height of bottom left...\r
+ wTR=intTR.Width(); //width of top right...\r
+ hTR=intTR.Height(); //height of top right...\r
+ \r
+ AddAveragingCont(GetPixelColorWithOverflow(xi1,yi1,ofMethod,rplColor), wBL*hBL, rr, gg, bb, aa); //bottom left pixel\r
+ AddAveragingCont(GetPixelColorWithOverflow(xi2,yi1,ofMethod,rplColor), wTR*hBL, rr, gg, bb, aa); //bottom right pixel\r
+ AddAveragingCont(GetPixelColorWithOverflow(xi1,yi2,ofMethod,rplColor), wBL*hTR, rr, gg, bb, aa); //top left pixel\r
+ AddAveragingCont(GetPixelColorWithOverflow(xi2,yi2,ofMethod,rplColor), wTR*hTR, rr, gg, bb, aa); //top right pixel\r
+ //bottom and top row\r
+ for (x=xi1+1; x<xi2; x++) {\r
+ AddAveragingCont(GetPixelColorWithOverflow(x,yi1,ofMethod,rplColor), hBL, rr, gg, bb, aa); //bottom row\r
+ AddAveragingCont(GetPixelColorWithOverflow(x,yi2,ofMethod,rplColor), hTR, rr, gg, bb, aa); //top row\r
+ }\r
+ //leftmost and rightmost column\r
+ for (y=yi1+1; y<yi2; y++) {\r
+ AddAveragingCont(GetPixelColorWithOverflow(xi1,y,ofMethod,rplColor), wBL, rr, gg, bb, aa); //left column\r
+ AddAveragingCont(GetPixelColorWithOverflow(xi2,y,ofMethod,rplColor), wTR, rr, gg, bb, aa); //right column\r
+ }\r
+ for (y=yi1+1; y<yi2; y++) {\r
+ for (x=xi1+1; x<xi2; x++) { \r
+ color=GetPixelColorWithOverflow(x,y,ofMethod,rplColor);\r
+ rr+=color.rgbRed;\r
+ gg+=color.rgbGreen;\r
+ bb+=color.rgbBlue;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ aa+=color.rgbReserved;\r
+#endif\r
+ }//for x\r
+ }//for y\r
+ } else {\r
+ //width or height greater than one:\r
+ CxRect2 intersect; //intersection with current pixel\r
+ CxPoint2 center;\r
+ for (y=yi1; y<=yi2; y++) {\r
+ for (x=xi1; x<=xi2; x++) {\r
+ intersect=area.CrossSection(CxRect2(((float)x)-0.5f, ((float)y)-0.5f, ((float)x)+0.5f, ((float)y)+0.5f));\r
+ center=intersect.Center();\r
+ color=GetPixelColorInterpolated(center.x, center.y, inMethod, ofMethod, rplColor);\r
+ cps=intersect.Surface();\r
+ rr+=color.rgbRed*cps;\r
+ gg+=color.rgbGreen*cps;\r
+ bb+=color.rgbBlue*cps;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ aa+=color.rgbReserved*cps;\r
+#endif\r
+ }//for x\r
+ }//for y \r
+ }//if\r
+ \r
+ s=area.Surface();\r
+ rr/=s; gg/=s; bb/=s; aa/=s;\r
+ if (rr>255) rr=255; if (rr<0) rr=0; color.rgbRed=(BYTE) rr;\r
+ if (gg>255) gg=255; if (gg<0) gg=0; color.rgbGreen=(BYTE) gg;\r
+ if (bb>255) bb=255; if (bb<0) bb=0; color.rgbBlue=(BYTE) bb;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ if (aa>255) aa=255; if (aa<0) aa=0; color.rgbReserved=(BYTE) aa;\r
+ }//if\r
+#endif\r
+ }//if\r
+ return color;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBSpline(const float x)\r
+{\r
+ if (x>2.0f) return 0.0f;\r
+ // thanks to Kristian Kratzenstein\r
+ float a, b, c, d;\r
+ float xm1 = x - 1.0f; // Was calculatet anyway cause the "if((x-1.0f) < 0)"\r
+ float xp1 = x + 1.0f;\r
+ float xp2 = x + 2.0f;\r
+\r
+ if ((xp2) <= 0.0f) a = 0.0f; else a = xp2*xp2*xp2; // Only float, not float -> double -> float\r
+ if ((xp1) <= 0.0f) b = 0.0f; else b = xp1*xp1*xp1;\r
+ if (x <= 0) c = 0.0f; else c = x*x*x; \r
+ if ((xm1) <= 0.0f) d = 0.0f; else d = xm1*xm1*xm1;\r
+\r
+ return (0.16666666666666666667f * (a - (4.0f * b) + (6.0f * c) - (4.0f * d)));\r
+\r
+ /* equivalent <Vladimรญr Kloucek>\r
+ if (x < -2.0)\r
+ return(0.0f);\r
+ if (x < -1.0)\r
+ return((2.0f+x)*(2.0f+x)*(2.0f+x)*0.16666666666666666667f);\r
+ if (x < 0.0)\r
+ return((4.0f+x*x*(-6.0f-3.0f*x))*0.16666666666666666667f);\r
+ if (x < 1.0)\r
+ return((4.0f+x*x*(-6.0f+3.0f*x))*0.16666666666666666667f);\r
+ if (x < 2.0)\r
+ return((2.0f-x)*(2.0f-x)*(2.0f-x)*0.16666666666666666667f);\r
+ return(0.0f);\r
+ */\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Bilinear interpolation kernel:\r
+ \verbatim\r
+ /\r
+ | 1-t , if 0 <= t <= 1\r
+ h(t) = | t+1 , if -1 <= t < 0\r
+ | 0 , otherwise\r
+ \\r
+ \endverbatim\r
+ * ***bd*** 2.2004\r
+ */\r
+float CxImage::KernelLinear(const float t)\r
+{\r
+// if (0<=t && t<=1) return 1-t;\r
+// if (-1<=t && t<0) return 1+t;\r
+// return 0;\r
+ \r
+ //<Vladimรญr Kloucek>\r
+ if (t < -1.0f)\r
+ return 0.0f;\r
+ if (t < 0.0f)\r
+ return 1.0f+t;\r
+ if (t < 1.0f)\r
+ return 1.0f-t;\r
+ return 0.0f;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Bicubic interpolation kernel (a=-1):\r
+ \verbatim\r
+ /\r
+ | 1-2|t|**2+|t|**3 , if |t| < 1\r
+ h(t) = | 4-8|t|+5|t|**2-|t|**3 , if 1<=|t|<2\r
+ | 0 , otherwise\r
+ \\r
+ \endverbatim\r
+ * ***bd*** 2.2004\r
+ */\r
+float CxImage::KernelCubic(const float t)\r
+{\r
+ float abs_t = (float)fabs(t);\r
+ float abs_t_sq = abs_t * abs_t;\r
+ if (abs_t<1) return 1-2*abs_t_sq+abs_t_sq*abs_t;\r
+ if (abs_t<2) return 4 - 8*abs_t +5*abs_t_sq - abs_t_sq*abs_t;\r
+ return 0;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Bicubic kernel (for a=-1 it is the same as BicubicKernel):\r
+ \verbatim\r
+ /\r
+ | (a+2)|t|**3 - (a+3)|t|**2 + 1 , |t| <= 1\r
+ h(t) = | a|t|**3 - 5a|t|**2 + 8a|t| - 4a , 1 < |t| <= 2\r
+ | 0 , otherwise\r
+ \\r
+ \endverbatim\r
+ * Often used values for a are -1 and -1/2.\r
+ */\r
+float CxImage::KernelGeneralizedCubic(const float t, const float a)\r
+{\r
+ float abs_t = (float)fabs(t);\r
+ float abs_t_sq = abs_t * abs_t;\r
+ if (abs_t<1) return (a+2)*abs_t_sq*abs_t - (a+3)*abs_t_sq + 1;\r
+ if (abs_t<2) return a*abs_t_sq*abs_t - 5*a*abs_t_sq + 8*a*abs_t - 4*a;\r
+ return 0;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Lanczos windowed sinc interpolation kernel with radius r.\r
+ \verbatim\r
+ /\r
+ h(t) = | sinc(t)*sinc(t/r) , if |t|<r\r
+ | 0 , otherwise\r
+ \\r
+ \endverbatim\r
+ * ***bd*** 2.2004\r
+ */\r
+float CxImage::KernelLanczosSinc(const float t, const float r)\r
+{\r
+ if (fabs(t) > r) return 0;\r
+ if (t==0) return 1;\r
+ float pit=PI*t;\r
+ float pitd=pit/r;\r
+ return (float)((sin(pit)/pit) * (sin(pitd)/pitd));\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBox(const float x)\r
+{\r
+ if (x < -0.5f)\r
+ return 0.0f;\r
+ if (x < 0.5f)\r
+ return 1.0f;\r
+ return 0.0f;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelHermite(const float x)\r
+{\r
+ if (x < -1.0f)\r
+ return 0.0f;\r
+ if (x < 0.0f)\r
+ return (-2.0f*x-3.0f)*x*x+1.0f;\r
+ if (x < 1.0f)\r
+ return (2.0f*x-3.0f)*x*x+1.0f;\r
+ return 0.0f;\r
+// if (fabs(x)>1) return 0.0f;\r
+// return(0.5f+0.5f*(float)cos(PI*x));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelHanning(const float x)\r
+{\r
+ if (fabs(x)>1) return 0.0f;\r
+ return (0.5f+0.5f*(float)cos(PI*x))*((float)sin(PI*x)/(PI*x));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelHamming(const float x)\r
+{\r
+ if (x < -1.0f)\r
+ return 0.0f;\r
+ if (x < 0.0f)\r
+ return 0.92f*(-2.0f*x-3.0f)*x*x+1.0f;\r
+ if (x < 1.0f)\r
+ return 0.92f*(2.0f*x-3.0f)*x*x+1.0f;\r
+ return 0.0f;\r
+// if (fabs(x)>1) return 0.0f;\r
+// return(0.54f+0.46f*(float)cos(PI*x));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelSinc(const float x)\r
+{\r
+ if (x == 0.0)\r
+ return(1.0);\r
+ return((float)sin(PI*x)/(PI*x));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBlackman(const float x)\r
+{\r
+ //if (fabs(x)>1) return 0.0f;\r
+ return (0.42f+0.5f*(float)cos(PI*x)+0.08f*(float)cos(2.0f*PI*x));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBessel_J1(const float x)\r
+{\r
+ double p, q;\r
+ \r
+ register long i;\r
+ \r
+ static const double\r
+ Pone[] =\r
+ {\r
+ 0.581199354001606143928050809e+21,\r
+ -0.6672106568924916298020941484e+20,\r
+ 0.2316433580634002297931815435e+19,\r
+ -0.3588817569910106050743641413e+17,\r
+ 0.2908795263834775409737601689e+15,\r
+ -0.1322983480332126453125473247e+13,\r
+ 0.3413234182301700539091292655e+10,\r
+ -0.4695753530642995859767162166e+7,\r
+ 0.270112271089232341485679099e+4\r
+ },\r
+ Qone[] =\r
+ {\r
+ 0.11623987080032122878585294e+22,\r
+ 0.1185770712190320999837113348e+20,\r
+ 0.6092061398917521746105196863e+17,\r
+ 0.2081661221307607351240184229e+15,\r
+ 0.5243710262167649715406728642e+12,\r
+ 0.1013863514358673989967045588e+10,\r
+ 0.1501793594998585505921097578e+7,\r
+ 0.1606931573481487801970916749e+4,\r
+ 0.1e+1\r
+ };\r
+ \r
+ p = Pone[8];\r
+ q = Qone[8];\r
+ for (i=7; i >= 0; i--)\r
+ {\r
+ p = p*x*x+Pone[i];\r
+ q = q*x*x+Qone[i];\r
+ }\r
+ return (float)(p/q);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBessel_P1(const float x)\r
+{\r
+ double p, q;\r
+ \r
+ register long i;\r
+ \r
+ static const double\r
+ Pone[] =\r
+ {\r
+ 0.352246649133679798341724373e+5,\r
+ 0.62758845247161281269005675e+5,\r
+ 0.313539631109159574238669888e+5,\r
+ 0.49854832060594338434500455e+4,\r
+ 0.2111529182853962382105718e+3,\r
+ 0.12571716929145341558495e+1\r
+ },\r
+ Qone[] =\r
+ {\r
+ 0.352246649133679798068390431e+5,\r
+ 0.626943469593560511888833731e+5,\r
+ 0.312404063819041039923015703e+5,\r
+ 0.4930396490181088979386097e+4,\r
+ 0.2030775189134759322293574e+3,\r
+ 0.1e+1\r
+ };\r
+ \r
+ p = Pone[5];\r
+ q = Qone[5];\r
+ for (i=4; i >= 0; i--)\r
+ {\r
+ p = p*(8.0/x)*(8.0/x)+Pone[i];\r
+ q = q*(8.0/x)*(8.0/x)+Qone[i];\r
+ }\r
+ return (float)(p/q);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBessel_Q1(const float x)\r
+{\r
+ double p, q;\r
+ \r
+ register long i;\r
+ \r
+ static const double\r
+ Pone[] =\r
+ {\r
+ 0.3511751914303552822533318e+3,\r
+ 0.7210391804904475039280863e+3,\r
+ 0.4259873011654442389886993e+3,\r
+ 0.831898957673850827325226e+2,\r
+ 0.45681716295512267064405e+1,\r
+ 0.3532840052740123642735e-1\r
+ },\r
+ Qone[] =\r
+ {\r
+ 0.74917374171809127714519505e+4,\r
+ 0.154141773392650970499848051e+5,\r
+ 0.91522317015169922705904727e+4,\r
+ 0.18111867005523513506724158e+4,\r
+ 0.1038187585462133728776636e+3,\r
+ 0.1e+1\r
+ };\r
+ \r
+ p = Pone[5];\r
+ q = Qone[5];\r
+ for (i=4; i >= 0; i--)\r
+ {\r
+ p = p*(8.0/x)*(8.0/x)+Pone[i];\r
+ q = q*(8.0/x)*(8.0/x)+Qone[i];\r
+ }\r
+ return (float)(p/q);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBessel_Order1(float x)\r
+{\r
+ float p, q;\r
+ \r
+ if (x == 0.0)\r
+ return (0.0f);\r
+ p = x;\r
+ if (x < 0.0)\r
+ x=(-x);\r
+ if (x < 8.0)\r
+ return(p*KernelBessel_J1(x));\r
+ 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)*\r
+ (-1.0f/sqrt(2.0f)*(sin(x)+cos(x))));\r
+ if (p < 0.0f)\r
+ q = (-q);\r
+ return (q);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelBessel(const float x)\r
+{\r
+ if (x == 0.0f)\r
+ return(PI/4.0f);\r
+ return(KernelBessel_Order1(PI*x)/(2.0f*x));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelGaussian(const float x)\r
+{\r
+ return (float)(exp(-2.0f*x*x)*0.79788456080287f/*sqrt(2.0f/PI)*/);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelQuadratic(const float x)\r
+{\r
+ if (x < -1.5f)\r
+ return(0.0f);\r
+ if (x < -0.5f)\r
+ return(0.5f*(x+1.5f)*(x+1.5f));\r
+ if (x < 0.5f)\r
+ return(0.75f-x*x);\r
+ if (x < 1.5f)\r
+ return(0.5f*(x-1.5f)*(x-1.5f));\r
+ return(0.0f);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelMitchell(const float x)\r
+{\r
+#define KM_B (1.0f/3.0f)\r
+#define KM_C (1.0f/3.0f)\r
+#define KM_P0 (( 6.0f - 2.0f * KM_B ) / 6.0f)\r
+#define KM_P2 ((-18.0f + 12.0f * KM_B + 6.0f * KM_C) / 6.0f)\r
+#define KM_P3 (( 12.0f - 9.0f * KM_B - 6.0f * KM_C) / 6.0f)\r
+#define KM_Q0 (( 8.0f * KM_B + 24.0f * KM_C) / 6.0f)\r
+#define KM_Q1 ((-12.0f * KM_B - 48.0f * KM_C) / 6.0f)\r
+#define KM_Q2 (( 6.0f * KM_B + 30.0f * KM_C) / 6.0f)\r
+#define KM_Q3 (( -1.0f * KM_B - 6.0f * KM_C) / 6.0f)\r
+ \r
+ if (x < -2.0)\r
+ return(0.0f);\r
+ if (x < -1.0)\r
+ return(KM_Q0-x*(KM_Q1-x*(KM_Q2-x*KM_Q3)));\r
+ if (x < 0.0f)\r
+ return(KM_P0+x*x*(KM_P2-x*KM_P3));\r
+ if (x < 1.0f)\r
+ return(KM_P0+x*x*(KM_P2+x*KM_P3));\r
+ if (x < 2.0f)\r
+ return(KM_Q0+x*(KM_Q1+x*(KM_Q2+x*KM_Q3)));\r
+ return(0.0f);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelCatrom(const float x)\r
+{\r
+ if (x < -2.0)\r
+ return(0.0f);\r
+ if (x < -1.0)\r
+ return(0.5f*(4.0f+x*(8.0f+x*(5.0f+x))));\r
+ if (x < 0.0)\r
+ return(0.5f*(2.0f+x*x*(-5.0f-3.0f*x)));\r
+ if (x < 1.0)\r
+ return(0.5f*(2.0f+x*x*(-5.0f+3.0f*x)));\r
+ if (x < 2.0)\r
+ return(0.5f*(4.0f+x*(-8.0f+x*(5.0f-x))));\r
+ return(0.0f);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+float CxImage::KernelPower(const float x, const float a)\r
+{\r
+ if (fabs(x)>1) return 0.0f;\r
+ return (1.0f - (float)fabs(pow(x,a)));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ImaIter.h\r
+ * Purpose: Declaration of the Platform Independent Image Base Class\r
+ * Author: Alejandro Aguilar Sierra\r
+ * Created: 1995\r
+ * Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>\r
+ *\r
+ * 07/08/2001 Davide Pizzolato - www.xdp.it\r
+ * - removed slow loops\r
+ * - added safe checks\r
+ *\r
+ * Permission is given by the author to freely redistribute and include\r
+ * this code in any program as long as this credit is given where due.\r
+ *\r
+ * COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY\r
+ * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES\r
+ * THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE\r
+ * OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED\r
+ * CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT\r
+ * THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY\r
+ * SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL\r
+ * PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER\r
+ * THIS DISCLAIMER.\r
+ *\r
+ * Use at your own risk!\r
+ * ==========================================================\r
+ */\r
+\r
+#if !defined(__ImaIter_h)\r
+#define __ImaIter_h\r
+\r
+#include "ximage.h"\r
+#include "ximadef.h"\r
+\r
+class CImageIterator\r
+{\r
+friend class CxImage;\r
+protected:\r
+ int Itx, Ity; // Counters\r
+ int Stepx, Stepy;\r
+ BYTE* IterImage; // Image pointer\r
+ CxImage *ima;\r
+public:\r
+ // Constructors\r
+ CImageIterator ( void );\r
+ CImageIterator ( CxImage *image );\r
+ operator CxImage* ();\r
+\r
+ // Iterators\r
+ BOOL ItOK ();\r
+ void Reset ();\r
+ void Upset ();\r
+ void SetRow(BYTE *buf, int n);\r
+ void GetRow(BYTE *buf, int n);\r
+ BYTE GetByte( ) { return IterImage[Itx]; }\r
+ void SetByte(BYTE b) { IterImage[Itx] = b; }\r
+ BYTE* GetRow(void);\r
+ BYTE* GetRow(int n);\r
+ BOOL NextRow();\r
+ BOOL PrevRow();\r
+ BOOL NextByte();\r
+ BOOL PrevByte();\r
+\r
+ void SetSteps(int x, int y=0) { Stepx = x; Stepy = y; }\r
+ void GetSteps(int *x, int *y) { *x = Stepx; *y = Stepy; }\r
+ BOOL NextStep();\r
+ BOOL PrevStep();\r
+\r
+ void SetY(int y); /* AD - for interlace */\r
+ int GetY() {return Ity;}\r
+ BOOL GetCol(BYTE* pCol, DWORD x);\r
+ BOOL SetCol(BYTE* pCol, DWORD x);\r
+};\r
+\r
+/////////////////////////////////////////////////////////////////////\r
+inline\r
+CImageIterator::CImageIterator(void)\r
+{\r
+ ima = 0;\r
+ IterImage = 0;\r
+ Itx = Ity = 0;\r
+ Stepx = Stepy = 0;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline\r
+CImageIterator::CImageIterator(CxImage *imageImpl): ima(imageImpl)\r
+{\r
+ if (ima) IterImage = ima->GetBits();\r
+ Itx = Ity = 0;\r
+ Stepx = Stepy = 0;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline\r
+CImageIterator::operator CxImage* ()\r
+{\r
+ return ima;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::ItOK ()\r
+{\r
+ if (ima) return ima->IsInside(Itx, Ity);\r
+ else return FALSE;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline void CImageIterator::Reset()\r
+{\r
+ if (ima) IterImage = ima->GetBits();\r
+ else IterImage=0;\r
+ Itx = Ity = 0;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline void CImageIterator::Upset()\r
+{\r
+ Itx = 0;\r
+ Ity = ima->GetHeight()-1;\r
+ IterImage = ima->GetBits() + ima->GetEffWidth()*(ima->GetHeight()-1);\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::NextRow()\r
+{\r
+ if (++Ity >= (int)ima->GetHeight()) return 0;\r
+ IterImage += ima->GetEffWidth();\r
+ return 1;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::PrevRow()\r
+{\r
+ if (--Ity < 0) return 0;\r
+ IterImage -= ima->GetEffWidth();\r
+ return 1;\r
+}\r
+/* AD - for interlace */\r
+inline void CImageIterator::SetY(int y)\r
+{\r
+ if ((y < 0) || (y > (int)ima->GetHeight())) return;\r
+ Ity = y;\r
+ IterImage = ima->GetBits() + ima->GetEffWidth()*y;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline void CImageIterator::SetRow(BYTE *buf, int n)\r
+{\r
+ if (n<0) n = (int)ima->GetEffWidth();\r
+ else n = min(n,(int)ima->GetEffWidth());\r
+\r
+ if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0)) memcpy(IterImage,buf,n);\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline void CImageIterator::GetRow(BYTE *buf, int n)\r
+{\r
+ if ((IterImage!=NULL)&&(buf!=NULL)&&(n>0))\r
+ memcpy(buf,IterImage,min(n,(int)ima->GetEffWidth()));\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BYTE* CImageIterator::GetRow()\r
+{\r
+ return IterImage;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BYTE* CImageIterator::GetRow(int n)\r
+{\r
+ SetY(n);\r
+ return IterImage;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::NextByte()\r
+{\r
+ if (++Itx < (int)ima->GetEffWidth()) return 1;\r
+ else\r
+ if (++Ity < (int)ima->GetHeight()){\r
+ IterImage += ima->GetEffWidth();\r
+ Itx = 0;\r
+ return 1;\r
+ } else\r
+ return 0;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::PrevByte()\r
+{\r
+ if (--Itx >= 0) return 1;\r
+ else\r
+ if (--Ity >= 0){\r
+ IterImage -= ima->GetEffWidth();\r
+ Itx = 0;\r
+ return 1;\r
+ } else\r
+ return 0;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::NextStep()\r
+{\r
+ Itx += Stepx;\r
+ if (Itx < (int)ima->GetEffWidth()) return 1;\r
+ else {\r
+ Ity += Stepy;\r
+ if (Ity < (int)ima->GetHeight()){\r
+ IterImage += ima->GetEffWidth();\r
+ Itx = 0;\r
+ return 1;\r
+ } else\r
+ return 0;\r
+ }\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::PrevStep()\r
+{\r
+ Itx -= Stepx;\r
+ if (Itx >= 0) return 1;\r
+ else { \r
+ Ity -= Stepy;\r
+ if (Ity >= 0 && Ity < (int)ima->GetHeight()) {\r
+ IterImage -= ima->GetEffWidth();\r
+ Itx = 0;\r
+ return 1;\r
+ } else\r
+ return 0;\r
+ }\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::GetCol(BYTE* pCol, DWORD x)\r
+{\r
+ if ((pCol==0)||(ima->GetBpp()<8)||(x>=ima->GetWidth()))\r
+ return 0;\r
+ DWORD h = ima->GetHeight();\r
+ //DWORD line = ima->GetEffWidth();\r
+ BYTE bytes = (BYTE)(ima->GetBpp()>>3);\r
+ BYTE* pSrc;\r
+ for (DWORD y=0;y<h;y++){\r
+ pSrc = ima->GetBits(y) + x*bytes;\r
+ for (BYTE w=0;w<bytes;w++){\r
+ *pCol++=*pSrc++;\r
+ }\r
+ }\r
+ return 1;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+inline BOOL CImageIterator::SetCol(BYTE* pCol, DWORD x)\r
+{\r
+ if ((pCol==0)||(ima->GetBpp()<8)||(x>=ima->GetWidth()))\r
+ return 0;\r
+ DWORD h = ima->GetHeight();\r
+ //DWORD line = ima->GetEffWidth();\r
+ BYTE bytes = (BYTE)(ima->GetBpp()>>3);\r
+ BYTE* pSrc;\r
+ for (DWORD y=0;y<h;y++){\r
+ pSrc = ima->GetBits(y) + x*bytes;\r
+ for (BYTE w=0;w<bytes;w++){\r
+ *pSrc++=*pCol++;\r
+ }\r
+ }\r
+ return 1;\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximajas.cpp\r
+ * Purpose: Platform Independent JasPer Image Class Loader and Writer\r
+ * 12/Apr/2003 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximajas.h"\r
+\r
+#if CXIMAGE_SUPPORT_JASPER\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageJAS::Decode(CxFile *hFile, DWORD imagetype)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ jas_image_t *image=0;\r
+ jas_stream_t *in=0;\r
+ jas_matrix_t **bufs=0;\r
+ long i,error=0;\r
+ int fmt;\r
+ //jas_setdbglevel(0);\r
+\r
+ cx_try\r
+ {\r
+ if (jas_init())\r
+ cx_throw("cannot initialize jasper");\r
+\r
+ in = jas_stream_fdopen(0, "rb");\r
+ if (!in)\r
+ cx_throw("error: cannot open standard input");\r
+\r
+ CxFileJas src(hFile,in);\r
+\r
+ fmt = jas_image_getfmt(in);\r
+ if (fmt<0)\r
+ cx_throw("error: unknowm format");\r
+\r
+ image = jas_image_decode(in, fmt, 0);\r
+ if (!image){\r
+ fmt = -1;\r
+ cx_throw("error: cannot load image data");\r
+ }\r
+\r
+ char szfmt[4];\r
+ *szfmt = '\0';\r
+ strncpy(szfmt,jas_image_fmttostr(fmt),3);\r
+ szfmt[3] = '\0';\r
+\r
+ fmt = -1;\r
+#if CXIMAGE_SUPPORT_JP2\r
+ if (strcmp(szfmt,"jp2")==0) fmt = CXIMAGE_FORMAT_JP2;\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPC\r
+ if (strcmp(szfmt,"jpc")==0) fmt = CXIMAGE_FORMAT_JPC;\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAS\r
+ if (strcmp(szfmt,"ras")==0) fmt = CXIMAGE_FORMAT_RAS;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNM\r
+ if (strcmp(szfmt,"pnm")==0) fmt = CXIMAGE_FORMAT_PNM;\r
+#endif\r
+#if CXIMAGE_SUPPORT_PGX\r
+ if (strcmp(szfmt,"pgx")==0) fmt = CXIMAGE_FORMAT_PGX;\r
+#endif\r
+\r
+ //if (fmt<0)\r
+ // cx_throw("error: unknowm format");\r
+\r
+ long x,y,w,h,depth,cmptno;\r
+\r
+ w = jas_image_cmptwidth(image,0);\r
+ h = jas_image_cmptheight(image,0);\r
+ depth = jas_image_cmptprec(image,0);\r
+\r
+ if (info.nEscape == -1){\r
+ head.biWidth = w;\r
+ head.biHeight= h;\r
+ info.dwType = fmt<0 ? 0 : fmt;\r
+ cx_throw("output dimensions returned");\r
+ }\r
+\r
+ if (image->numcmpts_ > 64 || image->numcmpts_ < 0)\r
+ cx_throw("error: too many components");\r
+\r
+ // <LD> 01/Jan/2005: Always force conversion to sRGB. Seems to be required for many types of JPEG2000 file.\r
+ // if (depth!=1 && depth!=4 && depth!=8)\r
+ if (image->numcmpts_>=3 && depth <=8)\r
+ {\r
+ jas_image_t *newimage;\r
+ jas_cmprof_t *outprof;\r
+ //jas_eprintf("forcing conversion to sRGB\n");\r
+ outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB);\r
+ if (!outprof) {\r
+ cx_throw("cannot create sRGB profile");\r
+ }\r
+ newimage = jas_image_chclrspc(image, outprof, JAS_CMXFORM_INTENT_PER);\r
+ if (!newimage) {\r
+ jas_cmprof_destroy(outprof); // <LD> 01/Jan/2005: Destroy color profile on error.\r
+ cx_throw("cannot convert to sRGB");\r
+ }\r
+ jas_image_destroy(image);\r
+ jas_cmprof_destroy(outprof);\r
+ image = newimage;\r
+ }\r
+\r
+ bufs = (jas_matrix_t **)calloc(image->numcmpts_, sizeof(jas_matrix_t**));\r
+ for (i = 0; i < image->numcmpts_; ++i) {\r
+ bufs[i] = jas_matrix_create(1, w);\r
+ if (!bufs[i]) {\r
+ cx_throw("error: cannot allocate memory");\r
+ }\r
+ }\r
+\r
+ int nshift = (depth>8) ? (depth-8) : 0;\r
+\r
+ if (image->numcmpts_==3 &&\r
+ image->cmpts_[0]->width_ == image->cmpts_[1]->width_ &&\r
+ image->cmpts_[1]->width_ == image->cmpts_[2]->width_ &&\r
+ image->cmpts_[0]->height_ == image->cmpts_[1]->height_ &&\r
+ image->cmpts_[1]->height_ == image->cmpts_[2]->height_ &&\r
+ image->cmpts_[0]->prec_ == image->cmpts_[1]->prec_ &&\r
+ image->cmpts_[1]->prec_ == image->cmpts_[2]->prec_ )\r
+ {\r
+\r
+ if(!Create(w,h,24,fmt))\r
+ cx_throw("");\r
+\r
+ RGBQUAD c;\r
+ for (y=0; y<h; y++) {\r
+ for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {\r
+ jas_image_readcmpt(image, cmptno, 0, y, w, 1, bufs[cmptno]);\r
+ }\r
+\r
+ for (x=0; x<w; x++){\r
+ c.rgbRed = (BYTE)((jas_matrix_getv(bufs[0], x)>>nshift));\r
+ c.rgbGreen = (BYTE)((jas_matrix_getv(bufs[1], x)>>nshift));\r
+ c.rgbBlue = (BYTE)((jas_matrix_getv(bufs[2], x)>>nshift));\r
+ SetPixelColor(x,h-1-y,c);\r
+ }\r
+ }\r
+ } else {\r
+ info.nNumFrames = image->numcmpts_;\r
+ if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)){\r
+ cx_throw("wrong frame!");\r
+ }\r
+ for (cmptno=0; cmptno<=info.nFrame; cmptno++) {\r
+ w = jas_image_cmptwidth(image,cmptno);\r
+ h = jas_image_cmptheight(image,cmptno);\r
+ depth = jas_image_cmptprec(image,cmptno);\r
+ if (depth>8) depth=8;\r
+ if(!Create(w,h,depth,imagetype))\r
+ cx_throw("");\r
+ SetGrayPalette();\r
+ for (y=0; y<h; y++) {\r
+ jas_image_readcmpt(image, cmptno, 0, y, w, 1, bufs[0]);\r
+ for (x=0; x<w; x++){\r
+ SetPixelIndex(x,h-1-y,(BYTE)((jas_matrix_getv(bufs[0], x)>>nshift)));\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (info.nEscape == -1 && fmt>0){\r
+ error = 0;\r
+ } else {\r
+ error = 1;\r
+ }\r
+ }\r
+\r
+ if (bufs) {\r
+ for (i = 0; i < image->numcmpts_; ++i){ if (bufs[i]) jas_matrix_destroy(bufs[i]);}\r
+ free(bufs);\r
+ }\r
+ jas_cleanup();\r
+ if (image) jas_image_destroy(image);\r
+ if (in) jas_stream_close(in);\r
+ return (error==0);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageJAS::Encode(CxFile * hFile, DWORD imagetype)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ if (head.biClrUsed!=0 && !IsGrayScale()){\r
+ strcpy(info.szLastError,"JasPer can save only RGB or GrayScale images");\r
+ return false;\r
+ }\r
+\r
+ jas_image_t *image=0;\r
+ jas_stream_t *out=0;\r
+ jas_matrix_t *cmpts[3];\r
+ long x,y,yflip,error=0;\r
+ uint_fast16_t cmptno, numcmpts=0;\r
+ jas_image_cmptparm_t cmptparms[3], *cmptparm;\r
+\r
+ cx_try {\r
+\r
+ if (jas_init())\r
+ cx_throw("cannot initialize jasper");\r
+\r
+ out = jas_stream_fdopen(0, "wb");\r
+ if (!out)\r
+ cx_throw("error: cannot open standard output");\r
+\r
+ CxFileJas src(hFile,out);\r
+\r
+ numcmpts = head.biClrUsed==0 ? 3 : 1;\r
+\r
+ for (cmptno = 0, cmptparm = cmptparms; cmptno < numcmpts; ++cmptno, ++cmptparm) {\r
+ cmptparm->tlx = 0;\r
+ cmptparm->tly = 0;\r
+ cmptparm->hstep = 1;\r
+ cmptparm->vstep = 1;\r
+ cmptparm->width = head.biWidth;\r
+ cmptparm->height = head.biHeight;\r
+ cmptparm->prec = 8;\r
+ cmptparm->sgnd = false;\r
+ }\r
+\r
+ /* Create image object. */\r
+ image = jas_image_create(numcmpts, cmptparms, JAS_CLRSPC_UNKNOWN);\r
+ if (!image)\r
+ cx_throw("error : jas_image_create");\r
+\r
+ if (numcmpts == 3) {\r
+ jas_image_setclrspc(image, JAS_CLRSPC_SRGB);\r
+ jas_image_setcmpttype(image, 0,\r
+ JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));\r
+ jas_image_setcmpttype(image, 1,\r
+ JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));\r
+ jas_image_setcmpttype(image, 2,\r
+ JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));\r
+ } else {\r
+ jas_image_setclrspc(image, JAS_CLRSPC_SGRAY);\r
+ jas_image_setcmpttype(image, 0,\r
+ JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));\r
+ }\r
+\r
+\r
+ for (x = 0; x < numcmpts; ++x) { cmpts[x] = 0; }\r
+ /* Create temporary matrices to hold component data. */\r
+ for (x = 0; x < numcmpts; ++x) {\r
+ cmpts[x] = jas_matrix_create(1, head.biWidth);\r
+ if (!cmpts[x]) {\r
+ cx_throw("error : can't allocate memory");\r
+ }\r
+ }\r
+\r
+ RGBQUAD c;\r
+ for (y = 0; y < head.biHeight; ++y) {\r
+ for (x = 0; x < head.biWidth; ++x) {\r
+ if (head.biClrUsed==0){\r
+ c = GetPixelColor(x,y);\r
+ jas_matrix_setv(cmpts[0], x, c.rgbRed);\r
+ jas_matrix_setv(cmpts[1], x, c.rgbGreen);\r
+ jas_matrix_setv(cmpts[2], x, c.rgbBlue);\r
+ } else {\r
+ jas_matrix_setv(cmpts[0], x, GetPixelIndex(x,y));\r
+ }\r
+ }\r
+ yflip = head.biHeight - 1 - y;\r
+ for (cmptno = 0; cmptno < numcmpts; ++cmptno) {\r
+ if (jas_image_writecmpt(image, cmptno, 0, yflip, head.biWidth, 1, cmpts[cmptno])) {\r
+ cx_throw("error : jas_image_writecmpt");\r
+ }\r
+ }\r
+ }\r
+\r
+ char szfmt[4];\r
+ *szfmt = '\0';\r
+#if CXIMAGE_SUPPORT_JP2\r
+ if (imagetype == CXIMAGE_FORMAT_JP2) strcpy(szfmt,"jp2");\r
+#endif\r
+#if CXIMAGE_SUPPORT_JPC\r
+ if (imagetype == CXIMAGE_FORMAT_JPC) strcpy(szfmt,"jpc");\r
+#endif\r
+#if CXIMAGE_SUPPORT_RAS\r
+ if (imagetype == CXIMAGE_FORMAT_RAS) strcpy(szfmt,"ras");\r
+#endif\r
+#if CXIMAGE_SUPPORT_PNM\r
+ if (imagetype == CXIMAGE_FORMAT_PNM) strcpy(szfmt,"pnm");\r
+#endif\r
+#if CXIMAGE_SUPPORT_PGX\r
+ if (imagetype == CXIMAGE_FORMAT_PGX){\r
+ strcpy(szfmt,"pgx");\r
+ if (head.biClrUsed==0) cx_throw("PGX can save only GrayScale images");\r
+ }\r
+#endif\r
+ int outfmt = jas_image_strtofmt(szfmt);\r
+\r
+ char szoutopts[32];\r
+ sprintf(szoutopts,"rate=%.3f", info.fQuality/100.0f);\r
+\r
+ if (jas_image_encode(image, out, outfmt, szoutopts)) {\r
+ cx_throw("error: cannot encode image");\r
+ }\r
+ jas_stream_flush(out);\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ error = 1;\r
+ }\r
+\r
+ for (x = 0; x < numcmpts; ++x) { if (cmpts[x]) { jas_matrix_destroy(cmpts[x]); } }\r
+ jas_cleanup();\r
+ if (image) jas_image_destroy(image);\r
+ if (out) jas_stream_close(out);\r
+\r
+ return (error==0);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_JASPER\r
+\r
--- /dev/null
+/*\r
+ * File: ximajas.h\r
+ * Purpose: Jasper Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageJAS (c) 12/Apr/2003 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * based on JasPer Copyright (c) 2001-2003 Michael David Adams - All rights reserved.\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaJAS_h)\r
+#define __ximaJAS_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_JASPER\r
+\r
+#include "../jasper/include/jasper/jasper.h"\r
+\r
+class CxImageJAS: public CxImage\r
+{\r
+public:\r
+ CxImageJAS(): CxImage((DWORD)0) {} // <vho> cast to DWORD\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,0);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,0);}\r
+ bool Decode(CxFile * hFile, DWORD imagetype = 0);\r
+ bool Decode(FILE *hFile, DWORD imagetype = 0) { CxIOFile file(hFile); return Decode(&file,imagetype); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile, DWORD imagetype = 0);\r
+ bool Encode(FILE *hFile, DWORD imagetype = 0) { CxIOFile file(hFile); return Encode(&file,imagetype); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+protected:\r
+\r
+ class CxFileJas\r
+ {\r
+ public:\r
+ CxFileJas(CxFile* pFile,jas_stream_t *stream)\r
+ {\r
+ if (stream->obj_) jas_free(stream->obj_);\r
+ stream->obj_ = pFile;\r
+\r
+ // <vho> - cannot set the stream->ops_->functions here,\r
+ // because this overwrites a static structure in the Jasper library.\r
+ // This structure is used by Jasper for internal operations too, e.g. tempfile.\r
+ // However the ops_ pointer in the stream can be overwritten.\r
+\r
+ //stream->ops_->close_ = JasClose;\r
+ //stream->ops_->read_ = JasRead;\r
+ //stream->ops_->seek_ = JasSeek;\r
+ //stream->ops_->write_ = JasWrite;\r
+\r
+ jas_stream_CxFile.close_ = JasClose;\r
+ jas_stream_CxFile.read_ = JasRead;\r
+ jas_stream_CxFile.seek_ = JasSeek;\r
+ jas_stream_CxFile.write_ = JasWrite;\r
+\r
+ stream->ops_ = &jas_stream_CxFile;\r
+\r
+ // <vho> - end\r
+ }\r
+ static int JasRead(jas_stream_obj_t *obj, char *buf, int cnt)\r
+ { return ((CxFile*)obj)->Read(buf,1,cnt); }\r
+ static int JasWrite(jas_stream_obj_t *obj, char *buf, int cnt)\r
+ { return ((CxFile*)obj)->Write(buf,1,cnt); }\r
+ static long JasSeek(jas_stream_obj_t *obj, long offset, int origin)\r
+ { return ((CxFile*)obj)->Seek(offset,origin); }\r
+ static int JasClose(jas_stream_obj_t * /*obj*/)\r
+ { return 1; }\r
+\r
+ // <vho>\r
+private:\r
+ jas_stream_ops_t jas_stream_CxFile;\r
+ // <vho> - end\r
+\r
+ };\r
+\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximajbg.cpp\r
+ * Purpose: Platform Independent JBG Image Class Loader and Writer\r
+ * 18/Aug/2002 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximajbg.h"\r
+\r
+#if CXIMAGE_SUPPORT_JBG\r
+\r
+#include "ximaiter.h"\r
+\r
+#define JBIG_BUFSIZE 8192\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageJBG::Decode(CxFile *hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ struct jbg_dec_state jbig_state;\r
+ unsigned long xmax = 4294967295UL, ymax = 4294967295UL;\r
+ unsigned int len, cnt;\r
+ BYTE *buffer,*p;\r
+ int result;\r
+\r
+ cx_try\r
+ {\r
+ jbg_dec_init(&jbig_state);\r
+ jbg_dec_maxsize(&jbig_state, xmax, ymax);\r
+\r
+ buffer = (BYTE*)malloc(JBIG_BUFSIZE);\r
+ if (!buffer) cx_throw("Sorry, not enough memory available!");\r
+\r
+ result = JBG_EAGAIN;\r
+ do {\r
+ len = hFile->Read(buffer, 1, JBIG_BUFSIZE);\r
+ if (!len) break;\r
+ cnt = 0;\r
+ p = buffer;\r
+ while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) {\r
+ result = jbg_dec_in(&jbig_state, p, len, &cnt);\r
+ p += cnt;\r
+ len -= cnt;\r
+ }\r
+ } while (result == JBG_EAGAIN || result == JBG_EOK);\r
+\r
+ if (hFile->Error())\r
+ cx_throw("Problem while reading input file");\r
+ if (result != JBG_EOK && result != JBG_EOK_INTR)\r
+ cx_throw("Problem with input file"); \r
+\r
+ int w, h, bpp, planes, ew;\r
+\r
+ w = jbg_dec_getwidth(&jbig_state);\r
+ h = jbg_dec_getheight(&jbig_state);\r
+ planes = jbg_dec_getplanes(&jbig_state);\r
+ bpp = (planes+7)>>3;\r
+ ew = (w + 7)>>3;\r
+\r
+ if (info.nEscape == -1){\r
+ head.biWidth = w;\r
+ head.biHeight= h;\r
+ info.dwType = CXIMAGE_FORMAT_JBG;\r
+ cx_throw("output dimensions returned");\r
+ }\r
+\r
+ switch (planes){\r
+ case 1:\r
+ {\r
+ BYTE* binary_image = jbg_dec_getimage(&jbig_state, 0);\r
+\r
+ if (!Create(w,h,1,CXIMAGE_FORMAT_JBG))\r
+ cx_throw("");\r
+\r
+ SetPaletteColor(0,255,255,255);\r
+ SetPaletteColor(1,0,0,0);\r
+\r
+ CImageIterator iter(this);\r
+ iter.Upset();\r
+ for (int i=0;i<h;i++){\r
+ iter.SetRow(binary_image+i*ew,ew);\r
+ iter.PrevRow();\r
+ }\r
+\r
+ break;\r
+ }\r
+ default:\r
+ cx_throw("cannot decode images with more than 1 plane");\r
+ }\r
+\r
+ jbg_dec_free(&jbig_state);\r
+ free(buffer);\r
+\r
+ } cx_catch {\r
+ jbg_dec_free(&jbig_state);\r
+ if (buffer) free(buffer);\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_JBG) return true;\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageJBG::Encode(CxFile * hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ if (head.biBitCount != 1){\r
+ strcpy(info.szLastError,"JBG can save only 1-bpp images");\r
+ return false;\r
+ }\r
+\r
+ int w, h, bpp, planes, ew, i, j, x, y;\r
+\r
+ w = head.biWidth;\r
+ h = head.biHeight;\r
+ planes = 1;\r
+ bpp = (planes+7)>>3;\r
+ ew = (w + 7)>>3;\r
+\r
+ BYTE mask;\r
+ RGBQUAD *rgb = GetPalette();\r
+ if (CompareColors(&rgb[0],&rgb[1])<0) mask=255; else mask=0;\r
+\r
+ BYTE *buffer = (BYTE*)malloc(ew*h*2);\r
+ if (!buffer) {\r
+ strcpy(info.szLastError,"Sorry, not enough memory available!");\r
+ return false;\r
+ }\r
+\r
+ for (y=0; y<h; y++){\r
+ i= y*ew;\r
+ j= (h-y-1)*info.dwEffWidth;\r
+ for (x=0; x<ew; x++){\r
+ buffer[i + x]=info.pImage[j + x]^mask;\r
+ }\r
+ }\r
+\r
+ struct jbg_enc_state jbig_state;\r
+ jbg_enc_init(&jbig_state, w, h, planes, &buffer, jbig_data_out, hFile);\r
+\r
+ //jbg_enc_layers(&jbig_state, 2);\r
+ //jbg_enc_lrlmax(&jbig_state, 800, 600);\r
+\r
+ // Specify a few other options (each is ignored if negative)\r
+ int dl = -1, dh = -1, d = -1, l0 = -1, mx = -1;\r
+ int options = JBG_TPDON | JBG_TPBON | JBG_DPON;\r
+ int order = JBG_ILEAVE | JBG_SMID;\r
+ jbg_enc_lrange(&jbig_state, dl, dh);\r
+ jbg_enc_options(&jbig_state, order, options, l0, mx, -1);\r
+\r
+ // now encode everything and send it to data_out()\r
+ jbg_enc_out(&jbig_state);\r
+\r
+ // give encoder a chance to free its temporary data structures\r
+ jbg_enc_free(&jbig_state);\r
+\r
+ free(buffer);\r
+\r
+ if (hFile->Error()){\r
+ strcpy(info.szLastError,"Problem while writing JBG file");\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_JBG\r
+\r
--- /dev/null
+/*\r
+ * File: ximajbg.h\r
+ * Purpose: JBG Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageJBG (c) 18/Aug/2002 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * based on LIBJBG Copyright (c) 2002, Markus Kuhn - All rights reserved.\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaJBG_h)\r
+#define __ximaJBG_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_JBG\r
+\r
+extern "C" {\r
+#include "../jbig/jbig.h"\r
+};\r
+\r
+class CxImageJBG: public CxImage\r
+{\r
+public:\r
+ CxImageJBG(): CxImage(CXIMAGE_FORMAT_JBG) {}\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JBG);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JBG);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+protected:\r
+ static void jbig_data_out(BYTE *buffer, unsigned int len, void *file)\r
+ {((CxFile*)file)->Write(buffer,len,1);}\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximajpg.cpp\r
+ * Purpose: Platform Independent JPEG Image Class Loader and Writer\r
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+ \r
+#include "ximajpg.h"\r
+\r
+#if CXIMAGE_SUPPORT_JPG\r
+\r
+#include "../jpeg/jmorecfg.h"\r
+\r
+#include "ximaiter.h"\r
+ \r
+#include <setjmp.h>\r
+\r
+struct jpg_error_mgr {\r
+ struct jpeg_error_mgr pub; /* "public" fields */\r
+ jmp_buf setjmp_buffer; /* for return to caller */\r
+ char* buffer; /* error message <CSC>*/\r
+};\r
+typedef jpg_error_mgr *jpg_error_ptr;\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Here's the routine that will replace the standard error_exit method:\r
+////////////////////////////////////////////////////////////////////////////////\r
+static void\r
+ima_jpeg_error_exit (j_common_ptr cinfo)\r
+{\r
+ /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */\r
+ jpg_error_ptr myerr = (jpg_error_ptr) cinfo->err;\r
+ /* Create the message */\r
+ myerr->pub.format_message (cinfo, myerr->buffer);\r
+ /* Send it to stderr, adding a newline */\r
+ /* Return control to the setjmp point */\r
+ longjmp(myerr->setjmp_buffer, 1);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImageJPG::CxImageJPG(): CxImage(CXIMAGE_FORMAT_JPG)\r
+{\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+ m_exif = NULL;\r
+ memset(&m_exifinfo, 0, sizeof(EXIFINFO));\r
+#endif\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImageJPG::~CxImageJPG()\r
+{\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+ if (m_exif) delete m_exif;\r
+#endif\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+bool CxImageJPG::DecodeExif(CxFile * hFile)\r
+{\r
+ m_exif = new CxExifInfo(&m_exifinfo);\r
+ if (m_exif){\r
+ long pos=hFile->Tell();\r
+ m_exif->DecodeExif(hFile);\r
+ hFile->Seek(pos,SEEK_SET);\r
+ return m_exif->m_exifinfo->IsExif;\r
+ } else {\r
+ return false;\r
+ }\r
+}\r
+#endif //CXIMAGEJPG_SUPPORT_EXIF\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageJPG::Decode(CxFile * hFile)\r
+{\r
+\r
+ bool is_exif = false;\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+ is_exif = DecodeExif(hFile);\r
+#endif\r
+\r
+ CImageIterator iter(this);\r
+ /* This struct contains the JPEG decompression parameters and pointers to\r
+ * working space (which is allocated as needed by the JPEG library).\r
+ */\r
+ struct jpeg_decompress_struct cinfo;\r
+ /* We use our private extension JPEG error handler. <CSC> */\r
+ struct jpg_error_mgr jerr;\r
+ jerr.buffer=info.szLastError;\r
+ /* More stuff */\r
+ JSAMPARRAY buffer; /* Output row buffer */\r
+ int row_stride; /* physical row width in output buffer */\r
+\r
+ /* In this example we want to open the input file before doing anything else,\r
+ * so that the setjmp() error recovery below can assume the file is open.\r
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that\r
+ * requires it in order to read binary files.\r
+ */\r
+\r
+ /* Step 1: allocate and initialize JPEG decompression object */\r
+ /* We set up the normal JPEG error routines, then override error_exit. */\r
+ cinfo.err = jpeg_std_error(&jerr.pub);\r
+ jerr.pub.error_exit = ima_jpeg_error_exit;\r
+\r
+ /* Establish the setjmp return context for my_error_exit to use. */\r
+ if (setjmp(jerr.setjmp_buffer)) {\r
+ /* If we get here, the JPEG code has signaled an error.\r
+ * We need to clean up the JPEG object, close the input file, and return.\r
+ */\r
+ jpeg_destroy_decompress(&cinfo);\r
+ return 0;\r
+ }\r
+ /* Now we can initialize the JPEG decompression object. */\r
+ jpeg_create_decompress(&cinfo);\r
+\r
+ /* Step 2: specify data source (eg, a file) */\r
+ //jpeg_stdio_src(&cinfo, infile);\r
+ CxFileJpg src(hFile);\r
+ cinfo.src = &src;\r
+\r
+ /* Step 3: read file parameters with jpeg_read_header() */\r
+ (void) jpeg_read_header(&cinfo, TRUE);\r
+\r
+ /* Step 4 <chupeev> handle decoder options*/\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_GRAYSCALE) != 0)\r
+ cinfo.out_color_space = JCS_GRAYSCALE;\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_QUANTIZE) != 0) {\r
+ cinfo.quantize_colors = TRUE;\r
+ cinfo.desired_number_of_colors = GetJpegQuality();\r
+ }\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_DITHER) != 0)\r
+ cinfo.dither_mode = m_nDither;\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_ONEPASS) != 0)\r
+ cinfo.two_pass_quantize = FALSE;\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & DECODE_NOSMOOTH) != 0)\r
+ cinfo.do_fancy_upsampling = FALSE;\r
+\r
+//<DP>: Load true color images as RGB (no quantize) \r
+/* Step 4: set parameters for decompression */\r
+/* if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) {\r
+ * cinfo.quantize_colors = TRUE;\r
+ * cinfo.desired_number_of_colors = 128;\r
+ *}\r
+ */ //</DP>\r
+\r
+ // Set the scale <ignacio>\r
+ cinfo.scale_denom = GetJpegScale();\r
+\r
+ // Borrowed the idea from GIF implementation <ignacio>\r
+ if (info.nEscape == -1) {\r
+ // Return output dimensions only\r
+ jpeg_calc_output_dimensions(&cinfo);\r
+ head.biWidth = cinfo.output_width;\r
+ head.biHeight = cinfo.output_height;\r
+ info.dwType = CXIMAGE_FORMAT_JPG;\r
+ jpeg_destroy_decompress(&cinfo);\r
+ return true;\r
+ }\r
+\r
+ /* Step 5: Start decompressor */\r
+ jpeg_start_decompress(&cinfo);\r
+\r
+ /* We may need to do some setup of our own at this point before reading\r
+ * the data. After jpeg_start_decompress() we have the correct scaled\r
+ * output image dimensions available, as well as the output colormap\r
+ * if we asked for color quantization.\r
+ */\r
+ //Create the image using output dimensions <ignacio>\r
+ //Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);\r
+ Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG);\r
+\r
+ if (!pDib) longjmp(jerr.setjmp_buffer, 1); //<DP> check if the image has been created\r
+\r
+ if (is_exif){\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+ if ((m_exifinfo.Xresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0))\r
+ SetXDPI((long)(m_exifinfo.Xresolution/m_exifinfo.ResolutionUnit));\r
+ if ((m_exifinfo.Yresolution != 0.0) && (m_exifinfo.ResolutionUnit != 0))\r
+ SetYDPI((long)(m_exifinfo.Yresolution/m_exifinfo.ResolutionUnit));\r
+#endif\r
+ } else {\r
+ switch (cinfo.density_unit) {\r
+ case 0: // [andy] fix for aspect ratio...\r
+ if((cinfo.Y_density > 0) && (cinfo.X_density > 0)){\r
+ SetYDPI((long)(GetXDPI()*(float(cinfo.Y_density)/float(cinfo.X_density))));\r
+ }\r
+ break;\r
+ case 2: // [andy] fix: cinfo.X/Y_density is pixels per centimeter\r
+ SetXDPI((long)floor(cinfo.X_density * 2.54 + 0.5));\r
+ SetYDPI((long)floor(cinfo.Y_density * 2.54 + 0.5));\r
+ break;\r
+ default:\r
+ SetXDPI(cinfo.X_density);\r
+ SetYDPI(cinfo.Y_density);\r
+ }\r
+ }\r
+\r
+ if (cinfo.out_color_space==JCS_GRAYSCALE){\r
+ SetGrayPalette();\r
+ head.biClrUsed =256;\r
+ } else {\r
+ if (cinfo.quantize_colors){\r
+ SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]);\r
+ head.biClrUsed=cinfo.actual_number_of_colors;\r
+ } else {\r
+ head.biClrUsed=0;\r
+ }\r
+ }\r
+\r
+ /* JSAMPLEs per row in output buffer */\r
+ row_stride = cinfo.output_width * cinfo.output_components;\r
+\r
+ /* Make a one-row-high sample array that will go away when done with image */\r
+ buffer = (*cinfo.mem->alloc_sarray)\r
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);\r
+\r
+ /* Step 6: while (scan lines remain to be read) */\r
+ /* jpeg_read_scanlines(...); */\r
+ /* Here we use the library's state variable cinfo.output_scanline as the\r
+ * loop counter, so that we don't have to keep track ourselves.\r
+ */\r
+ iter.Upset();\r
+ while (cinfo.output_scanline < cinfo.output_height) {\r
+\r
+ if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding\r
+ \r
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);\r
+ // info.nProgress = (long)(100*cinfo.output_scanline/cinfo.output_height);\r
+ //<DP> Step 6a: CMYK->RGB */ \r
+ if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){\r
+ BYTE k,*dst,*src;\r
+ dst=iter.GetRow();\r
+ src=buffer[0];\r
+ for(long x3=0,x4=0; x3<(long)info.dwEffWidth && x4<row_stride; x3+=3, x4+=4){\r
+ k=src[x4+3];\r
+ dst[x3] =(BYTE)((k * src[x4+2])/255);\r
+ dst[x3+1]=(BYTE)((k * src[x4+1])/255);\r
+ dst[x3+2]=(BYTE)((k * src[x4+0])/255);\r
+ }\r
+ } else {\r
+ /* Assume put_scanline_someplace wants a pointer and sample count. */\r
+ iter.SetRow(buffer[0], row_stride);\r
+ }\r
+ iter.PrevRow();\r
+ }\r
+\r
+ /* Step 7: Finish decompression */\r
+ (void) jpeg_finish_decompress(&cinfo);\r
+ /* We can ignore the return value since suspension is not possible\r
+ * with the stdio data source.\r
+ */\r
+\r
+ //<DP> Step 7A: Swap red and blue components\r
+ // not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison>\r
+ if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){\r
+ BYTE* r0=GetBits();\r
+ for(long y=0;y<head.biHeight;y++){\r
+ if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding\r
+ RGBtoBGR(r0,3*head.biWidth);\r
+ r0+=info.dwEffWidth;\r
+ }\r
+ }\r
+\r
+ /* Step 8: Release JPEG decompression object */\r
+ /* This is an important step since it will release a good deal of memory. */\r
+ jpeg_destroy_decompress(&cinfo);\r
+\r
+ /* At this point you may want to check to see whether any corrupt-data\r
+ * warnings occurred (test whether jerr.pub.num_warnings is nonzero).\r
+ */\r
+\r
+ /* And we're done! */\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageJPG::Encode(CxFile * hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ if (head.biClrUsed!=0 && !IsGrayScale()){\r
+ strcpy(info.szLastError,"JPEG can save only RGB or GreyScale images");\r
+ return false;\r
+ } \r
+\r
+ // necessary for EXIF, and for roll backs\r
+ long pos=hFile->Tell();\r
+\r
+ /* This struct contains the JPEG compression parameters and pointers to\r
+ * working space (which is allocated as needed by the JPEG library).\r
+ * It is possible to have several such structures, representing multiple\r
+ * compression/decompression processes, in existence at once. We refer\r
+ * to any one struct (and its associated working data) as a "JPEG object".\r
+ */\r
+ struct jpeg_compress_struct cinfo;\r
+ /* This struct represents a JPEG error handler. It is declared separately\r
+ * because applications often want to supply a specialized error handler\r
+ * (see the second half of this file for an example). But here we just\r
+ * take the easy way out and use the standard error handler, which will\r
+ * print a message on stderr and call exit() if compression fails.\r
+ * Note that this struct must live as long as the main JPEG parameter\r
+ * struct, to avoid dangling-pointer problems.\r
+ */\r
+ //struct jpeg_error_mgr jerr;\r
+ /* We use our private extension JPEG error handler. <CSC> */\r
+ struct jpg_error_mgr jerr;\r
+ jerr.buffer=info.szLastError;\r
+ /* More stuff */\r
+ int row_stride; /* physical row width in image buffer */\r
+ JSAMPARRAY buffer; /* Output row buffer */\r
+\r
+ /* Step 1: allocate and initialize JPEG compression object */\r
+ /* We have to set up the error handler first, in case the initialization\r
+ * step fails. (Unlikely, but it could happen if you are out of memory.)\r
+ * This routine fills in the contents of struct jerr, and returns jerr's\r
+ * address which we place into the link field in cinfo.\r
+ */\r
+ //cinfo.err = jpeg_std_error(&jerr); <CSC>\r
+ /* We set up the normal JPEG error routines, then override error_exit. */\r
+ cinfo.err = jpeg_std_error(&jerr.pub);\r
+ jerr.pub.error_exit = ima_jpeg_error_exit;\r
+\r
+ /* Establish the setjmp return context for my_error_exit to use. */\r
+ if (setjmp(jerr.setjmp_buffer)) {\r
+ /* If we get here, the JPEG code has signaled an error.\r
+ * We need to clean up the JPEG object, close the input file, and return.\r
+ */\r
+ strcpy(info.szLastError, jerr.buffer); //<CSC>\r
+ jpeg_destroy_compress(&cinfo);\r
+ return 0;\r
+ }\r
+ \r
+ /* Now we can initialize the JPEG compression object. */\r
+ jpeg_create_compress(&cinfo);\r
+ /* Step 2: specify data destination (eg, a file) */\r
+ /* Note: steps 2 and 3 can be done in either order. */\r
+ /* Here we use the library-supplied code to send compressed data to a\r
+ * stdio stream. You can also write your own code to do something else.\r
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that\r
+ * requires it in order to write binary files.\r
+ */\r
+\r
+ //jpeg_stdio_dest(&cinfo, outfile);\r
+ CxFileJpg dest(hFile);\r
+ cinfo.dest = &dest;\r
+\r
+ /* Step 3: set parameters for compression */\r
+ /* First we supply a description of the input image.\r
+ * Four fields of the cinfo struct must be filled in:\r
+ */\r
+ cinfo.image_width = GetWidth(); // image width and height, in pixels\r
+ cinfo.image_height = GetHeight();\r
+\r
+ if (IsGrayScale()){\r
+ cinfo.input_components = 1; // # of color components per pixel\r
+ cinfo.in_color_space = JCS_GRAYSCALE; /* colorspace of input image */\r
+ } else {\r
+ cinfo.input_components = 3; // # of color components per pixel\r
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */\r
+ }\r
+\r
+ /* Now use the library's routine to set default compression parameters.\r
+ * (You must set at least cinfo.in_color_space before calling this,\r
+ * since the defaults depend on the source color space.)\r
+ */\r
+ jpeg_set_defaults(&cinfo);\r
+ /* Now you can set any non-default parameters you wish to.\r
+ * Here we just illustrate the use of quality (quantization table) scaling:\r
+ */\r
+\r
+//#ifdef C_ARITH_CODING_SUPPORTED\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_ARITHMETIC) != 0)\r
+ cinfo.arith_code = TRUE;\r
+//#endif\r
+\r
+//#ifdef ENTROPY_OPT_SUPPORTED\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_OPTIMIZE) != 0)\r
+ cinfo.optimize_coding = TRUE;\r
+//#endif\r
+\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_GRAYSCALE) != 0)\r
+ jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);\r
+\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SMOOTHING) != 0)\r
+ cinfo.smoothing_factor = m_nSmoothing;\r
+\r
+ jpeg_set_quality(&cinfo, GetJpegQuality(), (GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_BASELINE) != 0);\r
+\r
+//#ifdef C_PROGRESSIVE_SUPPORTED\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_PROGRESSIVE) != 0)\r
+ jpeg_simple_progression(&cinfo);\r
+//#endif\r
+\r
+#ifdef C_LOSSLESS_SUPPORTED\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_LOSSLESS) != 0)\r
+ jpeg_simple_lossless(&cinfo, m_nPredictor, m_nPointTransform);\r
+#endif\r
+\r
+ //SetCodecOption(ENCODE_SUBSAMPLE_444 | GetCodecOption(CXIMAGE_FORMAT_JPG),CXIMAGE_FORMAT_JPG);\r
+\r
+ // 2x2, 1x1, 1x1 (4:1:1) : High (default sub sampling)\r
+ cinfo.comp_info[0].h_samp_factor = 2;\r
+ cinfo.comp_info[0].v_samp_factor = 2;\r
+ cinfo.comp_info[1].h_samp_factor = 1;\r
+ cinfo.comp_info[1].v_samp_factor = 1;\r
+ cinfo.comp_info[2].h_samp_factor = 1;\r
+ cinfo.comp_info[2].v_samp_factor = 1;\r
+\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_422) != 0){\r
+ // 2x1, 1x1, 1x1 (4:2:2) : Medium\r
+ cinfo.comp_info[0].h_samp_factor = 2;\r
+ cinfo.comp_info[0].v_samp_factor = 1;\r
+ cinfo.comp_info[1].h_samp_factor = 1;\r
+ cinfo.comp_info[1].v_samp_factor = 1;\r
+ cinfo.comp_info[2].h_samp_factor = 1;\r
+ cinfo.comp_info[2].v_samp_factor = 1;\r
+ }\r
+\r
+ if ((GetCodecOption(CXIMAGE_FORMAT_JPG) & ENCODE_SUBSAMPLE_444) != 0){\r
+ // 1x1 1x1 1x1 (4:4:4) : None\r
+ cinfo.comp_info[0].h_samp_factor = 1;\r
+ cinfo.comp_info[0].v_samp_factor = 1;\r
+ cinfo.comp_info[1].h_samp_factor = 1;\r
+ cinfo.comp_info[1].v_samp_factor = 1;\r
+ cinfo.comp_info[2].h_samp_factor = 1;\r
+ cinfo.comp_info[2].v_samp_factor = 1;\r
+ }\r
+\r
+ cinfo.density_unit=1;\r
+ cinfo.X_density=(unsigned short)GetXDPI();\r
+ cinfo.Y_density=(unsigned short)GetYDPI();\r
+\r
+ /* Step 4: Start compressor */\r
+ /* TRUE ensures that we will write a complete interchange-JPEG file.\r
+ * Pass TRUE unless you are very sure of what you're doing.\r
+ */\r
+ jpeg_start_compress(&cinfo, TRUE);\r
+\r
+ /* Step 5: while (scan lines remain to be written) */\r
+ /* jpeg_write_scanlines(...); */\r
+ /* Here we use the library's state variable cinfo.next_scanline as the\r
+ * loop counter, so that we don't have to keep track ourselves.\r
+ * To keep things simple, we pass one scanline per call; you can pass\r
+ * more if you wish, though.\r
+ */\r
+ row_stride = info.dwEffWidth; /* JSAMPLEs per row in image_buffer */\r
+\r
+ //<DP> "8+row_stride" fix heap deallocation problem during debug???\r
+ buffer = (*cinfo.mem->alloc_sarray)\r
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, 8+row_stride, 1);\r
+\r
+ CImageIterator iter(this);\r
+\r
+ iter.Upset();\r
+ while (cinfo.next_scanline < cinfo.image_height) {\r
+ // info.nProgress = (long)(100*cinfo.next_scanline/cinfo.image_height);\r
+ iter.GetRow(buffer[0], row_stride);\r
+ // not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison>\r
+ if (head.biClrUsed==0){ // swap R & B for RGB images\r
+ RGBtoBGR(buffer[0], row_stride); // Lance : 1998/09/01 : Bug ID: EXP-2.1.1-9\r
+ }\r
+ iter.PrevRow();\r
+ (void) jpeg_write_scanlines(&cinfo, buffer, 1);\r
+ }\r
+\r
+ /* Step 6: Finish compression */\r
+ jpeg_finish_compress(&cinfo);\r
+\r
+ /* Step 7: release JPEG compression object */\r
+ /* This is an important step since it will release a good deal of memory. */\r
+ jpeg_destroy_compress(&cinfo);\r
+\r
+\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+ if (m_exif && m_exif->m_exifinfo->IsExif){\r
+ // discard useless sections (if any) read from original image\r
+ m_exif->DiscardAllButExif();\r
+ // read new created image, to split the sections\r
+ hFile->Seek(pos,SEEK_SET);\r
+ m_exif->DecodeExif(hFile,EXIF_READ_IMAGE);\r
+ // save back the image, adding EXIF section\r
+ hFile->Seek(pos,SEEK_SET);\r
+ m_exif->EncodeExif(hFile);\r
+ }\r
+#endif\r
+\r
+\r
+ /* And we're done! */\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_JPG\r
+\r
--- /dev/null
+/*\r
+ * File: ximajpg.h\r
+ * Purpose: JPG Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageJPG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes\r
+ *\r
+ * Special thanks to Chris Shearer Cooper for CxFileJpg tips & code\r
+ *\r
+ * EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>\r
+ *\r
+ * original CImageJPG and CImageIterator implementation are:\r
+ * Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>\r
+ *\r
+ * This software is based in part on the work of the Independent JPEG Group.\r
+ * Copyright (C) 1991-1998, Thomas G. Lane.\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaJPEG_h)\r
+#define __ximaJPEG_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_JPG\r
+\r
+#define CXIMAGEJPG_SUPPORT_EXIF 1\r
+\r
+extern "C" {\r
+ #include "../jpeg/jpeglib.h"\r
+ #include "../jpeg/jerror.h"\r
+}\r
+\r
+class DLL_EXP CxImageJPG: public CxImage\r
+{\r
+public:\r
+ CxImageJPG();\r
+ ~CxImageJPG();\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_JPG);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_JPG);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+/*\r
+ * EXIF support based on jhead-1.8 by Matthias Wandel <mwandel(at)rim(dot)net>\r
+ */\r
+\r
+#if CXIMAGEJPG_SUPPORT_EXIF\r
+\r
+#define MAX_COMMENT 1000\r
+#define MAX_SECTIONS 20\r
+\r
+typedef struct tag_ExifInfo {\r
+ char Version [5];\r
+ char CameraMake [32];\r
+ char CameraModel [40];\r
+ char DateTime [20];\r
+ int Height, Width;\r
+ int Orientation;\r
+ int IsColor;\r
+ int Process;\r
+ int FlashUsed;\r
+ float FocalLength;\r
+ float ExposureTime;\r
+ float ApertureFNumber;\r
+ float Distance;\r
+ float CCDWidth;\r
+ float ExposureBias;\r
+ int Whitebalance;\r
+ int MeteringMode;\r
+ int ExposureProgram;\r
+ int ISOequivalent;\r
+ int CompressionLevel;\r
+ float FocalplaneXRes;\r
+ float FocalplaneYRes;\r
+ float FocalplaneUnits;\r
+ float Xresolution;\r
+ float Yresolution;\r
+ float ResolutionUnit;\r
+ float Brightness;\r
+ char Comments[MAX_COMMENT];\r
+\r
+ unsigned char * ThumbnailPointer; /* Pointer at the thumbnail */\r
+ unsigned ThumbnailSize; /* Size of thumbnail. */\r
+\r
+ bool IsExif;\r
+} EXIFINFO;\r
+\r
+//--------------------------------------------------------------------------\r
+// JPEG markers consist of one or more 0xFF bytes, followed by a marker\r
+// code byte (which is not an FF). Here are the marker codes of interest\r
+// in this program. (See jdmarker.c for a more complete list.)\r
+//--------------------------------------------------------------------------\r
+\r
+#define M_SOF0 0xC0 // Start Of Frame N\r
+#define M_SOF1 0xC1 // N indicates which compression process\r
+#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use\r
+#define M_SOF3 0xC3\r
+#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers\r
+#define M_SOF6 0xC6\r
+#define M_SOF7 0xC7\r
+#define M_SOF9 0xC9\r
+#define M_SOF10 0xCA\r
+#define M_SOF11 0xCB\r
+#define M_SOF13 0xCD\r
+#define M_SOF14 0xCE\r
+#define M_SOF15 0xCF\r
+#define M_SOI 0xD8 // Start Of Image (beginning of datastream)\r
+#define M_EOI 0xD9 // End Of Image (end of datastream)\r
+#define M_SOS 0xDA // Start Of Scan (begins compressed data)\r
+#define M_JFIF 0xE0 // Jfif marker\r
+#define M_EXIF 0xE1 // Exif marker\r
+#define M_COM 0xFE // COMment \r
+\r
+#define PSEUDO_IMAGE_MARKER 0x123; // Extra value.\r
+\r
+#define EXIF_READ_EXIF 0x01\r
+#define EXIF_READ_IMAGE 0x02\r
+#define EXIF_READ_ALL 0x03\r
+\r
+class DLL_EXP CxExifInfo\r
+{\r
+\r
+typedef struct tag_Section_t{\r
+ BYTE* Data;\r
+ int Type;\r
+ unsigned Size;\r
+} Section_t;\r
+\r
+public:\r
+ EXIFINFO* m_exifinfo;\r
+ char m_szLastError[256];\r
+ CxExifInfo(EXIFINFO* info = NULL);\r
+ ~CxExifInfo();\r
+ bool DecodeExif(CxFile * hFile, int nReadMode = EXIF_READ_EXIF);\r
+ bool EncodeExif(CxFile * hFile);\r
+ void DiscardAllButExif();\r
+protected:\r
+ bool process_EXIF(unsigned char * CharBuf, unsigned int length);\r
+ void process_COM (const BYTE * Data, int length);\r
+ void process_SOFn (const BYTE * Data, int marker);\r
+ int Get16u(void * Short);\r
+ int Get16m(void * Short);\r
+ long Get32s(void * Long);\r
+ unsigned long Get32u(void * Long);\r
+ double ConvertAnyFormat(void * ValuePtr, int Format);\r
+ void* FindSection(int SectionType);\r
+ bool ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,\r
+ EXIFINFO * const pInfo, unsigned char ** const LastExifRefdP, int NestingLevel=0);\r
+ int ExifImageWidth;\r
+ int MotorolaOrder;\r
+ Section_t Sections[MAX_SECTIONS];\r
+ int SectionsRead;\r
+ bool freeinfo;\r
+};\r
+\r
+ CxExifInfo* m_exif;\r
+ EXIFINFO m_exifinfo;\r
+ bool DecodeExif(CxFile * hFile);\r
+ bool DecodeExif(FILE * hFile) { CxIOFile file(hFile); return DecodeExif(&file); }\r
+\r
+#endif //CXIMAGEJPG_SUPPORT_EXIF\r
+\r
+////////////////////////////////////////////////////////////////////////////////////////\r
+////////////////////// C x F i l e J p g ////////////////////////////////\r
+////////////////////////////////////////////////////////////////////////////////////////\r
+\r
+// thanks to Chris Shearer Cooper <cscooper(at)frii(dot)com>\r
+class CxFileJpg : public jpeg_destination_mgr, public jpeg_source_mgr\r
+ {\r
+public:\r
+ enum { eBufSize = 4096 };\r
+\r
+ CxFileJpg(CxFile* pFile)\r
+ {\r
+ m_pFile = pFile;\r
+\r
+ init_destination = InitDestination;\r
+ empty_output_buffer = EmptyOutputBuffer;\r
+ term_destination = TermDestination;\r
+\r
+ init_source = InitSource;\r
+ fill_input_buffer = FillInputBuffer;\r
+ skip_input_data = SkipInputData;\r
+ resync_to_restart = jpeg_resync_to_restart; // use default method\r
+ term_source = TermSource;\r
+ next_input_byte = NULL; //* => next byte to read from buffer \r
+ bytes_in_buffer = 0; //* # of bytes remaining in buffer \r
+\r
+ m_pBuffer = new unsigned char[eBufSize];\r
+ }\r
+ ~CxFileJpg()\r
+ {\r
+ delete [] m_pBuffer;\r
+ }\r
+\r
+ static void InitDestination(j_compress_ptr cinfo)\r
+ {\r
+ CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;\r
+ pDest->next_output_byte = pDest->m_pBuffer;\r
+ pDest->free_in_buffer = eBufSize;\r
+ }\r
+\r
+ static boolean EmptyOutputBuffer(j_compress_ptr cinfo)\r
+ {\r
+ CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;\r
+ if (pDest->m_pFile->Write(pDest->m_pBuffer,1,eBufSize)!=(size_t)eBufSize)\r
+ ERREXIT(cinfo, JERR_FILE_WRITE);\r
+ pDest->next_output_byte = pDest->m_pBuffer;\r
+ pDest->free_in_buffer = eBufSize;\r
+ return TRUE;\r
+ }\r
+\r
+ static void TermDestination(j_compress_ptr cinfo)\r
+ {\r
+ CxFileJpg* pDest = (CxFileJpg*)cinfo->dest;\r
+ size_t datacount = eBufSize - pDest->free_in_buffer;\r
+ /* Write any data remaining in the buffer */\r
+ if (datacount > 0) {\r
+ if (!pDest->m_pFile->Write(pDest->m_pBuffer,1,datacount))\r
+ ERREXIT(cinfo, JERR_FILE_WRITE);\r
+ }\r
+ pDest->m_pFile->Flush();\r
+ /* Make sure we wrote the output file OK */\r
+ if (pDest->m_pFile->Error()) ERREXIT(cinfo, JERR_FILE_WRITE);\r
+ return;\r
+ }\r
+\r
+ static void InitSource(j_decompress_ptr cinfo)\r
+ {\r
+ CxFileJpg* pSource = (CxFileJpg*)cinfo->src;\r
+ pSource->m_bStartOfFile = TRUE;\r
+ }\r
+\r
+ static boolean FillInputBuffer(j_decompress_ptr cinfo)\r
+ {\r
+ size_t nbytes;\r
+ CxFileJpg* pSource = (CxFileJpg*)cinfo->src;\r
+ nbytes = pSource->m_pFile->Read(pSource->m_pBuffer,1,eBufSize);\r
+ if (nbytes <= 0){\r
+ if (pSource->m_bStartOfFile) //* Treat empty input file as fatal error \r
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);\r
+ WARNMS(cinfo, JWRN_JPEG_EOF);\r
+ // Insert a fake EOI marker \r
+ pSource->m_pBuffer[0] = (JOCTET) 0xFF;\r
+ pSource->m_pBuffer[1] = (JOCTET) JPEG_EOI;\r
+ nbytes = 2;\r
+ }\r
+ pSource->next_input_byte = pSource->m_pBuffer;\r
+ pSource->bytes_in_buffer = nbytes;\r
+ pSource->m_bStartOfFile = FALSE;\r
+ return TRUE;\r
+ }\r
+\r
+ static void SkipInputData(j_decompress_ptr cinfo, long num_bytes)\r
+ {\r
+ CxFileJpg* pSource = (CxFileJpg*)cinfo->src;\r
+ if (num_bytes > 0){\r
+ while (num_bytes > (long)pSource->bytes_in_buffer){\r
+ num_bytes -= (long)pSource->bytes_in_buffer;\r
+ FillInputBuffer(cinfo);\r
+ // note we assume that fill_input_buffer will never return FALSE,\r
+ // so suspension need not be handled.\r
+ }\r
+ pSource->next_input_byte += (size_t) num_bytes;\r
+ pSource->bytes_in_buffer -= (size_t) num_bytes;\r
+ }\r
+ }\r
+\r
+ static void TermSource(j_decompress_ptr /*cinfo*/)\r
+ {\r
+ return;\r
+ }\r
+protected:\r
+ CxFile *m_pFile;\r
+ unsigned char *m_pBuffer;\r
+ bool m_bStartOfFile;\r
+};\r
+\r
+public:\r
+ enum CODEC_OPTION\r
+ {\r
+ ENCODE_BASELINE = 0x1,\r
+ ENCODE_ARITHMETIC = 0x2,\r
+ ENCODE_GRAYSCALE = 0x4,\r
+ ENCODE_OPTIMIZE = 0x8,\r
+ ENCODE_PROGRESSIVE = 0x10,\r
+ ENCODE_LOSSLESS = 0x20,\r
+ ENCODE_SMOOTHING = 0x40,\r
+ DECODE_GRAYSCALE = 0x80,\r
+ DECODE_QUANTIZE = 0x100,\r
+ DECODE_DITHER = 0x200,\r
+ DECODE_ONEPASS = 0x400,\r
+ DECODE_NOSMOOTH = 0x800,\r
+ ENCODE_SUBSAMPLE_422 = 0x1000,\r
+ ENCODE_SUBSAMPLE_444 = 0x2000\r
+ }; \r
+\r
+ int m_nPredictor;\r
+ int m_nPointTransform;\r
+ int m_nSmoothing;\r
+ int m_nQuantize;\r
+ J_DITHER_MODE m_nDither;\r
+\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+// xImalpha.cpp : Alpha channel functions\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa AlphaSetMax\r
+ */\r
+BYTE CxImage::AlphaGetMax() const\r
+{\r
+ return info.nAlphaMax;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets global Alpha (opacity) value applied to the whole image,\r
+ * valid only for painting functions.\r
+ * \param nAlphaMax: can be from 0 to 255\r
+ */\r
+void CxImage::AlphaSetMax(BYTE nAlphaMax)\r
+{\r
+ info.nAlphaMax=nAlphaMax;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if the image has a valid alpha channel.\r
+ */\r
+bool CxImage::AlphaIsValid()\r
+{\r
+ return pAlpha!=0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Enables the alpha palette, so the Draw() function changes its behavior.\r
+ */\r
+void CxImage::AlphaPaletteEnable(bool enable)\r
+{\r
+ info.bAlphaPaletteEnabled=enable;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * True if the alpha palette is enabled for painting.\r
+ */\r
+bool CxImage::AlphaPaletteIsEnabled()\r
+{\r
+ return info.bAlphaPaletteEnabled;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the alpha channel to full transparent. AlphaSet(0) has the same effect\r
+ */\r
+void CxImage::AlphaClear()\r
+{\r
+ if (pAlpha) memset(pAlpha,0,head.biWidth * head.biHeight);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the alpha level for the whole image.\r
+ * \param level : from 0 (transparent) to 255 (opaque)\r
+ */\r
+void CxImage::AlphaSet(BYTE level)\r
+{\r
+ if (pAlpha) memset(pAlpha,level,head.biWidth * head.biHeight);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Allocates an empty (opaque) alpha channel.\r
+ */\r
+bool CxImage::AlphaCreate()\r
+{\r
+ if (pAlpha==NULL) {\r
+ pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight);\r
+ if (pAlpha) memset(pAlpha,255,head.biWidth * head.biHeight);\r
+ }\r
+ return (pAlpha!=0);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::AlphaDelete()\r
+{\r
+ if (pAlpha) { free(pAlpha); pAlpha=0; }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::AlphaInvert()\r
+{\r
+ if (pAlpha) {\r
+ BYTE *iSrc=pAlpha;\r
+ long n=head.biHeight*head.biWidth;\r
+ for(long i=0; i < n; i++){\r
+ *iSrc=(BYTE)~(*(iSrc));\r
+ iSrc++;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Imports an existing alpa channel from another image with the same width and height.\r
+ */\r
+bool CxImage::AlphaCopy(CxImage &from)\r
+{\r
+ if (from.pAlpha == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;\r
+ if (pAlpha==NULL) pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight);\r
+ if (pAlpha==NULL) return false;\r
+ memcpy(pAlpha,from.pAlpha,head.biWidth * head.biHeight);\r
+ info.nAlphaMax=from.info.nAlphaMax;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Creates the alpha channel from a gray scale image.\r
+ */\r
+bool CxImage::AlphaSet(CxImage &from)\r
+{\r
+ if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;\r
+ if (pAlpha==NULL) pAlpha = (BYTE*)malloc(head.biWidth * head.biHeight);\r
+ BYTE* src = from.info.pImage;\r
+ BYTE* dst = pAlpha;\r
+ if (src==NULL || dst==NULL) return false;\r
+ for (long y=0; y<head.biHeight; y++){\r
+ memcpy(dst,src,head.biWidth);\r
+ dst += head.biWidth;\r
+ src += from.info.dwEffWidth;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the alpha level for a single pixel \r
+ */\r
+void CxImage::AlphaSet(const long x,const long y,const BYTE level)\r
+{\r
+ if (pAlpha && IsInside(x,y)) pAlpha[x+y*head.biWidth]=level;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Gets the alpha level for a single pixel \r
+ */\r
+BYTE CxImage::AlphaGet(const long x,const long y)\r
+{\r
+ if (pAlpha && IsInside(x,y)) return pAlpha[x+y*head.biWidth];\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns pointer to alpha data for pixel (x,y).\r
+ *\r
+ * \author ***bd*** 2.2004\r
+ */\r
+BYTE* CxImage::AlphaGetPointer(const long x,const long y)\r
+{\r
+ if (pAlpha && IsInside(x,y)) return pAlpha+x+y*head.biWidth;\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Get alpha value without boundscheck (a bit faster). Pixel must be inside the image.\r
+ *\r
+ * \author ***bd*** 2.2004\r
+ */\r
+BYTE CxImage::BlindAlphaGet(const long x,const long y)\r
+{\r
+#ifdef _DEBUG\r
+ if (!IsInside(x,y) || (pAlpha==0))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ return 0;\r
+ #endif\r
+#endif\r
+ return pAlpha[x+y*head.biWidth];\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Resets the alpha palette \r
+ */\r
+void CxImage::AlphaPaletteClear()\r
+{\r
+ RGBQUAD c;\r
+ for(WORD ip=0; ip<head.biClrUsed;ip++){\r
+ c=GetPaletteColor((BYTE)ip);\r
+ c.rgbReserved=0;\r
+ SetPaletteColor((BYTE)ip,c);\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if the image has a valid alpha palette. \r
+ */\r
+bool CxImage::AlphaPaletteIsValid()\r
+{\r
+ RGBQUAD c;\r
+ for(WORD ip=0; ip<head.biClrUsed;ip++){\r
+ c=GetPaletteColor((BYTE)ip);\r
+ if (c.rgbReserved != 0) return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Blends the alpha channel and the alpha palette with the pixels. The result is a 24 bit image.\r
+ * The background color can be selected using SetTransColor().\r
+ */\r
+void CxImage::AlphaStrip()\r
+{\r
+ bool bAlphaPaletteIsValid = AlphaPaletteIsValid();\r
+ bool bAlphaIsValid = AlphaIsValid();\r
+ if (!(bAlphaIsValid || bAlphaPaletteIsValid)) return;\r
+ RGBQUAD c;\r
+ long a, a1;\r
+ if (head.biBitCount==24){\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ c = BlindGetPixelColor(x,y);\r
+ if (bAlphaIsValid) a=(BlindAlphaGet(x,y)*info.nAlphaMax)/255; else a=info.nAlphaMax;\r
+ a1 = 256-a;\r
+ c.rgbBlue = (BYTE)((c.rgbBlue * a + a1 * info.nBkgndColor.rgbBlue)>>8);\r
+ c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8);\r
+ c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8);\r
+ BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ AlphaDelete();\r
+ } else {\r
+ CxImage tmp(head.biWidth,head.biHeight,24);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return;\r
+ }\r
+\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ c = BlindGetPixelColor(x,y);\r
+ if (bAlphaIsValid) a=(BlindAlphaGet(x,y)*info.nAlphaMax)/255; else a=info.nAlphaMax;\r
+ if (bAlphaPaletteIsValid) a=(c.rgbReserved*a)/255;\r
+ a1 = 256-a;\r
+ c.rgbBlue = (BYTE)((c.rgbBlue * a + a1 * info.nBkgndColor.rgbBlue)>>8);\r
+ c.rgbGreen = (BYTE)((c.rgbGreen * a + a1 * info.nBkgndColor.rgbGreen)>>8);\r
+ c.rgbRed = (BYTE)((c.rgbRed * a + a1 * info.nBkgndColor.rgbRed)>>8);\r
+ tmp.BlindSetPixelColor(x,y,c);\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ }\r
+ return;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::AlphaFlip()\r
+{\r
+ if (!pAlpha) return false;\r
+\r
+ BYTE *buff = (BYTE*)malloc(head.biWidth);\r
+ if (!buff) return false;\r
+\r
+ BYTE *iSrc,*iDst;\r
+ iSrc = pAlpha + (head.biHeight-1)*head.biWidth;\r
+ iDst = pAlpha;\r
+ for (long i=0; i<(head.biHeight/2); ++i)\r
+ {\r
+ memcpy(buff, iSrc, head.biWidth);\r
+ memcpy(iSrc, iDst, head.biWidth);\r
+ memcpy(iDst, buff, head.biWidth);\r
+ iSrc-=head.biWidth;\r
+ iDst+=head.biWidth;\r
+ }\r
+\r
+ free(buff);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::AlphaMirror()\r
+{\r
+ if (!pAlpha) return false;\r
+ BYTE* pAlpha2 = (BYTE*)malloc(head.biWidth * head.biHeight);\r
+ if (!pAlpha2) return false;\r
+ BYTE *iSrc,*iDst;\r
+ long wdt=head.biWidth-1;\r
+ iSrc=pAlpha + wdt;\r
+ iDst=pAlpha2;\r
+ for(long y=0; y < head.biHeight; y++){\r
+ for(long x=0; x <= wdt; x++)\r
+ *(iDst+x)=*(iSrc-x);\r
+ iSrc+=head.biWidth;\r
+ iDst+=head.biWidth;\r
+ }\r
+ free(pAlpha);\r
+ pAlpha=pAlpha2;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Exports the alpha channel in a 8bpp grayscale image. \r
+ */\r
+bool CxImage::AlphaSplit(CxImage *dest)\r
+{\r
+ if (!pAlpha || !dest) return false;\r
+\r
+ CxImage tmp(head.biWidth,head.biHeight,8);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ tmp.BlindSetPixelIndex(x,y,pAlpha[x+y*head.biWidth]);\r
+ }\r
+ }\r
+\r
+ tmp.SetGrayPalette();\r
+ dest->Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Exports the alpha palette channel in a 8bpp grayscale image. \r
+ */\r
+bool CxImage::AlphaPaletteSplit(CxImage *dest)\r
+{\r
+ if (!AlphaPaletteIsValid() || !dest) return false;\r
+\r
+ CxImage tmp(head.biWidth,head.biHeight,8);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ tmp.BlindSetPixelIndex(x,y,BlindGetPixelColor(x,y).rgbReserved);\r
+ }\r
+ }\r
+\r
+ tmp.SetGrayPalette();\r
+ dest->Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Merge in the alpha layer the transparent color mask\r
+ * (previously set with SetTransColor or SetTransIndex) \r
+ */\r
+bool CxImage::AlphaFromTransparency()\r
+{\r
+ if (!IsValid() || !IsTransparent())\r
+ return false;\r
+\r
+ AlphaCreate();\r
+\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ if (IsTransparent(x,y)){\r
+ AlphaSet(x,y,0);\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
--- /dev/null
+// xImaLyr.cpp : Layers functions\r
+/* 21/04/2003 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_LAYERS\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * If the object is an internal layer, GetParent return its parent in the hierarchy.\r
+ */\r
+CxImage* CxImage::GetParent() const\r
+{\r
+ return info.pParent;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Number of layers allocated directly by the object.\r
+ */\r
+long CxImage::GetNumLayers() const\r
+{\r
+ return info.nNumLayers;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Creates an empty layer. If position is less than 0, the new layer will be placed in the last position\r
+ */\r
+bool CxImage::LayerCreate(long position)\r
+{\r
+ if ( position < 0 || position > info.nNumLayers ) position = info.nNumLayers;\r
+\r
+ CxImage** ptmp = new CxImage*[info.nNumLayers + 1];\r
+ if (ptmp==0) return false;\r
+\r
+ int i=0;\r
+ for (int n=0; n<info.nNumLayers; n++){\r
+ if (position == n){\r
+ ptmp[n] = new CxImage();\r
+ i=1;\r
+ }\r
+ ptmp[n+i]=ppLayers[n];\r
+ }\r
+ if (i==0) ptmp[info.nNumLayers] = new CxImage();\r
+\r
+ if (ptmp[position]){\r
+ ptmp[position]->info.pParent = this;\r
+ } else {\r
+ free(ptmp);\r
+ return false;\r
+ }\r
+\r
+ info.nNumLayers++;\r
+ delete [] ppLayers;\r
+ ppLayers = ptmp;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Deletes a layer. If position is less than 0, the last layer will be deleted\r
+ */\r
+bool CxImage::LayerDelete(long position)\r
+{\r
+ if ( position >= info.nNumLayers ) return false;\r
+ if ( position < 0) position = info.nNumLayers - 1;\r
+ if ( position < 0) return false;\r
+\r
+ if (info.nNumLayers>1){\r
+\r
+ CxImage** ptmp = new CxImage*[info.nNumLayers - 1];\r
+ if (ptmp==0) return false;\r
+\r
+ int i=0;\r
+ for (int n=0; n<info.nNumLayers; n++){\r
+ if (position == n){\r
+ delete ppLayers[n];\r
+ i=1;\r
+ }\r
+ ptmp[n]=ppLayers[n+i];\r
+ }\r
+\r
+ info.nNumLayers--;\r
+ delete [] ppLayers;\r
+ ppLayers = ptmp;\r
+\r
+ } else {\r
+ delete ppLayers[0];\r
+ delete [] ppLayers;\r
+ ppLayers = 0;\r
+ info.nNumLayers = 0;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::LayerDeleteAll()\r
+{\r
+ if (ppLayers) { \r
+ for(long n=0; n<info.nNumLayers;n++){ delete ppLayers[n]; }\r
+ delete [] ppLayers; ppLayers=0; info.nNumLayers = 0;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns a pointer to a layer. If position is less than 0, the last layer will be returned\r
+ */\r
+CxImage* CxImage::GetLayer(long position)\r
+{\r
+ if ( ppLayers == NULL) return NULL;\r
+ if ( info.nNumLayers == 0) return NULL;\r
+ if ( position >= info.nNumLayers ) return NULL;\r
+ if ( position < 0) position = info.nNumLayers - 1;\r
+ return ppLayers[position];\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_LAYERS\r
--- /dev/null
+/*\r
+ * File: ximamng.cpp\r
+ * Purpose: Platform Independent MNG Image Class Loader and Writer\r
+ * Author: 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximamng.h"\r
+\r
+#if CXIMAGE_SUPPORT_MNG\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// callbacks for the mng decoder:\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// memory allocation; data must be zeroed\r
+static mng_ptr\r
+mymngalloc( mng_uint32 size )\r
+{\r
+ return (mng_ptr)calloc(1, size);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// memory deallocation\r
+static void mymngfree(mng_ptr p, mng_uint32 size)\r
+{\r
+ free(p);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Stream open/close:\r
+// since the user is responsible for opening and closing the file,\r
+// we leave the default implementation open\r
+static mng_bool mymngopenstream(mng_handle mng) { return MNG_TRUE; }\r
+static mng_bool mymngopenstreamwrite(mng_handle mng) { return MNG_TRUE; }\r
+static mng_bool mymngclosestream(mng_handle mng) { return MNG_TRUE; }\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// feed data to the decoder\r
+static mng_bool mymngreadstream(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread)\r
+{\r
+ mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);\r
+ // read the requested amount of data from the file\r
+ *bytesread = mymng->file->Read( buffer, sizeof(BYTE), size);\r
+ return MNG_TRUE;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+static mng_bool mymngwritestream (mng_handle mng, mng_ptr pBuf, mng_uint32 iSize, mng_uint32 *iWritten)\r
+{\r
+ mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);\r
+ // write it\r
+ *iWritten = mymng->file->Write (pBuf, 1, iSize);\r
+ return MNG_TRUE;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// the header's been read. set up the display stuff\r
+static mng_bool mymngprocessheader( mng_handle mng, mng_uint32 width, mng_uint32 height )\r
+{\r
+ // normally the image buffer is allocated here,\r
+ // but in this module we don't know nothing about\r
+ // the final environment.\r
+\r
+ mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);\r
+ \r
+ mymng->width = width;\r
+ mymng->height = height;\r
+ mymng->bpp = 24;\r
+ mymng->effwdt = ((((width * mymng->bpp) + 31) >> 5) << 2);\r
+\r
+ if (mng->bUseBKGD){\r
+ mymng->nBkgndIndex = 0;\r
+ mymng->nBkgndColor.rgbRed = mng->iBGred >> 8;\r
+ mymng->nBkgndColor.rgbGreen =mng->iBGgreen >> 8;\r
+ mymng->nBkgndColor.rgbBlue = mng->iBGblue >> 8;\r
+ }\r
+\r
+ mymng->image = (BYTE*)malloc(height * mymng->effwdt);\r
+\r
+ // tell the mng decoder about our bit-depth choice\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ mng_set_canvasstyle( mng, MNG_CANVAS_RGB8_A8 );\r
+ mymng->alpha = (BYTE*)malloc(height * width);\r
+#else\r
+ mng_set_canvasstyle( mng, MNG_CANVAS_BGR8);\r
+ mymng->alpha = NULL;\r
+#endif\r
+ return MNG_TRUE;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// return a row pointer for the decoder to fill\r
+static mng_ptr mymnggetcanvasline( mng_handle mng, mng_uint32 line )\r
+{\r
+ mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);\r
+ return (mng_ptr)(mymng->image + (mymng->effwdt * (mymng->height - 1 - line)));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// return a row pointer for the decoder to fill for alpha channel\r
+static mng_ptr mymnggetalphaline( mng_handle mng, mng_uint32 line )\r
+{\r
+ mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);\r
+ return (mng_ptr)(mymng->alpha + (mymng->width * (mymng->height - 1 - line)));\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// timer\r
+static mng_uint32 mymnggetticks(mng_handle mng)\r
+{\r
+#ifdef WIN32\r
+ return (mng_uint32)GetTickCount();\r
+#else\r
+ return 0;\r
+#endif\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Refresh: actual frame need to be updated (Invalidate)\r
+static mng_bool mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)\r
+{\r
+// mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);\r
+ return MNG_TRUE;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// interframe delay callback\r
+static mng_bool mymngsettimer(mng_handle mng, mng_uint32 msecs)\r
+{\r
+ mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);\r
+ mymng->delay = msecs; // set the timer for when the decoder wants to be woken\r
+ return MNG_TRUE;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+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)\r
+{\r
+ return mng_cleanup(&mng); //<Arkadiy Olovyannikov>\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+// CxImage members\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImageMNG::CxImageMNG(): CxImage(CXIMAGE_FORMAT_MNG)\r
+{\r
+ hmng = NULL;\r
+ memset(&mnginfo,0,sizeof(mngstuff));\r
+ mnginfo.nBkgndIndex = -1;\r
+ mnginfo.speed = 1.0f;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImageMNG::~CxImageMNG()\r
+{\r
+ // cleanup and return\r
+ if (mnginfo.thread){ //close the animation thread\r
+ mnginfo.animation_enabled=0;\r
+ ResumeThread(mnginfo.thread);\r
+ WaitForSingleObject(mnginfo.thread,500);\r
+ CloseHandle(mnginfo.thread);\r
+ }\r
+ // free objects\r
+ if (mnginfo.image) free(mnginfo.image);\r
+ if (mnginfo.alpha) free(mnginfo.alpha);\r
+ if (hmng) mng_cleanup(&hmng); //be sure it's not needed any more. (active timers ?)\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageMNG::SetCallbacks(mng_handle mng)\r
+{\r
+ // set the callbacks\r
+ mng_setcb_errorproc(mng, mymngerror);\r
+ mng_setcb_openstream(mng, mymngopenstream);\r
+ mng_setcb_closestream(mng, mymngclosestream);\r
+ mng_setcb_readdata(mng, mymngreadstream);\r
+ mng_setcb_processheader(mng, mymngprocessheader);\r
+ mng_setcb_getcanvasline(mng, mymnggetcanvasline);\r
+ mng_setcb_refresh(mng, mymngrefresh);\r
+ mng_setcb_gettickcount(mng, mymnggetticks);\r
+ mng_setcb_settimer(mng, mymngsettimer);\r
+ mng_setcb_refresh(mng, mymngrefresh);\r
+ mng_setcb_getalphaline(mng, mymnggetalphaline);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// can't use the CxImage implementation because it looses mnginfo\r
+bool CxImageMNG::Load(const TCHAR * imageFileName){\r
+ FILE* hFile; //file handle to read the image\r
+#ifdef WIN32\r
+ if ((hFile=_tfopen(imageFileName,_T("rb")))==NULL) return false; // For UNICODE support\r
+#else\r
+ if ((hFile=fopen(imageFileName,"rb"))==NULL) return false;\r
+#endif\r
+ bool bOK = Decode(hFile);\r
+ fclose(hFile);\r
+ return bOK;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageMNG::Decode(CxFile *hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ cx_try\r
+ {\r
+ // set up the mng decoder for our stream\r
+ hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL);\r
+ if (hmng == NULL) cx_throw("could not initialize libmng"); \r
+\r
+ // set the file we want to play\r
+ mnginfo.file = hFile;\r
+\r
+ // Set the colorprofile, lcms uses this:\r
+ mng_set_srgb(hmng, MNG_TRUE );\r
+ // Set white as background color:\r
+ WORD Red,Green,Blue;\r
+ Red = Green = Blue = (255 << 8) + 255;\r
+ mng_set_bgcolor(hmng, Red, Green, Blue );\r
+ // If PNG Background is available, use it:\r
+ mng_set_usebkgd(hmng, MNG_TRUE );\r
+\r
+ // No need to store chunks:\r
+ mng_set_storechunks(hmng, MNG_FALSE);\r
+ // No need to wait: straight reading\r
+ mng_set_suspensionmode(hmng, MNG_FALSE);\r
+\r
+ SetCallbacks(hmng);\r
+\r
+ mng_datap pData = (mng_datap)hmng;\r
+\r
+ // read in the image\r
+ info.nNumFrames=0;\r
+ int retval=MNG_NOERROR;\r
+\r
+ retval = mng_readdisplay(hmng);\r
+\r
+ if (retval != MNG_NOERROR && retval != MNG_NEEDTIMERWAIT){\r
+ mng_store_error(hmng,retval,0,0);\r
+ if (hmng->zErrortext){\r
+ cx_throw(hmng->zErrortext);\r
+ } else {\r
+ cx_throw("Error in MNG file");\r
+ }\r
+ }\r
+\r
+ if (info.nEscape == -1) {\r
+ // Return output dimensions only\r
+ head.biWidth = hmng->iWidth;\r
+ head.biHeight = hmng->iHeight;\r
+ info.dwType = CXIMAGE_FORMAT_MNG;\r
+ return true;\r
+ }\r
+\r
+ // read all\r
+ while(pData->bReading){\r
+ retval = mng_display_resume(hmng);\r
+ info.nNumFrames++;\r
+ }\r
+\r
+ // single frame check:\r
+ if (retval != MNG_NEEDTIMERWAIT){\r
+ info.nNumFrames--;\r
+ } else {\r
+ mnginfo.animation=1;\r
+ }\r
+\r
+ if (info.nNumFrames<=0) info.nNumFrames=1;\r
+\r
+ if (mnginfo.animation_enabled==0){\r
+ // select the frame\r
+ if (info.nFrame>=0 && info.nFrame<info.nNumFrames){\r
+ for (int n=0;n<info.nFrame;n++) mng_display_resume(hmng);\r
+ } else cx_throw("Error: frame not present in MNG file");\r
+ }\r
+\r
+ if (mnginfo.nBkgndIndex >= 0){\r
+ info.nBkgndIndex = mnginfo.nBkgndIndex;\r
+ info.nBkgndColor.rgbRed = mnginfo.nBkgndColor.rgbRed;\r
+ info.nBkgndColor.rgbGreen = mnginfo.nBkgndColor.rgbGreen;\r
+ info.nBkgndColor.rgbBlue = mnginfo.nBkgndColor.rgbBlue;\r
+ }\r
+\r
+ //store the newly created image\r
+ if (Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG)){\r
+ memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ SwapRGB2BGR();\r
+ AlphaCreate();\r
+ if(AlphaIsValid() && mnginfo.alpha){\r
+ memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height);\r
+ }\r
+#endif\r
+ } else cx_throw("CxImageMNG::Decode cannot create image");\r
+\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageMNG::Encode(CxFile *hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ cx_try\r
+ {\r
+ if (head.biClrUsed != 0) cx_throw("MNG encoder can save only RGB images");\r
+ // set the file we want to play\r
+ mnginfo.file = hFile;\r
+ mnginfo.bpp = head.biBitCount;\r
+ mnginfo.effwdt = info.dwEffWidth;\r
+ mnginfo.height = head.biHeight;\r
+ mnginfo.width = head.biWidth;\r
+\r
+ mnginfo.image = (BYTE*)malloc(head.biSizeImage);\r
+ if (mnginfo.image == NULL) cx_throw("could not allocate memory for MNG");\r
+ memcpy(mnginfo.image,info.pImage, head.biSizeImage);\r
+\r
+ // set up the mng decoder for our stream\r
+ hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL);\r
+ if (hmng == NULL) cx_throw("could not initialize libmng"); \r
+\r
+ mng_setcb_openstream(hmng, mymngopenstreamwrite );\r
+ mng_setcb_closestream(hmng, mymngclosestream);\r
+ mng_setcb_writedata(hmng, mymngwritestream);\r
+\r
+ // Write File:\r
+ mng_create(hmng);\r
+ // Just a single Frame (save a normal PNG):\r
+ WritePNG(hmng, 0, 1 );\r
+ // Now write file:\r
+ mng_write(hmng);\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Writes a single PNG datastream\r
+void CxImageMNG::WritePNG( mng_handle hMNG, int Frame, int FrameCount )\r
+{\r
+ mngstuff *mymng = (mngstuff *)mng_get_userdata(hMNG);\r
+ \r
+ int OffsetX=0,OffsetY=0,OffsetW=mymng->width,OffsetH=mymng->height;\r
+\r
+ BYTE *tmpbuffer = new BYTE[ (mymng->effwdt+1) * mymng->height];\r
+ if( tmpbuffer == 0 ) return;\r
+\r
+ // Write DEFI chunk.\r
+ mng_putchunk_defi( hMNG, 0, 0, 0, MNG_TRUE, OffsetX, OffsetY, MNG_FALSE, 0, 0, 0, 0 );\r
+ \r
+ // Write Header:\r
+ mng_putchunk_ihdr(\r
+ hMNG, \r
+ OffsetW, OffsetH, \r
+ MNG_BITDEPTH_8, \r
+ MNG_COLORTYPE_RGB, \r
+ MNG_COMPRESSION_DEFLATE, \r
+ MNG_FILTER_ADAPTIVE, \r
+ MNG_INTERLACE_NONE \r
+ );\r
+\r
+ // transfer data, add Filterbyte:\r
+ for( int Row=0; Row<OffsetH; Row++ ){\r
+ // First Byte in each Scanline is Filterbyte: Currently 0 -> No Filter.\r
+ tmpbuffer[Row*(mymng->effwdt+1)]=0; \r
+ // Copy the scanline: (reverse order)\r
+ memcpy(tmpbuffer+Row*(mymng->effwdt+1)+1, \r
+ mymng->image+((OffsetH-1-(OffsetY+Row))*(mymng->effwdt))+OffsetX,mymng->effwdt);\r
+ // swap red and blue components\r
+ RGBtoBGR(tmpbuffer+Row*(mymng->effwdt+1)+1,mymng->effwdt);\r
+ } \r
+\r
+ // Compress data with ZLib (Deflate):\r
+ BYTE *dstbuffer = new BYTE[(mymng->effwdt+1)*OffsetH];\r
+ if( dstbuffer == 0 ) return;\r
+ DWORD dstbufferSize=(mymng->effwdt+1)*OffsetH;\r
+\r
+ // Compress data:\r
+ if(Z_OK != compress2((Bytef *)dstbuffer,(ULONG *)&dstbufferSize,(const Bytef*)tmpbuffer,\r
+ (ULONG) (mymng->effwdt+1)*OffsetH,9 )) return;\r
+\r
+ // Write Data into MNG File:\r
+ mng_putchunk_idat( hMNG, dstbufferSize, (mng_ptr*)dstbuffer);\r
+ mng_putchunk_iend(hMNG);\r
+\r
+ // Free the stuff:\r
+ delete [] tmpbuffer;\r
+ delete [] dstbuffer;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImageMNG::Resume()\r
+{\r
+ if (MNG_NEEDTIMERWAIT == mng_display_resume(hmng)){\r
+ if (info.pImage==NULL){\r
+ Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG);\r
+ }\r
+ if (IsValid()){\r
+ memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ SwapRGB2BGR();\r
+ AlphaCreate();\r
+ if(AlphaIsValid() && mnginfo.alpha){\r
+ memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height);\r
+ }\r
+#endif\r
+ }\r
+ } else {\r
+ mnginfo.animation_enabled = 0;\r
+ }\r
+ return mnginfo.animation_enabled;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageMNG::SetSpeed(float speed)\r
+{\r
+ if (speed>10.0) mnginfo.speed = 10.0f;\r
+ else if (speed<0.1) mnginfo.speed = 0.1f;\r
+ else mnginfo.speed=speed;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_MNG\r
--- /dev/null
+/*\r
+ * File: ximamng.h\r
+ * Purpose: Declaration of the MNG Image Class\r
+ * Author: Davide Pizzolato - www.xdp.it\r
+ * Created: 2001\r
+ */\r
+/* ==========================================================\r
+ * CxImageMNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Special thanks to Frank Haug <f.haug(at)jdm(dot)de> for suggestions and code.\r
+ *\r
+ * original mng.cpp code created by Nikolaus Brennig, November 14th, 2000. <virtualnik(at)nol(dot)at>\r
+ *\r
+ * LIBMNG Copyright (c) 2000,2001 Gerard Juyn (gerard@libmng.com)\r
+ * ==========================================================\r
+ */\r
+\r
+#if !defined(__ximaMNG_h)\r
+#define __ximaMNG_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_MNG\r
+\r
+//#define MNG_NO_CMS\r
+#define MNG_SUPPORT_DISPLAY\r
+#define MNG_SUPPORT_READ\r
+#define MNG_SUPPORT_WRITE\r
+#define MNG_ACCESS_CHUNKS\r
+#define MNG_STORE_CHUNKS\r
+\r
+extern "C" {\r
+#include "../mng/libmng.h"\r
+#include "../mng/libmng_data.h"\r
+#include "../mng/libmng_error.h"\r
+}\r
+\r
+//unsigned long _stdcall RunMNGThread(void *lpParam);\r
+\r
+typedef struct tagmngstuff \r
+{\r
+ CxFile *file;\r
+ BYTE *image;\r
+ BYTE *alpha;\r
+ HANDLE thread;\r
+ mng_uint32 delay;\r
+ mng_uint32 width;\r
+ mng_uint32 height;\r
+ mng_uint32 effwdt;\r
+ mng_int16 bpp;\r
+ mng_bool animation;\r
+ mng_bool animation_enabled;\r
+ float speed;\r
+ long nBkgndIndex;\r
+ RGBQUAD nBkgndColor;\r
+} mngstuff;\r
+\r
+class CxImageMNG: public CxImage\r
+{\r
+public:\r
+ CxImageMNG();\r
+ ~CxImageMNG();\r
+\r
+ bool Load(const TCHAR * imageFileName);\r
+\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+ bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_MNG);}\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+ long Resume();\r
+ void SetSpeed(float speed);\r
+ \r
+ mng_handle hmng;\r
+ mngstuff mnginfo;\r
+protected:\r
+ void WritePNG(mng_handle hMNG, int Frame, int FrameCount );\r
+ void SetCallbacks(mng_handle mng);\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+// xImaPal.cpp : Palette and Pixel functions\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * returns the palette dimension in byte\r
+ */\r
+DWORD CxImage::GetPaletteSize()\r
+{\r
+ return (head.biClrUsed * sizeof(RGBQUAD));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPaletteColor(BYTE idx, BYTE r, BYTE g, BYTE b, BYTE alpha)\r
+{\r
+ if ((pDib)&&(head.biClrUsed)){\r
+ BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
+ if (idx<head.biClrUsed){\r
+ long ldx=idx*sizeof(RGBQUAD);\r
+ iDst[ldx++] = (BYTE) b;\r
+ iDst[ldx++] = (BYTE) g;\r
+ iDst[ldx++] = (BYTE) r;\r
+ iDst[ldx] = (BYTE) alpha;\r
+ info.last_c_isvalid = false;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPaletteColor(BYTE idx, RGBQUAD c)\r
+{\r
+ if ((pDib)&&(head.biClrUsed)){\r
+ BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
+ if (idx<head.biClrUsed){\r
+ long ldx=idx*sizeof(RGBQUAD);\r
+ iDst[ldx++] = (BYTE) c.rgbBlue;\r
+ iDst[ldx++] = (BYTE) c.rgbGreen;\r
+ iDst[ldx++] = (BYTE) c.rgbRed;\r
+ iDst[ldx] = (BYTE) c.rgbReserved;\r
+ info.last_c_isvalid = false;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPaletteColor(BYTE idx, COLORREF cr)\r
+{\r
+ if ((pDib)&&(head.biClrUsed)){\r
+ BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
+ if (idx<head.biClrUsed){\r
+ long ldx=idx*sizeof(RGBQUAD);\r
+ iDst[ldx++] = (BYTE) GetBValue(cr);\r
+ iDst[ldx++] = (BYTE) GetGValue(cr);\r
+ iDst[ldx++] = (BYTE) GetRValue(cr);\r
+ iDst[ldx] = (BYTE) 0;\r
+ info.last_c_isvalid = false;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * returns the pointer to the first palette index\r
+ */\r
+RGBQUAD* CxImage::GetPalette() const\r
+{\r
+ if ((pDib)&&(head.biClrUsed))\r
+ return (RGBQUAD*)((BYTE*)pDib + sizeof(BITMAPINFOHEADER));\r
+ return NULL;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns the color of the specified index.\r
+ */\r
+RGBQUAD CxImage::GetPaletteColor(BYTE idx)\r
+{\r
+ RGBQUAD rgb = {0,0,0,0};\r
+ if ((pDib)&&(head.biClrUsed)){\r
+ BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
+ if (idx<head.biClrUsed){\r
+ long ldx=idx*sizeof(RGBQUAD);\r
+ rgb.rgbBlue = iDst[ldx++];\r
+ rgb.rgbGreen=iDst[ldx++];\r
+ rgb.rgbRed =iDst[ldx++];\r
+ rgb.rgbReserved = iDst[ldx];\r
+ }\r
+ }\r
+ return rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns the palette index of the specified pixel.\r
+ */\r
+BYTE CxImage::GetPixelIndex(long x,long y)\r
+{\r
+ if ((pDib==NULL)||(head.biClrUsed==0)) return 0;\r
+\r
+ if ((x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) {\r
+ if (info.nBkgndIndex >= 0) return (BYTE)info.nBkgndIndex;\r
+ else return *info.pImage;\r
+ }\r
+ if (head.biBitCount==8){\r
+ return info.pImage[y*info.dwEffWidth + x];\r
+ } else {\r
+ BYTE pos;\r
+ BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];\r
+ if (head.biBitCount==4){\r
+ pos = (BYTE)(4*(1-x%2));\r
+ iDst &= (0x0F<<pos);\r
+ return (BYTE)(iDst >> pos);\r
+ } else if (head.biBitCount==1){\r
+ pos = (BYTE)(7-x%8);\r
+ iDst &= (0x01<<pos);\r
+ return (BYTE)(iDst >> pos);\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+BYTE CxImage::BlindGetPixelIndex(const long x,const long y)\r
+{\r
+#ifdef _DEBUG\r
+ if ((pDib==NULL) || (head.biClrUsed==0) || !IsInside(x,y))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ return 0;\r
+ #endif\r
+#endif\r
+\r
+ if (head.biBitCount==8){\r
+ return info.pImage[y*info.dwEffWidth + x];\r
+ } else {\r
+ BYTE pos;\r
+ BYTE iDst= info.pImage[y*info.dwEffWidth + (x*head.biBitCount >> 3)];\r
+ if (head.biBitCount==4){\r
+ pos = (BYTE)(4*(1-x%2));\r
+ iDst &= (0x0F<<pos);\r
+ return (BYTE)(iDst >> pos);\r
+ } else if (head.biBitCount==1){\r
+ pos = (BYTE)(7-x%8);\r
+ iDst &= (0x01<<pos);\r
+ return (BYTE)(iDst >> pos);\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::GetPixelColor(long x,long y, bool bGetAlpha)\r
+{\r
+// RGBQUAD rgb={0,0,0,0};\r
+ RGBQUAD rgb=info.nBkgndColor; //<mpwolski>\r
+ if ((pDib==NULL)||(x<0)||(y<0)||\r
+ (x>=head.biWidth)||(y>=head.biHeight)){\r
+ if (info.nBkgndIndex >= 0){\r
+ if (head.biBitCount<24) return GetPaletteColor((BYTE)info.nBkgndIndex);\r
+ else return info.nBkgndColor;\r
+ } else if (pDib) return GetPixelColor(0,0);\r
+ return rgb;\r
+ }\r
+\r
+ if (head.biClrUsed){\r
+ rgb = GetPaletteColor(BlindGetPixelIndex(x,y));\r
+ } else {\r
+ BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
+ rgb.rgbBlue = *iDst++;\r
+ rgb.rgbGreen= *iDst++;\r
+ rgb.rgbRed = *iDst;\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);\r
+#else\r
+ rgb.rgbReserved = 0;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ return rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * This is (a bit) faster version of GetPixelColor. \r
+ * It tests bounds only in debug mode (_DEBUG defined).\r
+ * \r
+ * It is an error to request out-of-borders pixel with this method. \r
+ * In DEBUG mode an exception will be thrown, and data will be violated in non-DEBUG mode. \r
+ * \author ***bd*** 2.2004\r
+ */\r
+RGBQUAD CxImage::BlindGetPixelColor(const long x,const long y, bool bGetAlpha)\r
+{\r
+ RGBQUAD rgb;\r
+#ifdef _DEBUG\r
+ if ((pDib==NULL) || !IsInside(x,y))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ {rgb.rgbReserved = 0; return rgb;}\r
+ #endif\r
+#endif\r
+\r
+ if (head.biClrUsed){\r
+ rgb = GetPaletteColor(BlindGetPixelIndex(x,y));\r
+ } else {\r
+ BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
+ rgb.rgbBlue = *iDst++;\r
+ rgb.rgbGreen= *iDst++;\r
+ rgb.rgbRed = *iDst;\r
+ rgb.rgbReserved = 0; //needed for images without alpha layer\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pAlpha && bGetAlpha) rgb.rgbReserved = BlindAlphaGet(x,y);\r
+#else\r
+ rgb.rgbReserved = 0;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ return rgb;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+BYTE CxImage::GetPixelGray(long x, long y)\r
+{\r
+ RGBQUAD color = GetPixelColor(x,y);\r
+ return (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::BlindSetPixelIndex(long x,long y,BYTE i)\r
+{\r
+#ifdef _DEBUG\r
+ if ((pDib==NULL)||(head.biClrUsed==0)||\r
+ (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ return;\r
+ #endif\r
+#endif\r
+\r
+ if (head.biBitCount==8){\r
+ info.pImage[y*info.dwEffWidth + x]=i;\r
+ return;\r
+ } else {\r
+ BYTE pos;\r
+ BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3);\r
+ if (head.biBitCount==4){\r
+ pos = (BYTE)(4*(1-x%2));\r
+ *iDst &= ~(0x0F<<pos);\r
+ *iDst |= ((i & 0x0F)<<pos);\r
+ return;\r
+ } else if (head.biBitCount==1){\r
+ pos = (BYTE)(7-x%8);\r
+ *iDst &= ~(0x01<<pos);\r
+ *iDst |= ((i & 0x01)<<pos);\r
+ return;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPixelIndex(long x,long y,BYTE i)\r
+{\r
+ if ((pDib==NULL)||(head.biClrUsed==0)||\r
+ (x<0)||(y<0)||(x>=head.biWidth)||(y>=head.biHeight)) return ;\r
+\r
+ if (head.biBitCount==8){\r
+ info.pImage[y*info.dwEffWidth + x]=i;\r
+ return;\r
+ } else {\r
+ BYTE pos;\r
+ BYTE* iDst= info.pImage + y*info.dwEffWidth + (x*head.biBitCount >> 3);\r
+ if (head.biBitCount==4){\r
+ pos = (BYTE)(4*(1-x%2));\r
+ *iDst &= ~(0x0F<<pos);\r
+ *iDst |= ((i & 0x0F)<<pos);\r
+ return;\r
+ } else if (head.biBitCount==1){\r
+ pos = (BYTE)(7-x%8);\r
+ *iDst &= ~(0x01<<pos);\r
+ *iDst |= ((i & 0x01)<<pos);\r
+ return;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPixelColor(long x,long y,COLORREF cr)\r
+{\r
+ SetPixelColor(x,y,RGBtoRGBQUAD(cr));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::BlindSetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha)\r
+{\r
+#ifdef _DEBUG\r
+ if ((pDib==NULL)||(x<0)||(y<0)||\r
+ (x>=head.biWidth)||(y>=head.biHeight))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ return;\r
+ #endif\r
+#endif\r
+ if (head.biClrUsed)\r
+ BlindSetPixelIndex(x,y,GetNearestIndex(c));\r
+ else {\r
+ BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
+ *iDst++ = c.rgbBlue;\r
+ *iDst++ = c.rgbGreen;\r
+ *iDst = c.rgbRed;\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPixelColor(long x,long y,RGBQUAD c, bool bSetAlpha)\r
+{\r
+ if ((pDib==NULL)||(x<0)||(y<0)||\r
+ (x>=head.biWidth)||(y>=head.biHeight)) return;\r
+ if (head.biClrUsed)\r
+ BlindSetPixelIndex(x,y,GetNearestIndex(c));\r
+ else {\r
+ BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
+ *iDst++ = c.rgbBlue;\r
+ *iDst++ = c.rgbGreen;\r
+ *iDst = c.rgbRed;\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Blends the current pixel color with a new color.\r
+ * \param x,y = pixel\r
+ * \param c = new color\r
+ * \param blend = can be from 0 (no effect) to 1 (full effect).\r
+ * \param bSetAlpha = if true, blends also the alpha component stored in c.rgbReserved\r
+ */\r
+void CxImage::BlendPixelColor(long x,long y,RGBQUAD c, float blend, bool bSetAlpha)\r
+{\r
+ if ((pDib==NULL)||(x<0)||(y<0)||\r
+ (x>=head.biWidth)||(y>=head.biHeight)) return;\r
+\r
+ int a0 = (int)(256*blend);\r
+ int a1 = 256 - a0;\r
+\r
+ RGBQUAD c0 = BlindGetPixelColor(x,y);\r
+ c.rgbRed = (BYTE)((c.rgbRed * a0 + c0.rgbRed * a1)>>8);\r
+ c.rgbBlue = (BYTE)((c.rgbBlue * a0 + c0.rgbBlue * a1)>>8);\r
+ c.rgbGreen = (BYTE)((c.rgbGreen * a0 + c0.rgbGreen * a1)>>8);\r
+\r
+ if (head.biClrUsed)\r
+ BlindSetPixelIndex(x,y,GetNearestIndex(c));\r
+ else {\r
+ BYTE* iDst = info.pImage + y*info.dwEffWidth + x*3;\r
+ *iDst++ = c.rgbBlue;\r
+ *iDst++ = c.rgbGreen;\r
+ *iDst = c.rgbRed;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (bSetAlpha) AlphaSet(x,y,c.rgbReserved);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns the best palette index that matches a specified color.\r
+ */\r
+BYTE CxImage::GetNearestIndex(RGBQUAD c)\r
+{\r
+ if ((pDib==NULL)||(head.biClrUsed==0)) return 0;\r
+\r
+ // <RJ> check matching with the previous result\r
+ if (info.last_c_isvalid && (*(long*)&info.last_c == *(long*)&c)) return info.last_c_index;\r
+ info.last_c = c;\r
+ info.last_c_isvalid = true;\r
+\r
+ BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
+ long distance=200000;\r
+ int i,j = 0;\r
+ long k,l;\r
+ int m = (int)(head.biClrImportant==0 ? head.biClrUsed : head.biClrImportant);\r
+ for(i=0,l=0;i<m;i++,l+=sizeof(RGBQUAD)){\r
+ k = (iDst[l]-c.rgbBlue)*(iDst[l]-c.rgbBlue)+\r
+ (iDst[l+1]-c.rgbGreen)*(iDst[l+1]-c.rgbGreen)+\r
+ (iDst[l+2]-c.rgbRed)*(iDst[l+2]-c.rgbRed);\r
+// k = abs(iDst[l]-c.rgbBlue)+abs(iDst[l+1]-c.rgbGreen)+abs(iDst[l+2]-c.rgbRed);\r
+ if (k==0){\r
+ j=i;\r
+ break;\r
+ }\r
+ if (k<distance){\r
+ distance=k;\r
+ j=i;\r
+ }\r
+ }\r
+ info.last_c_index = (BYTE)j;\r
+ return (BYTE)j;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * swaps the blue and red components (for RGB images)\r
+ * \param buffer : pointer to the pixels\r
+ * \param length : number of bytes to swap. lenght may not exceed the scan line.\r
+ */\r
+void CxImage::RGBtoBGR(BYTE *buffer, int length)\r
+{\r
+ if (buffer && (head.biClrUsed==0)){\r
+ BYTE temp;\r
+ length = min(length,(int)info.dwEffWidth);\r
+ length = min(length,(int)(3*head.biWidth));\r
+ for (int i=0;i<length;i+=3){\r
+ temp = buffer[i]; buffer[i] = buffer[i+2]; buffer[i+2] = temp;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+RGBQUAD CxImage::RGBtoRGBQUAD(COLORREF cr)\r
+{\r
+ RGBQUAD c;\r
+ c.rgbRed = GetRValue(cr); /* get R, G, and B out of DWORD */\r
+ c.rgbGreen = GetGValue(cr);\r
+ c.rgbBlue = GetBValue(cr);\r
+ c.rgbReserved=0;\r
+ return c;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+COLORREF CxImage::RGBQUADtoRGB (RGBQUAD c)\r
+{\r
+ return RGB(c.rgbRed,c.rgbGreen,c.rgbBlue);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns the color of the specified index.\r
+ * \param i = palette index\r
+ * \param r, g, b = output color channels\r
+ */\r
+bool CxImage::GetPaletteColor(BYTE i, BYTE* r, BYTE* g, BYTE* b)\r
+{\r
+ RGBQUAD* ppal=GetPalette();\r
+ if (ppal) {\r
+ *r = ppal[i].rgbRed;\r
+ *g = ppal[i].rgbGreen;\r
+ *b = ppal[i].rgbBlue; \r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPalette(DWORD n, BYTE *r, BYTE *g, BYTE *b)\r
+{\r
+ if ((!r)||(pDib==NULL)||(head.biClrUsed==0)) return;\r
+ if (!g) g = r;\r
+ if (!b) b = g;\r
+ RGBQUAD* ppal=GetPalette();\r
+ DWORD m=min(n,head.biClrUsed);\r
+ for (DWORD i=0; i<m;i++){\r
+ ppal[i].rgbRed=r[i];\r
+ ppal[i].rgbGreen=g[i];\r
+ ppal[i].rgbBlue=b[i];\r
+ }\r
+ info.last_c_isvalid = false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPalette(rgb_color *rgb,DWORD nColors)\r
+{\r
+ if ((!rgb)||(pDib==NULL)||(head.biClrUsed==0)) return;\r
+ RGBQUAD* ppal=GetPalette();\r
+ DWORD m=min(nColors,head.biClrUsed);\r
+ for (DWORD i=0; i<m;i++){\r
+ ppal[i].rgbRed=rgb[i].r;\r
+ ppal[i].rgbGreen=rgb[i].g;\r
+ ppal[i].rgbBlue=rgb[i].b;\r
+ }\r
+ info.last_c_isvalid = false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::SetPalette(RGBQUAD* pPal,DWORD nColors)\r
+{\r
+ if ((pPal==NULL)||(pDib==NULL)||(head.biClrUsed==0)) return;\r
+ memcpy(GetPalette(),pPal,min(GetPaletteSize(),nColors*sizeof(RGBQUAD)));\r
+ info.last_c_isvalid = false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets (or replaces) the palette to gray scale palette.\r
+ * The function doesn't change the pixels; for standard\r
+ * gray scale conversion use GrayScale().\r
+ */\r
+void CxImage::SetGrayPalette()\r
+{\r
+ if ((pDib==NULL)||(head.biClrUsed==0)) return;\r
+ RGBQUAD* pal=GetPalette();\r
+ for (DWORD ni=0;ni<head.biClrUsed;ni++)\r
+ pal[ni].rgbBlue=pal[ni].rgbGreen = pal[ni].rgbRed = (BYTE)(ni*(255/(head.biClrUsed-1)));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Colorize the palette.\r
+ * \sa Colorize\r
+ */\r
+void CxImage::BlendPalette(COLORREF cr,long perc)\r
+{\r
+ if ((pDib==NULL)||(head.biClrUsed==0)) return;\r
+ BYTE* iDst = (BYTE*)(pDib) + sizeof(BITMAPINFOHEADER);\r
+ DWORD i,r,g,b;\r
+ RGBQUAD* pPal=(RGBQUAD*)iDst;\r
+ r = GetRValue(cr);\r
+ g = GetGValue(cr);\r
+ b = GetBValue(cr);\r
+ if (perc>100) perc=100;\r
+ for(i=0;i<head.biClrUsed;i++){\r
+ pPal[i].rgbBlue=(BYTE)((pPal[i].rgbBlue*(100-perc)+b*perc)/100);\r
+ pPal[i].rgbGreen =(BYTE)((pPal[i].rgbGreen*(100-perc)+g*perc)/100);\r
+ pPal[i].rgbRed =(BYTE)((pPal[i].rgbRed*(100-perc)+r*perc)/100);\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns true if the image has 256 colors and a linear grey scale palette.\r
+ */\r
+bool CxImage::IsGrayScale()\r
+{\r
+ RGBQUAD* ppal=GetPalette();\r
+ if(!(pDib && ppal && head.biClrUsed)) return false;\r
+ for(DWORD i=0;i<head.biClrUsed;i++){\r
+ if (ppal[i].rgbBlue!=i || ppal[i].rgbGreen!=i || ppal[i].rgbRed!=i) return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * swap two indexes in the image and their colors in the palette\r
+ */\r
+void CxImage::SwapIndex(BYTE idx1, BYTE idx2)\r
+{\r
+ RGBQUAD* ppal=GetPalette();\r
+ if(!(pDib && ppal)) return;\r
+ //swap the colors\r
+ RGBQUAD tempRGB=GetPaletteColor(idx1);\r
+ SetPaletteColor(idx1,GetPaletteColor(idx2));\r
+ SetPaletteColor(idx2,tempRGB);\r
+ //swap the pixels\r
+ BYTE idx;\r
+ for(long y=0; y < head.biHeight; y++){\r
+ for(long x=0; x < head.biWidth; x++){\r
+ idx=BlindGetPixelIndex(x,y);\r
+ if (idx==idx1) BlindSetPixelIndex(x,y,idx2);\r
+ if (idx==idx2) BlindSetPixelIndex(x,y,idx1);\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * swap Red and Blue colors\r
+ */\r
+void CxImage::SwapRGB2BGR()\r
+{\r
+ if (!pDib) return;\r
+\r
+ if (head.biClrUsed){\r
+ RGBQUAD* ppal=GetPalette();\r
+ BYTE b;\r
+ if(!ppal) return;\r
+ for(WORD a=0;a<head.biClrUsed;a++){\r
+ b=ppal[a].rgbBlue; ppal[a].rgbBlue=ppal[a].rgbRed; ppal[a].rgbRed=b;\r
+ }\r
+ } else {\r
+ for(long y=0;y<head.biHeight;y++){\r
+ RGBtoBGR(GetBits(y),3*head.biWidth);\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::IsTransparent(long x, long y)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ if (info.nBkgndIndex>=0){\r
+ if (head.biClrUsed){\r
+ if (GetPixelIndex(x,y) == info.nBkgndIndex) return true;\r
+ } else {\r
+ RGBQUAD ct = info.nBkgndColor;\r
+ RGBQUAD c = GetPixelColor(x,y,false);\r
+ if (*(long*)&c==*(long*)&ct) return true;\r
+ }\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pAlpha) return AlphaGet(x,y)==0;\r
+#endif\r
+\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::GetTransparentMask(CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ CxImage tmp;\r
+ tmp.Create(head.biWidth, head.biHeight, 1, GetType());\r
+ tmp.SetStdPalette();\r
+ tmp.Clear(0);\r
+\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ if (IsTransparent(x,y)){\r
+ tmp.BlindSetPixelIndex(x,y,1);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (iDst) iDst->Transfer(tmp);\r
+ else Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if image has the same palette, if any.\r
+ * \param img = image to compare.\r
+ * \param bCheckAlpha = check also the rgbReserved field.\r
+ */\r
+bool CxImage::IsSamePalette(CxImage &img, bool bCheckAlpha)\r
+{\r
+ if (head.biClrUsed != img.head.biClrUsed)\r
+ return false;\r
+ if (head.biClrUsed == 0)\r
+ return false;\r
+\r
+ RGBQUAD c1,c2;\r
+ for (DWORD n=0; n<head.biClrUsed; n++){\r
+ c1 = GetPaletteColor((BYTE)n);\r
+ c2 = img.GetPaletteColor((BYTE)n);\r
+ if (c1.rgbRed != c2.rgbRed) return false;\r
+ if (c1.rgbBlue != c2.rgbBlue) return false;\r
+ if (c1.rgbGreen != c2.rgbGreen) return false;\r
+ if (bCheckAlpha && (c1.rgbReserved != c2.rgbReserved)) return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa SetClrImportant\r
+ */\r
+DWORD CxImage::GetClrImportant() const\r
+{\r
+ return head.biClrImportant;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * sets the maximum number of colors that some functions like\r
+ * DecreaseBpp() or GetNearestIndex() will use on indexed images\r
+ * \param ncolors should be less than 2^bpp,\r
+ * or 0 if all the colors are important.\r
+ */\r
+void CxImage::SetClrImportant(DWORD ncolors)\r
+{\r
+ if (ncolors==0 || ncolors>256) {\r
+ head.biClrImportant = 0;\r
+ return;\r
+ }\r
+\r
+ switch(head.biBitCount){\r
+ case 1:\r
+ head.biClrImportant = min(ncolors,2);\r
+ break;\r
+ case 4:\r
+ head.biClrImportant = min(ncolors,16);\r
+ break;\r
+ case 8:\r
+ head.biClrImportant = ncolors;\r
+ break;\r
+ }\r
+ return;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns pointer to pixel. Currently implemented only for truecolor images.\r
+ * \r
+ * \param x,y - coordinates\r
+ *\r
+ * \return pointer to first byte of pixel data\r
+ *\r
+ * \author ***bd*** 2.2004\r
+ */\r
+void* CxImage::BlindGetPixelPointer(const long x, const long y)\r
+{\r
+#ifdef _DEBUG\r
+ if ((pDib==NULL) || !IsInside(x,y))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ return 0;\r
+ #endif\r
+#endif\r
+ if (!IsIndexed())\r
+ return info.pImage + y*info.dwEffWidth + x*3;\r
+ else\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, COLORREF cr)\r
+{\r
+ DrawLine(StartX, EndX, StartY, EndY, RGBtoRGBQUAD(cr));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImage::DrawLine(int StartX, int EndX, int StartY, int EndY, RGBQUAD color, bool bSetAlpha)\r
+{\r
+ if (!pDib) return;\r
+ //////////////////////////////////////////////////////\r
+ // Draws a line using the Bresenham line algorithm\r
+ // Thanks to Jordan DeLozier <JDL>\r
+ //////////////////////////////////////////////////////\r
+ int x1 = StartX;\r
+ int y1 = StartY;\r
+ int x = x1; // Start x off at the first pixel\r
+ int y = y1; // Start y off at the first pixel\r
+ int x2 = EndX;\r
+ int y2 = EndY;\r
+\r
+ int xinc1,xinc2,yinc1,yinc2; // Increasing values\r
+ int den, num, numadd,numpixels; \r
+ int deltax = abs(x2 - x1); // The difference between the x's\r
+ int deltay = abs(y2 - y1); // The difference between the y's\r
+\r
+ // Get Increasing Values\r
+ if (x2 >= x1) { // The x-values are increasing\r
+ xinc1 = 1;\r
+ xinc2 = 1;\r
+ } else { // The x-values are decreasing\r
+ xinc1 = -1;\r
+ xinc2 = -1;\r
+ }\r
+\r
+ if (y2 >= y1) { // The y-values are increasing\r
+ yinc1 = 1;\r
+ yinc2 = 1;\r
+ } else { // The y-values are decreasing\r
+ yinc1 = -1;\r
+ yinc2 = -1;\r
+ }\r
+\r
+ // Actually draw the line\r
+ if (deltax >= deltay) // There is at least one x-value for every y-value\r
+ {\r
+ xinc1 = 0; // Don't change the x when numerator >= denominator\r
+ yinc2 = 0; // Don't change the y for every iteration\r
+ den = deltax;\r
+ num = deltax / 2;\r
+ numadd = deltay;\r
+ numpixels = deltax; // There are more x-values than y-values\r
+ }\r
+ else // There is at least one y-value for every x-value\r
+ {\r
+ xinc2 = 0; // Don't change the x for every iteration\r
+ yinc1 = 0; // Don't change the y when numerator >= denominator\r
+ den = deltay;\r
+ num = deltay / 2;\r
+ numadd = deltax;\r
+ numpixels = deltay; // There are more y-values than x-values\r
+ }\r
+ \r
+ for (int curpixel = 0; curpixel <= numpixels; curpixel++)\r
+ {\r
+ // Draw the current pixel\r
+ SetPixelColor(x,y,color,bSetAlpha);\r
+ \r
+ num += numadd; // Increase the numerator by the top of the fraction\r
+ if (num >= den) // Check if numerator >= denominator\r
+ {\r
+ num -= den; // Calculate the new numerator value\r
+ x += xinc1; // Change the x as appropriate\r
+ y += yinc1; // Change the y as appropriate\r
+ }\r
+ x += xinc2; // Change the x as appropriate\r
+ y += yinc2; // Change the y as appropriate\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets a palette with standard colors for 1, 4 and 8 bpp images.\r
+ */\r
+void CxImage::SetStdPalette()\r
+{\r
+ if (!pDib) return;\r
+ switch (head.biBitCount){\r
+ case 8:\r
+ {\r
+ 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,\r
+ 192,220,192,0,240,202,166,0,212,240,255,0,177,226,255,0,142,212,255,0,107,198,255,0,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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,\r
+ 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};\r
+ memcpy(GetPalette(),pal256,1024);\r
+ break;\r
+ }\r
+ case 4:\r
+ {\r
+ 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,\r
+ 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};\r
+ memcpy(GetPalette(),pal16,64);\r
+ break;\r
+ }\r
+ case 1:\r
+ {\r
+ const BYTE pal2[8]={0,0,0,0,255,255,255,0};\r
+ memcpy(GetPalette(),pal2,8);\r
+ break;\r
+ }\r
+ }\r
+ info.last_c_isvalid = false;\r
+ return;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
--- /dev/null
+/*\r
+ * File: ximapcx.cpp\r
+ * Purpose: Platform Independent PCX Image Class Loader and Writer\r
+ * 05/Jan/2002 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ *\r
+ * based on ppmtopcx.c - convert a portable pixmap to PCX\r
+ * Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)\r
+ * based on ppmtopcx.c by Michael Davidson\r
+ */\r
+\r
+#include "ximapcx.h"\r
+\r
+#if CXIMAGE_SUPPORT_PCX\r
+\r
+#include "xmemfile.h"\r
+\r
+#define PCX_MAGIC 0X0A // PCX magic number\r
+#define PCX_256_COLORS 0X0C // magic number for 256 colors\r
+#define PCX_HDR_SIZE 128 // size of PCX header\r
+#define PCX_MAXCOLORS 256\r
+#define PCX_MAXPLANES 4\r
+#define PCX_MAXVAL 255\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImagePCX::Decode(CxFile *hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ PCXHEADER pcxHeader;\r
+ int i, x, y, y2, nbytes, count, Height, Width;\r
+ BYTE c, ColorMap[PCX_MAXCOLORS][3];\r
+ BYTE *pcximage = NULL, *lpHead1 = NULL, *lpHead2 = NULL;\r
+ BYTE *pcxplanes, *pcxpixels;\r
+\r
+ cx_try\r
+ {\r
+ if (hFile->Read(&pcxHeader,sizeof(PCXHEADER),1)==0) cx_throw("Can't read PCX image");\r
+\r
+ PCX_toh(&pcxHeader);\r
+\r
+ if (pcxHeader.Manufacturer != PCX_MAGIC) cx_throw("Error: Not a PCX file");\r
+ // Check for PCX run length encoding\r
+ if (pcxHeader.Encoding != 1) cx_throw("PCX file has unknown encoding scheme");\r
+ \r
+ Width = (pcxHeader.Xmax - pcxHeader.Xmin) + 1;\r
+ Height = (pcxHeader.Ymax - pcxHeader.Ymin) + 1;\r
+ info.xDPI = pcxHeader.Hres;\r
+ info.yDPI = pcxHeader.Vres;\r
+\r
+ if (info.nEscape == -1){\r
+ head.biWidth = Width;\r
+ head.biHeight= Height;\r
+ info.dwType = CXIMAGE_FORMAT_PCX;\r
+ return true;\r
+ }\r
+\r
+ // Check that we can handle this image format\r
+ if (pcxHeader.ColorPlanes > 4)\r
+ cx_throw("Can't handle image with more than 4 planes");\r
+\r
+ // Create the image\r
+ if (pcxHeader.ColorPlanes >= 3 && pcxHeader.BitsPerPixel == 8){\r
+ Create (Width, Height, 24, CXIMAGE_FORMAT_PCX);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pcxHeader.ColorPlanes==4) AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 1)\r
+ Create (Width, Height, 4, CXIMAGE_FORMAT_PCX);\r
+ else\r
+ Create (Width, Height, pcxHeader.BitsPerPixel, CXIMAGE_FORMAT_PCX);\r
+\r
+ if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
+\r
+ //Read the image and check if it's ok\r
+ nbytes = pcxHeader.BytesPerLine * pcxHeader.ColorPlanes * Height;\r
+ lpHead1 = pcximage = (BYTE*)malloc(nbytes);\r
+ while (nbytes > 0){\r
+ if (hFile == NULL || hFile->Eof()) cx_throw("corrupted PCX");\r
+\r
+ hFile->Read(&c,1,1);\r
+ if ((c & 0XC0) != 0XC0){ // Repeated group\r
+ *pcximage++ = c;\r
+ --nbytes;\r
+ continue;\r
+ }\r
+ count = c & 0X3F; // extract count\r
+ hFile->Read(&c,1,1);\r
+ if (count > nbytes) cx_throw("repeat count spans end of image");\r
+\r
+ nbytes -= count;\r
+ while (--count >=0) *pcximage++ = c;\r
+ }\r
+ pcximage = lpHead1;\r
+\r
+ //store the palette\r
+ for (i = 0; i < 16; i++){\r
+ ColorMap[i][0] = pcxHeader.ColorMap[i][0];\r
+ ColorMap[i][1] = pcxHeader.ColorMap[i][1];\r
+ ColorMap[i][2] = pcxHeader.ColorMap[i][2];\r
+ }\r
+ if (pcxHeader.BitsPerPixel == 8 && pcxHeader.ColorPlanes == 1){\r
+ hFile->Read(&c,1,1);\r
+ if (c != PCX_256_COLORS) cx_throw("bad color map signature");\r
+ \r
+ for (i = 0; i < PCX_MAXCOLORS; i++){\r
+ hFile->Read(&ColorMap[i][0],1,1);\r
+ hFile->Read(&ColorMap[i][1],1,1);\r
+ hFile->Read(&ColorMap[i][2],1,1);\r
+ }\r
+ }\r
+ if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){\r
+ ColorMap[0][0] = ColorMap[0][1] = ColorMap[0][2] = 0;\r
+ ColorMap[1][0] = ColorMap[1][1] = ColorMap[1][2] = 255;\r
+ }\r
+\r
+ for (DWORD idx=0; idx<head.biClrUsed; idx++) SetPaletteColor((BYTE)idx,ColorMap[idx][0],ColorMap[idx][1],ColorMap[idx][2]);\r
+\r
+ lpHead2 = pcxpixels = (BYTE *)malloc(Width + pcxHeader.BytesPerLine * 8);\r
+ // Convert the image\r
+ for (y = 0; y < Height; y++){\r
+\r
+ if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
+\r
+ y2=Height-1-y;\r
+ pcxpixels = lpHead2;\r
+ pcxplanes = pcximage + (y * pcxHeader.BytesPerLine * pcxHeader.ColorPlanes);\r
+\r
+ if (pcxHeader.ColorPlanes == 3 && pcxHeader.BitsPerPixel == 8){\r
+ // Deal with 24 bit color image\r
+ for (x = 0; x < Width; x++){\r
+ SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));\r
+ }\r
+ continue;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ } else if (pcxHeader.ColorPlanes == 4 && pcxHeader.BitsPerPixel == 8){\r
+ for (x = 0; x < Width; x++){\r
+ SetPixelColor(x,y2,RGB(pcxplanes[x],pcxplanes[pcxHeader.BytesPerLine + x],pcxplanes[2*pcxHeader.BytesPerLine + x]));\r
+ AlphaSet(x,y2,pcxplanes[3*pcxHeader.BytesPerLine + x]);\r
+ }\r
+ continue;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ } else if (pcxHeader.ColorPlanes == 1) {\r
+ if (!PCX_UnpackPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){\r
+ cx_throw("PCX_UnpackPixels: Can't handle packed pixels with more than 1 plane");\r
+ }\r
+ } else {\r
+ if (!PCX_PlanesToPixels(pcxpixels, pcxplanes, pcxHeader.BytesPerLine, pcxHeader.ColorPlanes, pcxHeader.BitsPerPixel)){\r
+ cx_throw("PCX_PlanesToPixels: more than 4 planes or more than 1 bit per pixel");\r
+ }\r
+ }\r
+ for (x = 0; x < Width; x++) SetPixelIndex(x,y2,pcxpixels[x]);\r
+ }\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (lpHead1){ free(lpHead1); lpHead1 = NULL; }\r
+ if (lpHead2){ free(lpHead2); lpHead2 = NULL; }\r
+ return false;\r
+ }\r
+ if (lpHead1){ free(lpHead1); lpHead1 = NULL; }\r
+ if (lpHead2){ free(lpHead2); lpHead2 = NULL; }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImagePCX::Encode(CxFile * hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ cx_try\r
+ {\r
+ PCXHEADER pcxHeader;\r
+ memset(&pcxHeader,0,sizeof(pcxHeader));\r
+ pcxHeader.Manufacturer = PCX_MAGIC;\r
+ pcxHeader.Version = 5;\r
+ pcxHeader.Encoding = 1;\r
+ pcxHeader.Xmin = 0;\r
+ pcxHeader.Ymin = 0;\r
+ pcxHeader.Xmax = (WORD)head.biWidth-1;\r
+ pcxHeader.Ymax = (WORD)head.biHeight-1;\r
+ pcxHeader.Hres = (WORD)info.xDPI;\r
+ pcxHeader.Vres = (WORD)info.yDPI;\r
+ pcxHeader.Reserved = 0;\r
+ pcxHeader.PaletteType = head.biClrUsed==0;\r
+\r
+ switch(head.biBitCount){\r
+ case 24:\r
+ case 8:\r
+ {\r
+ pcxHeader.BitsPerPixel = 8;\r
+ pcxHeader.ColorPlanes = head.biClrUsed==0 ? 3 : 1;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid() && head.biClrUsed==0) pcxHeader.ColorPlanes =4;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ pcxHeader.BytesPerLine = (WORD)head.biWidth;\r
+ break;\r
+ }\r
+ default: //(4 1)\r
+ pcxHeader.BitsPerPixel = 1;\r
+ pcxHeader.ColorPlanes = head.biClrUsed==16 ? 4 : 1;\r
+ pcxHeader.BytesPerLine = (WORD)((head.biWidth * pcxHeader.BitsPerPixel + 7)>>3);\r
+ }\r
+\r
+ if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 1){\r
+ pcxHeader.ColorMap[0][0] = pcxHeader.ColorMap[0][1] = pcxHeader.ColorMap[0][2] = 0;\r
+ pcxHeader.ColorMap[1][0] = pcxHeader.ColorMap[1][1] = pcxHeader.ColorMap[1][2] = 255;\r
+ }\r
+ if (pcxHeader.BitsPerPixel == 1 && pcxHeader.ColorPlanes == 4){\r
+ RGBQUAD c;\r
+ for (int i = 0; i < 16; i++){\r
+ c=GetPaletteColor(i);\r
+ pcxHeader.ColorMap[i][0] = c.rgbRed;\r
+ pcxHeader.ColorMap[i][1] = c.rgbGreen;\r
+ pcxHeader.ColorMap[i][2] = c.rgbBlue;\r
+ }\r
+ }\r
+\r
+ pcxHeader.BytesPerLine = (pcxHeader.BytesPerLine + 1)&(~1);\r
+\r
+ PCX_toh(&pcxHeader);\r
+ if (hFile->Write(&pcxHeader, sizeof(pcxHeader), 1) == 0 )\r
+ cx_throw("cannot write PCX header");\r
+ PCX_toh(&pcxHeader);\r
+\r
+ CxMemFile buffer;\r
+ buffer.Open();\r
+\r
+ BYTE c,n;\r
+ long x,y;\r
+ if (head.biClrUsed==0){\r
+ for (y = head.biHeight-1; y >=0 ; y--){\r
+ for (int p=0; p<pcxHeader.ColorPlanes; p++){\r
+ c=n=0;\r
+ for (x = 0; x<head.biWidth; x++){\r
+ if (p==0)\r
+ PCX_PackPixels(BlindGetPixelColor(x,y).rgbRed,c,n,buffer);\r
+ else if (p==1)\r
+ PCX_PackPixels(BlindGetPixelColor(x,y).rgbGreen,c,n,buffer);\r
+ else if (p==2)\r
+ PCX_PackPixels(BlindGetPixelColor(x,y).rgbBlue,c,n,buffer);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ else if (p==3)\r
+ PCX_PackPixels(BlindAlphaGet(x,y),c,n,buffer);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);\r
+ }\r
+ }\r
+\r
+ hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);\r
+\r
+ } else if (head.biBitCount==8) {\r
+\r
+ for (y = head.biHeight-1; y >=0 ; y--){\r
+ c=n=0;\r
+ for (x = 0; x<head.biWidth; x++){\r
+ PCX_PackPixels(GetPixelIndex(x,y),c,n,buffer);\r
+ }\r
+ PCX_PackPixels(-1-(head.biWidth&0x1),c,n,buffer);\r
+ }\r
+\r
+ hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);\r
+\r
+ if (head.biBitCount == 8){\r
+ hFile->PutC(0x0C);\r
+ BYTE* pal = (BYTE*)malloc(768);\r
+ RGBQUAD c;\r
+ for (int i=0;i<256;i++){\r
+ c=GetPaletteColor(i);\r
+ pal[3*i+0] = c.rgbRed;\r
+ pal[3*i+1] = c.rgbGreen;\r
+ pal[3*i+2] = c.rgbBlue;\r
+ }\r
+ hFile->Write(pal,768,1);\r
+ free(pal);\r
+ }\r
+ } else { //(head.biBitCount==4) || (head.biBitCount==1)\r
+\r
+ RGBQUAD *rgb = GetPalette();\r
+ bool binvert = false;\r
+ if (CompareColors(&rgb[0],&rgb[1])>0) binvert=(head.biBitCount==1);\r
+ \r
+ BYTE* plane = (BYTE*)malloc(pcxHeader.BytesPerLine);\r
+ BYTE* raw = (BYTE*)malloc(head.biWidth);\r
+\r
+ for(y = head.biHeight-1; y >=0 ; y--) {\r
+\r
+ for( x = 0; x < head.biWidth; x++) raw[x] = (BYTE)GetPixelIndex(x,y);\r
+\r
+ if (binvert) for( x = 0; x < head.biWidth; x++) raw[x] = 1-raw[x];\r
+\r
+ for( x = 0; x < pcxHeader.ColorPlanes; x++ ) {\r
+ PCX_PixelsToPlanes(raw, head.biWidth, plane, x);\r
+ PCX_PackPlanes(plane, pcxHeader.BytesPerLine, buffer);\r
+ }\r
+ }\r
+\r
+ free(plane);\r
+ free(raw);\r
+\r
+ hFile->Write(buffer.GetBuffer(false),buffer.Tell(),1);\r
+\r
+ }\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Convert multi-plane format into 1 pixel per byte\r
+// from unpacked file data bitplanes[] into pixel row pixels[]\r
+// image Height rows, with each row having planes image planes each\r
+// bytesperline bytes\r
+bool CxImagePCX::PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)\r
+{\r
+ int i, j, npixels;\r
+ BYTE * p;\r
+ if (planes > 4) return false;\r
+ if (bitsperpixel != 1) return false;\r
+\r
+ // Clear the pixel buffer\r
+ npixels = (bytesperline * 8) / bitsperpixel;\r
+ p = pixels;\r
+ while (--npixels >= 0) *p++ = 0;\r
+\r
+ // Do the format conversion\r
+ for (i = 0; i < planes; i++){\r
+ int pixbit, bits, mask;\r
+ p = pixels;\r
+ pixbit = (1 << i); // pixel bit for this plane\r
+ for (j = 0; j < bytesperline; j++){\r
+ bits = *bitplanes++;\r
+ for (mask = 0X80; mask != 0; mask >>= 1, p++)\r
+ if (bits & mask) *p |= pixbit;\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// convert packed pixel format into 1 pixel per byte\r
+// from unpacked file data bitplanes[] into pixel row pixels[]\r
+// image Height rows, with each row having planes image planes each\r
+// bytesperline bytes\r
+bool CxImagePCX::PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel)\r
+{\r
+ register int bits;\r
+ if (planes != 1) return false;\r
+ \r
+ if (bitsperpixel == 8){ // 8 bits/pixels, no unpacking needed\r
+ while (bytesperline-- > 0) *pixels++ = *bitplanes++;\r
+ } else if (bitsperpixel == 4){ // 4 bits/pixel, two pixels per byte\r
+ while (bytesperline-- > 0){\r
+ bits = *bitplanes++;\r
+ *pixels++ = (BYTE)((bits >> 4) & 0X0F);\r
+ *pixels++ = (BYTE)((bits) & 0X0F);\r
+ }\r
+ } else if (bitsperpixel == 2){ // 2 bits/pixel, four pixels per byte\r
+ while (bytesperline-- > 0){\r
+ bits = *bitplanes++;\r
+ *pixels++ = (BYTE)((bits >> 6) & 0X03);\r
+ *pixels++ = (BYTE)((bits >> 4) & 0X03);\r
+ *pixels++ = (BYTE)((bits >> 2) & 0X03);\r
+ *pixels++ = (BYTE)((bits) & 0X03);\r
+ }\r
+ } else if (bitsperpixel == 1){ // 1 bits/pixel, 8 pixels per byte\r
+ while (bytesperline-- > 0){\r
+ bits = *bitplanes++;\r
+ *pixels++ = ((bits & 0X80) != 0);\r
+ *pixels++ = ((bits & 0X40) != 0);\r
+ *pixels++ = ((bits & 0X20) != 0);\r
+ *pixels++ = ((bits & 0X10) != 0);\r
+ *pixels++ = ((bits & 0X08) != 0);\r
+ *pixels++ = ((bits & 0X04) != 0);\r
+ *pixels++ = ((bits & 0X02) != 0);\r
+ *pixels++ = ((bits & 0X01) != 0);\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/* PCX_PackPixels(const long p,BYTE &c, BYTE &n, long &l, CxFile &f)\r
+ * p = current pixel (-1 ends the line -2 ends odd line)\r
+ * c = previous pixel\r
+ * n = number of consecutive pixels\r
+ */\r
+void CxImagePCX::PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f)\r
+{\r
+ if (p!=c && n){\r
+ if (n==1 && c<0xC0){\r
+ f.PutC(c);\r
+ } else {\r
+ f.PutC(0xC0|n);\r
+ f.PutC(c);\r
+ }\r
+ n=0;\r
+ }\r
+ if (n==0x3F) {\r
+ f.PutC(0xFF);\r
+ f.PutC(c);\r
+ n=0;\r
+ }\r
+ if (p==-2) f.PutC(0);\r
+ c=(BYTE)p;\r
+ n++;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImagePCX::PCX_PackPlanes(BYTE* buff, const long size, CxFile &f)\r
+{\r
+ BYTE *start,*end;\r
+ BYTE c, previous, count;\r
+\r
+ start = buff;\r
+ end = buff + size;\r
+ previous = *start++;\r
+ count = 1;\r
+\r
+ while (start < end) {\r
+ c = *start++;\r
+ if (c == previous && count < 63) {\r
+ ++count;\r
+ continue;\r
+ }\r
+\r
+ if (count > 1 || (previous & 0xc0) == 0xc0) {\r
+ f.PutC( count | 0xc0 );\r
+ }\r
+ f.PutC(previous);\r
+ previous = c;\r
+ count = 1;\r
+ }\r
+\r
+ if (count > 1 || (previous & 0xc0) == 0xc0) {\r
+ count |= 0xc0;\r
+ f.PutC(count);\r
+ }\r
+ f.PutC(previous);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImagePCX::PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane)\r
+{\r
+ int cbit, x, mask;\r
+ unsigned char *cp = buf-1;\r
+\r
+ mask = 1 << plane;\r
+ cbit = -1;\r
+ for( x = 0; x < width; x++ ) {\r
+ if( cbit < 0 ) {\r
+ cbit = 7;\r
+ *++cp = 0;\r
+ }\r
+ if( raw[x] & mask )\r
+ *cp |= (1<<cbit);\r
+ --cbit;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImagePCX::PCX_toh(PCXHEADER* p)\r
+{\r
+ p->Xmin = ntohs(p->Xmin);\r
+ p->Ymin = ntohs(p->Ymin);\r
+ p->Xmax = ntohs(p->Xmax);\r
+ p->Ymax = ntohs(p->Ymax);\r
+ p->Hres = ntohs(p->Hres);\r
+ p->Vres = ntohs(p->Vres);\r
+ p->BytesPerLine = ntohs(p->BytesPerLine);\r
+ p->PaletteType = ntohs(p->PaletteType);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_PCX\r
--- /dev/null
+/*\r
+ * File: ximapcx.h\r
+ * Purpose: PCX Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImagePCX (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Parts of the code come from Paintlib: Copyright (c) 1996-1998 Ulrich von Zadow\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaPCX_h)\r
+#define __ximaPCX_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_PCX\r
+\r
+class CxImagePCX: public CxImage\r
+{\r
+// PCX Image File\r
+#pragma pack(1)\r
+typedef struct tagPCXHEADER\r
+{\r
+ char Manufacturer; // always 0X0A\r
+ char Version; // version number\r
+ char Encoding; // always 1\r
+ char BitsPerPixel; // color bits\r
+ WORD Xmin, Ymin; // image origin\r
+ WORD Xmax, Ymax; // image dimensions\r
+ WORD Hres, Vres; // resolution values\r
+ BYTE ColorMap[16][3]; // color palette\r
+ char Reserved;\r
+ char ColorPlanes; // color planes\r
+ WORD BytesPerLine; // line buffer size\r
+ WORD PaletteType; // grey or color palette\r
+ char Filter[58];\r
+} PCXHEADER;\r
+#pragma pack()\r
+\r
+public:\r
+ CxImagePCX(): CxImage(CXIMAGE_FORMAT_PCX) {}\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PCX);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PCX);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+protected:\r
+ bool PCX_PlanesToPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel);\r
+ bool PCX_UnpackPixels(BYTE * pixels, BYTE * bitplanes, short bytesperline, short planes, short bitsperpixel);\r
+ void PCX_PackPixels(const long p,BYTE &c, BYTE &n, CxFile &f);\r
+ void PCX_PackPlanes(BYTE* buff, const long size, CxFile &f);\r
+ void PCX_PixelsToPlanes(BYTE* raw, long width, BYTE* buf, long plane);\r
+ void PCX_toh(PCXHEADER* p);\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximapng.cpp\r
+ * Purpose: Platform Independent PNG Image Class Loader and Writer\r
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximapng.h"\r
+\r
+#if CXIMAGE_SUPPORT_PNG\r
+\r
+#include "ximaiter.h"\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImagePNG::ima_png_error(png_struct *png_ptr, char *message)\r
+{\r
+ strcpy(info.szLastError,message);\r
+ longjmp(png_ptr->jmpbuf, 1);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImagePNG::expand2to4bpp(BYTE* prow)\r
+{\r
+ BYTE *psrc,*pdst;\r
+ BYTE pos,idx;\r
+ for(long x=head.biWidth-1;x>=0;x--){\r
+ psrc = prow + ((2*x)>>3);\r
+ pdst = prow + ((4*x)>>3);\r
+ pos = (BYTE)(2*(3-x%4));\r
+ idx = (BYTE)((*psrc & (0x03<<pos))>>pos);\r
+ pos = (BYTE)(4*(1-x%2));\r
+ *pdst &= ~(0x0F<<pos);\r
+ *pdst |= (idx & 0x0F)<<pos;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImagePNG::Decode(CxFile *hFile)\r
+{\r
+ png_struct *png_ptr;\r
+ png_info *info_ptr;\r
+ BYTE *row_pointers=NULL;\r
+ CImageIterator iter(this);\r
+\r
+ cx_try\r
+ {\r
+ /* Create and initialize the png_struct with the desired error handler\r
+ * functions. If you want to use the default stderr and longjump method,\r
+ * you can supply NULL for the last three parameters. We also supply the\r
+ * the compiler header file version, so that we know if the application\r
+ * was compiled with a compatible version of the library. REQUIRED */\r
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,NULL,NULL);\r
+ if (png_ptr == NULL) cx_throw("Failed to create PNG structure");\r
+\r
+ /* Allocate/initialize the memory for image information. REQUIRED. */\r
+ info_ptr = png_create_info_struct(png_ptr);\r
+ if (info_ptr == NULL) {\r
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);\r
+ cx_throw("Failed to initialize PNG info structure");\r
+ }\r
+\r
+ /* Set error handling if you are using the setjmp/longjmp method (this is\r
+ * the normal method of doing things with libpng). REQUIRED unless you\r
+ * set up your own error handlers in the png_create_read_struct() earlier. */\r
+ if (setjmp(png_ptr->jmpbuf)) {\r
+ /* Free all of the memory associated with the png_ptr and info_ptr */\r
+ delete [] row_pointers;\r
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);\r
+ cx_throw("");\r
+ }\r
+\r
+ // use custom I/O functions\r
+ png_set_read_fn(png_ptr, hFile, /*(png_rw_ptr)*/user_read_data);\r
+ png_set_error_fn(png_ptr,info.szLastError,/*(png_error_ptr)*/user_error_fn,NULL);\r
+\r
+ /* read the file information */\r
+ png_read_info(png_ptr, info_ptr);\r
+\r
+ if (info.nEscape == -1){\r
+ head.biWidth = info_ptr->width;\r
+ head.biHeight= info_ptr->height;\r
+ info.dwType = CXIMAGE_FORMAT_PNG;\r
+ longjmp(png_ptr->jmpbuf, 1);\r
+ }\r
+\r
+ /* calculate new number of channels */\r
+ int channels=0;\r
+ switch(info_ptr->color_type){\r
+ case PNG_COLOR_TYPE_GRAY:\r
+ case PNG_COLOR_TYPE_PALETTE:\r
+ channels = 1;\r
+ break;\r
+ case PNG_COLOR_TYPE_GRAY_ALPHA:\r
+ channels = 2;\r
+ break;\r
+ case PNG_COLOR_TYPE_RGB:\r
+ channels = 3;\r
+ break;\r
+ case PNG_COLOR_TYPE_RGB_ALPHA:\r
+ channels = 4;\r
+ break;\r
+ default:\r
+ strcpy(info.szLastError,"unknown PNG color type");\r
+ longjmp(png_ptr->jmpbuf, 1);\r
+ }\r
+\r
+ //find the right pixel depth used for cximage\r
+ int pixel_depth = info_ptr->pixel_depth;\r
+ if (channels == 1 && pixel_depth>8) pixel_depth=8;\r
+ if (channels == 2) pixel_depth=8;\r
+ if (channels >= 3) pixel_depth=24;\r
+\r
+ if (!Create(info_ptr->width, info_ptr->height, pixel_depth, CXIMAGE_FORMAT_PNG)){\r
+ longjmp(png_ptr->jmpbuf, 1);\r
+ }\r
+\r
+ /* get metrics */\r
+ switch (info_ptr->phys_unit_type)\r
+ {\r
+ case PNG_RESOLUTION_UNKNOWN:\r
+ SetXDPI(info_ptr->x_pixels_per_unit);\r
+ SetYDPI(info_ptr->y_pixels_per_unit);\r
+ break;\r
+ case PNG_RESOLUTION_METER:\r
+ SetXDPI((long)floor(info_ptr->x_pixels_per_unit * 254.0 / 10000.0 + 0.5));\r
+ SetYDPI((long)floor(info_ptr->y_pixels_per_unit * 254.0 / 10000.0 + 0.5));\r
+ break;\r
+ }\r
+\r
+ if (info_ptr->num_palette>0){\r
+ SetPalette((rgb_color*)info_ptr->palette,info_ptr->num_palette);\r
+ SetClrImportant(info_ptr->num_palette);\r
+ } else if (info_ptr->bit_depth ==2) { //<DP> needed for 2 bpp grayscale PNGs\r
+ SetPaletteColor(0,0,0,0);\r
+ SetPaletteColor(1,85,85,85);\r
+ SetPaletteColor(2,170,170,170);\r
+ SetPaletteColor(3,255,255,255);\r
+ } else SetGrayPalette(); //<DP> needed for grayscale PNGs\r
+ \r
+ int nshift = max(0,(info_ptr->bit_depth>>3)-1)<<3;\r
+\r
+ if (info_ptr->num_trans!=0){ //palette transparency\r
+ if (info_ptr->num_trans==1){\r
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE){\r
+ info.nBkgndIndex = info_ptr->trans_values.index;\r
+ } else{\r
+ info.nBkgndIndex = info_ptr->trans_values.gray>>nshift;\r
+ }\r
+ }\r
+ if (info_ptr->num_trans>1){\r
+ RGBQUAD* pal=GetPalette();\r
+ if (pal){\r
+ DWORD ip;\r
+ for (ip=0;ip<min(head.biClrUsed,(unsigned long)info_ptr->num_trans);ip++)\r
+ pal[ip].rgbReserved=info_ptr->trans[ip];\r
+ for (ip=info_ptr->num_trans;ip<head.biClrUsed;ip++){\r
+ pal[ip].rgbReserved=255;\r
+ }\r
+ info.bAlphaPaletteEnabled=true;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (channels == 3){ //check RGB binary transparency\r
+ png_bytep trans;\r
+ int num_trans;\r
+ png_color_16 *image_background;\r
+ if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &image_background)){\r
+ info.nBkgndColor.rgbRed = (BYTE)(info_ptr->trans_values.red>>nshift);\r
+ info.nBkgndColor.rgbGreen = (BYTE)(info_ptr->trans_values.green>>nshift);\r
+ info.nBkgndColor.rgbBlue = (BYTE)(info_ptr->trans_values.blue>>nshift);\r
+ info.nBkgndColor.rgbReserved = 0;\r
+ info.nBkgndIndex = 0;\r
+ }\r
+ }\r
+\r
+ int alpha_present = (channels - 1) % 2;\r
+ if (alpha_present){\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ AlphaCreate();\r
+#else\r
+ png_set_strip_alpha(png_ptr);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+\r
+ // <vho> - flip the RGB pixels to BGR (or RGBA to BGRA)\r
+ if (info_ptr->color_type & PNG_COLOR_MASK_COLOR){\r
+ png_set_bgr(png_ptr);\r
+ }\r
+\r
+ // <vho> - handle cancel\r
+ if (info.nEscape) longjmp(png_ptr->jmpbuf, 1);\r
+\r
+ // row_bytes is the width x number of channels x (bit-depth / 8)\r
+ row_pointers = new BYTE[info_ptr->rowbytes + 8];\r
+\r
+ // turn on interlace handling\r
+ int number_passes = png_set_interlace_handling(png_ptr);\r
+\r
+ if (number_passes>1){\r
+ SetCodecOption(1);\r
+ } else {\r
+ SetCodecOption(0);\r
+ }\r
+\r
+ int chan_offset = info_ptr->bit_depth >> 3;\r
+ int pixel_offset = info_ptr->pixel_depth >> 3;\r
+\r
+ for (int pass=0; pass < number_passes; pass++) {\r
+ iter.Upset();\r
+ int y=0;\r
+ do {\r
+\r
+ // <vho> - handle cancel\r
+ if (info.nEscape) longjmp(png_ptr->jmpbuf, 1);\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ if (AlphaIsValid()) {\r
+\r
+ //compute the correct position of the line\r
+ long ax,ay;\r
+ ay = head.biHeight-1-y;\r
+ BYTE* prow= iter.GetRow(ay);\r
+\r
+ //recover data from previous scan\r
+ if (info_ptr->interlace_type && pass>0 && pass!=7){\r
+ for(ax=0;ax<head.biWidth;ax++){\r
+ long px = ax * pixel_offset;\r
+ if (channels == 2){\r
+ row_pointers[px] = prow[ax];\r
+ row_pointers[px+chan_offset]=AlphaGet(ax,ay);\r
+ } else {\r
+ long qx = ax * 3;\r
+ row_pointers[px] =prow[qx];\r
+ row_pointers[px+chan_offset] =prow[qx+1];\r
+ row_pointers[px+chan_offset*2]=prow[qx+2];\r
+ row_pointers[px+chan_offset*3]=AlphaGet(ax,ay);\r
+ }\r
+ }\r
+ }\r
+\r
+ //read next row\r
+ png_read_row(png_ptr, row_pointers, NULL);\r
+\r
+ //RGBA -> RGB + A\r
+ for(ax=0;ax<head.biWidth;ax++){\r
+ long px = ax * pixel_offset;\r
+ if (channels == 2){\r
+ prow[ax] = row_pointers[px];\r
+ AlphaSet(ax,ay,row_pointers[px+chan_offset]);\r
+ } else {\r
+ long qx = ax * 3;\r
+ prow[qx] =row_pointers[px];\r
+ prow[qx+1]=row_pointers[px+chan_offset];\r
+ prow[qx+2]=row_pointers[px+chan_offset*2];\r
+ AlphaSet(ax,ay,row_pointers[px+chan_offset*3]);\r
+ }\r
+ }\r
+ } else\r
+#endif // CXIMAGE_SUPPORT_ALPHA // vho\r
+ {\r
+ //recover data from previous scan\r
+ if (info_ptr->interlace_type && pass>0){\r
+ iter.GetRow(row_pointers, info_ptr->rowbytes);\r
+ //re-expand buffer for images with bit depth > 8\r
+ if (info_ptr->bit_depth > 8){\r
+ for(long ax=(head.biWidth*channels-1);ax>=0;ax--)\r
+ row_pointers[ax*chan_offset] = row_pointers[ax];\r
+ }\r
+ }\r
+\r
+ //read next row\r
+ png_read_row(png_ptr, row_pointers, NULL);\r
+\r
+ //shrink 16 bit depth images down to 8 bits\r
+ if (info_ptr->bit_depth > 8){\r
+ for(long ax=0;ax<(head.biWidth*channels);ax++)\r
+ row_pointers[ax] = row_pointers[ax*chan_offset];\r
+ }\r
+\r
+ //copy the pixels\r
+ iter.SetRow(row_pointers, info_ptr->rowbytes);\r
+ //<DP> expand 2 bpp images only in the last pass\r
+ if (info_ptr->bit_depth==2 && pass==(number_passes-1))\r
+ expand2to4bpp(iter.GetRow());\r
+\r
+ //go on\r
+ iter.PrevRow();\r
+ }\r
+\r
+ y++;\r
+ } while(y<head.biHeight);\r
+ }\r
+\r
+ delete [] row_pointers;\r
+\r
+ /* read the rest of the file, getting any additional chunks in info_ptr */\r
+ png_read_end(png_ptr, info_ptr);\r
+\r
+ /* clean up after the read, and free any memory allocated - REQUIRED */\r
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_PNG) return true;\r
+ return false;\r
+ }\r
+ /* that's it */\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImagePNG::Encode(CxFile *hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ CImageIterator iter(this);\r
+ BYTE trans[256]; //for transparency (don't move)\r
+ png_struct *png_ptr;\r
+ png_info *info_ptr;\r
+\r
+ cx_try\r
+ {\r
+ /* Create and initialize the png_struct with the desired error handler\r
+ * functions. If you want to use the default stderr and longjump method,\r
+ * you can supply NULL for the last three parameters. We also check that\r
+ * the library version is compatible with the one used at compile time,\r
+ * in case we are using dynamically linked libraries. REQUIRED.\r
+ */\r
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,(void *)NULL,NULL,NULL);\r
+ if (png_ptr == NULL) cx_throw("Failed to create PNG structure");\r
+\r
+ /* Allocate/initialize the image information data. REQUIRED */\r
+ info_ptr = png_create_info_struct(png_ptr);\r
+ if (info_ptr == NULL){\r
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);\r
+ cx_throw("Failed to initialize PNG info structure");\r
+ }\r
+\r
+ /* Set error handling. REQUIRED if you aren't supplying your own\r
+ * error hadnling functions in the png_create_write_struct() call.\r
+ */\r
+ if (setjmp(png_ptr->jmpbuf)){\r
+ /* If we get here, we had a problem reading the file */\r
+ if (info_ptr->palette) free(info_ptr->palette);\r
+ png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr);\r
+ cx_throw("Error saving PNG file");\r
+ }\r
+ \r
+ /* set up the output control */\r
+ //png_init_io(png_ptr, hFile);\r
+\r
+ // use custom I/O functions\r
+ png_set_write_fn(png_ptr,hFile,/*(png_rw_ptr)*/user_write_data,/*(png_flush_ptr)*/user_flush_data);\r
+\r
+ /* set the file information here */\r
+ info_ptr->width = GetWidth();\r
+ info_ptr->height = GetHeight();\r
+ info_ptr->pixel_depth = (BYTE)GetBpp();\r
+ info_ptr->channels = (GetBpp()>8) ? (BYTE)3: (BYTE)1;\r
+ info_ptr->bit_depth = (BYTE)(GetBpp()/info_ptr->channels);\r
+ info_ptr->compression_type = info_ptr->filter_type = 0;\r
+ info_ptr->valid = 0;\r
+\r
+ switch(GetCodecOption(CXIMAGE_FORMAT_PNG)){\r
+ case 1:\r
+ info_ptr->interlace_type = PNG_INTERLACE_ADAM7;\r
+ break;\r
+ default:\r
+ info_ptr->interlace_type = PNG_INTERLACE_NONE;\r
+ }\r
+\r
+ /* set compression level */\r
+ //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);\r
+\r
+ bool bGrayScale = IsGrayScale();\r
+\r
+ if (GetNumColors()){\r
+ if (bGrayScale){\r
+ info_ptr->color_type = PNG_COLOR_TYPE_GRAY;\r
+ } else {\r
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;\r
+ }\r
+ } else {\r
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB;\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()){\r
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;\r
+ info_ptr->channels++;\r
+ info_ptr->bit_depth = 8;\r
+ info_ptr->pixel_depth += 8;\r
+ }\r
+#endif\r
+\r
+ /* set background */\r
+ png_color_16 image_background={ 0, 255, 255, 255, 0 };\r
+ RGBQUAD tc = GetTransColor();\r
+ if (info.nBkgndIndex>=0) {\r
+ image_background.blue = tc.rgbBlue;\r
+ image_background.green = tc.rgbGreen;\r
+ image_background.red = tc.rgbRed;\r
+ }\r
+ png_set_bKGD(png_ptr, info_ptr, &image_background);\r
+\r
+ /* set metrics */\r
+ png_set_pHYs(png_ptr, info_ptr, head.biXPelsPerMeter, head.biYPelsPerMeter, PNG_RESOLUTION_METER);\r
+\r
+ png_set_IHDR(png_ptr, info_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth,\r
+ info_ptr->color_type, info_ptr->interlace_type,\r
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);\r
+\r
+ //<DP> simple transparency\r
+ if (info.nBkgndIndex >= 0){\r
+ info_ptr->num_trans = 1;\r
+ info_ptr->valid |= PNG_INFO_tRNS;\r
+ info_ptr->trans = trans;\r
+ info_ptr->trans_values.index = (BYTE)info.nBkgndIndex;\r
+ info_ptr->trans_values.red = tc.rgbRed;\r
+ info_ptr->trans_values.green = tc.rgbGreen;\r
+ info_ptr->trans_values.blue = tc.rgbBlue;\r
+ info_ptr->trans_values.gray = info_ptr->trans_values.index;\r
+\r
+ // the transparency indexes start from 0 for non grayscale palette\r
+ if (!bGrayScale && head.biClrUsed && info.nBkgndIndex)\r
+ SwapIndex(0,(BYTE)info.nBkgndIndex);\r
+ }\r
+\r
+ /* set the palette if there is one */\r
+ if (GetPalette()){\r
+ if (!bGrayScale){\r
+ info_ptr->valid |= PNG_INFO_PLTE;\r
+ }\r
+\r
+ int nc = GetClrImportant();\r
+ if (nc==0) nc = GetNumColors();\r
+\r
+ if (info.bAlphaPaletteEnabled){\r
+ for(WORD ip=0; ip<nc;ip++)\r
+ trans[ip]=GetPaletteColor((BYTE)ip).rgbReserved;\r
+ info_ptr->num_trans = (WORD)nc;\r
+ info_ptr->valid |= PNG_INFO_tRNS;\r
+ info_ptr->trans = trans;\r
+ }\r
+\r
+ // copy the palette colors\r
+ info_ptr->palette = new png_color[nc];\r
+ info_ptr->num_palette = (png_uint_16) nc;\r
+ for (int i=0; i<nc; i++)\r
+ GetPaletteColor(i, &info_ptr->palette[i].red, &info_ptr->palette[i].green, &info_ptr->palette[i].blue);\r
+ } \r
+\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ //Merge the transparent color with the alpha channel\r
+ if (AlphaIsValid() && head.biBitCount==24 && info.nBkgndIndex>=0){\r
+ for(long y=0; y < head.biHeight; y++){\r
+ for(long x=0; x < head.biWidth ; x++){\r
+ RGBQUAD c=GetPixelColor(x,y,false);\r
+ if (*(long*)&c==*(long*)&tc)\r
+ AlphaSet(x,y,0);\r
+ } } }\r
+#endif // CXIMAGE_SUPPORT_ALPHA // <vho>\r
+\r
+ int row_size = max(info.dwEffWidth, info_ptr->width*info_ptr->channels*(info_ptr->bit_depth/8));\r
+ info_ptr->rowbytes = row_size;\r
+ BYTE *row_pointers = new BYTE[row_size];\r
+\r
+ /* write the file information */\r
+ png_write_info(png_ptr, info_ptr);\r
+\r
+ //interlace handling\r
+ int num_pass = png_set_interlace_handling(png_ptr);\r
+ for (int pass = 0; pass < num_pass; pass++){\r
+ //write image\r
+ iter.Upset();\r
+ long ay=head.biHeight-1;\r
+ RGBQUAD c;\r
+ do {\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ if (AlphaIsValid()){\r
+ for (long ax=head.biWidth-1; ax>=0;ax--){\r
+ c = BlindGetPixelColor(ax,ay);\r
+ int px = ax * info_ptr->channels;\r
+ if (!bGrayScale){\r
+ row_pointers[px++]=c.rgbRed;\r
+ row_pointers[px++]=c.rgbGreen;\r
+ }\r
+ row_pointers[px++]=c.rgbBlue;\r
+ row_pointers[px] = AlphaGet(ax,ay);\r
+ }\r
+ png_write_row(png_ptr, row_pointers);\r
+ ay--;\r
+ }\r
+ else\r
+#endif //CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ {\r
+ iter.GetRow(row_pointers, row_size);\r
+ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB) //HACK BY OP\r
+ RGBtoBGR(row_pointers, row_size);\r
+ png_write_row(png_ptr, row_pointers);\r
+ }\r
+ } while(iter.PrevRow());\r
+ }\r
+\r
+ delete [] row_pointers;\r
+\r
+ //if necessary, restore the original palette\r
+ if (!bGrayScale && head.biClrUsed && info.nBkgndIndex>0)\r
+ SwapIndex((BYTE)info.nBkgndIndex,0);\r
+\r
+ /* It is REQUIRED to call this to finish writing the rest of the file */\r
+ png_write_end(png_ptr, info_ptr);\r
+\r
+ /* if you malloced the palette, free it here */\r
+ if (info_ptr->palette){\r
+ delete [] (info_ptr->palette);\r
+ info_ptr->palette = NULL;\r
+ }\r
+\r
+ /* clean up after the write, and free any memory allocated */\r
+ png_destroy_write_struct(&png_ptr, (png_infopp)&info_ptr);\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return FALSE;\r
+ }\r
+ /* that's it */\r
+ return TRUE;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_PNG\r
--- /dev/null
+/*\r
+ * File: ximapng.h\r
+ * Purpose: PNG Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImagePNG (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes\r
+ *\r
+ * original CImagePNG and CImageIterator implementation are:\r
+ * Copyright: (c) 1995, Alejandro Aguilar Sierra <asierra(at)servidor(dot)unam(dot)mx>\r
+ *\r
+ * libpng Copyright (c) 1998-2003 Glenn Randers-Pehrson\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaPNG_h)\r
+#define __ximaPNG_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_PNG\r
+\r
+extern "C" {\r
+#include "../png/png.h"\r
+}\r
+\r
+class CxImagePNG: public CxImage\r
+{\r
+public:\r
+ CxImagePNG(): CxImage(CXIMAGE_FORMAT_PNG) {}\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_PNG);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_PNG);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+protected:\r
+ void ima_png_error(png_struct *png_ptr, char *message);\r
+ void expand2to4bpp(BYTE* prow);\r
+\r
+ static void PNGAPI user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)\r
+ {\r
+ CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr);\r
+ if (hFile == NULL || hFile->Read(data,1,length) != length) png_error(png_ptr, "Read Error");\r
+ }\r
+\r
+ static void PNGAPI user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)\r
+ {\r
+ CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr);\r
+ if (hFile == NULL || hFile->Write(data,1,length) != length) png_error(png_ptr, "Write Error");\r
+ }\r
+\r
+ static void PNGAPI user_flush_data(png_structp png_ptr)\r
+ {\r
+ CxFile* hFile = (CxFile*)png_get_io_ptr(png_ptr);\r
+ if (hFile == NULL || !hFile->Flush()) png_error(png_ptr, "Flush Error");\r
+ }\r
+\r
+ static void PNGAPI user_error_fn(png_structp png_ptr,png_const_charp error_msg)\r
+ {\r
+ strncpy((char*)png_ptr->error_ptr,error_msg,255);\r
+ longjmp(png_ptr->jmpbuf, 1);\r
+ }\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximaraw.cpp\r
+ * Purpose: Platform Independent RAW Image Class Loader\r
+ * 16/Dec/2007 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ * \r
+ * CxImageRAW (c) May/2006 pdw63\r
+ *\r
+ * based on dcraw.c -- Dave Coffin's raw photo decoder\r
+ * Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net\r
+ */\r
+\r
+#include "ximaraw.h"\r
+\r
+#if CXIMAGE_SUPPORT_RAW\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageRAW::Decode(CxFile *hFile)\r
+{\r
+ if (hFile==NULL)\r
+ return false;\r
+\r
+ DCRAW dcr;\r
+\r
+ cx_try\r
+ {\r
+ // initialization\r
+ dcr_init_dcraw(&dcr);\r
+\r
+ dcr.opt.user_qual = GetCodecOption(CXIMAGE_FORMAT_RAW) & 0x03;\r
+\r
+ // setup variables for debugging\r
+ char szClass[] = "CxImageRAW";\r
+ dcr.ifname = szClass;\r
+ dcr.sz_error = info.szLastError;\r
+\r
+ // setup library options, see dcr_print_manual for the available switches\r
+ // call dcr_parse_command_line_options(&dcr,0,0,0) to set default options\r
+ // if (dcr_parse_command_line_options(&dcr,argc,argv,&arg))\r
+ if (dcr_parse_command_line_options(&dcr,0,0,0)){\r
+ cx_throw("CxImageRAW: unknown option");\r
+ }\r
+\r
+ // set return point for error handling\r
+ if (setjmp (dcr.failure)) {\r
+ cx_throw("");\r
+ }\r
+\r
+ // install file manager\r
+ CxFileRaw src(hFile,&dcr);\r
+\r
+ // check file header\r
+ dcr_identify(&dcr);\r
+ \r
+ if(!dcr.is_raw){\r
+ cx_throw("CxImageRAW: not a raw image");\r
+ }\r
+\r
+ if (dcr.load_raw == NULL) {\r
+ cx_throw("CxImageRAW: missing raw decoder");\r
+ }\r
+\r
+ // verify special case\r
+ if (dcr.load_raw == dcr_kodak_ycbcr_load_raw) {\r
+ dcr.height += dcr.height & 1;\r
+ dcr.width += dcr.width & 1;\r
+ }\r
+\r
+ if (info.nEscape == -1){\r
+ head.biWidth = dcr.width;\r
+ head.biHeight= dcr.height;\r
+ info.dwType = CXIMAGE_FORMAT_RAW;\r
+ cx_throw("output dimensions returned");\r
+ }\r
+\r
+ // shrinked decoding available and requested?\r
+ dcr.shrink = dcr.filters && (dcr.opt.half_size || dcr.opt.threshold || dcr.opt.aber[0] != 1 || dcr.opt.aber[2] != 1);\r
+ dcr.iheight = (dcr.height + dcr.shrink) >> dcr.shrink;\r
+ dcr.iwidth = (dcr.width + dcr.shrink) >> dcr.shrink;\r
+\r
+ // install custom camera matrix\r
+ if (dcr.opt.use_camera_matrix && dcr.cmatrix[0][0] > 0.25) {\r
+ memcpy (dcr.rgb_cam, dcr.cmatrix, sizeof dcr.cmatrix);\r
+ dcr.raw_color = 0;\r
+ }\r
+\r
+ // allocate memory for the image\r
+ dcr.image = (ushort (*)[4]) calloc (dcr.iheight*dcr.iwidth, sizeof *dcr.image);\r
+ dcr_merror (&dcr, dcr.image, szClass);\r
+\r
+ if (dcr.meta_length) {\r
+ dcr.meta_data = (char *) malloc (dcr.meta_length);\r
+ dcr_merror (&dcr, dcr.meta_data, szClass);\r
+ }\r
+\r
+ // start image decoder\r
+ hFile->Seek(dcr.data_offset, SEEK_SET);\r
+ (*dcr.load_raw)(&dcr);\r
+\r
+ // post processing\r
+ if (dcr.zero_is_bad) dcr_remove_zeroes(&dcr);\r
+\r
+ dcr_bad_pixels(&dcr);\r
+\r
+ if (dcr.opt.dark_frame) dcr_subtract (&dcr,dcr.opt.dark_frame);\r
+\r
+ dcr.quality = 2 + !dcr.fuji_width;\r
+\r
+ if (dcr.opt.user_qual >= 0) dcr.quality = dcr.opt.user_qual;\r
+\r
+ if (dcr.opt.user_black >= 0) dcr.black = dcr.opt.user_black;\r
+\r
+#ifdef COLORCHECK\r
+ dcr_colorcheck(&dcr);\r
+#endif\r
+\r
+#if RESTRICTED\r
+ if (dcr.is_foveon && !dcr.opt.document_mode) dcr_foveon_interpolate(&dcr);\r
+#endif\r
+\r
+ if (!dcr.is_foveon && dcr.opt.document_mode < 2) dcr_scale_colors(&dcr);\r
+\r
+ // pixel interpolation and filters\r
+ dcr_pre_interpolate(&dcr);\r
+\r
+ if (dcr.filters && !dcr.opt.document_mode) {\r
+ if (dcr.quality == 0)\r
+ dcr_lin_interpolate(&dcr);\r
+ else if (dcr.quality == 1 || dcr.colors > 3)\r
+ dcr_vng_interpolate(&dcr);\r
+ else if (dcr.quality == 2)\r
+ dcr_ppg_interpolate(&dcr);\r
+ else\r
+ dcr_ahd_interpolate(&dcr);\r
+ }\r
+\r
+ if (dcr.mix_green) {\r
+ long i;\r
+ for (dcr.colors=3, i=0; i < dcr.height*dcr.width; i++) {\r
+ dcr.image[i][1] = (dcr.image[i][1] + dcr.image[i][3]) >> 1;\r
+ }\r
+ }\r
+\r
+ if (!dcr.is_foveon && dcr.colors == 3) dcr_median_filter(&dcr);\r
+\r
+ if (!dcr.is_foveon && dcr.opt.highlight == 2) dcr_blend_highlights(&dcr);\r
+\r
+ if (!dcr.is_foveon && dcr.opt.highlight > 2) dcr_recover_highlights(&dcr);\r
+\r
+ if (dcr.opt.use_fuji_rotate) dcr_fuji_rotate(&dcr);\r
+\r
+#ifndef NO_LCMS\r
+ if (dcr.opt.cam_profile) dcr_apply_profile (dcr.opt.cam_profile, dcr.opt.out_profile);\r
+#endif\r
+\r
+ // final conversion\r
+ dcr_convert_to_rgb(&dcr);\r
+\r
+ if (dcr.opt.use_fuji_rotate) dcr_stretch(&dcr);\r
+\r
+ dcr.iheight = dcr.height;\r
+ dcr.iwidth = dcr.width;\r
+ if (dcr.flip & 4) SWAP(dcr.height,dcr.width);\r
+\r
+ // ready to transfer data from dcr.image\r
+ if (!Create(dcr.width,dcr.height,24,CXIMAGE_FORMAT_RAW)){\r
+ cx_throw("");\r
+ }\r
+\r
+ uchar *ppm = (uchar *) calloc (dcr.width, dcr.colors*dcr.opt.output_bps/8);\r
+ ushort *ppm2 = (ushort *) ppm;\r
+ dcr_merror (&dcr, ppm, szClass);\r
+\r
+ uchar lut[0x10000];\r
+ if (dcr.opt.output_bps == 8) dcr_gamma_lut (&dcr, lut);\r
+\r
+ long c, row, col, soff, rstep, cstep;\r
+ soff = dcr_flip_index (&dcr, 0, 0);\r
+ cstep = dcr_flip_index (&dcr, 0, 1) - soff;\r
+ rstep = dcr_flip_index (&dcr, 1, 0) - dcr_flip_index (&dcr, 0, dcr.width);\r
+ for (row=0; row < dcr.height; row++, soff += rstep) {\r
+ for (col=0; col < dcr.width; col++, soff += cstep) {\r
+ if (dcr.opt.output_bps == 8)\r
+ for (c=0; c < dcr.colors; c++) ppm [col*dcr.colors+c] = lut[dcr.image[soff][c]];\r
+ else\r
+ for (c=0; c < dcr.colors; c++) ppm2[col*dcr.colors+c] = dcr.image[soff][c];\r
+ }\r
+ if (dcr.opt.output_bps == 16 && !dcr.opt.output_tiff && htons(0x55aa) != 0x55aa)\r
+ _swab ((char*)ppm2, (char*)ppm2, dcr.width*dcr.colors*2);\r
+\r
+ DWORD size = dcr.width * (dcr.colors*dcr.opt.output_bps/8);\r
+ RGBtoBGR(ppm,size);\r
+ memcpy(GetBits(dcr.height - 1 - row), ppm, min(size,GetEffWidth()));\r
+ }\r
+ free (ppm);\r
+\r
+\r
+ dcr_cleanup_dcraw(&dcr);\r
+\r
+ } cx_catch {\r
+\r
+ dcr_cleanup_dcraw(&dcr);\r
+\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_RAW) return true;\r
+ return false;\r
+ }\r
+ /* that's it */\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageRAW::Encode(CxFile * hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+ strcpy(info.szLastError, "Save RAW not supported");\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_RAW\r
+\r
--- /dev/null
+/*\r
+ * File: ximaraw.h\r
+ * Purpose: RAW Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageRAW (c) May/2006 pdw63\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ * Special thanks to David Coffin for dcraw without which this class would not exist\r
+ *\r
+ * libdcr (c) Dec/2007 Davide Pizzolato - www.xdp.it\r
+ *\r
+ * based on dcraw.c -- Dave Coffin's raw photo decoder\r
+ * Copyright 1997-2007 by Dave Coffin, dcoffin a cybercom o net\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaRAW_h)\r
+#define __ximaRAW_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_RAW\r
+\r
+extern "C" {\r
+ #include "../raw/libdcr.h"\r
+}\r
+\r
+class CxImageRAW: public CxImage\r
+{\r
+\r
+public:\r
+ CxImageRAW(): CxImage(CXIMAGE_FORMAT_RAW) {}\r
+\r
+// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);}\r
+// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+ enum CODEC_OPTION\r
+ {\r
+ DECODE_QUALITY_LIN = 0x00,\r
+ DECODE_QUALITY_VNG = 0x01,\r
+ DECODE_QUALITY_PPG = 0x02,\r
+ DECODE_QUALITY_AHD = 0x03,\r
+ }; \r
+\r
+protected:\r
+\r
+ class CxFileRaw\r
+ {\r
+ public:\r
+ CxFileRaw(CxFile* pFile,DCRAW *stream)\r
+ {\r
+ stream->obj_ = pFile;\r
+\r
+ ras_stream_CxFile.read_ = raw_sfile_read;\r
+ ras_stream_CxFile.write_ = raw_sfile_write;\r
+ ras_stream_CxFile.seek_ = raw_sfile_seek;\r
+ ras_stream_CxFile.close_ = raw_sfile_close;\r
+ ras_stream_CxFile.gets_ = raw_sfile_gets;\r
+ ras_stream_CxFile.eof_ = raw_sfile_eof;\r
+ ras_stream_CxFile.tell_ = raw_sfile_tell;\r
+ ras_stream_CxFile.getc_ = raw_sfile_getc;\r
+ ras_stream_CxFile.scanf_ = raw_sfile_scanf;\r
+\r
+ stream->ops_ = &ras_stream_CxFile;\r
+\r
+ }\r
+\r
+ static int raw_sfile_read(dcr_stream_obj *obj, void *buf, int size, int cnt)\r
+ { return ((CxFile*)obj)->Read(buf,size,cnt); }\r
+\r
+ static int raw_sfile_write(dcr_stream_obj *obj, void *buf, int size, int cnt)\r
+ { return ((CxFile*)obj)->Write(buf,size,cnt); }\r
+\r
+ static long raw_sfile_seek(dcr_stream_obj *obj, long offset, int origin)\r
+ { return ((CxFile*)obj)->Seek(offset,origin); }\r
+\r
+ static int raw_sfile_close(dcr_stream_obj *obj)\r
+ { return 1; /*((CxFile*)obj)->Close();*/ }\r
+\r
+ static char* raw_sfile_gets(dcr_stream_obj *obj, char *string, int n)\r
+ { return ((CxFile*)obj)->GetS(string,n); }\r
+\r
+ static int raw_sfile_eof(dcr_stream_obj *obj)\r
+ { return ((CxFile*)obj)->Eof(); }\r
+\r
+ static long raw_sfile_tell(dcr_stream_obj *obj)\r
+ { return ((CxFile*)obj)->Tell(); }\r
+\r
+ static int raw_sfile_getc(dcr_stream_obj *obj)\r
+ { return ((CxFile*)obj)->GetC(); }\r
+\r
+ static int raw_sfile_scanf(dcr_stream_obj *obj,const char *format, void* output)\r
+ { return ((CxFile*)obj)->Scanf(format, output); }\r
+\r
+ private:\r
+ dcr_stream_ops ras_stream_CxFile;\r
+ };\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+// xImaSel.cpp : Selection functions\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if the image has a valid selection.\r
+ */\r
+bool CxImage::SelectionIsValid()\r
+{\r
+ return pSelection!=0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Gets the smallest rectangle that contains the selection \r
+ */\r
+void CxImage::SelectionGetBox(RECT& r)\r
+{\r
+ memcpy(&r,&info.rSelectionBox,sizeof(RECT));\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Empties the selection.\r
+ */\r
+bool CxImage::SelectionClear(BYTE level)\r
+{\r
+ if (pSelection){\r
+ if (level==0){\r
+ memset(pSelection,0,head.biWidth * head.biHeight);\r
+ info.rSelectionBox.left = head.biWidth;\r
+ info.rSelectionBox.bottom = head.biHeight;\r
+ info.rSelectionBox.right = info.rSelectionBox.top = 0;\r
+ } else {\r
+ memset(pSelection,level,head.biWidth * head.biHeight);\r
+ info.rSelectionBox.right = head.biWidth;\r
+ info.rSelectionBox.top = head.biHeight;\r
+ info.rSelectionBox.left = info.rSelectionBox.bottom = 0;\r
+ }\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Allocates an empty selection.\r
+ */\r
+bool CxImage::SelectionCreate()\r
+{\r
+ SelectionDelete();\r
+ pSelection = (BYTE*)calloc(head.biWidth * head.biHeight, 1);\r
+ return (pSelection!=0);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Deallocates the selction.\r
+ */\r
+bool CxImage::SelectionDelete()\r
+{\r
+ if (pSelection){\r
+ free(pSelection);\r
+ pSelection=NULL;\r
+ }\r
+ info.rSelectionBox.left = head.biWidth;\r
+ info.rSelectionBox.bottom = head.biHeight;\r
+ info.rSelectionBox.right = info.rSelectionBox.top = 0;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if the coordinates are inside the selection.\r
+ */\r
+bool CxImage::SelectionIsInside(long x, long y)\r
+{\r
+ if (IsInside(x,y)){\r
+ if (pSelection==NULL) return true;\r
+ return pSelection[x+y*head.biWidth]!=0;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Checks if the coordinates are inside the selection.\r
+ * "blind" version assumes that (x,y) is inside to the image.\r
+ */\r
+bool CxImage::BlindSelectionIsInside(long x, long y)\r
+{\r
+#ifdef _DEBUG\r
+ if (!IsInside(x,y))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ return 0;\r
+ #endif\r
+#endif\r
+ if (pSelection==NULL) return true;\r
+ return pSelection[x+y*head.biWidth]!=0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adds a rectangle to the existing selection.\r
+ */\r
+bool CxImage::SelectionAddRect(RECT r, BYTE level)\r
+{\r
+ if (pSelection==NULL) SelectionCreate();\r
+ if (pSelection==NULL) return false;\r
+\r
+ RECT r2;\r
+ if (r.left<r.right) {r2.left=r.left; r2.right=r.right; } else {r2.left=r.right ; r2.right=r.left; }\r
+ if (r.bottom<r.top) {r2.bottom=r.bottom; r2.top=r.top; } else {r2.bottom=r.top ; r2.top=r.bottom; }\r
+\r
+ if (info.rSelectionBox.top <= r2.top) info.rSelectionBox.top = max(0L,min(head.biHeight,r2.top+1));\r
+ if (info.rSelectionBox.left > r2.left) info.rSelectionBox.left = max(0L,min(head.biWidth,r2.left));\r
+ if (info.rSelectionBox.right <= r2.right) info.rSelectionBox.right = max(0L,min(head.biWidth,r2.right+1));\r
+ if (info.rSelectionBox.bottom > r2.bottom) info.rSelectionBox.bottom = max(0L,min(head.biHeight,r2.bottom));\r
+\r
+ long ymin = max(0L,min(head.biHeight,r2.bottom));\r
+ long ymax = max(0L,min(head.biHeight,r2.top+1));\r
+ long xmin = max(0L,min(head.biWidth,r2.left));\r
+ long xmax = max(0L,min(head.biWidth,r2.right+1));\r
+\r
+ for (long y=ymin; y<ymax; y++)\r
+ memset(pSelection + xmin + y * head.biWidth, level, xmax-xmin);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adds an ellipse to the existing selection.\r
+ */\r
+bool CxImage::SelectionAddEllipse(RECT r, BYTE level)\r
+{\r
+ if (pSelection==NULL) SelectionCreate();\r
+ if (pSelection==NULL) return false;\r
+\r
+ long xradius = abs(r.right - r.left)/2;\r
+ long yradius = abs(r.top - r.bottom)/2;\r
+ if (xradius==0 || yradius==0) return false;\r
+\r
+ long xcenter = (r.right + r.left)/2;\r
+ long ycenter = (r.top + r.bottom)/2;\r
+\r
+ if (info.rSelectionBox.left > (xcenter - xradius)) info.rSelectionBox.left = max(0L,min(head.biWidth,(xcenter - xradius)));\r
+ if (info.rSelectionBox.right <= (xcenter + xradius)) info.rSelectionBox.right = max(0L,min(head.biWidth,(xcenter + xradius + 1)));\r
+ if (info.rSelectionBox.bottom > (ycenter - yradius)) info.rSelectionBox.bottom = max(0L,min(head.biHeight,(ycenter - yradius)));\r
+ if (info.rSelectionBox.top <= (ycenter + yradius)) info.rSelectionBox.top = max(0L,min(head.biHeight,(ycenter + yradius + 1)));\r
+\r
+ long xmin = max(0L,min(head.biWidth,xcenter - xradius));\r
+ long xmax = max(0L,min(head.biWidth,xcenter + xradius + 1));\r
+ long ymin = max(0L,min(head.biHeight,ycenter - yradius));\r
+ long ymax = max(0L,min(head.biHeight,ycenter + yradius + 1));\r
+\r
+ long y,yo;\r
+ for (y=ymin; y<min(ycenter,ymax); y++){\r
+ for (long x=xmin; x<xmax; x++){\r
+ yo = (long)(ycenter - yradius * sqrt(1-pow((float)(x - xcenter)/(float)xradius,2)));\r
+ if (yo<y) pSelection[x + y * head.biWidth] = level;\r
+ }\r
+ }\r
+ for (y=ycenter; y<ymax; y++){\r
+ for (long x=xmin; x<xmax; x++){\r
+ yo = (long)(ycenter + yradius * sqrt(1-pow((float)(x - xcenter)/(float)xradius,2)));\r
+ if (yo>y) pSelection[x + y * head.biWidth] = level;\r
+ }\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Inverts the selection.\r
+ * Note: the SelectionBox is set to "full image", call SelectionGetBox before (if necessary)\r
+ */\r
+bool CxImage::SelectionInvert()\r
+{\r
+ if (pSelection) {\r
+ BYTE *iSrc=pSelection;\r
+ long n=head.biHeight*head.biWidth;\r
+ for(long i=0; i < n; i++){\r
+ *iSrc=(BYTE)~(*(iSrc));\r
+ iSrc++;\r
+ }\r
+\r
+ SelectionRebuildBox();\r
+\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Imports an existing region from another image with the same width and height.\r
+ */\r
+bool CxImage::SelectionCopy(CxImage &from)\r
+{\r
+ if (from.pSelection == NULL || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight) return false;\r
+ if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight);\r
+ if (pSelection==NULL) return false;\r
+ memcpy(pSelection,from.pSelection,head.biWidth * head.biHeight);\r
+ memcpy(&info.rSelectionBox,&from.info.rSelectionBox,sizeof(RECT));\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adds a polygonal region to the existing selection. points points to an array of POINT structures.\r
+ * Each structure specifies the x-coordinate and y-coordinate of one vertex of the polygon.\r
+ * npoints specifies the number of POINT structures in the array pointed to by points.\r
+ */\r
+bool CxImage::SelectionAddPolygon(POINT *points, long npoints, BYTE level)\r
+{\r
+ if (points==NULL || npoints<3) return false;\r
+\r
+ if (pSelection==NULL) SelectionCreate();\r
+ if (pSelection==NULL) return false;\r
+\r
+ BYTE* plocal = (BYTE*)calloc(head.biWidth*head.biHeight, 1);\r
+ RECT localbox = {head.biWidth,0,0,head.biHeight};\r
+\r
+ long x,y,i=0;\r
+ POINT *current;\r
+ POINT *next = NULL;\r
+ POINT *start = NULL;\r
+ //trace contour\r
+ while (i < npoints){\r
+ current = &points[i];\r
+ if (current->x!=-1){\r
+ if (i==0 || (i>0 && points[i-1].x==-1)) start = &points[i];\r
+\r
+ if ((i+1)==npoints || points[i+1].x==-1)\r
+ next = start;\r
+ else\r
+ next = &points[i+1];\r
+\r
+ float beta;\r
+ if (current->x != next->x){\r
+ beta = (float)(next->y - current->y)/(float)(next->x - current->x);\r
+ if (current->x < next->x){\r
+ for (x=current->x; x<=next->x; x++){\r
+ y = (long)(current->y + (x - current->x) * beta);\r
+ if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
+ }\r
+ } else {\r
+ for (x=current->x; x>=next->x; x--){\r
+ y = (long)(current->y + (x - current->x) * beta);\r
+ if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
+ }\r
+ }\r
+ }\r
+ if (current->y != next->y){\r
+ beta = (float)(next->x - current->x)/(float)(next->y - current->y);\r
+ if (current->y < next->y){\r
+ for (y=current->y; y<=next->y; y++){\r
+ x = (long)(current->x + (y - current->y) * beta);\r
+ if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
+ }\r
+ } else {\r
+ for (y=current->y; y>=next->y; y--){\r
+ x = (long)(current->x + (y - current->y) * beta);\r
+ if (IsInside(x,y)) plocal[x + y * head.biWidth] = 255;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ RECT r2;\r
+ if (current->x < next->x) {r2.left=current->x; r2.right=next->x; } else {r2.left=next->x ; r2.right=current->x; }\r
+ if (current->y < next->y) {r2.bottom=current->y; r2.top=next->y; } else {r2.bottom=next->y ; r2.top=current->y; }\r
+ if (localbox.top < r2.top) localbox.top = max(0L,min(head.biHeight-1,r2.top+1));\r
+ if (localbox.left > r2.left) localbox.left = max(0L,min(head.biWidth-1,r2.left-1));\r
+ if (localbox.right < r2.right) localbox.right = max(0L,min(head.biWidth-1,r2.right+1));\r
+ if (localbox.bottom > r2.bottom) localbox.bottom = max(0L,min(head.biHeight-1,r2.bottom-1));\r
+\r
+ i++;\r
+ }\r
+\r
+ //fill the outer region\r
+ long npix=(localbox.right - localbox.left)*(localbox.top - localbox.bottom);\r
+ POINT* pix = (POINT*)calloc(npix,sizeof(POINT));\r
+ BYTE back=0, mark=1;\r
+ long fx, fy, fxx, fyy, first, last;\r
+ long xmin = 0;\r
+ long xmax = 0;\r
+ long ymin = 0;\r
+ long ymax = 0;\r
+\r
+ for (int side=0; side<4; side++){\r
+ switch(side){\r
+ case 0:\r
+ xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.bottom+1;\r
+ break;\r
+ case 1:\r
+ xmin=localbox.right; xmax=localbox.right+1; ymin=localbox.bottom; ymax=localbox.top+1;\r
+ break;\r
+ case 2:\r
+ xmin=localbox.left; xmax=localbox.right+1; ymin=localbox.top; ymax=localbox.top+1;\r
+ break;\r
+ case 3:\r
+ xmin=localbox.left; xmax=localbox.left+1; ymin=localbox.bottom; ymax=localbox.top+1;\r
+ break;\r
+ }\r
+ //fill from the border points\r
+ for(y=ymin;y<ymax;y++){\r
+ for(x=xmin;x<xmax;x++){\r
+ if (plocal[x+y*head.biWidth]==0){\r
+ // Subject: FLOOD FILL ROUTINE Date: 12-23-97 (00:57) \r
+ // Author: Petter Holmberg Code: QB, QBasic, PDS \r
+ // Origin: petter.holmberg@usa.net Packet: GRAPHICS.ABC\r
+ first=0;\r
+ last=1;\r
+ while(first!=last){\r
+ fx = pix[first].x;\r
+ fy = pix[first].y;\r
+ fxx = fx + x;\r
+ fyy = fy + y;\r
+ for(;;)\r
+ {\r
+ if ((plocal[fxx + fyy*head.biWidth] == back) &&\r
+ fxx>=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top )\r
+ {\r
+ plocal[fxx + fyy*head.biWidth] = mark;\r
+ if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){\r
+ pix[last].x = fx;\r
+ pix[last].y = fy - 1;\r
+ last++;\r
+ if (last == npix) last = 0;\r
+ }\r
+ if ((fyy + 1)<head.biHeight && plocal[fxx + (fyy + 1)*head.biWidth] == back){\r
+ pix[last].x = fx;\r
+ pix[last].y = fy + 1;\r
+ last++;\r
+ if (last == npix) last = 0;\r
+ }\r
+ } else {\r
+ break;\r
+ }\r
+ fx++;\r
+ fxx++;\r
+ };\r
+\r
+ fx = pix[first].x - 1;\r
+ fy = pix[first].y;\r
+ fxx = fx + x;\r
+ fyy = fy + y;\r
+\r
+ for( ;; )\r
+ {\r
+ if ((plocal[fxx + fyy*head.biWidth] == back) &&\r
+ fxx>=localbox.left && fxx<=localbox.right && fyy>=localbox.bottom && fyy<=localbox.top )\r
+ {\r
+ plocal[fxx + (y + fy)*head.biWidth] = mark;\r
+ if (fyy > 0 && plocal[fxx + (fyy - 1)*head.biWidth] == back){\r
+ pix[last].x = fx;\r
+ pix[last].y = fy - 1;\r
+ last++;\r
+ if (last == npix) last = 0;\r
+ }\r
+ if ((fyy + 1)<head.biHeight && plocal[fxx + (fyy + 1)*head.biWidth] == back){\r
+ pix[last].x = fx;\r
+ pix[last].y = fy + 1;\r
+ last++;\r
+ if (last == npix) last = 0;\r
+ }\r
+ } else {\r
+ break;\r
+ }\r
+ fx--;\r
+ fxx--;\r
+ }\r
+ \r
+ first++;\r
+ if (first == npix) first = 0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //transfer the region\r
+ long yoffset;\r
+ for (y=localbox.bottom; y<=localbox.top; y++){\r
+ yoffset = y * head.biWidth;\r
+ for (x=localbox.left; x<=localbox.right; x++)\r
+ if (plocal[x + yoffset]!=1) pSelection[x + yoffset]=level;\r
+ }\r
+ if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = min(head.biHeight,localbox.top + 1);\r
+ if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = min(head.biWidth,localbox.left);\r
+ if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = min(head.biWidth,localbox.right + 1);\r
+ if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = min(head.biHeight,localbox.bottom);\r
+\r
+ free(plocal);\r
+ free(pix);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adds to the selection all the pixels matching the specified color.\r
+ */\r
+bool CxImage::SelectionAddColor(RGBQUAD c, BYTE level)\r
+{\r
+ if (pSelection==NULL) SelectionCreate();\r
+ if (pSelection==NULL) return false;\r
+\r
+ RECT localbox = {head.biWidth,0,0,head.biHeight};\r
+\r
+ for (long y = 0; y < head.biHeight; y++){\r
+ for (long x = 0; x < head.biWidth; x++){\r
+ RGBQUAD color = BlindGetPixelColor(x, y);\r
+ if (color.rgbRed == c.rgbRed &&\r
+ color.rgbGreen == c.rgbGreen &&\r
+ color.rgbBlue == c.rgbBlue)\r
+ {\r
+ pSelection[x + y * head.biWidth] = level;\r
+\r
+ if (localbox.top < y) localbox.top = y;\r
+ if (localbox.left > x) localbox.left = x;\r
+ if (localbox.right < x) localbox.right = x;\r
+ if (localbox.bottom > y) localbox.bottom = y;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (info.rSelectionBox.top <= localbox.top) info.rSelectionBox.top = localbox.top + 1;\r
+ if (info.rSelectionBox.left > localbox.left) info.rSelectionBox.left = localbox.left;\r
+ if (info.rSelectionBox.right <= localbox.right) info.rSelectionBox.right = localbox.right + 1;\r
+ if (info.rSelectionBox.bottom > localbox.bottom) info.rSelectionBox.bottom = localbox.bottom;\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Adds a single pixel to the existing selection.\r
+ */\r
+bool CxImage::SelectionAddPixel(long x, long y, BYTE level)\r
+{\r
+ if (pSelection==NULL) SelectionCreate();\r
+ if (pSelection==NULL) return false;\r
+\r
+ if (IsInside(x,y)) {\r
+ pSelection[x + y * head.biWidth] = level; // set the correct mask bit\r
+\r
+ if (info.rSelectionBox.top <= y) info.rSelectionBox.top = y+1;\r
+ if (info.rSelectionBox.left > x) info.rSelectionBox.left = x;\r
+ if (info.rSelectionBox.right <= x) info.rSelectionBox.right = x+1;\r
+ if (info.rSelectionBox.bottom > y) info.rSelectionBox.bottom = y;\r
+\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Exports the selection channel in a 8bpp grayscale image.\r
+ */\r
+bool CxImage::SelectionSplit(CxImage *dest)\r
+{\r
+ if (!pSelection || !dest) return false;\r
+\r
+ CxImage tmp(head.biWidth,head.biHeight,8);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ for(long y=0; y<head.biHeight; y++){\r
+ for(long x=0; x<head.biWidth; x++){\r
+ tmp.BlindSetPixelIndex(x,y,pSelection[x+y*head.biWidth]);\r
+ }\r
+ }\r
+\r
+ tmp.SetGrayPalette();\r
+ dest->Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Creates the selection channel from a gray scale image.\r
+ * black = unselected\r
+ */\r
+bool CxImage::SelectionSet(CxImage &from)\r
+{\r
+ if (!from.IsGrayScale() || head.biWidth != from.head.biWidth || head.biHeight != from.head.biHeight){\r
+ strcpy(info.szLastError,"CxImage::SelectionSet: wrong width or height, or image is not gray scale");\r
+ return false;\r
+ }\r
+\r
+ if (pSelection==NULL) pSelection = (BYTE*)malloc(head.biWidth * head.biHeight);\r
+\r
+ BYTE* src = from.info.pImage;\r
+ BYTE* dst = pSelection;\r
+ if (src==NULL || dst==NULL){\r
+ strcpy(info.szLastError,"CxImage::SelectionSet: null pointer");\r
+ return false;\r
+ }\r
+\r
+ for (long y=0; y<head.biHeight; y++){\r
+ memcpy(dst,src,head.biWidth);\r
+ dst += head.biWidth;\r
+ src += from.info.dwEffWidth;\r
+ }\r
+\r
+ SelectionRebuildBox();\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Sets the Selection level for a single pixel\r
+ * internal use only: doesn't set SelectionBox. Use SelectionAddPixel\r
+ */\r
+void CxImage::SelectionSet(const long x,const long y,const BYTE level)\r
+{\r
+ if (pSelection && IsInside(x,y)) pSelection[x+y*head.biWidth]=level;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Gets the Selection level for a single pixel \r
+ */\r
+BYTE CxImage::SelectionGet(const long x,const long y)\r
+{\r
+ if (pSelection && IsInside(x,y)) return pSelection[x+y*head.biWidth];\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Rebuilds the SelectionBox \r
+ */\r
+void CxImage::SelectionRebuildBox()\r
+{\r
+ info.rSelectionBox.left = head.biWidth;\r
+ info.rSelectionBox.bottom = head.biHeight;\r
+ info.rSelectionBox.right = info.rSelectionBox.top = 0;\r
+\r
+ if (!pSelection)\r
+ return;\r
+\r
+ long x,y;\r
+\r
+ for (y=0; y<head.biHeight; y++){\r
+ for (x=0; x<info.rSelectionBox.left; x++){\r
+ if (pSelection[x+y*head.biWidth]){\r
+ info.rSelectionBox.left = x;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+\r
+ for (y=0; y<head.biHeight; y++){\r
+ for (x=head.biWidth-1; x>=info.rSelectionBox.right; x--){\r
+ if (pSelection[x+y*head.biWidth]){\r
+ info.rSelectionBox.right = x+1;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+\r
+ for (x=0; x<head.biWidth; x++){\r
+ for (y=0; y<info.rSelectionBox.bottom; y++){\r
+ if (pSelection[x+y*head.biWidth]){\r
+ info.rSelectionBox.bottom = y;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+\r
+ for (x=0; x<head.biWidth; x++){\r
+ for (y=head.biHeight-1; y>=info.rSelectionBox.top; y--){\r
+ if (pSelection[x+y*head.biWidth]){\r
+ info.rSelectionBox.top = y+1;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Gets the Selection level for a single pixel \r
+ * "blind" version assumes that (x,y) is inside to the image.\r
+ */\r
+BYTE CxImage::BlindSelectionGet(const long x,const long y)\r
+{\r
+#ifdef _DEBUG\r
+ if (!IsInside(x,y) || (pSelection==0))\r
+ #if CXIMAGE_SUPPORT_EXCEPTION_HANDLING\r
+ throw 0;\r
+ #else\r
+ return 0;\r
+ #endif\r
+#endif\r
+ return pSelection[x+y*head.biWidth];\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Returns pointer to selection data for pixel (x,y).\r
+ */\r
+BYTE* CxImage::SelectionGetPointer(const long x,const long y)\r
+{\r
+ if (pSelection && IsInside(x,y)) return pSelection+x+y*head.biWidth;\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::SelectionFlip()\r
+{\r
+ if (!pSelection) return false;\r
+\r
+ BYTE *buff = (BYTE*)malloc(head.biWidth);\r
+ if (!buff) return false;\r
+\r
+ BYTE *iSrc,*iDst;\r
+ iSrc = pSelection + (head.biHeight-1)*head.biWidth;\r
+ iDst = pSelection;\r
+ for (long i=0; i<(head.biHeight/2); ++i)\r
+ {\r
+ memcpy(buff, iSrc, head.biWidth);\r
+ memcpy(iSrc, iDst, head.biWidth);\r
+ memcpy(iDst, buff, head.biWidth);\r
+ iSrc-=head.biWidth;\r
+ iDst+=head.biWidth;\r
+ }\r
+\r
+ free(buff);\r
+\r
+ long top = info.rSelectionBox.top;\r
+ info.rSelectionBox.top = head.biHeight - info.rSelectionBox.bottom;\r
+ info.rSelectionBox.bottom = head.biHeight - top;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::SelectionMirror()\r
+{\r
+ if (!pSelection) return false;\r
+ BYTE* pSelection2 = (BYTE*)malloc(head.biWidth * head.biHeight);\r
+ if (!pSelection2) return false;\r
+ \r
+ BYTE *iSrc,*iDst;\r
+ long wdt=head.biWidth-1;\r
+ iSrc=pSelection + wdt;\r
+ iDst=pSelection2;\r
+ for(long y=0; y < head.biHeight; y++){\r
+ for(long x=0; x <= wdt; x++)\r
+ *(iDst+x)=*(iSrc-x);\r
+ iSrc+=head.biWidth;\r
+ iDst+=head.biWidth;\r
+ }\r
+ free(pSelection);\r
+ pSelection=pSelection2;\r
+ \r
+ long left = info.rSelectionBox.left;\r
+ info.rSelectionBox.left = head.biWidth - info.rSelectionBox.right;\r
+ info.rSelectionBox.right = head.biWidth - left;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_WINDOWS\r
+/**\r
+ * Converts the selection in a HRGN object.\r
+ */\r
+bool CxImage::SelectionToHRGN(HRGN& region)\r
+{\r
+ if (pSelection && region){ \r
+ for(int y = 0; y < head.biHeight; y++){\r
+ HRGN hTemp = NULL;\r
+ int iStart = -1;\r
+ int x = 0;\r
+ for(; x < head.biWidth; x++){\r
+ if (pSelection[x + y * head.biWidth] != 0){\r
+ if (iStart == -1) iStart = x;\r
+ continue;\r
+ }else{\r
+ if (iStart >= 0){\r
+ hTemp = CreateRectRgn(iStart, y, x, y + 1);\r
+ CombineRgn(region, hTemp, region, RGN_OR);\r
+ DeleteObject(hTemp);\r
+ iStart = -1;\r
+ }\r
+ }\r
+ }\r
+ if (iStart >= 0){\r
+ hTemp = CreateRectRgn(iStart, y, x, y + 1);\r
+ CombineRgn(region, hTemp, region, RGN_OR);\r
+ DeleteObject(hTemp);\r
+ iStart = -1;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+#endif //CXIMAGE_SUPPORT_WINDOWS\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
--- /dev/null
+/*\r
+ * File: ximaska.cpp\r
+ * Purpose: Platform Independent SKA Image Class Loader and Writer\r
+ * 25/Sep/2007 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximaska.h"\r
+\r
+#if CXIMAGE_SUPPORT_SKA\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageSKA::Decode(CxFile *hFile)\r
+{\r
+ if (hFile==NULL)\r
+ return false;\r
+\r
+ // read the header\r
+ SKAHEADER ska_header;\r
+ hFile->Read(&ska_header,sizeof(SKAHEADER),1);\r
+\r
+ ska_header.Width = ntohs(ska_header.Width);\r
+ ska_header.Height = ntohs(ska_header.Height);\r
+ ska_header.dwUnknown = ntohl(ska_header.dwUnknown);\r
+\r
+ // check header\r
+ if (ska_header.dwUnknown != 0x01000000 ||\r
+ ska_header.Width > 0x7FFF || ska_header.Height > 0x7FFF ||\r
+ ska_header.BppExp != 3)\r
+ return false;\r
+\r
+ if (info.nEscape == -1){\r
+ head.biWidth = ska_header.Width ;\r
+ head.biHeight= ska_header.Height;\r
+ info.dwType = CXIMAGE_FORMAT_SKA;\r
+ return true;\r
+ }\r
+\r
+ int bpp = 1<<ska_header.BppExp;\r
+\r
+ Create(ska_header.Width,ska_header.Height,bpp,CXIMAGE_FORMAT_SKA);\r
+ if (!IsValid())\r
+ return false;\r
+\r
+ // read the palette\r
+ int nColors = 1<<bpp;\r
+ rgb_color* ppal = (rgb_color*)malloc(nColors*sizeof(rgb_color));\r
+ if (!ppal) return false;\r
+ hFile->Read(ppal,nColors*sizeof(rgb_color),1);\r
+ SetPalette(ppal,nColors);\r
+ free(ppal);\r
+\r
+ //read the image\r
+ hFile->Read(GetBits(),ska_header.Width*ska_header.Height,1);\r
+\r
+ //reorder rows\r
+ if (GetEffWidth() != ska_header.Width){\r
+ BYTE *src,*dst;\r
+ src = GetBits() + ska_header.Width*(ska_header.Height-1);\r
+ dst = GetBits(ska_header.Height-1);\r
+ for(int y=0;y<ska_header.Height;y++){\r
+ memcpy(dst,src,ska_header.Width);\r
+ src -= ska_header.Width;\r
+ dst -= GetEffWidth();\r
+ }\r
+ }\r
+\r
+ Flip();\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageSKA::Encode(CxFile * hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ if(head.biBitCount > 8) {\r
+ strcpy(info.szLastError,"SKA Images must be 8 bit or less");\r
+ return false;\r
+ }\r
+\r
+ SKAHEADER ska_header;\r
+\r
+ ska_header.Width = (unsigned short)GetWidth();\r
+ ska_header.Height = (unsigned short)GetHeight();\r
+ ska_header.BppExp = 3;\r
+ ska_header.dwUnknown = 0x01000000;\r
+\r
+ ska_header.Width = ntohs(ska_header.Width);\r
+ ska_header.Height = ntohs(ska_header.Height);\r
+ ska_header.dwUnknown = ntohl(ska_header.dwUnknown);\r
+\r
+ hFile->Write(&ska_header,sizeof(SKAHEADER),1);\r
+\r
+ ska_header.Width = ntohs(ska_header.Width);\r
+ ska_header.Height = ntohs(ska_header.Height);\r
+ ska_header.dwUnknown = ntohl(ska_header.dwUnknown);\r
+\r
+ if (head.biBitCount<8) IncreaseBpp(8);\r
+\r
+ rgb_color pal[256];\r
+ for(int idx=0; idx<256; idx++){\r
+ GetPaletteColor(idx,&(pal[idx].r),&(pal[idx].g),&(pal[idx].b));\r
+ }\r
+\r
+ hFile->Write(pal,256*sizeof(rgb_color),1);\r
+\r
+ BYTE* src = GetBits(ska_header.Height-1);\r
+ for(int y=0;y<ska_header.Height;y++){\r
+ hFile->Write(src,ska_header.Width,1);\r
+ src -= GetEffWidth();\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_SKA\r
+\r
--- /dev/null
+/*\r
+ * File: ximaska.h\r
+ * Purpose: SKA Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageSKA (c) 25/Sep/2007 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaSKA_h)\r
+#define __ximaSKA_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_SKA\r
+\r
+class CxImageSKA: public CxImage\r
+{\r
+#pragma pack(1)\r
+ typedef struct tagSkaHeader {\r
+ unsigned short Width;\r
+ unsigned short Height;\r
+ BYTE BppExp;\r
+ DWORD dwUnknown;\r
+} SKAHEADER;\r
+#pragma pack()\r
+\r
+public:\r
+ CxImageSKA(): CxImage(CXIMAGE_FORMAT_SKA) {}\r
+\r
+// bool Load(const char * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_ICO);}\r
+// bool Save(const char * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_ICO);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximatga.cpp\r
+ * Purpose: Platform Independent TGA Image Class Loader and Writer\r
+ * 05/Jan/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximatga.h"\r
+\r
+#if CXIMAGE_SUPPORT_TGA\r
+\r
+#include "ximaiter.h"\r
+\r
+// Definitions for image types.\r
+#define TGA_Null 0\r
+#define TGA_Map 1\r
+#define TGA_RGB 2\r
+#define TGA_Mono 3\r
+#define TGA_RLEMap 9\r
+#define TGA_RLERGB 10\r
+#define TGA_RLEMono 11\r
+#define TGA_CompMap 32\r
+#define TGA_CompMap4 33\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageTGA::Decode(CxFile *hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ TGAHEADER tgaHead;\r
+\r
+ cx_try\r
+ {\r
+ if (hFile->Read(&tgaHead,sizeof(tgaHead),1)==0)\r
+ cx_throw("Not a TGA");\r
+\r
+ tga_toh(&tgaHead);\r
+\r
+ bool bCompressed;\r
+ switch (tgaHead.ImageType){\r
+ case TGA_Map:\r
+ case TGA_RGB:\r
+ case TGA_Mono:\r
+ bCompressed = false;\r
+ break;\r
+ case TGA_RLEMap:\r
+ case TGA_RLERGB:\r
+ case TGA_RLEMono:\r
+ bCompressed = true;\r
+ break;\r
+ default:\r
+ cx_throw("Unknown TGA image type");\r
+ }\r
+\r
+ if (tgaHead.ImageWidth==0 || tgaHead.ImageHeight==0 || tgaHead.PixelDepth==0 || tgaHead.CmapLength>256)\r
+ cx_throw("bad TGA header");\r
+\r
+ if (tgaHead.PixelDepth!=8 && tgaHead.PixelDepth!=15 && tgaHead.PixelDepth!=16 && tgaHead.PixelDepth!=24 && tgaHead.PixelDepth!=32)\r
+ cx_throw("bad TGA header");\r
+\r
+ if (info.nEscape == -1){\r
+ head.biWidth = tgaHead.ImageWidth ;\r
+ head.biHeight= tgaHead.ImageHeight;\r
+ info.dwType = CXIMAGE_FORMAT_TGA;\r
+ return true;\r
+ }\r
+\r
+ if (tgaHead.IdLength>0) hFile->Seek(tgaHead.IdLength,SEEK_CUR); //skip descriptor\r
+\r
+ Create(tgaHead.ImageWidth, tgaHead.ImageHeight, tgaHead.PixelDepth, CXIMAGE_FORMAT_TGA);\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ if (tgaHead.PixelDepth==32) AlphaCreate(); // Image has alpha channel\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ if (!IsValid()) cx_throw("TGA Create failed");\r
+ \r
+ if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
+\r
+ if (tgaHead.CmapType != 0){ // read the palette\r
+ rgb_color pal[256];\r
+ hFile->Read(pal,tgaHead.CmapLength*sizeof(rgb_color), 1);\r
+ for (int i=0;i<tgaHead.CmapLength; i++) SetPaletteColor((BYTE)i,pal[i].b,pal[i].g,pal[i].r);\r
+ }\r
+\r
+ if (tgaHead.ImageType == TGA_Mono || tgaHead.ImageType == TGA_RLEMono)\r
+ SetGrayPalette();\r
+\r
+ // Bits 4 & 5 of the Image Descriptor byte control the ordering of the pixels.\r
+ bool bXReversed = ((tgaHead.ImagDesc & 16) == 16);\r
+ bool bYReversed = ((tgaHead.ImagDesc & 32) == 32);\r
+\r
+ CImageIterator iter(this);\r
+ BYTE rleLeftover = 255; //for images with illegal packet boundary \r
+ BYTE* pDest;\r
+ for (int y=0; y < tgaHead.ImageHeight; y++){\r
+\r
+ if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
+\r
+ if (hFile == NULL || hFile->Eof()) cx_throw("corrupted TGA");\r
+\r
+ if (bYReversed) pDest = iter.GetRow(tgaHead.ImageHeight-y-1);\r
+ else pDest = iter.GetRow(y);\r
+\r
+ if (bCompressed) rleLeftover = ExpandCompressedLine(pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,rleLeftover);\r
+ else ExpandUncompressedLine (pDest,&tgaHead,hFile,tgaHead.ImageWidth,y,0);\r
+ }\r
+\r
+ if (bXReversed) Mirror();\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (bYReversed && tgaHead.PixelDepth==32) AlphaFlip(); //<lioucr>\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageTGA::Encode(CxFile * hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ if (head.biBitCount<8){\r
+ strcpy(info.szLastError,"Bit depth must be 8 or 24");\r
+ return false;\r
+ }\r
+\r
+ TGAHEADER tgaHead;\r
+\r
+ tgaHead.IdLength = 0; // Image ID Field Length\r
+ tgaHead.CmapType = GetPalette()!=0; // Color Map Type\r
+ tgaHead.ImageType = (head.biBitCount == 8) ? (BYTE)TGA_Map : (BYTE)TGA_RGB; // Image Type\r
+\r
+ tgaHead.CmapIndex=0; // First Entry Index\r
+ tgaHead.CmapLength=(head.biBitCount == 8) ? 256 : 0; // Color Map Length\r
+ tgaHead.CmapEntrySize=(head.biBitCount == 8) ? (BYTE)24 : (BYTE)0; // Color Map Entry Size\r
+\r
+ tgaHead.X_Origin=0; // X-origin of Image\r
+ tgaHead.Y_Origin=0; // Y-origin of Image\r
+ tgaHead.ImageWidth=(WORD)head.biWidth; // Image Width\r
+ tgaHead.ImageHeight=(WORD)head.biHeight; // Image Height\r
+ tgaHead.PixelDepth=(BYTE)head.biBitCount; // Pixel Depth\r
+ tgaHead.ImagDesc=0; // Image Descriptor\r
+\r
+ if (pAlpha && head.biBitCount==24) tgaHead.PixelDepth=32; \r
+\r
+ tga_toh(&tgaHead);\r
+ hFile->Write(&tgaHead,sizeof(TGAHEADER),1);\r
+ tga_toh(&tgaHead);\r
+\r
+ if (head.biBitCount==8){\r
+ rgb_color pal[256];\r
+ RGBQUAD* ppal = GetPalette();\r
+ for (int i=0;i<256; i++){\r
+ pal[i].r = ppal[i].rgbBlue;\r
+ pal[i].g = ppal[i].rgbGreen;\r
+ pal[i].b = ppal[i].rgbRed;\r
+ }\r
+ hFile->Write(&pal,256*sizeof(rgb_color),1);\r
+ }\r
+ \r
+ CImageIterator iter(this);\r
+ BYTE* pDest;\r
+ if (pAlpha==0 || head.biBitCount==8){\r
+ for (int y=0; y < tgaHead.ImageHeight; y++){\r
+ pDest = iter.GetRow(y);\r
+ hFile->Write(pDest,tgaHead.ImageWidth * (head.biBitCount >> 3),1);\r
+ }\r
+ } else {\r
+ pDest = (BYTE*)malloc(4*tgaHead.ImageWidth);\r
+ RGBQUAD c;\r
+ for (int y=0; y < tgaHead.ImageHeight; y++){\r
+ for(int x=0, x4=0;x<tgaHead.ImageWidth;x++, x4+=4){\r
+ c = BlindGetPixelColor(x,y);\r
+ pDest[x4+0]=c.rgbBlue;\r
+ pDest[x4+1]=c.rgbGreen;\r
+ pDest[x4+2]=c.rgbRed;\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ pDest[x4+3]=AlphaGet(x,y);\r
+#else\r
+ pDest[x4+3]=0;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ hFile->Write(pDest,4*tgaHead.ImageWidth,1);\r
+ }\r
+ free(pDest);\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+BYTE CxImageTGA::ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover)\r
+{\r
+ BYTE rle;\r
+ long filePos=0;\r
+ for (int x=0; x<width; ){\r
+ if (rleLeftover != 255){\r
+ rle = rleLeftover;\r
+ rleLeftover = 255;\r
+ } else {\r
+ hFile->Read(&rle,1,1);\r
+ }\r
+ if (rle & 128) { // RLE-Encoded packet\r
+ rle -= 127; // Calculate real repeat count.\r
+ if ((x+rle)>width){\r
+ rleLeftover = (BYTE)(128 + (rle - (width - x) - 1));\r
+ filePos = hFile->Tell();\r
+ rle = (BYTE)(width - x);\r
+ }\r
+ switch (ptgaHead->PixelDepth)\r
+ {\r
+ case 32: {\r
+ RGBQUAD color;\r
+ hFile->Read(&color,4,1);\r
+ for (int ix = 0; ix < rle; ix++){\r
+ memcpy(&pDest[3*ix],&color,3);\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ AlphaSet(ix+x,y,color.rgbReserved);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ break;\r
+ } \r
+ case 24: {\r
+ rgb_color triple;\r
+ hFile->Read(&triple,3,1);\r
+ for (int ix = 0; ix < rle; ix++) memcpy(&pDest[3*ix],&triple,3);\r
+ break;\r
+ }\r
+ case 15:\r
+ case 16: {\r
+ WORD pixel;\r
+ hFile->Read(&pixel,2,1);\r
+ rgb_color triple;\r
+ triple.r = (BYTE)(( pixel & 0x1F ) * 8); // red\r
+ triple.g = (BYTE)(( pixel >> 2 ) & 0x0F8); // green\r
+ triple.b = (BYTE)(( pixel >> 7 ) & 0x0F8); // blue\r
+ for (int ix = 0; ix < rle; ix++){\r
+ memcpy(&pDest[3*ix],&triple,3);\r
+ }\r
+ break;\r
+ }\r
+ case 8: {\r
+ BYTE pixel;\r
+ hFile->Read(&pixel,1,1);\r
+ for (int ix = 0; ix < rle; ix++) pDest[ix] = pixel;\r
+ }\r
+ }\r
+ if (rleLeftover!=255) hFile->Seek(filePos, SEEK_SET);\r
+ } else { // Raw packet\r
+ rle += 1; // Calculate real repeat count.\r
+ if ((x+rle)>width){\r
+ rleLeftover = (BYTE)(rle - (width - x) - 1);\r
+ rle = (BYTE)(width - x);\r
+ }\r
+ ExpandUncompressedLine(pDest,ptgaHead,hFile,rle,y,x);\r
+ }\r
+ if (head.biBitCount == 24) pDest += rle*3; else pDest += rle;\r
+ x += rle;\r
+ }\r
+ return rleLeftover;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageTGA::ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset)\r
+{\r
+ switch (ptgaHead->PixelDepth){\r
+ case 8:\r
+ hFile->Read(pDest,width,1);\r
+ break;\r
+ case 15:\r
+ case 16:{\r
+ BYTE* dst=pDest;\r
+ WORD pixel;\r
+ for (int x=0; x<width; x++){\r
+ hFile->Read(&pixel,2,1);\r
+ *dst++ = (BYTE)(( pixel & 0x1F ) * 8); // blue\r
+ *dst++ = (BYTE)(( pixel >> 2 ) & 0x0F8); // green\r
+ *dst++ = (BYTE)(( pixel >> 7 ) & 0x0F8); // red\r
+ }\r
+ break;\r
+ }\r
+ case 24:\r
+ hFile->Read(pDest,3*width,1);\r
+ break;\r
+ case 32:{\r
+ BYTE* dst=pDest;\r
+ for (int x=0; x<width; x++){\r
+ RGBQUAD pixel;\r
+ hFile->Read(&pixel,4,1);\r
+ *dst++ = pixel.rgbBlue;\r
+ *dst++ = pixel.rgbGreen;\r
+ *dst++ = pixel.rgbRed;\r
+#if CXIMAGE_SUPPORT_ALPHA // <vho>\r
+ AlphaSet(x+xoffset,y,pixel.rgbReserved); //alpha\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ break;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageTGA::tga_toh(TGAHEADER* p)\r
+{\r
+ p->CmapIndex = ntohs(p->CmapIndex);\r
+ p->CmapLength = ntohs(p->CmapLength);\r
+ p->X_Origin = ntohs(p->X_Origin);\r
+ p->Y_Origin = ntohs(p->Y_Origin);\r
+ p->ImageWidth = ntohs(p->ImageWidth);\r
+ p->ImageHeight = ntohs(p->ImageHeight);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_TGA\r
+\r
--- /dev/null
+/*\r
+ * File: ximatga.h\r
+ * Purpose: TARGA Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageTGA (c) 05/Jan/2002 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Parts of the code come from Paintlib : Copyright (c) 1996-1998 Ulrich von Zadow\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaTGA_h)\r
+#define __ximaTGA_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_TGA\r
+\r
+class CxImageTGA: public CxImage\r
+{\r
+#pragma pack(1)\r
+typedef struct tagTgaHeader\r
+{\r
+ BYTE IdLength; // Image ID Field Length\r
+ BYTE CmapType; // Color Map Type\r
+ BYTE ImageType; // Image Type\r
+\r
+ WORD CmapIndex; // First Entry Index\r
+ WORD CmapLength; // Color Map Length\r
+ BYTE CmapEntrySize; // Color Map Entry Size\r
+\r
+ WORD X_Origin; // X-origin of Image\r
+ WORD Y_Origin; // Y-origin of Image\r
+ WORD ImageWidth; // Image Width\r
+ WORD ImageHeight; // Image Height\r
+ BYTE PixelDepth; // Pixel Depth\r
+ BYTE ImagDesc; // Image Descriptor\r
+} TGAHEADER;\r
+#pragma pack()\r
+\r
+public:\r
+ CxImageTGA(): CxImage(CXIMAGE_FORMAT_TGA) {}\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TGA);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TGA);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+protected:\r
+ BYTE ExpandCompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, BYTE rleLeftover);\r
+ void ExpandUncompressedLine(BYTE* pDest,TGAHEADER* ptgaHead,CxFile *hFile,int width, int y, int xoffset);\r
+ void tga_toh(TGAHEADER* p);\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+#include "ximage.h"\r
+#include "ximath.h"\r
+#include <math.h>\r
+\r
+//this module should contain some classes for geometrical transformations\r
+//usable with selections, etc... once it's done, that is. :)\r
+\r
+CxPoint2::CxPoint2()\r
+{\r
+ x=y=0.0f;\r
+}\r
+\r
+CxPoint2::CxPoint2(float const x_, float const y_)\r
+{\r
+ x=x_;\r
+ y=y_;\r
+}\r
+\r
+CxPoint2::CxPoint2(CxPoint2 const &p)\r
+{\r
+ x=p.x;\r
+ y=p.y;\r
+}\r
+\r
+float CxPoint2::Distance(CxPoint2 const p2)\r
+{\r
+ return (float)sqrt((x-p2.x)*(x-p2.x)+(y-p2.y)*(y-p2.y));\r
+}\r
+\r
+float CxPoint2::Distance(float const x_, float const y_)\r
+{\r
+ return (float)sqrt((x-x_)*(x-x_)+(y-y_)*(y-y_));\r
+}\r
+\r
+CxRect2::CxRect2()\r
+{\r
+}\r
+\r
+CxRect2::CxRect2(float const x1_, float const y1_, float const x2_, float const y2_)\r
+{\r
+ botLeft.x=x1_;\r
+ botLeft.y=y1_;\r
+ topRight.x=x2_;\r
+ topRight.y=y2_;\r
+}\r
+\r
+CxRect2::CxRect2(CxRect2 const &p)\r
+{\r
+ botLeft=p.botLeft;\r
+ topRight=p.topRight;\r
+}\r
+\r
+float CxRect2::Surface() const\r
+/*\r
+ * Returns the surface of rectangle.\r
+ */\r
+{\r
+ return (topRight.x-botLeft.x)*(topRight.y-botLeft.y);\r
+}\r
+\r
+CxRect2 CxRect2::CrossSection(CxRect2 const &r2) const\r
+/*\r
+ * Returns crossection with another rectangle.\r
+ */\r
+{\r
+ CxRect2 cs;\r
+ cs.botLeft.x=max(botLeft.x, r2.botLeft.x);\r
+ cs.botLeft.y=max(botLeft.y, r2.botLeft.y);\r
+ cs.topRight.x=min(topRight.x, r2.topRight.x);\r
+ cs.topRight.y=min(topRight.y, r2.topRight.y);\r
+ if (cs.botLeft.x<=cs.topRight.x && cs.botLeft.y<=cs.topRight.y) {\r
+ return cs;\r
+ } else {\r
+ return CxRect2(0,0,0,0);\r
+ }//if\r
+}\r
+\r
+CxPoint2 CxRect2::Center() const\r
+/*\r
+ * Returns the center point of rectangle.\r
+ */\r
+{\r
+ return CxPoint2((topRight.x+botLeft.x)/2.0f, (topRight.y+botLeft.y)/2.0f);\r
+}\r
+\r
+float CxRect2::Width() const\r
+//returns rectangle width\r
+{\r
+ return topRight.x-botLeft.x;\r
+}\r
+\r
+float CxRect2::Height() const\r
+//returns rectangle height\r
+{\r
+ return topRight.y-botLeft.y;\r
+}\r
+\r
--- /dev/null
+#if !defined(__ximath_h)\r
+#define __ximath_h\r
+\r
+#include "ximadef.h"\r
+\r
+//***bd*** simple floating point point\r
+class DLL_EXP CxPoint2\r
+{\r
+public:\r
+ CxPoint2();\r
+ CxPoint2(float const x_, float const y_);\r
+ CxPoint2(CxPoint2 const &p);\r
+\r
+ float Distance(CxPoint2 const p2);\r
+ float Distance(float const x_, float const y_);\r
+\r
+ float x,y;\r
+};\r
+\r
+//and simple rectangle\r
+class DLL_EXP CxRect2\r
+{\r
+public:\r
+ CxRect2();\r
+ CxRect2(float const x1_, float const y1_, float const x2_, float const y2_);\r
+ CxRect2(CxPoint2 const &bl, CxPoint2 const &tr);\r
+ CxRect2(CxRect2 const &p);\r
+\r
+ float Surface() const;\r
+ CxRect2 CrossSection(CxRect2 const &r2) const;\r
+ CxPoint2 Center() const;\r
+ float Width() const;\r
+ float Height() const;\r
+\r
+ CxPoint2 botLeft;\r
+ CxPoint2 topRight;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*\r
+ * File: ximatif.cpp\r
+ * Purpose: Platform Independent TIFF Image Class Loader and Writer\r
+ * 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximatif.h"\r
+\r
+#if CXIMAGE_SUPPORT_TIF\r
+\r
+#define FIX_16BPP_DARKIMG // + VK: if uncomment, dark 16bpp images are fixed\r
+\r
+#include "../tiff/tiffio.h"\r
+\r
+#define CVT(x) (((x) * 255L) / ((1L<<16)-1))\r
+#define SCALE(x) (((x)*((1L<<16)-1))/255)\r
+#define CalculateLine(width,bitdepth) (((width * bitdepth) + 7) / 8)\r
+#define CalculatePitch(line) (line + 3 & ~3)\r
+\r
+extern "C" TIFF* _TIFFOpenEx(CxFile* stream, const char* mode);\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+CxImageTIF::~CxImageTIF()\r
+{\r
+ if (m_tif2) TIFFClose(m_tif2);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageTIF::Decode(CxFile * hFile)\r
+{\r
+ //Comment this line if you need more information on errors\r
+ // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann>\r
+\r
+ //Open file and fill the TIFF structure\r
+ // m_tif = TIFFOpen(imageFileName,"rb");\r
+ TIFF* m_tif = _TIFFOpenEx(hFile, "rb");\r
+\r
+ uint32 height=0;\r
+ uint32 width=0;\r
+ uint16 bitspersample=1;\r
+ uint16 samplesperpixel=1;\r
+ uint32 rowsperstrip=(DWORD)-1;\r
+ uint16 photometric=0;\r
+ uint16 compression=1;\r
+ uint16 orientation=ORIENTATION_TOPLEFT; //<vho>\r
+ uint16 res_unit; //<Trifon>\r
+ uint32 x, y;\r
+ float resolution, offset;\r
+ BOOL isRGB;\r
+ BYTE *bits; //pointer to source data\r
+ BYTE *bits2; //pointer to destination data\r
+\r
+ cx_try\r
+ {\r
+ //check if it's a tiff file\r
+ if (!m_tif)\r
+ cx_throw("Error encountered while opening TIFF file");\r
+\r
+ // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping\r
+ // info.nNumFrames=0;\r
+ // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++;\r
+ info.nNumFrames = TIFFNumberOfDirectories(m_tif);\r
+\r
+ if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame))\r
+ cx_throw("Error: page not present in TIFF file"); \r
+\r
+ //get image info\r
+ TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width);\r
+ TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height);\r
+ TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);\r
+ TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);\r
+ TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); \r
+ TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric);\r
+ TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation);\r
+\r
+ if (info.nEscape == -1) {\r
+ // Return output dimensions only\r
+ head.biWidth = width;\r
+ head.biHeight = height;\r
+ info.dwType = CXIMAGE_FORMAT_TIF;\r
+ cx_throw("output dimensions returned");\r
+ }\r
+\r
+ TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit);\r
+ if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution))\r
+ {\r
+ if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f);\r
+ SetXDPI((long)resolution);\r
+ }\r
+ if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution))\r
+ {\r
+ if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f);\r
+ SetYDPI((long)resolution);\r
+ }\r
+\r
+ if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset;\r
+ if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset;\r
+\r
+ head.biClrUsed=0;\r
+ info.nBkgndIndex =-1;\r
+\r
+ if (rowsperstrip>height){\r
+ rowsperstrip=height;\r
+ TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);\r
+ }\r
+\r
+ isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/\r
+ (photometric == PHOTOMETRIC_RGB) ||\r
+ (photometric == PHOTOMETRIC_YCBCR) ||\r
+ (photometric == PHOTOMETRIC_SEPARATED) ||\r
+ (photometric == PHOTOMETRIC_LOGL) ||\r
+ (photometric == PHOTOMETRIC_LOGLUV);\r
+\r
+ if (isRGB){\r
+ head.biBitCount=24;\r
+ }else{\r
+ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){\r
+ if (bitspersample == 1){\r
+ head.biBitCount=1; //B&W image\r
+ head.biClrUsed =2;\r
+ } else if (bitspersample == 4) {\r
+ head.biBitCount=4; //16 colors gray scale\r
+ head.biClrUsed =16;\r
+ } else {\r
+ head.biBitCount=8; //gray scale\r
+ head.biClrUsed =256;\r
+ }\r
+ } else if (bitspersample == 4) {\r
+ head.biBitCount=4; // 16 colors\r
+ head.biClrUsed=16;\r
+ } else {\r
+ head.biBitCount=8; //256 colors\r
+ head.biClrUsed=256;\r
+ }\r
+\r
+ if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB)\r
+ { head.biBitCount=24;\r
+ head.biClrUsed =0;\r
+ }\r
+ }\r
+\r
+ if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding\r
+\r
+ Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation\r
+ if (!pDib) cx_throw("CxImageTIF can't create image");\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs\r
+ if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression);\r
+ SetCodecOption(compression); // <DPR> save original compression type\r
+\r
+ if (isRGB) {\r
+ // Read the whole image into one big RGBA buffer using\r
+ // the traditional TIFFReadRGBAImage() API that we trust.\r
+ uint32* raster; // retrieve RGBA image\r
+ uint32 *row;\r
+\r
+ raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32));\r
+ if (raster == NULL) cx_throw("No space for raster buffer");\r
+ \r
+ // Read the image in one chunk into an RGBA array\r
+ if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) {\r
+ _TIFFfree(raster);\r
+ cx_throw("Corrupted TIFF file!");\r
+ }\r
+\r
+ // read the raster lines and save them in the DIB\r
+ // with RGB mode, we have to change the order of the 3 samples RGB\r
+ row = &raster[0];\r
+ bits2 = info.pImage;\r
+ for (y = 0; y < height; y++) {\r
+\r
+ if (info.nEscape){ // <vho> - cancel decoding\r
+ _TIFFfree(raster);\r
+ cx_throw("Cancelled");\r
+ }\r
+\r
+ bits = bits2;\r
+ for (x = 0; x < width; x++) {\r
+ *bits++ = (BYTE)TIFFGetB(row[x]);\r
+ *bits++ = (BYTE)TIFFGetG(row[x]);\r
+ *bits++ = (BYTE)TIFFGetR(row[x]);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x]));\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ row += width;\r
+ bits2 += info.dwEffWidth;\r
+ }\r
+ _TIFFfree(raster);\r
+ } else {\r
+ int BIG_palette = (bitspersample > 8) && // + VK\r
+ (photometric==PHOTOMETRIC_PALETTE); \r
+ if (BIG_palette && (bitspersample > 24)) // + VK\r
+ cx_throw("Too big palette to handle"); // + VK\r
+\r
+ RGBQUAD *pal;\r
+ pal=(RGBQUAD*)calloc(BIG_palette ? 1<<bitspersample : 256,sizeof(RGBQUAD)); \r
+ // ! VK: it coasts nothing but more correct to use 256 as temp palette storage\r
+ // ! VK: but for case of BIG palette it just copied\r
+ if (pal==NULL) cx_throw("Unable to allocate TIFF palette");\r
+\r
+ int bpp = bitspersample <= 8 ? bitspersample : 8; // + VK (to use instead of bitspersample for case of > 8)\r
+\r
+ // set up the colormap based on photometric \r
+ switch(photometric) {\r
+ case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types\r
+ case PHOTOMETRIC_MINISWHITE:\r
+ if (bitspersample == 1) { // Monochrome image\r
+ if (photometric == PHOTOMETRIC_MINISBLACK) {\r
+ pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;\r
+ } else {\r
+ pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255;\r
+ }\r
+ } else { // need to build the scale for greyscale images\r
+ if (photometric == PHOTOMETRIC_MINISBLACK) {\r
+ for (int i=0; i<(1<<bpp); i++){\r
+ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(i*(255/((1<<bpp)-1)));\r
+ }\r
+ } else {\r
+ for (int i=0; i<(1<<bpp); i++){\r
+ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(255-i*(255/((1<<bpp)-1)));\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ case PHOTOMETRIC_PALETTE: // color map indexed\r
+ uint16 *red;\r
+ uint16 *green;\r
+ uint16 *blue;\r
+ TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); \r
+\r
+ // Is the palette 16 or 8 bits ?\r
+ BOOL Palette16Bits = /*FALSE*/ BIG_palette;\r
+ if (!BIG_palette) {\r
+ int n= 1<<bpp;\r
+ while (n-- > 0) {\r
+ if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) {\r
+ Palette16Bits=TRUE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // load the palette in the DIB\r
+ for (int i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) {\r
+ if (Palette16Bits) {\r
+ pal[i].rgbRed =(BYTE) CVT(red[i]);\r
+ pal[i].rgbGreen = (BYTE) CVT(green[i]);\r
+ pal[i].rgbBlue = (BYTE) CVT(blue[i]); \r
+ } else {\r
+ pal[i].rgbRed = (BYTE) red[i];\r
+ pal[i].rgbGreen = (BYTE) green[i];\r
+ pal[i].rgbBlue = (BYTE) blue[i]; \r
+ }\r
+ }\r
+ break;\r
+ }\r
+ if (!BIG_palette) { // + VK (BIG palette is stored until image is ready)\r
+ SetPalette(pal,/*head.biClrUsed*/ 1<<bpp); //palette assign // * VK\r
+ free(pal); \r
+ pal = NULL; \r
+ }\r
+\r
+ // read the tiff lines and save them in the DIB\r
+ uint32 nrow;\r
+ uint32 ys;\r
+ int line = CalculateLine(width, bitspersample * samplesperpixel);\r
+ \r
+ long bitsize = TIFFStripSize(m_tif);\r
+ //verify bitsize: could be wrong if StripByteCounts is missing.\r
+ if (bitsize<(long)(head.biSizeImage*samplesperpixel))\r
+ bitsize = head.biSizeImage*samplesperpixel;\r
+\r
+ if ((bitspersample > 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64\r
+ bitsize *= (bitspersample + 7)/8; \r
+\r
+ int tiled_image = TIFFIsTiled(m_tif);\r
+ uint32 tw=0, tl=0;\r
+ BYTE* tilebuf=NULL;\r
+ if (tiled_image){\r
+ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw);\r
+ TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl);\r
+ rowsperstrip = tl;\r
+ bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw);\r
+ tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif));\r
+ }\r
+ \r
+ bits = (BYTE*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK\r
+ BYTE * bits16 = NULL; // + VK\r
+ int line16 = 0; // + VK\r
+\r
+ if (!tiled_image && bitspersample==16) { // + VK +\r
+ line16 = line;\r
+ line = CalculateLine(width, 8 * samplesperpixel);\r
+ bits16 = bits;\r
+ bits = (BYTE*)malloc(bitsize);\r
+ }\r
+\r
+ if (bits==NULL){\r
+ if (bits16) free(bits16); // + VK\r
+ if (pal) free(pal); // + VK\r
+ if (tilebuf)free(tilebuf); // + VK \r
+ cx_throw("CxImageTIF can't allocate memory");\r
+ }\r
+\r
+#ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it\r
+ BYTE* row_shifts = NULL;\r
+ if (bits16) row_shifts = (BYTE*)malloc(height); \r
+#endif\r
+\r
+ for (ys = 0; ys < height; ys += rowsperstrip) {\r
+\r
+ if (info.nEscape){ // <vho> - cancel decoding\r
+ free(bits);\r
+ cx_throw("Cancelled");\r
+ }\r
+\r
+ nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip);\r
+\r
+ if (tiled_image){\r
+ uint32 imagew = TIFFScanlineSize(m_tif);\r
+ uint32 tilew = TIFFTileRowSize(m_tif);\r
+ int iskew = imagew - tilew;\r
+ uint8* bufp = (uint8*) bits;\r
+\r
+ uint32 colb = 0;\r
+ for (uint32 col = 0; col < width; col += tw) {\r
+ if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){\r
+ free(tilebuf);\r
+ free(bits);\r
+ cx_throw("Corrupted tiled TIFF file!");\r
+ }\r
+\r
+ if (colb + tw > imagew) {\r
+ uint32 owidth = imagew - colb;\r
+ uint32 oskew = tilew - owidth;\r
+ TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew );\r
+ } else {\r
+ TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0);\r
+ }\r
+ colb += tilew;\r
+ }\r
+\r
+ } else {\r
+ if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), \r
+ (bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK\r
+\r
+#ifdef NOT_IGNORE_CORRUPTED\r
+ free(bits);\r
+ if (bits16) free(bits16); // + VK\r
+ cx_throw("Corrupted TIFF file!");\r
+#else\r
+ break;\r
+#endif\r
+ }\r
+ }\r
+\r
+ for (y = 0; y < nrow; y++) {\r
+ long offset=(nrow-y-1)*line;\r
+ if ((bitspersample==16) && !BIG_palette) { // * VK\r
+ long offset16 = (nrow-y-1)*line16; // + VK\r
+ if (bits16) { // + VK +\r
+#ifdef FIX_16BPP_DARKIMG\r
+ int the_shift;\r
+ BYTE hi_byte, hi_max=0;\r
+ DWORD xi;\r
+ for (xi=0;xi<(uint32)line;xi++) {\r
+ hi_byte = bits16[xi*2+offset16+1];\r
+ if(hi_byte>hi_max)\r
+ hi_max = hi_byte;\r
+ }\r
+ the_shift = (hi_max == 0) ? 8 : 0;\r
+ if (!the_shift)\r
+ while( ! (hi_max & 0x80) ) {\r
+ the_shift++;\r
+ hi_max <<= 1;\r
+ }\r
+ row_shifts[height-ys-nrow+y] = the_shift;\r
+ the_shift = 8 - the_shift;\r
+ for (xi=0;xi<(uint32)line;xi++) \r
+ bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift;\r
+#else\r
+ for (DWORD xi=0;xi<(uint32)line;xi++) \r
+ bits[xi+offset]=bits16[xi*2+offset16+1];\r
+#endif\r
+ } else {\r
+ for (DWORD xi=0;xi<width;xi++)\r
+ bits[xi+offset]=bits[xi*2+offset+1];\r
+ }\r
+ }\r
+ if (samplesperpixel==1) { \r
+ if (BIG_palette)\r
+ if (bits16) {\r
+ long offset16 = (nrow-y-1)*line16; // + VK\r
+ MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y),\r
+ bits16 + offset16, width, bitspersample, pal );\r
+ } else\r
+ MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y),\r
+ bits + offset, width, bitspersample, pal );\r
+ else if ((bitspersample == head.biBitCount) || \r
+ (bitspersample == 16)) //simple 8bpp, 4bpp image or 16bpp\r
+ memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,info.dwEffWidth);\r
+ else\r
+ MoveBits( info.pImage + info.dwEffWidth * (height-ys-nrow+y),\r
+ bits + offset, width, bitspersample );\r
+ } else if (samplesperpixel==2) { //8bpp image with alpha layer\r
+ int xi=0;\r
+ int ii=0;\r
+ int yi=height-ys-nrow+y;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (!pAlpha) AlphaCreate(); // + VK\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ while (ii<line){\r
+ SetPixelIndex(xi,yi,bits[ii+offset]);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaSet(xi,yi,bits[ii+offset+1]);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ ii+=2;\r
+ xi++;\r
+ if (xi>=(int)width){\r
+ yi--;\r
+ xi=0;\r
+ }\r
+ }\r
+ } else { //photometric==PHOTOMETRIC_CIELAB\r
+ if (head.biBitCount!=24){ //fix image\r
+ Create(width,height,24,CXIMAGE_FORMAT_TIF);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (samplesperpixel==4) AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+\r
+ int xi=0;\r
+ uint32 ii=0;\r
+ int yi=height-ys-nrow+y;\r
+ RGBQUAD c;\r
+ int l,a,b,bitsoffset;\r
+ double p,cx,cy,cz,cr,cg,cb;\r
+ while (ii</*line*/width){ // * VK\r
+ bitsoffset = ii*samplesperpixel+offset;\r
+ l=bits[bitsoffset];\r
+ a=bits[bitsoffset+1];\r
+ b=bits[bitsoffset+2];\r
+ if (a>127) a-=256;\r
+ if (b>127) b-=256;\r
+ // lab to xyz\r
+ p = (l/2.55 + 16) / 116.0;\r
+ cx = pow( p + a * 0.002, 3);\r
+ cy = pow( p, 3);\r
+ cz = pow( p - b * 0.005, 3);\r
+ // white point\r
+ cx*=0.95047;\r
+ //cy*=1.000;\r
+ cz*=1.0883;\r
+ // xyz to rgb\r
+ cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz;\r
+ cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz;\r
+ cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz;\r
+\r
+ if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055;\r
+ else cr = 12.92 * cr;\r
+ if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055;\r
+ else cg = 12.92 * cg;\r
+ if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055;\r
+ else cb = 12.92 * cb;\r
+\r
+ c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255)));\r
+ c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255)));\r
+ c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255)));\r
+\r
+ SetPixelColor(xi,yi,c);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ ii++;\r
+ xi++;\r
+ if (xi>=(int)width){\r
+ yi--;\r
+ xi=0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ free(bits);\r
+ if (bits16) free(bits16);\r
+\r
+#ifdef FIX_16BPP_DARKIMG\r
+ if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) {\r
+ // 1. calculate maximum necessary shift\r
+ int min_row_shift = 8;\r
+ for( y=0; y<height; y++ ) {\r
+ if (min_row_shift > row_shifts[y]) min_row_shift = row_shifts[y];\r
+ }\r
+ // 2. for rows having less shift value, correct such rows:\r
+ for( y=0; y<height; y++ ) {\r
+ if (min_row_shift < row_shifts[y]) {\r
+ int need_shift = row_shifts[y] - min_row_shift;\r
+ BYTE* data = info.pImage + info.dwEffWidth * y;\r
+ for( x=0; x<width; x++, data++ )\r
+ *data >>= need_shift;\r
+ }\r
+ }\r
+ }\r
+ if (row_shifts) free( row_shifts );\r
+#endif\r
+\r
+ if (tiled_image) free(tilebuf);\r
+ if (pal) free(pal);\r
+\r
+ switch(orientation){\r
+ case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */\r
+ Mirror();\r
+ break;\r
+ case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */\r
+ Flip();\r
+ Mirror();\r
+ break;\r
+ case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */\r
+ Flip();\r
+ break;\r
+ case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */\r
+ RotateRight();\r
+ Mirror();\r
+ break;\r
+ case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */\r
+ RotateLeft();\r
+ break;\r
+ case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */\r
+ RotateLeft();\r
+ Mirror();\r
+ break;\r
+ case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */\r
+ RotateRight();\r
+ break;\r
+ }\r
+\r
+ }\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (m_tif) TIFFClose(m_tif);\r
+ if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_TIF) return true;\r
+ return false;\r
+ }\r
+ TIFFClose(m_tif);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageTIF::Encode(CxFile * hFile, bool bAppend)\r
+{\r
+ cx_try\r
+ {\r
+ if (hFile==NULL) cx_throw(CXIMAGE_ERR_NOFILE);\r
+ if (pDib==NULL) cx_throw(CXIMAGE_ERR_NOIMAGE);\r
+\r
+ // <RJ> replaced "w+b" with "a", to append an image directly on an existing file\r
+ if (m_tif2==NULL) m_tif2=_TIFFOpenEx(hFile, "a");\r
+ if (m_tif2==NULL) cx_throw("initialization fail");\r
+\r
+ if (bAppend || m_pages) m_multipage=true;\r
+ m_pages++;\r
+\r
+ if (!EncodeBody(m_tif2,m_multipage,m_pages,m_pages)) cx_throw("Error saving TIFF file");\r
+ if (bAppend) {\r
+ if (!TIFFWriteDirectory(m_tif2)) cx_throw("Error saving TIFF directory");\r
+ }\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ if (m_tif2){\r
+ TIFFClose(m_tif2);\r
+ m_tif2=NULL;\r
+ m_multipage=false;\r
+ m_pages=0;\r
+ }\r
+ return false;\r
+ }\r
+ if (!bAppend){\r
+ TIFFClose(m_tif2);\r
+ m_tif2=NULL;\r
+ m_multipage=false;\r
+ m_pages=0;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// Thanks to Abe <God(dot)bless(at)marihuana(dot)com>\r
+bool CxImageTIF::Encode(CxFile * hFile, CxImage ** pImages, int pagecount)\r
+{\r
+ cx_try\r
+ {\r
+ if (hFile==NULL) cx_throw("invalid file pointer");\r
+ if (pImages==NULL || pagecount<=0) cx_throw("multipage TIFF, no images!");\r
+\r
+ int i;\r
+ for (i=0; i<pagecount; i++){\r
+ if (pImages[i]==NULL)\r
+ cx_throw("Bad image pointer");\r
+ if (!(pImages[i]->IsValid()))\r
+ cx_throw("Empty image");\r
+ }\r
+\r
+ CxImageTIF ghost;\r
+ for (i=0; i<pagecount; i++){\r
+ ghost.Ghost(pImages[i]);\r
+ if (!ghost.Encode(hFile,true)) cx_throw("Error saving TIFF file");\r
+ }\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return false;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageTIF::EncodeBody(TIFF *m_tif, bool multipage, int page, int pagecount)\r
+{\r
+ uint32 height=head.biHeight;\r
+ uint32 width=head.biWidth;\r
+ uint16 bitcount=head.biBitCount;\r
+ uint16 bitspersample;\r
+ uint16 samplesperpixel;\r
+ uint16 photometric=0;\r
+ uint16 compression;\r
+// uint16 pitch;\r
+// int line;\r
+ uint32 x, y;\r
+\r
+ samplesperpixel = ((bitcount == 24) || (bitcount == 32)) ? (BYTE)3 : (BYTE)1;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (bitcount==24 && AlphaIsValid()) { bitcount=32; samplesperpixel=4; }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ bitspersample = bitcount / samplesperpixel;\r
+\r
+ //set the PHOTOMETRIC tag\r
+ RGBQUAD *rgb = GetPalette();\r
+ switch (bitcount) {\r
+ case 1:\r
+ if (CompareColors(&rgb[0],&rgb[1])<0) {\r
+ /* <abe> some viewers do not handle PHOTOMETRIC_MINISBLACK:\r
+ * let's transform the image in PHOTOMETRIC_MINISWHITE\r
+ */\r
+ //invert the colors\r
+ RGBQUAD tempRGB=GetPaletteColor(0);\r
+ SetPaletteColor(0,GetPaletteColor(1));\r
+ SetPaletteColor(1,tempRGB);\r
+ //invert the pixels\r
+ BYTE *iSrc=info.pImage;\r
+ for (unsigned long i=0;i<head.biSizeImage;i++){\r
+ *iSrc=(BYTE)~(*(iSrc));\r
+ iSrc++;\r
+ }\r
+ photometric = PHOTOMETRIC_MINISWHITE;\r
+ //photometric = PHOTOMETRIC_MINISBLACK;\r
+ } else {\r
+ photometric = PHOTOMETRIC_MINISWHITE;\r
+ }\r
+ break;\r
+ case 4: // Check if the DIB has a color or a greyscale palette\r
+ case 8:\r
+ photometric = PHOTOMETRIC_MINISBLACK; //default to gray scale\r
+ for (x = 0; x < head.biClrUsed; x++) {\r
+ if ((rgb->rgbRed != x)||(rgb->rgbRed != rgb->rgbGreen)||(rgb->rgbRed != rgb->rgbBlue)){\r
+ photometric = PHOTOMETRIC_PALETTE;\r
+ break;\r
+ }\r
+ rgb++;\r
+ }\r
+ break;\r
+ case 24:\r
+ case 32:\r
+ photometric = PHOTOMETRIC_RGB; \r
+ break;\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid() && bitcount==8) samplesperpixel=2; //8bpp + alpha layer\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+// line = CalculateLine(width, bitspersample * samplesperpixel);\r
+// pitch = (uint16)CalculatePitch(line);\r
+\r
+ //prepare the palette struct\r
+ RGBQUAD pal[256];\r
+ if (GetPalette()){\r
+ BYTE b;\r
+ memcpy(pal,GetPalette(),GetPaletteSize());\r
+ for(WORD a=0;a<head.biClrUsed;a++){ //swap blue and red components\r
+ b=pal[a].rgbBlue; pal[a].rgbBlue=pal[a].rgbRed; pal[a].rgbRed=b;\r
+ }\r
+ }\r
+\r
+ // handle standard width/height/bpp stuff\r
+ TIFFSetField(m_tif, TIFFTAG_IMAGEWIDTH, width);\r
+ TIFFSetField(m_tif, TIFFTAG_IMAGELENGTH, height);\r
+ TIFFSetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);\r
+ TIFFSetField(m_tif, TIFFTAG_BITSPERSAMPLE, bitspersample);\r
+ TIFFSetField(m_tif, TIFFTAG_PHOTOMETRIC, photometric);\r
+ TIFFSetField(m_tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // single image plane \r
+ TIFFSetField(m_tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);\r
+\r
+ uint32 rowsperstrip = TIFFDefaultStripSize(m_tif, (uint32) -1); //<REC> gives better compression\r
+ TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);\r
+\r
+ // handle metrics\r
+ TIFFSetField(m_tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);\r
+ TIFFSetField(m_tif, TIFFTAG_XRESOLUTION, (float)info.xDPI);\r
+ TIFFSetField(m_tif, TIFFTAG_YRESOLUTION, (float)info.yDPI);\r
+// TIFFSetField(m_tif, TIFFTAG_XPOSITION, (float)info.xOffset);\r
+// TIFFSetField(m_tif, TIFFTAG_YPOSITION, (float)info.yOffset);\r
+\r
+ // multi-paging - Thanks to Abe <God(dot)bless(at)marihuana(dot)com>\r
+ if (multipage)\r
+ {\r
+ char page_number[20];\r
+ sprintf(page_number, "Page %d", page);\r
+\r
+ TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);\r
+ TIFFSetField(m_tif, TIFFTAG_PAGENUMBER, page,pagecount);\r
+ TIFFSetField(m_tif, TIFFTAG_PAGENAME, page_number);\r
+ } else {\r
+ TIFFSetField(m_tif, TIFFTAG_SUBFILETYPE, 0);\r
+ }\r
+\r
+ // palettes (image colormaps are automatically scaled to 16-bits)\r
+ if (photometric == PHOTOMETRIC_PALETTE) {\r
+ uint16 *r, *g, *b;\r
+ r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * 256);\r
+ g = r + 256;\r
+ b = g + 256;\r
+\r
+ for (int i = 255; i >= 0; i--) {\r
+ b[i] = (uint16)SCALE((uint16)pal[i].rgbRed);\r
+ g[i] = (uint16)SCALE((uint16)pal[i].rgbGreen);\r
+ r[i] = (uint16)SCALE((uint16)pal[i].rgbBlue);\r
+ }\r
+\r
+ TIFFSetField(m_tif, TIFFTAG_COLORMAP, r, g, b);\r
+ _TIFFfree(r);\r
+ }\r
+\r
+ // compression\r
+ if (GetCodecOption(CXIMAGE_FORMAT_TIF)) {\r
+ compression = (WORD)GetCodecOption(CXIMAGE_FORMAT_TIF);\r
+ } else {\r
+ switch (bitcount) {\r
+ case 1 :\r
+ compression = COMPRESSION_CCITTFAX4;\r
+ break;\r
+ case 4 :\r
+ case 8 :\r
+ compression = COMPRESSION_LZW;\r
+ break;\r
+ case 24 :\r
+ case 32 :\r
+ compression = COMPRESSION_JPEG;\r
+ break;\r
+ default :\r
+ compression = COMPRESSION_NONE;\r
+ break;\r
+ }\r
+ }\r
+ TIFFSetField(m_tif, TIFFTAG_COMPRESSION, compression);\r
+\r
+ switch (compression) {\r
+ case COMPRESSION_JPEG:\r
+ TIFFSetField(m_tif, TIFFTAG_JPEGQUALITY, GetJpegQuality());\r
+ TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, ((7+rowsperstrip)>>3)<<3);\r
+ break;\r
+ case COMPRESSION_LZW:\r
+ if (bitcount>=8) TIFFSetField(m_tif, TIFFTAG_PREDICTOR, 2);\r
+ break;\r
+ }\r
+\r
+ // read the DIB lines from bottom to top and save them in the TIF\r
+\r
+ BYTE *bits;\r
+ switch(bitcount) { \r
+ case 1 :\r
+ case 4 :\r
+ case 8 :\r
+ {\r
+ if (samplesperpixel==1){\r
+ bits = (BYTE*)malloc(info.dwEffWidth);\r
+ if (!bits) return false;\r
+ for (y = 0; y < height; y++) {\r
+ memcpy(bits,info.pImage + (height - y - 1)*info.dwEffWidth,info.dwEffWidth);\r
+ if (TIFFWriteScanline(m_tif,bits, y, 0)==-1){\r
+ free(bits);\r
+ return false;\r
+ }\r
+ }\r
+ free(bits);\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ else { //8bpp + alpha layer\r
+ bits = (BYTE*)malloc(2*width);\r
+ if (!bits) return false;\r
+ for (y = 0; y < height; y++) {\r
+ for (x=0;x<width;x++){\r
+ bits[2*x]=BlindGetPixelIndex(x,height - y - 1);\r
+ bits[2*x+1]=AlphaGet(x,height - y - 1);\r
+ }\r
+ if (TIFFWriteScanline(m_tif,bits, y, 0)==-1) {\r
+ free(bits);\r
+ return false;\r
+ }\r
+ }\r
+ free(bits);\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ break;\r
+ } \r
+ case 24:\r
+ {\r
+ BYTE *buffer = (BYTE *)malloc(info.dwEffWidth);\r
+ if (!buffer) return false;\r
+ for (y = 0; y < height; y++) {\r
+ // get a pointer to the scanline\r
+ memcpy(buffer, info.pImage + (height - y - 1)*info.dwEffWidth, info.dwEffWidth);\r
+ // TIFFs store color data RGB instead of BGR\r
+ BYTE *pBuf = buffer;\r
+ for (x = 0; x < width; x++) {\r
+ BYTE tmp = pBuf[0];\r
+ pBuf[0] = pBuf[2];\r
+ pBuf[2] = tmp;\r
+ pBuf += 3;\r
+ }\r
+ // write the scanline to disc\r
+ if (TIFFWriteScanline(m_tif, buffer, y, 0)==-1){\r
+ free(buffer);\r
+ return false;\r
+ }\r
+ }\r
+ free(buffer);\r
+ break;\r
+ } \r
+ case 32 :\r
+ {\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ BYTE *buffer = (BYTE *)malloc((info.dwEffWidth*4)/3);\r
+ if (!buffer) return false;\r
+ for (y = 0; y < height; y++) {\r
+ // get a pointer to the scanline\r
+ memcpy(buffer, info.pImage + (height - y - 1)*info.dwEffWidth, info.dwEffWidth);\r
+ // TIFFs store color data RGB instead of BGR\r
+ BYTE *pSrc = buffer + 3 * width;\r
+ BYTE *pDst = buffer + 4 * width;\r
+ for (x = 0; x < width; x++) {\r
+ pDst-=4;\r
+ pSrc-=3;\r
+ pDst[3] = AlphaGet(width-x-1,height-y-1);\r
+ pDst[2] = pSrc[0];\r
+ pDst[1] = pSrc[1];\r
+ pDst[0] = pSrc[2];\r
+ }\r
+ // write the scanline to disc\r
+ if (TIFFWriteScanline(m_tif, buffer, y, 0)==-1){\r
+ free(buffer);\r
+ return false;\r
+ }\r
+ }\r
+ free(buffer);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ break;\r
+ } \r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageTIF::TileToStrip(uint8* out, uint8* in, uint32 rows, uint32 cols, int outskew, int inskew)\r
+{\r
+ while (rows-- > 0) {\r
+ uint32 j = cols;\r
+ while (j-- > 0)\r
+ *out++ = *in++;\r
+ out += outskew;\r
+ in += inskew;\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+TIFF* CxImageTIF::TIFFOpenEx(CxFile * hFile)\r
+{\r
+ if (hFile) return _TIFFOpenEx(hFile, "rb");\r
+ return NULL;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageTIF::TIFFCloseEx(TIFF* tif)\r
+{\r
+ if (tif) TIFFClose(tif);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageTIF::MoveBits( BYTE* dest, BYTE* from, int count, int bpp )\r
+{ int offbits = 0;\r
+ uint16 w;\r
+ uint32 d;\r
+ if (bpp <= 8) {\r
+ while (count-- > 0) {\r
+ if (offbits + bpp <= 8)\r
+ w = *from >> (8 - offbits - bpp);\r
+ else {\r
+ w = *from++ << (offbits + bpp - 8);\r
+ w |= *from >> (16 - offbits - bpp);\r
+ }\r
+ offbits += bpp;\r
+ if (offbits >= 8) {\r
+ offbits -= 8;\r
+ if (offbits == 0) from++;\r
+ } \r
+ *dest++ = (BYTE)w & ((1 << bpp)-1);\r
+ }\r
+ } else if (bpp < 16) {\r
+ while (count-- > 0) {\r
+ d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3];\r
+ d >>= (24 - offbits);\r
+ *dest++ = (BYTE) ( d );\r
+ offbits += bpp;\r
+ while (offbits >= 8) {\r
+ from++;\r
+ offbits -= 8;\r
+ }\r
+ }\r
+ } else if (bpp < 32) {\r
+ while (count-- > 0) {\r
+ d = (*from << 24) | (from[1]<<16) | (from[2]<<8) | from[3];\r
+ //d = *(uint32*)from;\r
+ *dest++ = (BYTE) ( d >> (offbits + bpp - 8) );\r
+ offbits += bpp;\r
+ while (offbits >= 8) {\r
+ from++;\r
+ offbits -= 8;\r
+ }\r
+ }\r
+ } else {\r
+ while (count-- > 0) {\r
+ d = *(uint32*)from;\r
+ *dest++ = (BYTE) (d >> 24);\r
+ from += 4;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+void CxImageTIF::MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal )\r
+{ int offbits = 0;\r
+ uint32 d;\r
+ uint16 palidx;\r
+ while (count-- > 0) {\r
+ d = (*from << 24) | ( *( from + 1 ) << 16 )\r
+ | ( *( from + 2 ) << 8 )\r
+ | ( *( from + 3 ) );\r
+ palidx = (uint16) (d >> (32 - offbits - bpp));\r
+ if (bpp < 16) {\r
+ palidx <<= 16-bpp;\r
+ palidx = (palidx >> 8) | (palidx <<8);\r
+ palidx >>= 16-bpp;\r
+ } else palidx = (palidx >> 8) | (palidx << 8);\r
+ *dest++ = pal[palidx].rgbBlue;\r
+ *dest++ = pal[palidx].rgbGreen;\r
+ *dest++ = pal[palidx].rgbRed;\r
+ offbits += bpp;\r
+ while (offbits >= 8) {\r
+ from++;\r
+ offbits -= 8;\r
+ }\r
+ }\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#endif // CXIMAGE_SUPPORT_TIF\r
--- /dev/null
+/*\r
+ * File: ximatif.h\r
+ * Purpose: TIFF Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageTIF (c) 07/Aug/2001 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ *\r
+ * Special thanks to Troels Knakkergaard for new features, enhancements and bugfixes\r
+ *\r
+ * Special thanks to Abe <God(dot)bless(at)marihuana(dot)com> for MultiPageTIFF code.\r
+ *\r
+ * LibTIFF is:\r
+ * Copyright (c) 1988-1997 Sam Leffler\r
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.\r
+ * ==========================================================\r
+ */\r
+\r
+#if !defined(__ximatif_h)\r
+#define __ximatif_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_TIF\r
+\r
+#include "../tiff/tiffio.h"\r
+\r
+class DLL_EXP CxImageTIF: public CxImage\r
+{\r
+public:\r
+ CxImageTIF(): CxImage(CXIMAGE_FORMAT_TIF) {m_tif2=NULL; m_multipage=false; m_pages=0;}\r
+ ~CxImageTIF();\r
+\r
+ TIFF* TIFFOpenEx(CxFile * hFile);\r
+ void TIFFCloseEx(TIFF* tif);\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_TIF);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_TIF);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile, bool bAppend=false);\r
+ bool Encode(CxFile * hFile, CxImage ** pImages, int pagecount);\r
+ bool Encode(FILE *hFile, bool bAppend=false) { CxIOFile file(hFile); return Encode(&file,bAppend); }\r
+ bool Encode(FILE *hFile, CxImage ** pImages, int pagecount)\r
+ { CxIOFile file(hFile); return Encode(&file, pImages, pagecount); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+protected:\r
+ void TileToStrip(uint8* out, uint8* in, uint32 rows, uint32 cols, int outskew, int inskew);\r
+ bool EncodeBody(TIFF *m_tif, bool multipage=false, int page=0, int pagecount=0);\r
+ TIFF *m_tif2;\r
+ bool m_multipage;\r
+ int m_pages;\r
+ void MoveBits( BYTE* dest, BYTE* from, int count, int bpp );\r
+ void MoveBitsPal( BYTE* dest, BYTE*from, int count, int bpp, RGBQUAD* pal );\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+// xImaTran.cpp : Transformation functions\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+#include "ximath.h"\r
+\r
+#if CXIMAGE_SUPPORT_BASICTRANSFORMATIONS\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::GrayScale()\r
+{\r
+ if (!pDib) return false;\r
+ if (head.biBitCount<=8){\r
+ RGBQUAD* ppal=GetPalette();\r
+ int gray;\r
+ //converts the colors to gray, use the blue channel only\r
+ for(DWORD i=0;i<head.biClrUsed;i++){\r
+ gray=(int)RGB2GRAY(ppal[i].rgbRed,ppal[i].rgbGreen,ppal[i].rgbBlue);\r
+ ppal[i].rgbBlue = (BYTE)gray;\r
+ }\r
+ // preserve transparency\r
+ if (info.nBkgndIndex >= 0) info.nBkgndIndex = ppal[info.nBkgndIndex].rgbBlue;\r
+ //create a "real" 8 bit gray scale image\r
+ if (head.biBitCount==8){\r
+ BYTE *img=info.pImage;\r
+ for(DWORD i=0;i<head.biSizeImage;i++) img[i]=ppal[img[i]].rgbBlue;\r
+ SetGrayPalette();\r
+ }\r
+ //transform to 8 bit gray scale\r
+ if (head.biBitCount==4 || head.biBitCount==1){\r
+ CxImage ima;\r
+ ima.CopyInfo(*this);\r
+ if (!ima.Create(head.biWidth,head.biHeight,8,info.dwType)) return false;\r
+ ima.SetGrayPalette();\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ ima.SelectionCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ ima.AlphaCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ for (long y=0;y<head.biHeight;y++){\r
+ BYTE *iDst = ima.GetBits(y);\r
+ BYTE *iSrc = GetBits(y);\r
+ for (long x=0;x<head.biWidth; x++){\r
+ //iDst[x]=ppal[BlindGetPixelIndex(x,y)].rgbBlue;\r
+ if (head.biBitCount==4){\r
+ BYTE pos = (BYTE)(4*(1-x%2));\r
+ iDst[x]= ppal[(BYTE)((iSrc[x >> 1]&((BYTE)0x0F<<pos)) >> pos)].rgbBlue;\r
+ } else {\r
+ BYTE pos = (BYTE)(7-x%8);\r
+ iDst[x]= ppal[(BYTE)((iSrc[x >> 3]&((BYTE)0x01<<pos)) >> pos)].rgbBlue;\r
+ }\r
+ }\r
+ }\r
+ Transfer(ima);\r
+ }\r
+ } else { //from RGB to 8 bit gray scale\r
+ BYTE *iSrc=info.pImage;\r
+ CxImage ima;\r
+ ima.CopyInfo(*this);\r
+ if (!ima.Create(head.biWidth,head.biHeight,8,info.dwType)) return false;\r
+ ima.SetGrayPalette();\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ ima.SelectionCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ ima.AlphaCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ BYTE *img=ima.GetBits();\r
+ long l8=ima.GetEffWidth();\r
+ long l=head.biWidth * 3;\r
+ for(long y=0; y < head.biHeight; y++) {\r
+ for(long x=0,x8=0; x < l; x+=3,x8++) {\r
+ img[x8+y*l8]=(BYTE)RGB2GRAY(*(iSrc+x+2),*(iSrc+x+1),*(iSrc+x+0));\r
+ }\r
+ iSrc+=info.dwEffWidth;\r
+ }\r
+ Transfer(ima);\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa Mirror\r
+ * \author [qhbo]\r
+ */\r
+bool CxImage::Flip(bool bFlipSelection, bool bFlipAlpha)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ BYTE *buff = (BYTE*)malloc(info.dwEffWidth);\r
+ if (!buff) return false;\r
+\r
+ BYTE *iSrc,*iDst;\r
+ iSrc = GetBits(head.biHeight-1);\r
+ iDst = GetBits(0);\r
+ for (long i=0; i<(head.biHeight/2); ++i)\r
+ {\r
+ memcpy(buff, iSrc, info.dwEffWidth);\r
+ memcpy(iSrc, iDst, info.dwEffWidth);\r
+ memcpy(iDst, buff, info.dwEffWidth);\r
+ iSrc-=info.dwEffWidth;\r
+ iDst+=info.dwEffWidth;\r
+ }\r
+\r
+ free(buff);\r
+\r
+ if (bFlipSelection){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ SelectionFlip();\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ }\r
+\r
+ if (bFlipAlpha){\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ AlphaFlip();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \sa Flip\r
+ */\r
+bool CxImage::Mirror(bool bMirrorSelection, bool bMirrorAlpha)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ CxImage* imatmp = new CxImage(*this,false,true,true);\r
+ if (!imatmp) return false;\r
+ if (!imatmp->IsValid()){\r
+ delete imatmp;\r
+ return false;\r
+ }\r
+\r
+ BYTE *iSrc,*iDst;\r
+ long wdt=(head.biWidth-1) * (head.biBitCount==24 ? 3:1);\r
+ iSrc=info.pImage + wdt;\r
+ iDst=imatmp->info.pImage;\r
+ long x,y;\r
+ switch (head.biBitCount){\r
+ case 24:\r
+ for(y=0; y < head.biHeight; y++){\r
+ for(x=0; x <= wdt; x+=3){\r
+ *(iDst+x)=*(iSrc-x);\r
+ *(iDst+x+1)=*(iSrc-x+1);\r
+ *(iDst+x+2)=*(iSrc-x+2);\r
+ }\r
+ iSrc+=info.dwEffWidth;\r
+ iDst+=info.dwEffWidth;\r
+ }\r
+ break;\r
+ case 8:\r
+ for(y=0; y < head.biHeight; y++){\r
+ for(x=0; x <= wdt; x++)\r
+ *(iDst+x)=*(iSrc-x);\r
+ iSrc+=info.dwEffWidth;\r
+ iDst+=info.dwEffWidth;\r
+ }\r
+ break;\r
+ default:\r
+ for(y=0; y < head.biHeight; y++){\r
+ for(x=0; x <= wdt; x++)\r
+ imatmp->SetPixelIndex(x,y,GetPixelIndex(wdt-x,y));\r
+ }\r
+ }\r
+\r
+ if (bMirrorSelection){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ imatmp->SelectionMirror();\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ }\r
+\r
+ if (bMirrorAlpha){\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ imatmp->AlphaMirror();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+\r
+ Transfer(*imatmp);\r
+ delete imatmp;\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#define RBLOCK 64\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::RotateLeft(CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long newWidth = GetHeight();\r
+ long newHeight = GetWidth();\r
+\r
+ CxImage imgDest;\r
+ imgDest.CopyInfo(*this);\r
+ imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
+ imgDest.SetPalette(GetPalette());\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) imgDest.AlphaCreate();\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsValid()) imgDest.SelectionCreate();\r
+#endif\r
+\r
+ long x,x2,y,dlineup;\r
+ \r
+ // Speedy rotate for BW images <Robert Abram>\r
+ if (head.biBitCount == 1) {\r
+ \r
+ BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp;\r
+ ldiv_t div_r;\r
+\r
+ BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits();\r
+ dbitsmax = bdest + imgDest.head.biSizeImage - 1;\r
+ dlineup = 8 * imgDest.info.dwEffWidth - imgDest.head.biWidth;\r
+\r
+ imgDest.Clear(0);\r
+ for (y = 0; y < head.biHeight; y++) {\r
+ // Figure out the Column we are going to be copying to\r
+ div_r = ldiv(y + dlineup, (long)8);\r
+ // set bit pos of src column byte \r
+ bitpos = (BYTE)(1 << div_r.rem);\r
+ srcdisp = bsrc + y * info.dwEffWidth;\r
+ for (x = 0; x < (long)info.dwEffWidth; x++) {\r
+ // Get Source Bits\r
+ sbits = srcdisp + x;\r
+ // Get destination column\r
+ nrow = bdest + (x * 8) * imgDest.info.dwEffWidth + imgDest.info.dwEffWidth - 1 - div_r.quot;\r
+ for (long z = 0; z < 8; z++) {\r
+ // Get Destination Byte\r
+ dbits = nrow + z * imgDest.info.dwEffWidth;\r
+ if ((dbits < bdest) || (dbits > dbitsmax)) break;\r
+ if (*sbits & (128 >> z)) *dbits |= bitpos;\r
+ }\r
+ }\r
+ }//for y\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ for (x = 0; x < newWidth; x++){\r
+ x2=newWidth-x-1;\r
+ for (y = 0; y < newHeight; y++){\r
+ imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2));\r
+ }//for y\r
+ }//for x\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsValid()) {\r
+ imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top;\r
+ imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom;\r
+ imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left;\r
+ imgDest.info.rSelectionBox.top = info.rSelectionBox.right;\r
+ for (x = 0; x < newWidth; x++){\r
+ x2=newWidth-x-1;\r
+ for (y = 0; y < newHeight; y++){\r
+ imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2));\r
+ }//for y\r
+ }//for x\r
+ }\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+ } else {\r
+ //anything other than BW:\r
+ //bd, 10. 2004: This optimized version of rotation rotates image by smaller blocks. It is quite\r
+ //a bit faster than obvious algorithm, because it produces much less CPU cache misses.\r
+ //This optimization can be tuned by changing block size (RBLOCK). 96 is good value for current\r
+ //CPUs (tested on Athlon XP and Celeron D). Larger value (if CPU has enough cache) will increase\r
+ //speed somehow, but once you drop out of CPU's cache, things will slow down drastically.\r
+ //For older CPUs with less cache, lower value would yield better results.\r
+ \r
+ BYTE *srcPtr, *dstPtr; //source and destionation for 24-bit version\r
+ int xs, ys; //x-segment and y-segment\r
+ for (xs = 0; xs < newWidth; xs+=RBLOCK) { //for all image blocks of RBLOCK*RBLOCK pixels\r
+ for (ys = 0; ys < newHeight; ys+=RBLOCK) {\r
+ if (head.biBitCount==24) {\r
+ //RGB24 optimized pixel access:\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){ //do rotation\r
+ info.nProgress = (long)(100*x/newWidth);\r
+ x2=newWidth-x-1;\r
+ dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(x,ys);\r
+ srcPtr = (BYTE*) BlindGetPixelPointer(ys, x2);\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ //imgDest.SetPixelColor(x, y, GetPixelColor(y, x2));\r
+ *(dstPtr) = *(srcPtr);\r
+ *(dstPtr+1) = *(srcPtr+1);\r
+ *(dstPtr+2) = *(srcPtr+2);\r
+ srcPtr += 3;\r
+ dstPtr += imgDest.info.dwEffWidth;\r
+ }//for y\r
+ }//for x\r
+ } else {\r
+ //anything else than 24bpp (and 1bpp): palette\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
+ info.nProgress = (long)(100*x/newWidth); //<Anatoly Ivasyuk>\r
+ x2=newWidth-x-1;\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y, x2));\r
+ }//for y\r
+ }//for x\r
+ }//if (version selection)\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) {\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
+ x2=newWidth-x-1;\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ imgDest.AlphaSet(x,y,BlindAlphaGet(y, x2));\r
+ }//for y\r
+ }//for x\r
+ }//if (alpha channel)\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsValid()) {\r
+ imgDest.info.rSelectionBox.left = newWidth-info.rSelectionBox.top;\r
+ imgDest.info.rSelectionBox.right = newWidth-info.rSelectionBox.bottom;\r
+ imgDest.info.rSelectionBox.bottom = info.rSelectionBox.left;\r
+ imgDest.info.rSelectionBox.top = info.rSelectionBox.right;\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
+ x2=newWidth-x-1;\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ imgDest.SelectionSet(x,y,BlindSelectionGet(y, x2));\r
+ }//for y\r
+ }//for x\r
+ }//if (selection)\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ }//for ys\r
+ }//for xs\r
+ }//if\r
+\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(imgDest);\r
+ else Transfer(imgDest);\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::RotateRight(CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long newWidth = GetHeight();\r
+ long newHeight = GetWidth();\r
+\r
+ CxImage imgDest;\r
+ imgDest.CopyInfo(*this);\r
+ imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
+ imgDest.SetPalette(GetPalette());\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) imgDest.AlphaCreate();\r
+#endif\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsValid()) imgDest.SelectionCreate();\r
+#endif\r
+\r
+ long x,y,y2;\r
+ // Speedy rotate for BW images <Robert Abram>\r
+ if (head.biBitCount == 1) {\r
+ \r
+ BYTE *sbits, *dbits, *dbitsmax, bitpos, *nrow,*srcdisp;\r
+ ldiv_t div_r;\r
+\r
+ BYTE *bsrc = GetBits(), *bdest = imgDest.GetBits();\r
+ dbitsmax = bdest + imgDest.head.biSizeImage - 1;\r
+\r
+ imgDest.Clear(0);\r
+ for (y = 0; y < head.biHeight; y++) {\r
+ // Figure out the Column we are going to be copying to\r
+ div_r = ldiv(y, (long)8);\r
+ // set bit pos of src column byte \r
+ bitpos = (BYTE)(128 >> div_r.rem);\r
+ srcdisp = bsrc + y * info.dwEffWidth;\r
+ for (x = 0; x < (long)info.dwEffWidth; x++) {\r
+ // Get Source Bits\r
+ sbits = srcdisp + x;\r
+ // Get destination column\r
+ nrow = bdest + (imgDest.head.biHeight-1-(x*8)) * imgDest.info.dwEffWidth + div_r.quot;\r
+ for (long z = 0; z < 8; z++) {\r
+ // Get Destination Byte\r
+ dbits = nrow - z * imgDest.info.dwEffWidth;\r
+ if ((dbits < bdest) || (dbits > dbitsmax)) break;\r
+ if (*sbits & (128 >> z)) *dbits |= bitpos;\r
+ }\r
+ }\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()){\r
+ for (y = 0; y < newHeight; y++){\r
+ y2=newHeight-y-1;\r
+ for (x = 0; x < newWidth; x++){\r
+ imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x));\r
+ }\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsValid()){\r
+ imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom;\r
+ imgDest.info.rSelectionBox.right = info.rSelectionBox.top;\r
+ imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right;\r
+ imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left;\r
+ for (y = 0; y < newHeight; y++){\r
+ y2=newHeight-y-1;\r
+ for (x = 0; x < newWidth; x++){\r
+ imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x));\r
+ }\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+ } else {\r
+ //anything else but BW\r
+ BYTE *srcPtr, *dstPtr; //source and destionation for 24-bit version\r
+ int xs, ys; //x-segment and y-segment\r
+ for (xs = 0; xs < newWidth; xs+=RBLOCK) {\r
+ for (ys = 0; ys < newHeight; ys+=RBLOCK) {\r
+ if (head.biBitCount==24) {\r
+ //RGB24 optimized pixel access:\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ info.nProgress = (long)(100*y/newHeight); //<Anatoly Ivasyuk>\r
+ y2=newHeight-y-1;\r
+ dstPtr = (BYTE*) imgDest.BlindGetPixelPointer(xs,y);\r
+ srcPtr = (BYTE*) BlindGetPixelPointer(y2, xs);\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
+ //imgDest.SetPixelColor(x, y, GetPixelColor(y2, x));\r
+ *(dstPtr) = *(srcPtr);\r
+ *(dstPtr+1) = *(srcPtr+1);\r
+ *(dstPtr+2) = *(srcPtr+2);\r
+ dstPtr += 3;\r
+ srcPtr += info.dwEffWidth;\r
+ }//for x\r
+ }//for y\r
+ } else {\r
+ //anything else than BW & RGB24: palette\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ info.nProgress = (long)(100*y/newHeight); //<Anatoly Ivasyuk>\r
+ y2=newHeight-y-1;\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
+ imgDest.SetPixelIndex(x, y, BlindGetPixelIndex(y2, x));\r
+ }//for x\r
+ }//for y\r
+ }//if\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()){\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ y2=newHeight-y-1;\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
+ imgDest.AlphaSet(x,y,BlindAlphaGet(y2, x));\r
+ }//for x\r
+ }//for y\r
+ }//if (has alpha)\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsValid()){\r
+ imgDest.info.rSelectionBox.left = info.rSelectionBox.bottom;\r
+ imgDest.info.rSelectionBox.right = info.rSelectionBox.top;\r
+ imgDest.info.rSelectionBox.bottom = newHeight-info.rSelectionBox.right;\r
+ imgDest.info.rSelectionBox.top = newHeight-info.rSelectionBox.left;\r
+ for (y = ys; y < min(newHeight, ys+RBLOCK); y++){\r
+ y2=newHeight-y-1;\r
+ for (x = xs; x < min(newWidth, xs+RBLOCK); x++){\r
+ imgDest.SelectionSet(x,y,BlindSelectionGet(y2, x));\r
+ }//for x\r
+ }//for y\r
+ }//if (has alpha)\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ }//for ys\r
+ }//for xs\r
+ }//if\r
+\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(imgDest);\r
+ else Transfer(imgDest);\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::Negative()\r
+{\r
+ if (!pDib) return false;\r
+\r
+ if (head.biBitCount<=8){\r
+ if (IsGrayScale()){ //GRAYSCALE, selection\r
+ if (pSelection){\r
+ for(long y=info.rSelectionBox.bottom; y<info.rSelectionBox.top; y++){\r
+ for(long x=info.rSelectionBox.left; x<info.rSelectionBox.right; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ BlindSetPixelIndex(x,y,(BYTE)(255-BlindGetPixelIndex(x,y)));\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ BYTE *iSrc=info.pImage;\r
+ for(unsigned long i=0; i < head.biSizeImage; i++){\r
+ *iSrc=(BYTE)~(*(iSrc));\r
+ iSrc++;\r
+ }\r
+ }\r
+ } else { //PALETTE, full image\r
+ RGBQUAD* ppal=GetPalette();\r
+ for(DWORD i=0;i<head.biClrUsed;i++){\r
+ ppal[i].rgbBlue =(BYTE)(255-ppal[i].rgbBlue);\r
+ ppal[i].rgbGreen =(BYTE)(255-ppal[i].rgbGreen);\r
+ ppal[i].rgbRed =(BYTE)(255-ppal[i].rgbRed);\r
+ }\r
+ }\r
+ } else {\r
+ if (pSelection==NULL){ //RGB, full image\r
+ BYTE *iSrc=info.pImage;\r
+ for(unsigned long i=0; i < head.biSizeImage; i++){\r
+ *iSrc=(BYTE)~(*(iSrc));\r
+ iSrc++;\r
+ }\r
+ } else { // RGB with selection\r
+ RGBQUAD color;\r
+ for(long y=info.rSelectionBox.bottom; y<info.rSelectionBox.top; y++){\r
+ for(long x=info.rSelectionBox.left; x<info.rSelectionBox.right; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ color = BlindGetPixelColor(x,y);\r
+ color.rgbRed = (BYTE)(255-color.rgbRed);\r
+ color.rgbGreen = (BYTE)(255-color.rgbGreen);\r
+ color.rgbBlue = (BYTE)(255-color.rgbBlue);\r
+ BlindSetPixelColor(x,y,color);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ //<DP> invert transparent color too\r
+ info.nBkgndColor.rgbBlue = (BYTE)(255-info.nBkgndColor.rgbBlue);\r
+ info.nBkgndColor.rgbGreen = (BYTE)(255-info.nBkgndColor.rgbGreen);\r
+ info.nBkgndColor.rgbRed = (BYTE)(255-info.nBkgndColor.rgbRed);\r
+ }\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_BASICTRANSFORMATIONS\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_TRANSFORMATION\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::Rotate(float angle, CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ // Copyright (c) 1996-1998 Ulrich von Zadow\r
+\r
+ // Negative the angle, because the y-axis is negative.\r
+ double ang = -angle*acos((float)0)/90;\r
+ int newWidth, newHeight;\r
+ int nWidth = GetWidth();\r
+ int nHeight= GetHeight();\r
+ double cos_angle = cos(ang);\r
+ double sin_angle = sin(ang);\r
+\r
+ // Calculate the size of the new bitmap\r
+ POINT p1={0,0};\r
+ POINT p2={nWidth,0};\r
+ POINT p3={0,nHeight};\r
+ POINT p4={nWidth,nHeight};\r
+ CxPoint2 newP1,newP2,newP3,newP4, leftTop, rightTop, leftBottom, rightBottom;\r
+\r
+ newP1.x = (float)p1.x;\r
+ newP1.y = (float)p1.y;\r
+ newP2.x = (float)(p2.x*cos_angle - p2.y*sin_angle);\r
+ newP2.y = (float)(p2.x*sin_angle + p2.y*cos_angle);\r
+ newP3.x = (float)(p3.x*cos_angle - p3.y*sin_angle);\r
+ newP3.y = (float)(p3.x*sin_angle + p3.y*cos_angle);\r
+ newP4.x = (float)(p4.x*cos_angle - p4.y*sin_angle);\r
+ newP4.y = (float)(p4.x*sin_angle + p4.y*cos_angle);\r
+\r
+ leftTop.x = min(min(newP1.x,newP2.x),min(newP3.x,newP4.x));\r
+ leftTop.y = min(min(newP1.y,newP2.y),min(newP3.y,newP4.y));\r
+ rightBottom.x = max(max(newP1.x,newP2.x),max(newP3.x,newP4.x));\r
+ rightBottom.y = max(max(newP1.y,newP2.y),max(newP3.y,newP4.y));\r
+ leftBottom.x = leftTop.x;\r
+ leftBottom.y = rightBottom.y;\r
+ rightTop.x = rightBottom.x;\r
+ rightTop.y = leftTop.y;\r
+\r
+ newWidth = (int) floor(0.5f + rightTop.x - leftTop.x);\r
+ newHeight= (int) floor(0.5f + leftBottom.y - leftTop.y);\r
+ CxImage imgDest;\r
+ imgDest.CopyInfo(*this);\r
+ imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
+ imgDest.SetPalette(GetPalette());\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if(AlphaIsValid()) //MTA: Fix for rotation problem when the image has an alpha channel\r
+ {\r
+ imgDest.AlphaCreate();\r
+ imgDest.AlphaClear();\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ int x,y,newX,newY,oldX,oldY;\r
+\r
+ if (head.biClrUsed==0){ //RGB\r
+ for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){\r
+ info.nProgress = (long)(100*newY/newHeight);\r
+ if (info.nEscape) break;\r
+ for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){\r
+ oldX = (long)(x*cos_angle + y*sin_angle + 0.5);\r
+ oldY = (long)(y*cos_angle - x*sin_angle + 0.5);\r
+ imgDest.SetPixelColor(newX,newY,GetPixelColor(oldX,oldY));\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ }\r
+ } else { //PALETTE\r
+ for (y = (int)leftTop.y, newY = 0; y<=(int)leftBottom.y; y++,newY++){\r
+ info.nProgress = (long)(100*newY/newHeight);\r
+ if (info.nEscape) break;\r
+ for (x = (int)leftTop.x, newX = 0; x<=(int)rightTop.x; x++,newX++){\r
+ oldX = (long)(x*cos_angle + y*sin_angle + 0.5);\r
+ oldY = (long)(y*cos_angle - x*sin_angle + 0.5);\r
+ imgDest.SetPixelIndex(newX,newY,GetPixelIndex(oldX,oldY));\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ imgDest.AlphaSet(newX,newY,AlphaGet(oldX,oldY)); //MTA: copy the alpha value\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ }\r
+ }\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(imgDest);\r
+ else Transfer(imgDest);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Rotates image around it's center.\r
+ * Method can use interpolation with paletted images, but does not change pallete, so results vary.\r
+ * (If you have only four colours in a palette, there's not much room for interpolation.)\r
+ * \r
+ * \param angle - angle in degrees (positive values rotate clockwise)\r
+ * \param *iDst - destination image (if null, this image is changed)\r
+ * \param inMethod - interpolation method used\r
+ * (IM_NEAREST_NEIGHBOUR produces aliasing (fast), IM_BILINEAR softens picture a bit (slower)\r
+ * IM_SHARPBICUBIC is slower and produces some halos...)\r
+ * \param ofMethod - overflow method (how to choose colour of pixels that have no source)\r
+ * \param replColor - replacement colour to use (OM_COLOR, OM_BACKGROUND with no background colour...)\r
+ * \param optimizeRightAngles - call faster methods for 90, 180, and 270 degree rotations. Faster methods\r
+ * are called for angles, where error (in location of corner pixels) is less\r
+ * than 0.25 pixels.\r
+ * \param bKeepOriginalSize - rotates the image without resizing.\r
+ *\r
+ * \author ***bd*** 2.2004\r
+ */\r
+bool CxImage::Rotate2(float angle, \r
+ CxImage *iDst, \r
+ InterpolationMethod inMethod, \r
+ OverflowMethod ofMethod, \r
+ RGBQUAD *replColor,\r
+ bool const optimizeRightAngles,\r
+ bool const bKeepOriginalSize)\r
+{\r
+ if (!pDib) return false; //no dib no go\r
+ \r
+ double ang = -angle*acos(0.0f)/90.0f; //convert angle to radians and invert (positive angle performs clockwise rotation)\r
+ float cos_angle = (float) cos(ang); //these two are needed later (to rotate)\r
+ float sin_angle = (float) sin(ang);\r
+ \r
+ //Calculate the size of the new bitmap (rotate corners of image)\r
+ CxPoint2 p[4]; //original corners of the image\r
+ p[0]=CxPoint2(-0.5f,-0.5f);\r
+ p[1]=CxPoint2(GetWidth()-0.5f,-0.5f);\r
+ p[2]=CxPoint2(-0.5f,GetHeight()-0.5f);\r
+ p[3]=CxPoint2(GetWidth()-0.5f,GetHeight()-0.5f);\r
+ CxPoint2 newp[4]; //rotated positions of corners\r
+ //(rotate corners)\r
+ if (bKeepOriginalSize){\r
+ for (int i=0; i<4; i++) {\r
+ newp[i].x = p[i].x;\r
+ newp[i].y = p[i].y;\r
+ }//for\r
+ } else {\r
+ for (int i=0; i<4; i++) {\r
+ newp[i].x = (p[i].x*cos_angle - p[i].y*sin_angle);\r
+ newp[i].y = (p[i].x*sin_angle + p[i].y*cos_angle);\r
+ }//for i\r
+ \r
+ if (optimizeRightAngles) { \r
+ //For rotations of 90, -90 or 180 or 0 degrees, call faster routines\r
+ if (newp[3].Distance(CxPoint2(GetHeight()-0.5f, 0.5f-GetWidth())) < 0.25) \r
+ //rotation right for circa 90 degrees (diagonal pixels less than 0.25 pixel away from 90 degree rotation destination)\r
+ return RotateRight(iDst);\r
+ if (newp[3].Distance(CxPoint2(0.5f-GetHeight(), -0.5f+GetWidth())) < 0.25) \r
+ //rotation left for ~90 degrees\r
+ return RotateLeft(iDst);\r
+ if (newp[3].Distance(CxPoint2(0.5f-GetWidth(), 0.5f-GetHeight())) < 0.25) \r
+ //rotation left for ~180 degrees\r
+ return Rotate180(iDst);\r
+ if (newp[3].Distance(p[3]) < 0.25) {\r
+ //rotation not significant\r
+ if (iDst) iDst->Copy(*this); //copy image to iDst, if required\r
+ return true; //and we're done\r
+ }//if\r
+ }//if\r
+ }//if\r
+\r
+ //(read new dimensions from location of corners)\r
+ float minx = (float) min(min(newp[0].x,newp[1].x),min(newp[2].x,newp[3].x));\r
+ float miny = (float) min(min(newp[0].y,newp[1].y),min(newp[2].y,newp[3].y));\r
+ float maxx = (float) max(max(newp[0].x,newp[1].x),max(newp[2].x,newp[3].x));\r
+ float maxy = (float) max(max(newp[0].y,newp[1].y),max(newp[2].y,newp[3].y));\r
+ int newWidth = (int) floor(maxx-minx+0.5f);\r
+ int newHeight= (int) floor(maxy-miny+0.5f);\r
+ float ssx=((maxx+minx)- ((float) newWidth-1))/2.0f; //start for x\r
+ float ssy=((maxy+miny)- ((float) newHeight-1))/2.0f; //start for y\r
+\r
+ float newxcenteroffset = 0.5f * newWidth;\r
+ float newycenteroffset = 0.5f * newHeight;\r
+ if (bKeepOriginalSize){\r
+ ssx -= 0.5f * GetWidth();\r
+ ssy -= 0.5f * GetHeight();\r
+ }\r
+\r
+ //create destination image\r
+ CxImage imgDest;\r
+ imgDest.CopyInfo(*this);\r
+ imgDest.Create(newWidth,newHeight,GetBpp(),GetType());\r
+ imgDest.SetPalette(GetPalette());\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if(AlphaIsValid()) imgDest.AlphaCreate(); //MTA: Fix for rotation problem when the image has an alpha channel\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ \r
+ RGBQUAD rgb; //pixel colour\r
+ RGBQUAD rc;\r
+ if (replColor!=0) \r
+ rc=*replColor; \r
+ else {\r
+ rc.rgbRed=255; rc.rgbGreen=255; rc.rgbBlue=255; rc.rgbReserved=0;\r
+ }//if\r
+ float x,y; //destination location (float, with proper offset)\r
+ float origx, origy; //origin location\r
+ int destx, desty; //destination location\r
+ \r
+ y=ssy; //initialize y\r
+ if (!IsIndexed()){ //RGB24\r
+ //optimized RGB24 implementation (direct write to destination):\r
+ BYTE *pxptr;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ BYTE *pxptra=0;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ for (desty=0; desty<newHeight; desty++) {\r
+ info.nProgress = (long)(100*desty/newHeight);\r
+ if (info.nEscape) break;\r
+ //initialize x\r
+ x=ssx;\r
+ //calculate pointer to first byte in row\r
+ pxptr=(BYTE *)imgDest.BlindGetPixelPointer(0, desty);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ //calculate pointer to first byte in row\r
+ if (AlphaIsValid()) pxptra=imgDest.AlphaGetPointer(0, desty);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ for (destx=0; destx<newWidth; destx++) {\r
+ //get source pixel coordinate for current destination point\r
+ //origx = (cos_angle*(x-head.biWidth/2)+sin_angle*(y-head.biHeight/2))+newWidth/2;\r
+ //origy = (cos_angle*(y-head.biHeight/2)-sin_angle*(x-head.biWidth/2))+newHeight/2;\r
+ origx = cos_angle*x+sin_angle*y;\r
+ origy = cos_angle*y-sin_angle*x;\r
+ if (bKeepOriginalSize){\r
+ origx += newxcenteroffset;\r
+ origy += newycenteroffset;\r
+ }\r
+ rgb = GetPixelColorInterpolated(origx, origy, inMethod, ofMethod, &rc); //get interpolated colour value\r
+ //copy alpha and colour value to destination\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pxptra) *pxptra++ = rgb.rgbReserved;\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ *pxptr++ = rgb.rgbBlue;\r
+ *pxptr++ = rgb.rgbGreen;\r
+ *pxptr++ = rgb.rgbRed;\r
+ x++;\r
+ }//for destx\r
+ y++;\r
+ }//for desty\r
+ } else { \r
+ //non-optimized implementation for paletted images\r
+ for (desty=0; desty<newHeight; desty++) {\r
+ info.nProgress = (long)(100*desty/newHeight);\r
+ if (info.nEscape) break;\r
+ x=ssx;\r
+ for (destx=0; destx<newWidth; destx++) {\r
+ //get source pixel coordinate for current destination point\r
+ origx=(cos_angle*x+sin_angle*y);\r
+ origy=(cos_angle*y-sin_angle*x);\r
+ if (bKeepOriginalSize){\r
+ origx += newxcenteroffset;\r
+ origy += newycenteroffset;\r
+ }\r
+ rgb = GetPixelColorInterpolated(origx, origy, inMethod, ofMethod, &rc);\r
+ //***!*** SetPixelColor is slow for palleted images\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) \r
+ imgDest.SetPixelColor(destx,desty,rgb,true);\r
+ else \r
+#endif //CXIMAGE_SUPPORT_ALPHA \r
+ imgDest.SetPixelColor(destx,desty,rgb,false);\r
+ x++;\r
+ }//for destx\r
+ y++;\r
+ }//for desty\r
+ }\r
+ //select the destination\r
+ \r
+ if (iDst) iDst->Transfer(imgDest);\r
+ else Transfer(imgDest);\r
+ \r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::Rotate180(CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long wid = GetWidth();\r
+ long ht = GetHeight();\r
+\r
+ CxImage imgDest;\r
+ imgDest.CopyInfo(*this);\r
+ imgDest.Create(wid,ht,GetBpp(),GetType());\r
+ imgDest.SetPalette(GetPalette());\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) imgDest.AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ long x,y,y2;\r
+ for (y = 0; y < ht; y++){\r
+ info.nProgress = (long)(100*y/ht); //<Anatoly Ivasyuk>\r
+ y2=ht-y-1;\r
+ for (x = 0; x < wid; x++){\r
+ if(head.biClrUsed==0)//RGB\r
+ imgDest.SetPixelColor(wid-x-1, y2, BlindGetPixelColor(x, y));\r
+ else //PALETTE\r
+ imgDest.SetPixelIndex(wid-x-1, y2, BlindGetPixelIndex(x, y));\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) imgDest.AlphaSet(wid-x-1, y2,BlindAlphaGet(x, y));\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ }\r
+ }\r
+\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(imgDest);\r
+ else Transfer(imgDest);\r
+ return true;\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Resizes the image. mode can be 0 for slow (bilinear) method ,\r
+ * 1 for fast (nearest pixel) method, or 2 for accurate (bicubic spline interpolation) method.\r
+ * The function is faster with 24 and 1 bpp images, slow for 4 bpp images and slowest for 8 bpp images.\r
+ */\r
+bool CxImage::Resample(long newx, long newy, int mode, CxImage* iDst)\r
+{\r
+ if (newx==0 || newy==0) return false;\r
+\r
+ if (head.biWidth==newx && head.biHeight==newy){\r
+ if (iDst) iDst->Copy(*this);\r
+ return true;\r
+ }\r
+\r
+ float xScale, yScale, fX, fY;\r
+ xScale = (float)head.biWidth / (float)newx;\r
+ yScale = (float)head.biHeight / (float)newy;\r
+\r
+ CxImage newImage;\r
+ newImage.CopyInfo(*this);\r
+ newImage.Create(newx,newy,head.biBitCount,GetType());\r
+ newImage.SetPalette(GetPalette());\r
+ if (!newImage.IsValid()){\r
+ strcpy(info.szLastError,newImage.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ switch (mode) {\r
+ case 1: // nearest pixel\r
+ { \r
+ for(long y=0; y<newy; y++){\r
+ info.nProgress = (long)(100*y/newy);\r
+ if (info.nEscape) break;\r
+ fY = y * yScale;\r
+ for(long x=0; x<newx; x++){\r
+ fX = x * xScale;\r
+ newImage.SetPixelColor(x,y,GetPixelColor((long)fX,(long)fY));\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 2: // bicubic interpolation by Blake L. Carlson <blake-carlson(at)uiowa(dot)edu\r
+ {\r
+ float f_x, f_y, a, b, rr, gg, bb, r1, r2;\r
+ int i_x, i_y, xx, yy;\r
+ RGBQUAD rgb;\r
+ BYTE* iDst;\r
+ for(long y=0; y<newy; y++){\r
+ info.nProgress = (long)(100*y/newy);\r
+ if (info.nEscape) break;\r
+ f_y = (float) y * yScale - 0.5f;\r
+ i_y = (int) floor(f_y);\r
+ a = f_y - (float)floor(f_y);\r
+ for(long x=0; x<newx; x++){\r
+ f_x = (float) x * xScale - 0.5f;\r
+ i_x = (int) floor(f_x);\r
+ b = f_x - (float)floor(f_x);\r
+\r
+ rr = gg = bb = 0.0f;\r
+ for(int m=-1; m<3; m++) {\r
+ r1 = KernelBSpline((float) m - a);\r
+ yy = i_y+m;\r
+ if (yy<0) yy=0;\r
+ if (yy>=head.biHeight) yy = head.biHeight-1;\r
+ for(int n=-1; n<3; n++) {\r
+ r2 = r1 * KernelBSpline(b - (float)n);\r
+ xx = i_x+n;\r
+ if (xx<0) xx=0;\r
+ if (xx>=head.biWidth) xx=head.biWidth-1;\r
+\r
+ if (head.biClrUsed){\r
+ rgb = GetPixelColor(xx,yy);\r
+ } else {\r
+ iDst = info.pImage + yy*info.dwEffWidth + xx*3;\r
+ rgb.rgbBlue = *iDst++;\r
+ rgb.rgbGreen= *iDst++;\r
+ rgb.rgbRed = *iDst;\r
+ }\r
+\r
+ rr += rgb.rgbRed * r2;\r
+ gg += rgb.rgbGreen * r2;\r
+ bb += rgb.rgbBlue * r2;\r
+ }\r
+ }\r
+\r
+ if (head.biClrUsed)\r
+ newImage.SetPixelColor(x,y,RGB(rr,gg,bb));\r
+ else {\r
+ iDst = newImage.info.pImage + y*newImage.info.dwEffWidth + x*3;\r
+ *iDst++ = (BYTE)bb;\r
+ *iDst++ = (BYTE)gg;\r
+ *iDst = (BYTE)rr;\r
+ }\r
+\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ default: // bilinear interpolation\r
+ if (!(head.biWidth>newx && head.biHeight>newy && head.biBitCount==24)) {\r
+ // (c) 1999 Steve McMahon (steve@dogma.demon.co.uk)\r
+ long ifX, ifY, ifX1, ifY1, xmax, ymax;\r
+ float ir1, ir2, ig1, ig2, ib1, ib2, dx, dy;\r
+ BYTE r,g,b;\r
+ RGBQUAD rgb1, rgb2, rgb3, rgb4;\r
+ xmax = head.biWidth-1;\r
+ ymax = head.biHeight-1;\r
+ for(long y=0; y<newy; y++){\r
+ info.nProgress = (long)(100*y/newy);\r
+ if (info.nEscape) break;\r
+ fY = y * yScale;\r
+ ifY = (int)fY;\r
+ ifY1 = min(ymax, ifY+1);\r
+ dy = fY - ifY;\r
+ for(long x=0; x<newx; x++){\r
+ fX = x * xScale;\r
+ ifX = (int)fX;\r
+ ifX1 = min(xmax, ifX+1);\r
+ dx = fX - ifX;\r
+ // Interpolate using the four nearest pixels in the source\r
+ if (head.biClrUsed){\r
+ rgb1=GetPaletteColor(GetPixelIndex(ifX,ifY));\r
+ rgb2=GetPaletteColor(GetPixelIndex(ifX1,ifY));\r
+ rgb3=GetPaletteColor(GetPixelIndex(ifX,ifY1));\r
+ rgb4=GetPaletteColor(GetPixelIndex(ifX1,ifY1));\r
+ }\r
+ else {\r
+ BYTE* iDst;\r
+ iDst = info.pImage + ifY*info.dwEffWidth + ifX*3;\r
+ rgb1.rgbBlue = *iDst++; rgb1.rgbGreen= *iDst++; rgb1.rgbRed =*iDst;\r
+ iDst = info.pImage + ifY*info.dwEffWidth + ifX1*3;\r
+ rgb2.rgbBlue = *iDst++; rgb2.rgbGreen= *iDst++; rgb2.rgbRed =*iDst;\r
+ iDst = info.pImage + ifY1*info.dwEffWidth + ifX*3;\r
+ rgb3.rgbBlue = *iDst++; rgb3.rgbGreen= *iDst++; rgb3.rgbRed =*iDst;\r
+ iDst = info.pImage + ifY1*info.dwEffWidth + ifX1*3;\r
+ rgb4.rgbBlue = *iDst++; rgb4.rgbGreen= *iDst++; rgb4.rgbRed =*iDst;\r
+ }\r
+ // Interplate in x direction:\r
+ ir1 = rgb1.rgbRed + (rgb3.rgbRed - rgb1.rgbRed) * dy;\r
+ ig1 = rgb1.rgbGreen + (rgb3.rgbGreen - rgb1.rgbGreen) * dy;\r
+ ib1 = rgb1.rgbBlue + (rgb3.rgbBlue - rgb1.rgbBlue) * dy;\r
+ ir2 = rgb2.rgbRed + (rgb4.rgbRed - rgb2.rgbRed) * dy;\r
+ ig2 = rgb2.rgbGreen + (rgb4.rgbGreen - rgb2.rgbGreen) * dy;\r
+ ib2 = rgb2.rgbBlue + (rgb4.rgbBlue - rgb2.rgbBlue) * dy;\r
+ // Interpolate in y:\r
+ r = (BYTE)(ir1 + (ir2-ir1) * dx);\r
+ g = (BYTE)(ig1 + (ig2-ig1) * dx);\r
+ b = (BYTE)(ib1 + (ib2-ib1) * dx);\r
+ // Set output\r
+ newImage.SetPixelColor(x,y,RGB(r,g,b));\r
+ }\r
+ } \r
+ } else {\r
+ //high resolution shrink, thanks to Henrik Stellmann <henrik.stellmann@volleynet.de>\r
+ const long ACCURACY = 1000;\r
+ long i,j; // index for faValue\r
+ long x,y; // coordinates in source image\r
+ BYTE* pSource;\r
+ BYTE* pDest = newImage.info.pImage;\r
+ long* naAccu = new long[3 * newx + 3];\r
+ long* naCarry = new long[3 * newx + 3];\r
+ long* naTemp;\r
+ long nWeightX,nWeightY;\r
+ float fEndX;\r
+ long nScale = (long)(ACCURACY * xScale * yScale);\r
+\r
+ memset(naAccu, 0, sizeof(long) * 3 * newx);\r
+ memset(naCarry, 0, sizeof(long) * 3 * newx);\r
+\r
+ int u, v = 0; // coordinates in dest image\r
+ float fEndY = yScale - 1.0f;\r
+ for (y = 0; y < head.biHeight; y++){\r
+ info.nProgress = (long)(100*y/head.biHeight); //<Anatoly Ivasyuk>\r
+ if (info.nEscape) break;\r
+ pSource = info.pImage + y * info.dwEffWidth;\r
+ u = i = 0;\r
+ fEndX = xScale - 1.0f;\r
+ if ((float)y < fEndY) { // complete source row goes into dest row\r
+ for (x = 0; x < head.biWidth; x++){\r
+ if ((float)x < fEndX){ // complete source pixel goes into dest pixel\r
+ for (j = 0; j < 3; j++) naAccu[i + j] += (*pSource++) * ACCURACY;\r
+ } else { // source pixel is splitted for 2 dest pixels\r
+ nWeightX = (long)(((float)x - fEndX) * ACCURACY);\r
+ for (j = 0; j < 3; j++){\r
+ naAccu[i] += (ACCURACY - nWeightX) * (*pSource);\r
+ naAccu[3 + i++] += nWeightX * (*pSource++);\r
+ }\r
+ fEndX += xScale;\r
+ u++;\r
+ }\r
+ }\r
+ } else { // source row is splitted for 2 dest rows \r
+ nWeightY = (long)(((float)y - fEndY) * ACCURACY);\r
+ for (x = 0; x < head.biWidth; x++){\r
+ if ((float)x < fEndX){ // complete source pixel goes into 2 pixel\r
+ for (j = 0; j < 3; j++){\r
+ naAccu[i + j] += ((ACCURACY - nWeightY) * (*pSource));\r
+ naCarry[i + j] += nWeightY * (*pSource++);\r
+ }\r
+ } else { // source pixel is splitted for 4 dest pixels\r
+ nWeightX = (int)(((float)x - fEndX) * ACCURACY);\r
+ for (j = 0; j < 3; j++) {\r
+ naAccu[i] += ((ACCURACY - nWeightY) * (ACCURACY - nWeightX)) * (*pSource) / ACCURACY;\r
+ *pDest++ = (BYTE)(naAccu[i] / nScale);\r
+ naCarry[i] += (nWeightY * (ACCURACY - nWeightX) * (*pSource)) / ACCURACY;\r
+ naAccu[i + 3] += ((ACCURACY - nWeightY) * nWeightX * (*pSource)) / ACCURACY;\r
+ naCarry[i + 3] = (nWeightY * nWeightX * (*pSource)) / ACCURACY;\r
+ i++;\r
+ pSource++;\r
+ }\r
+ fEndX += xScale;\r
+ u++;\r
+ }\r
+ }\r
+ if (u < newx){ // possibly not completed due to rounding errors\r
+ for (j = 0; j < 3; j++) *pDest++ = (BYTE)(naAccu[i++] / nScale);\r
+ }\r
+ naTemp = naCarry;\r
+ naCarry = naAccu;\r
+ naAccu = naTemp;\r
+ memset(naCarry, 0, sizeof(int) * 3); // need only to set first pixel zero\r
+ pDest = newImage.info.pImage + (++v * newImage.info.dwEffWidth);\r
+ fEndY += yScale;\r
+ }\r
+ }\r
+ if (v < newy){ // possibly not completed due to rounding errors\r
+ for (i = 0; i < 3 * newx; i++) *pDest++ = (BYTE)(naAccu[i] / nScale);\r
+ }\r
+ delete [] naAccu;\r
+ delete [] naCarry;\r
+ }\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()){\r
+ newImage.AlphaCreate();\r
+ for(long y=0; y<newy; y++){\r
+ fY = y * yScale;\r
+ for(long x=0; x<newx; x++){\r
+ fX = x * xScale;\r
+ newImage.AlphaSet(x,y,AlphaGet((long)fX,(long)fY));\r
+ }\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(newImage);\r
+ else Transfer(newImage);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * New simpler resample. Adds new interpolation methods and simplifies code (using GetPixelColorInterpolated\r
+ * and GetAreaColorInterpolated). It also (unlike old method) interpolates alpha layer. \r
+ *\r
+ * \param newx, newy - size of resampled image\r
+ * \param inMethod - interpolation method to use (see comments at GetPixelColorInterpolated)\r
+ * If image size is being reduced, averaging is used instead (or simultaneously with) inMethod.\r
+ * \param ofMethod - what to replace outside pixels by (only significant for bordering pixels of enlarged image)\r
+ * \param iDst - pointer to destination CxImage or NULL.\r
+ * \param disableAveraging - force no averaging when shrinking images (Produces aliasing.\r
+ * You probably just want to leave this off...)\r
+ *\r
+ * \author ***bd*** 2.2004\r
+ */\r
+bool CxImage::Resample2(\r
+ long newx, long newy, \r
+ InterpolationMethod const inMethod, \r
+ OverflowMethod const ofMethod, \r
+ CxImage* const iDst,\r
+ bool const disableAveraging)\r
+{\r
+ if (newx<=0 || newy<=0 || !pDib) return false;\r
+ \r
+ if (head.biWidth==newx && head.biHeight==newy) {\r
+ //image already correct size (just copy and return)\r
+ if (iDst) iDst->Copy(*this);\r
+ return true;\r
+ }//if\r
+ \r
+ //calculate scale of new image (less than 1 for enlarge)\r
+ float xScale, yScale;\r
+ xScale = (float)head.biWidth / (float)newx; \r
+ yScale = (float)head.biHeight / (float)newy;\r
+ \r
+ //create temporary destination image\r
+ CxImage newImage;\r
+ newImage.CopyInfo(*this);\r
+ newImage.Create(newx,newy,head.biBitCount,GetType());\r
+ newImage.SetPalette(GetPalette());\r
+ if (!newImage.IsValid()){\r
+ strcpy(info.szLastError,newImage.GetLastError());\r
+ return false;\r
+ }\r
+ \r
+ //and alpha channel if required\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) newImage.AlphaCreate();\r
+ BYTE *pxptra = 0; // destination alpha data\r
+#endif\r
+ \r
+ float sX, sY; //source location\r
+ long dX,dY; //destination pixel (int value)\r
+ if ((xScale<=1 && yScale<=1) || disableAveraging) {\r
+ //image is being enlarged (or interpolation on demand)\r
+ if (!IsIndexed()) {\r
+ //RGB24 image (optimized version with direct writes)\r
+ RGBQUAD q; //pixel colour\r
+ BYTE *pxptr; //pointer to destination pixel\r
+ for(dY=0; dY<newy; dY++){\r
+ info.nProgress = (long)(100*dY/newy);\r
+ if (info.nEscape) break;\r
+ sY = (dY + 0.5f) * yScale - 0.5f;\r
+ pxptr=(BYTE*)(newImage.BlindGetPixelPointer(0,dY));\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ pxptra=newImage.AlphaGetPointer(0,dY);\r
+#endif\r
+ for(dX=0; dX<newx; dX++){\r
+ sX = (dX + 0.5f) * xScale - 0.5f;\r
+ q=GetPixelColorInterpolated(sX,sY,inMethod,ofMethod,0);\r
+ *pxptr++=q.rgbBlue;\r
+ *pxptr++=q.rgbGreen;\r
+ *pxptr++=q.rgbRed;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pxptra) *pxptra++=q.rgbReserved;\r
+#endif\r
+ }//for dX\r
+ }//for dY\r
+ } else {\r
+ //enlarge paletted image. Slower method.\r
+ for(dY=0; dY<newy; dY++){\r
+ info.nProgress = (long)(100*dY/newy);\r
+ if (info.nEscape) break;\r
+ sY = (dY + 0.5f) * yScale - 0.5f;\r
+ for(dX=0; dX<newx; dX++){\r
+ sX = (dX + 0.5f) * xScale - 0.5f;\r
+ newImage.SetPixelColor(dX,dY,GetPixelColorInterpolated(sX,sY,inMethod,ofMethod,0),true);\r
+ }//for x\r
+ }//for y\r
+ }//if\r
+ } else {\r
+ //image size is being reduced (averaging enabled)\r
+ for(dY=0; dY<newy; dY++){\r
+ info.nProgress = (long)(100*dY/newy); if (info.nEscape) break;\r
+ sY = (dY+0.5f) * yScale - 0.5f;\r
+ for(dX=0; dX<newx; dX++){\r
+ sX = (dX+0.5f) * xScale - 0.5f;\r
+ newImage.SetPixelColor(dX,dY,GetAreaColorInterpolated(sX, sY, xScale, yScale, inMethod, ofMethod,0),true);\r
+ }//for x\r
+ }//for y\r
+ }//if\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid() && pxptra == 0){\r
+ for(long y=0; y<newy; y++){\r
+ dY = (long)(y * yScale);\r
+ for(long x=0; x<newx; x++){\r
+ dX = (long)(x * xScale);\r
+ newImage.AlphaSet(x,y,AlphaGet(dX,dY));\r
+ }\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ //copy new image to the destination\r
+ if (iDst) \r
+ iDst->Transfer(newImage);\r
+ else \r
+ Transfer(newImage);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Reduces the number of bits per pixel to nbit (1, 4 or 8).\r
+ * ppal points to a valid palette for the final image; if not supplied the function will use a standard palette.\r
+ * ppal is not necessary for reduction to 1 bpp.\r
+ */\r
+bool CxImage::DecreaseBpp(DWORD nbit, bool errordiffusion, RGBQUAD* ppal, DWORD clrimportant)\r
+{\r
+ if (!pDib) return false;\r
+ if (head.biBitCount < nbit){\r
+ strcpy(info.szLastError,"DecreaseBpp: target BPP greater than source BPP");\r
+ return false;\r
+ }\r
+ if (head.biBitCount == nbit){\r
+ if (clrimportant==0) return true;\r
+ if (head.biClrImportant && (head.biClrImportant<clrimportant)) return true;\r
+ }\r
+\r
+ long er,eg,eb;\r
+ RGBQUAD c,ce;\r
+\r
+ CxImage tmp;\r
+ tmp.CopyInfo(*this);\r
+ tmp.Create(head.biWidth,head.biHeight,(WORD)nbit,info.dwType);\r
+ if (clrimportant) tmp.SetClrImportant(clrimportant);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ tmp.SelectionCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ if (ppal) {\r
+ if (clrimportant) {\r
+ tmp.SetPalette(ppal,clrimportant);\r
+ } else {\r
+ tmp.SetPalette(ppal,1<<tmp.head.biBitCount);\r
+ }\r
+ } else {\r
+ tmp.SetStdPalette();\r
+ }\r
+\r
+ for (long y=0;y<head.biHeight;y++){\r
+ if (info.nEscape) break;\r
+ info.nProgress = (long)(100*y/head.biHeight);\r
+ for (long x=0;x<head.biWidth;x++){\r
+ if (!errordiffusion){\r
+ tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y));\r
+ } else {\r
+ c = BlindGetPixelColor(x,y);\r
+ tmp.BlindSetPixelColor(x,y,c);\r
+\r
+ ce = tmp.BlindGetPixelColor(x,y);\r
+ er=(long)c.rgbRed - (long)ce.rgbRed;\r
+ eg=(long)c.rgbGreen - (long)ce.rgbGreen;\r
+ eb=(long)c.rgbBlue - (long)ce.rgbBlue;\r
+\r
+ c = GetPixelColor(x+1,y);\r
+ c.rgbRed = (BYTE)min(255L,max(0L,(long)c.rgbRed + ((er*7)/16)));\r
+ c.rgbGreen = (BYTE)min(255L,max(0L,(long)c.rgbGreen + ((eg*7)/16)));\r
+ c.rgbBlue = (BYTE)min(255L,max(0L,(long)c.rgbBlue + ((eb*7)/16)));\r
+ SetPixelColor(x+1,y,c);\r
+ int coeff=1;\r
+ for(int i=-1; i<2; i++){\r
+ switch(i){\r
+ case -1:\r
+ coeff=2; break;\r
+ case 0:\r
+ coeff=4; break;\r
+ case 1:\r
+ coeff=1; break;\r
+ }\r
+ c = GetPixelColor(x+i,y+1);\r
+ c.rgbRed = (BYTE)min(255L,max(0L,(long)c.rgbRed + ((er * coeff)/16)));\r
+ c.rgbGreen = (BYTE)min(255L,max(0L,(long)c.rgbGreen + ((eg * coeff)/16)));\r
+ c.rgbBlue = (BYTE)min(255L,max(0L,(long)c.rgbBlue + ((eb * coeff)/16)));\r
+ SetPixelColor(x+i,y+1,c);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Increases the number of bits per pixel of the image.\r
+ * \param nbit: 4, 8, 24\r
+ */\r
+bool CxImage::IncreaseBpp(DWORD nbit)\r
+{\r
+ if (!pDib) return false;\r
+ switch (nbit){\r
+ case 4:\r
+ {\r
+ if (head.biBitCount==4) return true;\r
+ if (head.biBitCount>4) return false;\r
+\r
+ CxImage tmp;\r
+ tmp.CopyInfo(*this);\r
+ tmp.Create(head.biWidth,head.biHeight,4,info.dwType);\r
+ tmp.SetPalette(GetPalette(),GetNumColors());\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ tmp.SelectionCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ for (long y=0;y<head.biHeight;y++){\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+ tmp.BlindSetPixelIndex(x,y,BlindGetPixelIndex(x,y));\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+ }\r
+ case 8:\r
+ {\r
+ if (head.biBitCount==8) return true;\r
+ if (head.biBitCount>8) return false;\r
+\r
+ CxImage tmp;\r
+ tmp.CopyInfo(*this);\r
+ tmp.Create(head.biWidth,head.biHeight,8,info.dwType);\r
+ tmp.SetPalette(GetPalette(),GetNumColors());\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ tmp.SelectionCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ for (long y=0;y<head.biHeight;y++){\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+ tmp.BlindSetPixelIndex(x,y,BlindGetPixelIndex(x,y));\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+ }\r
+ case 24:\r
+ {\r
+ if (head.biBitCount==24) return true;\r
+ if (head.biBitCount>24) return false;\r
+\r
+ CxImage tmp;\r
+ tmp.CopyInfo(*this);\r
+ tmp.Create(head.biWidth,head.biHeight,24,info.dwType);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ if (info.nBkgndIndex>=0) //translate transparency\r
+ tmp.info.nBkgndColor=GetPaletteColor((BYTE)info.nBkgndIndex);\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ tmp.SelectionCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaCopy(*this);\r
+ if (AlphaPaletteIsValid() && !AlphaIsValid()) tmp.AlphaCreate();\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ for (long y=0;y<head.biHeight;y++){\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+ tmp.BlindSetPixelColor(x,y,BlindGetPixelColor(x,y),true);\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Converts the image to B&W using the desired method :\r
+ * - 0 = Floyd-Steinberg\r
+ * - 1 = Ordered-Dithering (4x4) \r
+ * - 2 = Burkes\r
+ * - 3 = Stucki\r
+ * - 4 = Jarvis-Judice-Ninke\r
+ * - 5 = Sierra\r
+ * - 6 = Stevenson-Arce\r
+ * - 7 = Bayer (4x4 ordered dithering) \r
+ */\r
+bool CxImage::Dither(long method)\r
+{\r
+ if (!pDib) return false;\r
+ if (head.biBitCount == 1) return true;\r
+ \r
+ GrayScale();\r
+\r
+ CxImage tmp;\r
+ tmp.CopyInfo(*this);\r
+ tmp.Create(head.biWidth, head.biHeight, 1, info.dwType);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ tmp.SelectionCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaCopy(*this);\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ switch (method){\r
+ case 1:\r
+ {\r
+ // Multi-Level Ordered-Dithering by Kenny Hoff (Oct. 12, 1995)\r
+ #define dth_NumRows 4\r
+ #define dth_NumCols 4\r
+ #define dth_NumIntensityLevels 2\r
+ #define dth_NumRowsLessOne (dth_NumRows-1)\r
+ #define dth_NumColsLessOne (dth_NumCols-1)\r
+ #define dth_RowsXCols (dth_NumRows*dth_NumCols)\r
+ #define dth_MaxIntensityVal 255\r
+ #define dth_MaxDitherIntensityVal (dth_NumRows*dth_NumCols*(dth_NumIntensityLevels-1))\r
+\r
+ int DitherMatrix[dth_NumRows][dth_NumCols] = {{0,8,2,10}, {12,4,14,6}, {3,11,1,9}, {15,7,13,5} };\r
+ \r
+ unsigned char Intensity[dth_NumIntensityLevels] = { 0,1 }; // 2 LEVELS B/W\r
+ //unsigned char Intensity[NumIntensityLevels] = { 0,255 }; // 2 LEVELS\r
+ //unsigned char Intensity[NumIntensityLevels] = { 0,127,255 }; // 3 LEVELS\r
+ //unsigned char Intensity[NumIntensityLevels] = { 0,85,170,255 }; // 4 LEVELS\r
+ //unsigned char Intensity[NumIntensityLevels] = { 0,63,127,191,255 }; // 5 LEVELS\r
+ //unsigned char Intensity[NumIntensityLevels] = { 0,51,102,153,204,255 }; // 6 LEVELS\r
+ //unsigned char Intensity[NumIntensityLevels] = { 0,42,85,127,170,213,255 }; // 7 LEVELS\r
+ //unsigned char Intensity[NumIntensityLevels] = { 0,36,73,109,145,182,219,255 }; // 8 LEVELS\r
+ int DitherIntensity, DitherMatrixIntensity, Offset, DeviceIntensity;\r
+ unsigned char DitherValue;\r
+ \r
+ for (long y=0;y<head.biHeight;y++){\r
+ info.nProgress = (long)(100*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+\r
+ DeviceIntensity = BlindGetPixelIndex(x,y);\r
+ DitherIntensity = DeviceIntensity*dth_MaxDitherIntensityVal/dth_MaxIntensityVal;\r
+ DitherMatrixIntensity = DitherIntensity % dth_RowsXCols;\r
+ Offset = DitherIntensity / dth_RowsXCols;\r
+ if (DitherMatrix[y&dth_NumRowsLessOne][x&dth_NumColsLessOne] < DitherMatrixIntensity)\r
+ DitherValue = Intensity[1+Offset];\r
+ else\r
+ DitherValue = Intensity[0+Offset];\r
+\r
+ tmp.BlindSetPixelIndex(x,y,DitherValue);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 2:\r
+ {\r
+ //Burkes error diffusion (Thanks to Franco Gerevini)\r
+ int TotalCoeffSum = 32;\r
+ long error, nlevel, coeff=1;\r
+ BYTE level;\r
+\r
+ for (long y = 0; y < head.biHeight; y++) {\r
+ info.nProgress = (long)(100 * y / head.biHeight);\r
+ if (info.nEscape) \r
+ break;\r
+ for (long x = 0; x < head.biWidth; x++) {\r
+ level = BlindGetPixelIndex(x, y);\r
+ if (level > 128) {\r
+ tmp.SetPixelIndex(x, y, 1);\r
+ error = level - 255;\r
+ } else {\r
+ tmp.SetPixelIndex(x, y, 0);\r
+ error = level;\r
+ }\r
+\r
+ nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 1, y, level);\r
+ nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 2, y, level);\r
+ int i;\r
+ for (i = -2; i < 3; i++) {\r
+ switch (i) {\r
+ case -2:\r
+ coeff = 2;\r
+ break;\r
+ case -1:\r
+ coeff = 4;\r
+ break;\r
+ case 0:\r
+ coeff = 8; \r
+ break;\r
+ case 1:\r
+ coeff = 4; \r
+ break;\r
+ case 2:\r
+ coeff = 2; \r
+ break;\r
+ }\r
+ nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + i, y + 1, level);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 3:\r
+ {\r
+ //Stucki error diffusion (Thanks to Franco Gerevini)\r
+ int TotalCoeffSum = 42;\r
+ long error, nlevel, coeff=1;\r
+ BYTE level;\r
+\r
+ for (long y = 0; y < head.biHeight; y++) {\r
+ info.nProgress = (long)(100 * y / head.biHeight);\r
+ if (info.nEscape) \r
+ break;\r
+ for (long x = 0; x < head.biWidth; x++) {\r
+ level = BlindGetPixelIndex(x, y);\r
+ if (level > 128) {\r
+ tmp.SetPixelIndex(x, y, 1);\r
+ error = level - 255;\r
+ } else {\r
+ tmp.SetPixelIndex(x, y, 0);\r
+ error = level;\r
+ }\r
+\r
+ nlevel = GetPixelIndex(x + 1, y) + (error * 8) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 1, y, level);\r
+ nlevel = GetPixelIndex(x + 2, y) + (error * 4) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 2, y, level);\r
+ int i;\r
+ for (i = -2; i < 3; i++) {\r
+ switch (i) {\r
+ case -2:\r
+ coeff = 2;\r
+ break;\r
+ case -1:\r
+ coeff = 4;\r
+ break;\r
+ case 0:\r
+ coeff = 8; \r
+ break;\r
+ case 1:\r
+ coeff = 4; \r
+ break;\r
+ case 2:\r
+ coeff = 2; \r
+ break;\r
+ }\r
+ nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + i, y + 1, level);\r
+ }\r
+ for (i = -2; i < 3; i++) {\r
+ switch (i) {\r
+ case -2:\r
+ coeff = 1;\r
+ break;\r
+ case -1:\r
+ coeff = 2;\r
+ break;\r
+ case 0:\r
+ coeff = 4; \r
+ break;\r
+ case 1:\r
+ coeff = 2; \r
+ break;\r
+ case 2:\r
+ coeff = 1; \r
+ break;\r
+ }\r
+ nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + i, y + 2, level);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 4:\r
+ {\r
+ //Jarvis, Judice and Ninke error diffusion (Thanks to Franco Gerevini)\r
+ int TotalCoeffSum = 48;\r
+ long error, nlevel, coeff=1;\r
+ BYTE level;\r
+\r
+ for (long y = 0; y < head.biHeight; y++) {\r
+ info.nProgress = (long)(100 * y / head.biHeight);\r
+ if (info.nEscape) \r
+ break;\r
+ for (long x = 0; x < head.biWidth; x++) {\r
+ level = BlindGetPixelIndex(x, y);\r
+ if (level > 128) {\r
+ tmp.SetPixelIndex(x, y, 1);\r
+ error = level - 255;\r
+ } else {\r
+ tmp.SetPixelIndex(x, y, 0);\r
+ error = level;\r
+ }\r
+\r
+ nlevel = GetPixelIndex(x + 1, y) + (error * 7) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 1, y, level);\r
+ nlevel = GetPixelIndex(x + 2, y) + (error * 5) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 2, y, level);\r
+ int i;\r
+ for (i = -2; i < 3; i++) {\r
+ switch (i) {\r
+ case -2:\r
+ coeff = 3;\r
+ break;\r
+ case -1:\r
+ coeff = 5;\r
+ break;\r
+ case 0:\r
+ coeff = 7; \r
+ break;\r
+ case 1:\r
+ coeff = 5; \r
+ break;\r
+ case 2:\r
+ coeff = 3; \r
+ break;\r
+ }\r
+ nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + i, y + 1, level);\r
+ }\r
+ for (i = -2; i < 3; i++) {\r
+ switch (i) {\r
+ case -2:\r
+ coeff = 1;\r
+ break;\r
+ case -1:\r
+ coeff = 3;\r
+ break;\r
+ case 0:\r
+ coeff = 5; \r
+ break;\r
+ case 1:\r
+ coeff = 3; \r
+ break;\r
+ case 2:\r
+ coeff = 1; \r
+ break;\r
+ }\r
+ nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + i, y + 2, level);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 5:\r
+ {\r
+ //Sierra error diffusion (Thanks to Franco Gerevini)\r
+ int TotalCoeffSum = 32;\r
+ long error, nlevel, coeff=1;\r
+ BYTE level;\r
+\r
+ for (long y = 0; y < head.biHeight; y++) {\r
+ info.nProgress = (long)(100 * y / head.biHeight);\r
+ if (info.nEscape) \r
+ break;\r
+ for (long x = 0; x < head.biWidth; x++) {\r
+ level = BlindGetPixelIndex(x, y);\r
+ if (level > 128) {\r
+ tmp.SetPixelIndex(x, y, 1);\r
+ error = level - 255;\r
+ } else {\r
+ tmp.SetPixelIndex(x, y, 0);\r
+ error = level;\r
+ }\r
+\r
+ nlevel = GetPixelIndex(x + 1, y) + (error * 5) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 1, y, level);\r
+ nlevel = GetPixelIndex(x + 2, y) + (error * 3) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + 2, y, level);\r
+ int i;\r
+ for (i = -2; i < 3; i++) {\r
+ switch (i) {\r
+ case -2:\r
+ coeff = 2;\r
+ break;\r
+ case -1:\r
+ coeff = 4;\r
+ break;\r
+ case 0:\r
+ coeff = 5; \r
+ break;\r
+ case 1:\r
+ coeff = 4; \r
+ break;\r
+ case 2:\r
+ coeff = 2; \r
+ break;\r
+ }\r
+ nlevel = GetPixelIndex(x + i, y + 1) + (error * coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + i, y + 1, level);\r
+ }\r
+ for (i = -1; i < 2; i++) {\r
+ switch (i) {\r
+ case -1:\r
+ coeff = 2;\r
+ break;\r
+ case 0:\r
+ coeff = 3; \r
+ break;\r
+ case 1:\r
+ coeff = 2; \r
+ break;\r
+ }\r
+ nlevel = GetPixelIndex(x + i, y + 2) + (error * coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(x + i, y + 2, level);\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 6:\r
+ {\r
+ //Stevenson and Arce error diffusion (Thanks to Franco Gerevini)\r
+ int TotalCoeffSum = 200;\r
+ long error, nlevel;\r
+ BYTE level;\r
+\r
+ for (long y = 0; y < head.biHeight; y++) {\r
+ info.nProgress = (long)(100 * y / head.biHeight);\r
+ if (info.nEscape) \r
+ break;\r
+ for (long x = 0; x < head.biWidth; x++) {\r
+ level = BlindGetPixelIndex(x, y);\r
+ if (level > 128) {\r
+ tmp.SetPixelIndex(x, y, 1);\r
+ error = level - 255;\r
+ } else {\r
+ tmp.SetPixelIndex(x, y, 0);\r
+ error = level;\r
+ }\r
+\r
+ int tmp_index_x = x + 2;\r
+ int tmp_index_y = y;\r
+ int tmp_coeff = 32;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x - 3;\r
+ tmp_index_y = y + 1;\r
+ tmp_coeff = 12;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x - 1;\r
+ tmp_coeff = 26;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x + 1;\r
+ tmp_coeff = 30;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x + 3;\r
+ tmp_coeff = 16;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x - 2;\r
+ tmp_index_y = y + 2;\r
+ tmp_coeff = 12;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x;\r
+ tmp_coeff = 26;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x + 2;\r
+ tmp_coeff = 12;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x - 3;\r
+ tmp_index_y = y + 3;\r
+ tmp_coeff = 5;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x - 1;\r
+ tmp_coeff = 12;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x + 1;\r
+ tmp_coeff = 12;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+\r
+ tmp_index_x = x + 3;\r
+ tmp_coeff = 5;\r
+ nlevel = GetPixelIndex(tmp_index_x, tmp_index_y) + (error * tmp_coeff) / TotalCoeffSum;\r
+ level = (BYTE)min(255, max(0, (int)nlevel));\r
+ SetPixelIndex(tmp_index_x, tmp_index_y, level);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 7:\r
+ {\r
+ // Bayer ordered dither\r
+ int order = 4;\r
+ //create Bayer matrix\r
+ if (order>4) order = 4;\r
+ int size = (1 << (2*order));\r
+ BYTE* Bmatrix = (BYTE*) malloc(size * sizeof(BYTE));\r
+ for(int i = 0; i < size; i++) {\r
+ int n = order;\r
+ int x = i / n;\r
+ int y = i % n;\r
+ int dither = 0;\r
+ while (n-- > 0){\r
+ dither = (((dither<<1)|((x&1) ^ (y&1)))<<1) | (y&1);\r
+ x >>= 1;\r
+ y >>= 1;\r
+ }\r
+ Bmatrix[i] = (BYTE)(dither);\r
+ }\r
+\r
+ int scale = max(0,(8-2*order));\r
+ int level;\r
+ for (long y=0;y<head.biHeight;y++){\r
+ info.nProgress = (long)(100*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+ level = BlindGetPixelIndex(x,y) >> scale;\r
+ if(level > Bmatrix[ (x % order) + order * (y % order) ]){\r
+ tmp.SetPixelIndex(x,y,1);\r
+ } else {\r
+ tmp.SetPixelIndex(x,y,0);\r
+ }\r
+ }\r
+ }\r
+\r
+ free(Bmatrix);\r
+\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ // Floyd-Steinberg error diffusion (Thanks to Steve McMahon)\r
+ long error,nlevel,coeff=1;\r
+ BYTE level;\r
+\r
+ for (long y=0;y<head.biHeight;y++){\r
+ info.nProgress = (long)(100*y/head.biHeight);\r
+ if (info.nEscape) break;\r
+ for (long x=0;x<head.biWidth;x++){\r
+\r
+ level = BlindGetPixelIndex(x,y);\r
+ if (level > 128){\r
+ tmp.SetPixelIndex(x,y,1);\r
+ error = level-255;\r
+ } else {\r
+ tmp.SetPixelIndex(x,y,0);\r
+ error = level;\r
+ }\r
+\r
+ nlevel = GetPixelIndex(x+1,y) + (error * 7)/16;\r
+ level = (BYTE)min(255,max(0,(int)nlevel));\r
+ SetPixelIndex(x+1,y,level);\r
+ for(int i=-1; i<2; i++){\r
+ switch(i){\r
+ case -1:\r
+ coeff=3; break;\r
+ case 0:\r
+ coeff=5; break;\r
+ case 1:\r
+ coeff=1; break;\r
+ }\r
+ nlevel = GetPixelIndex(x+i,y+1) + (error * coeff)/16;\r
+ level = (BYTE)min(255,max(0,(int)nlevel));\r
+ SetPixelIndex(x+i,y+1,level);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ tmp.SetPaletteColor(0,0,0,0);\r
+ tmp.SetPaletteColor(1,255,255,255);\r
+ Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * CropRotatedRectangle\r
+ * \param topx,topy : topmost and leftmost point of the rectangle \r
+ (topmost, and if there are 2 topmost points, the left one)\r
+ * \param width : size of the right hand side of rect, from (topx,topy) roundwalking clockwise\r
+ * \param height : size of the left hand side of rect, from (topx,topy) roundwalking clockwise\r
+ * \param angle : angle of the right hand side of rect, from (topx,topy)\r
+ * \param iDst : pointer to destination image (if 0, this image is modified)\r
+ * \author [VATI]\r
+ */\r
+bool CxImage::CropRotatedRectangle( long topx, long topy, long width, long height, float angle, CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ \r
+ long startx,starty,endx,endy;\r
+ double cos_angle = cos(angle/*/57.295779513082320877*/);\r
+ double sin_angle = sin(angle/*/57.295779513082320877*/);\r
+\r
+ // if there is nothing special, call the original Crop():\r
+ if ( fabs(angle)<0.0002 )\r
+ return Crop( topx, topy, topx+width, topy+height, iDst);\r
+\r
+ startx = min(topx, topx - (long)(sin_angle*(double)height));\r
+ endx = topx + (long)(cos_angle*(double)width);\r
+ endy = topy + (long)(cos_angle*(double)height + sin_angle*(double)width);\r
+ // check: corners of the rectangle must be inside\r
+ if ( IsInside( startx, topy )==false ||\r
+ IsInside( endx, endy ) == false )\r
+ return false;\r
+\r
+ // first crop to bounding rectangle\r
+ CxImage tmp(*this, true, false, true);\r
+ // tmp.Copy(*this, true, false, true);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+ if (!tmp.Crop( startx, topy, endx, endy)){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+ \r
+ // the midpoint of the image now became the same as the midpoint of the rectangle\r
+ // rotate new image with minus angle amount\r
+ if ( false == tmp.Rotate( (float)(-angle*57.295779513082320877) ) ) // Rotate expects angle in degrees\r
+ return false;\r
+\r
+ // crop rotated image to the original selection rectangle\r
+ endx = (tmp.head.biWidth+width)/2;\r
+ startx = (tmp.head.biWidth-width)/2;\r
+ starty = (tmp.head.biHeight+height)/2;\r
+ endy = (tmp.head.biHeight-height)/2;\r
+ if ( false == tmp.Crop( startx, starty, endx, endy ) )\r
+ return false;\r
+\r
+ if (iDst) iDst->Transfer(tmp);\r
+ else Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::Crop(const RECT& rect, CxImage* iDst)\r
+{\r
+ return Crop(rect.left, rect.top, rect.right, rect.bottom, iDst);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::Crop(long left, long top, long right, long bottom, CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long startx = max(0L,min(left,head.biWidth));\r
+ long endx = max(0L,min(right,head.biWidth));\r
+ long starty = head.biHeight - max(0L,min(top,head.biHeight));\r
+ long endy = head.biHeight - max(0L,min(bottom,head.biHeight));\r
+\r
+ if (startx==endx || starty==endy) return false;\r
+\r
+ if (startx>endx) {long tmp=startx; startx=endx; endx=tmp;}\r
+ if (starty>endy) {long tmp=starty; starty=endy; endy=tmp;}\r
+\r
+ CxImage tmp(endx-startx,endy-starty,head.biBitCount,info.dwType);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ tmp.SetPalette(GetPalette(),head.biClrUsed);\r
+ tmp.info.nBkgndIndex = info.nBkgndIndex;\r
+ tmp.info.nBkgndColor = info.nBkgndColor;\r
+\r
+ switch (head.biBitCount) {\r
+ case 1:\r
+ case 4:\r
+ {\r
+ for(long y=starty, yd=0; y<endy; y++, yd++){\r
+ info.nProgress = (long)(100*(y-starty)/(endy-starty)); //<Anatoly Ivasyuk>\r
+ for(long x=startx, xd=0; x<endx; x++, xd++){\r
+ tmp.SetPixelIndex(xd,yd,GetPixelIndex(x,y));\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 8:\r
+ case 24:\r
+ {\r
+ int linelen = tmp.head.biWidth * tmp.head.biBitCount >> 3;\r
+ BYTE* pDest = tmp.info.pImage;\r
+ BYTE* pSrc = info.pImage + starty * info.dwEffWidth + (startx*head.biBitCount >> 3);\r
+ for(long y=starty; y<endy; y++){\r
+ info.nProgress = (long)(100*(y-starty)/(endy-starty)); //<Anatoly Ivasyuk>\r
+ memcpy(pDest,pSrc,linelen);\r
+ pDest+=tmp.info.dwEffWidth;\r
+ pSrc+=info.dwEffWidth;\r
+ }\r
+ }\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()){ //<oboolo>\r
+ tmp.AlphaCreate();\r
+ if (!tmp.AlphaIsValid()) return false;\r
+ BYTE* pDest = tmp.pAlpha;\r
+ BYTE* pSrc = pAlpha + startx + starty*head.biWidth;\r
+ for (long y=starty; y<endy; y++){\r
+ memcpy(pDest,pSrc,endx-startx);\r
+ pDest+=tmp.head.biWidth;\r
+ pSrc+=head.biWidth;\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(tmp);\r
+ else Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * \param xgain, ygain : can be from 0 to 1.\r
+ * \param xpivot, ypivot : is the center of the transformation.\r
+ * \param bEnableInterpolation : if true, enables bilinear interpolation.\r
+ * \return true if everything is ok \r
+ */\r
+bool CxImage::Skew(float xgain, float ygain, long xpivot, long ypivot, bool bEnableInterpolation)\r
+{\r
+ if (!pDib) return false;\r
+ float nx,ny;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ nx = x + (xgain*(y - ypivot));\r
+ ny = y + (ygain*(x - xpivot));\r
+#if CXIMAGE_SUPPORT_INTERPOLATION\r
+ if (bEnableInterpolation){\r
+ tmp.SetPixelColor(x,y,GetPixelColorInterpolated(nx, ny, CxImage::IM_BILINEAR, CxImage::OM_BACKGROUND),true);\r
+ } else\r
+#endif //CXIMAGE_SUPPORT_INTERPOLATION\r
+ {\r
+ if (head.biClrUsed==0){\r
+ tmp.SetPixelColor(x,y,GetPixelColor((long)nx,(long)ny));\r
+ } else {\r
+ tmp.SetPixelIndex(x,y,GetPixelIndex((long)nx,(long)ny));\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaSet(x,y,AlphaGet((long)nx,(long)ny));\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Expands the borders.\r
+ * \param left, top, right, bottom = additional dimensions, should be greater than 0.\r
+ * \param canvascolor = border color. canvascolor.rgbReserved will set the alpha channel (if any) in the border.\r
+ * \param iDst = pointer to destination image (if it's 0, this image is modified)\r
+ * \return true if everything is ok \r
+ * \author [Colin Urquhart]; changes [DP]\r
+ */\r
+bool CxImage::Expand(long left, long top, long right, long bottom, RGBQUAD canvascolor, CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ if ((left < 0) || (right < 0) || (bottom < 0) || (top < 0)) return false;\r
+\r
+ long newWidth = head.biWidth + left + right;\r
+ long newHeight = head.biHeight + top + bottom;\r
+\r
+ right = left + head.biWidth - 1;\r
+ top = bottom + head.biHeight - 1;\r
+ \r
+ CxImage tmp;\r
+ tmp.CopyInfo(*this);\r
+ if (!tmp.Create(newWidth, newHeight, head.biBitCount, info.dwType)){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ tmp.SetPalette(GetPalette(),head.biClrUsed);\r
+\r
+ switch (head.biBitCount) {\r
+ case 1:\r
+ case 4:\r
+ {\r
+ BYTE pixel = tmp.GetNearestIndex(canvascolor);\r
+ for(long y=0; y < newHeight; y++){\r
+ info.nProgress = (long)(100*y/newHeight);\r
+ for(long x=0; x < newWidth; x++){\r
+ if ((y < bottom) || (y > top) || (x < left) || (x > right)) {\r
+ tmp.SetPixelIndex(x,y, pixel);\r
+ } else {\r
+ tmp.SetPixelIndex(x,y,GetPixelIndex(x-left,y-bottom));\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case 8:\r
+ case 24:\r
+ {\r
+ if (head.biBitCount == 8) {\r
+ BYTE pixel = tmp.GetNearestIndex( canvascolor);\r
+ memset(tmp.info.pImage, pixel, + (tmp.info.dwEffWidth * newHeight));\r
+ } else {\r
+ for (long y = 0; y < newHeight; ++y) {\r
+ BYTE *pDest = tmp.info.pImage + (y * tmp.info.dwEffWidth);\r
+ for (long x = 0; x < newWidth; ++x) {\r
+ *pDest++ = canvascolor.rgbBlue;\r
+ *pDest++ = canvascolor.rgbGreen;\r
+ *pDest++ = canvascolor.rgbRed;\r
+ }\r
+ }\r
+ }\r
+\r
+ BYTE* pDest = tmp.info.pImage + (tmp.info.dwEffWidth * bottom) + (left*(head.biBitCount >> 3));\r
+ BYTE* pSrc = info.pImage;\r
+ for(long y=bottom; y <= top; y++){\r
+ info.nProgress = (long)(100*y/(1 + top - bottom));\r
+ memcpy(pDest,pSrc,(head.biBitCount >> 3) * (right - left + 1));\r
+ pDest+=tmp.info.dwEffWidth;\r
+ pSrc+=info.dwEffWidth;\r
+ }\r
+ }\r
+ }\r
+\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (SelectionIsValid()){\r
+ if (!tmp.SelectionCreate())\r
+ return false;\r
+ BYTE* pSrc = SelectionGetPointer();\r
+ BYTE* pDst = tmp.SelectionGetPointer(left,bottom);\r
+ for(long y=bottom; y <= top; y++){\r
+ memcpy(pDst,pSrc, (right - left + 1));\r
+ pSrc+=head.biWidth;\r
+ pDst+=tmp.head.biWidth;\r
+ }\r
+ tmp.info.rSelectionBox.left = info.rSelectionBox.left + left;\r
+ tmp.info.rSelectionBox.right = info.rSelectionBox.right + left;\r
+ tmp.info.rSelectionBox.top = info.rSelectionBox.top + bottom;\r
+ tmp.info.rSelectionBox.bottom = info.rSelectionBox.bottom + bottom;\r
+ }\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()){\r
+ if (!tmp.AlphaCreate())\r
+ return false;\r
+ tmp.AlphaSet(canvascolor.rgbReserved);\r
+ BYTE* pSrc = AlphaGetPointer();\r
+ BYTE* pDst = tmp.AlphaGetPointer(left,bottom);\r
+ for(long y=bottom; y <= top; y++){\r
+ memcpy(pDst,pSrc, (right - left + 1));\r
+ pSrc+=head.biWidth;\r
+ pDst+=tmp.head.biWidth;\r
+ }\r
+ }\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(tmp);\r
+ else Transfer(tmp);\r
+\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImage::Expand(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst)\r
+{\r
+ //thanks to <Colin Urquhart>\r
+\r
+ if (!pDib) return false;\r
+\r
+ if ((newx < head.biWidth) || (newy < head.biHeight)) return false;\r
+\r
+ int nAddLeft = (newx - head.biWidth) / 2;\r
+ int nAddTop = (newy - head.biHeight) / 2;\r
+\r
+ return Expand(nAddLeft, nAddTop, newx - (head.biWidth + nAddLeft), newy - (head.biHeight + nAddTop), canvascolor, iDst);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Resamples the image with the correct aspect ratio, and fills the borders.\r
+ * \param newx, newy = thumbnail size.\r
+ * \param canvascolor = border color.\r
+ * \param iDst = pointer to destination image (if it's 0, this image is modified).\r
+ * \return true if everything is ok.\r
+ * \author [Colin Urquhart]\r
+ */\r
+bool CxImage::Thumbnail(long newx, long newy, RGBQUAD canvascolor, CxImage* iDst)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ if ((newx <= 0) || (newy <= 0)) return false;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ // determine whether we need to shrink the image\r
+ if ((head.biWidth > newx) || (head.biHeight > newy)) {\r
+ float fScale;\r
+ float fAspect = (float) newx / (float) newy;\r
+ if (fAspect * head.biHeight > head.biWidth) {\r
+ fScale = (float) newy / head.biHeight;\r
+ } else {\r
+ fScale = (float) newx / head.biWidth;\r
+ }\r
+ tmp.Resample((long) (fScale * head.biWidth), (long) (fScale * head.biHeight), 0);\r
+ }\r
+\r
+ // expand the frame\r
+ tmp.Expand(newx, newy, canvascolor, iDst);\r
+\r
+ //select the destination\r
+ if (iDst) iDst->Transfer(tmp);\r
+ else Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Perform circle_based transformations.\r
+ * \param type - for different transformations\r
+ * - 0 for normal (proturberant) FishEye\r
+ * - 1 for reverse (concave) FishEye\r
+ * - 2 for Swirle \r
+ * - 3 for Cilinder mirror\r
+ * - 4 for bathroom\r
+ *\r
+ * \param rmax - effect radius. If 0, the whole image is processed\r
+ * \param Koeff - only for swirle\r
+ * \author Arkadiy Olovyannikov ark(at)msun(dot)ru\r
+ */\r
+bool CxImage::CircleTransform(int type,long rmax,float Koeff)\r
+{\r
+ if (!pDib) return false;\r
+\r
+ long nx,ny;\r
+ double angle,radius,rnew;\r
+\r
+ CxImage tmp(*this);\r
+ if (!tmp.IsValid()){\r
+ strcpy(info.szLastError,tmp.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ long xmin,xmax,ymin,ymax,xmid,ymid;\r
+ if (pSelection){\r
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
+ } else {\r
+ xmin = ymin = 0;\r
+ xmax = head.biWidth; ymax=head.biHeight;\r
+ }\r
+ \r
+ xmid = (long) (tmp.GetWidth()/2);\r
+ ymid = (long) (tmp.GetHeight()/2);\r
+\r
+ if (!rmax) rmax=(long)sqrt((float)((xmid-xmin)*(xmid-xmin)+(ymid-ymin)*(ymid-ymin)));\r
+ if (Koeff==0.0f) Koeff=1.0f;\r
+\r
+ for(long y=ymin; y<ymax; y++){\r
+ info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));\r
+ if (info.nEscape) break;\r
+ for(long x=xmin; x<xmax; x++){\r
+#if CXIMAGE_SUPPORT_SELECTION\r
+ if (BlindSelectionIsInside(x,y))\r
+#endif //CXIMAGE_SUPPORT_SELECTION\r
+ {\r
+ nx=xmid-x;\r
+ ny=ymid-y;\r
+ radius=sqrt((float)(nx*nx+ny*ny));\r
+ if (radius<rmax) {\r
+ angle=atan2((double)ny,(double)nx);\r
+ if (type==0) rnew=radius*radius/rmax;\r
+ else if (type==1) rnew=sqrt(radius*rmax);\r
+ else if (type==2) {rnew=radius;angle += radius / Koeff;}\r
+ else rnew = 1; // potentially uninitialized\r
+ if (type<3){\r
+ nx = xmid + (long)(rnew * cos(angle));\r
+ ny = ymid - (long)(rnew * sin(angle));\r
+ }\r
+ else if (type==3){\r
+ nx = (long)fabs((angle*xmax/6.2831852));\r
+ ny = (long)fabs((radius*ymax/rmax));\r
+ }\r
+ else {\r
+ nx=x+(x%32)-16;\r
+ ny=y;\r
+ }\r
+// nx=max(xmin,min(nx,xmax));\r
+// ny=max(ymin,min(ny,ymax));\r
+ }\r
+ else { nx=-1;ny=-1;}\r
+ if (head.biClrUsed==0){\r
+ tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));\r
+ } else {\r
+ tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));\r
+ }\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ tmp.AlphaSet(x,y,AlphaGet(nx,ny));\r
+#endif //CXIMAGE_SUPPORT_ALPHA\r
+ }\r
+ }\r
+ }\r
+ Transfer(tmp);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Faster way to almost properly shrink image. Algorithm produces results comparable with "high resoultion shrink"\r
+ * when resulting image is much smaller (that would be 3 times or more) than original. When\r
+ * resulting image is only slightly smaller, results are closer to nearest pixel.\r
+ * This algorithm works by averaging, but it does not calculate fractions of pixels. It adds whole\r
+ * source pixels to the best destionation. It is not geometrically "correct".\r
+ * It's main advantage over "high" resulution shrink is speed, so it's useful, when speed is most\r
+ * important (preview thumbnails, "map" view, ...).\r
+ * Method is optimized for RGB24 images.\r
+ * \r
+ * \param newx, newy - size of destination image (must be smaller than original!)\r
+ * \param iDst - pointer to destination image (if it's 0, this image is modified)\r
+ * \param bChangeBpp - flag points to change result image bpp (if it's true, this result image bpp = 24 (useful for B/W image thumbnails))\r
+ *\r
+ * \return true if everything is ok\r
+ * \author [bd], 9.2004; changes [Artiom Mirolubov], 1.2005\r
+ */\r
+bool CxImage::QIShrink(long newx, long newy, CxImage* const iDst, bool bChangeBpp)\r
+{\r
+ if (!pDib) return false;\r
+ \r
+ if (newx>head.biWidth || newy>head.biHeight) { \r
+ //let me repeat... this method can't enlarge image\r
+ strcpy(info.szLastError,"QIShrink can't enlarge image");\r
+ return false;\r
+ }\r
+\r
+ if (newx==head.biWidth && newy==head.biHeight) {\r
+ //image already correct size (just copy and return)\r
+ if (iDst) iDst->Copy(*this);\r
+ return true;\r
+ }//if\r
+ \r
+ //create temporary destination image\r
+ CxImage newImage;\r
+ newImage.CopyInfo(*this);\r
+ newImage.Create(newx,newy,(bChangeBpp)?24:head.biBitCount,GetType());\r
+ newImage.SetPalette(GetPalette());\r
+ if (!newImage.IsValid()){\r
+ strcpy(info.szLastError,newImage.GetLastError());\r
+ return false;\r
+ }\r
+\r
+ //and alpha channel if required\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (AlphaIsValid()) newImage.AlphaCreate();\r
+#endif\r
+\r
+ const int oldx = head.biWidth;\r
+ const int oldy = head.biHeight;\r
+\r
+ int accuCellSize = 4;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ BYTE *alphaPtr;\r
+ if (AlphaIsValid()) accuCellSize=5;\r
+#endif\r
+\r
+ unsigned int *accu = new unsigned int[newx*accuCellSize]; //array for suming pixels... one pixel for every destination column\r
+ unsigned int *accuPtr; //pointer for walking through accu\r
+ //each cell consists of blue, red, green component and count of pixels summed in this cell\r
+ memset(accu, 0, newx * accuCellSize * sizeof(unsigned int)); //clear accu\r
+\r
+ if (!IsIndexed()) {\r
+ //RGB24 version with pointers\r
+ BYTE *destPtr, *srcPtr, *destPtrS, *srcPtrS; //destination and source pixel, and beginnings of current row\r
+ srcPtrS=(BYTE*)BlindGetPixelPointer(0,0);\r
+ destPtrS=(BYTE*)newImage.BlindGetPixelPointer(0,0);\r
+ int ex=0, ey=0; //ex and ey replace division... \r
+ int dy=0;\r
+ //(we just add pixels, until by adding newx or newy we get a number greater than old size... then\r
+ // it's time to move to next pixel)\r
+ \r
+ for(int y=0; y<oldy; y++){ //for all source rows\r
+ info.nProgress = (long)(100*y/oldy); if (info.nEscape) break;\r
+ ey += newy; \r
+ ex = 0; //restart with ex = 0\r
+ accuPtr=accu; //restart from beginning of accu\r
+ srcPtr=srcPtrS; //and from new source line\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ alphaPtr = AlphaGetPointer(0, y);\r
+#endif\r
+\r
+ for(int x=0; x<oldx; x++){ //for all source columns\r
+ ex += newx;\r
+ *accuPtr += *(srcPtr++); //add current pixel to current accu slot\r
+ *(accuPtr+1) += *(srcPtr++);\r
+ *(accuPtr+2) += *(srcPtr++);\r
+ (*(accuPtr+3)) ++;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (alphaPtr) *(accuPtr+4) += *(alphaPtr++);\r
+#endif\r
+ if (ex>oldx) { //when we reach oldx, it's time to move to new slot\r
+ accuPtr += accuCellSize;\r
+ ex -= oldx; //(substract oldx from ex and resume from there on)\r
+ }//if (ex overflow)\r
+ }//for x\r
+\r
+ if (ey>=oldy) { //now when this happens\r
+ ey -= oldy; //it's time to move to new destination row\r
+ destPtr = destPtrS; //reset pointers to proper initial values\r
+ accuPtr = accu;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ alphaPtr = newImage.AlphaGetPointer(0, dy++);\r
+#endif\r
+ for (int k=0; k<newx; k++) { //copy accu to destination row (divided by number of pixels in each slot)\r
+ *(destPtr++) = (BYTE)(*(accuPtr) / *(accuPtr+3));\r
+ *(destPtr++) = (BYTE)(*(accuPtr+1) / *(accuPtr+3));\r
+ *(destPtr++) = (BYTE)(*(accuPtr+2) / *(accuPtr+3));\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (alphaPtr) *(alphaPtr++) = (BYTE)(*(accuPtr+4) / *(accuPtr+3));\r
+#endif\r
+ accuPtr += accuCellSize;\r
+ }//for k\r
+ memset(accu, 0, newx * accuCellSize * sizeof(unsigned int)); //clear accu\r
+ destPtrS += newImage.info.dwEffWidth;\r
+ }//if (ey overflow)\r
+\r
+ srcPtrS += info.dwEffWidth; //next round we start from new source row\r
+ }//for y\r
+ } else {\r
+ //standard version with GetPixelColor...\r
+ int ex=0, ey=0; //ex and ey replace division... \r
+ int dy=0;\r
+ //(we just add pixels, until by adding newx or newy we get a number greater than old size... then\r
+ // it's time to move to next pixel)\r
+ RGBQUAD rgb;\r
+ \r
+ for(int y=0; y<oldy; y++){ //for all source rows\r
+ info.nProgress = (long)(100*y/oldy); if (info.nEscape) break;\r
+ ey += newy; \r
+ ex = 0; //restart with ex = 0\r
+ accuPtr=accu; //restart from beginning of accu\r
+ for(int x=0; x<oldx; x++){ //for all source columns\r
+ ex += newx;\r
+ rgb = GetPixelColor(x, y, true);\r
+ *accuPtr += rgb.rgbBlue; //add current pixel to current accu slot\r
+ *(accuPtr+1) += rgb.rgbRed;\r
+ *(accuPtr+2) += rgb.rgbGreen;\r
+ (*(accuPtr+3)) ++;\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pAlpha) *(accuPtr+4) += rgb.rgbReserved;\r
+#endif\r
+ if (ex>oldx) { //when we reach oldx, it's time to move to new slot\r
+ accuPtr += accuCellSize;\r
+ ex -= oldx; //(substract oldx from ex and resume from there on)\r
+ }//if (ex overflow)\r
+ }//for x\r
+\r
+ if (ey>=oldy) { //now when this happens\r
+ ey -= oldy; //it's time to move to new destination row\r
+ accuPtr = accu;\r
+ for (int dx=0; dx<newx; dx++) { //copy accu to destination row (divided by number of pixels in each slot)\r
+ rgb.rgbBlue = (BYTE)(*(accuPtr) / *(accuPtr+3));\r
+ rgb.rgbRed = (BYTE)(*(accuPtr+1) / *(accuPtr+3));\r
+ rgb.rgbGreen= (BYTE)(*(accuPtr+2) / *(accuPtr+3));\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if (pAlpha) rgb.rgbReserved = (BYTE)(*(accuPtr+4) / *(accuPtr+3));\r
+#endif\r
+ newImage.SetPixelColor(dx, dy, rgb, pAlpha!=0);\r
+ accuPtr += accuCellSize;\r
+ }//for dx\r
+ memset(accu, 0, newx * accuCellSize * sizeof(unsigned int)); //clear accu\r
+ dy++;\r
+ }//if (ey overflow)\r
+ }//for y\r
+ }//if\r
+\r
+ delete [] accu; //delete helper array\r
+ \r
+ //copy new image to the destination\r
+ if (iDst) \r
+ iDst->Transfer(newImage);\r
+ else \r
+ Transfer(newImage);\r
+ return true;\r
+\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_TRANSFORMATION\r
--- /dev/null
+/*\r
+ * File: ximawbmp.cpp\r
+ * Purpose: Platform Independent WBMP Image Class Loader and Writer\r
+ * 12/Jul/2002 Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximawbmp.h"\r
+\r
+#if CXIMAGE_SUPPORT_WBMP\r
+\r
+#include "ximaiter.h"\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageWBMP::Decode(CxFile *hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ WBMPHEADER wbmpHead;\r
+\r
+ cx_try\r
+ {\r
+ ReadOctet(hFile, &wbmpHead.Type);\r
+\r
+ DWORD dat;\r
+ ReadOctet(hFile, &dat);\r
+ wbmpHead.FixHeader = (BYTE)dat;\r
+\r
+ ReadOctet(hFile, &wbmpHead.ImageWidth);\r
+ ReadOctet(hFile, &wbmpHead.ImageHeight);\r
+\r
+ if (hFile->Eof())\r
+ cx_throw("Not a WBMP");\r
+\r
+ if (wbmpHead.Type != 0)\r
+ cx_throw("Unsupported WBMP type"); \r
+\r
+ head.biWidth = wbmpHead.ImageWidth;\r
+ head.biHeight= wbmpHead.ImageHeight;\r
+\r
+ if (head.biWidth<=0 || head.biHeight<=0)\r
+ cx_throw("Corrupted WBMP");\r
+\r
+ if (info.nEscape == -1){\r
+ info.dwType = CXIMAGE_FORMAT_WBMP;\r
+ return true;\r
+ }\r
+\r
+ Create(head.biWidth, head.biHeight, 1, CXIMAGE_FORMAT_WBMP);\r
+ if (!IsValid()) cx_throw("WBMP Create failed");\r
+ SetGrayPalette();\r
+\r
+ int linewidth=(head.biWidth+7)/8;\r
+ CImageIterator iter(this);\r
+ iter.Upset();\r
+ for (long y=0; y < head.biHeight; y++){\r
+ hFile->Read(iter.GetRow(),linewidth,1);\r
+ iter.PrevRow();\r
+ }\r
+\r
+ } cx_catch {\r
+ if (strcmp(message,"")) strncpy(info.szLastError,message,255);\r
+ return FALSE;\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageWBMP::ReadOctet(CxFile * hFile, DWORD *data)\r
+{\r
+ BYTE c;\r
+ *data = 0;\r
+ do {\r
+ if (hFile->Eof()) return false;\r
+ c = (BYTE)hFile->GetC();\r
+ *data <<= 7;\r
+ *data |= (c & 0x7F);\r
+ } while ((c&0x80)!=0);\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageWBMP::Encode(CxFile * hFile)\r
+{\r
+ if (EncodeSafeCheck(hFile)) return false;\r
+\r
+ //check format limits\r
+ if (head.biBitCount!=1){\r
+ strcpy(info.szLastError,"Can't save this image as WBMP");\r
+ return false;\r
+ }\r
+\r
+ WBMPHEADER wbmpHead;\r
+ wbmpHead.Type=0;\r
+ wbmpHead.FixHeader=0;\r
+ wbmpHead.ImageWidth=head.biWidth;\r
+ wbmpHead.ImageHeight=head.biHeight;\r
+\r
+ // Write the file header\r
+ hFile->PutC('\0');\r
+ hFile->PutC('\0');\r
+ WriteOctet(hFile,wbmpHead.ImageWidth);\r
+ WriteOctet(hFile,wbmpHead.ImageHeight);\r
+ // Write the pixels\r
+ int linewidth=(wbmpHead.ImageWidth+7)/8;\r
+ CImageIterator iter(this);\r
+ iter.Upset();\r
+ for (DWORD y=0; y < wbmpHead.ImageHeight; y++){\r
+ hFile->Write(iter.GetRow(),linewidth,1);\r
+ iter.PrevRow();\r
+ }\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageWBMP::WriteOctet(CxFile * hFile, const DWORD data)\r
+{\r
+ int ns = 0;\r
+ while (data>>(ns+7)) ns+=7;\r
+ while (ns>0){\r
+ if (!hFile->PutC(0x80 | (BYTE)(data>>ns))) return false;\r
+ ns-=7;\r
+ }\r
+ if (!(hFile->PutC((BYTE)(0x7F & data)))) return false;\r
+ return true;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif // CXIMAGE_SUPPORT_WBMP\r
+\r
--- /dev/null
+/*\r
+ * File: ximawbmp.h\r
+ * Purpose: WBMP Image Class Loader and Writer\r
+ */\r
+/* ==========================================================\r
+ * CxImageWBMP (c) 12/Jul/2002 Davide Pizzolato - www.xdp.it\r
+ * For conditions of distribution and use, see copyright notice in ximage.h\r
+ * ==========================================================\r
+ */\r
+#if !defined(__ximaWBMP_h)\r
+#define __ximaWBMP_h\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_WBMP\r
+\r
+class CxImageWBMP: public CxImage\r
+{\r
+#pragma pack(1)\r
+typedef struct tagWbmpHeader\r
+{\r
+ DWORD Type; // 0\r
+ BYTE FixHeader; // 0\r
+ DWORD ImageWidth; // Image Width\r
+ DWORD ImageHeight; // Image Height\r
+} WBMPHEADER;\r
+#pragma pack()\r
+public:\r
+ CxImageWBMP(): CxImage(CXIMAGE_FORMAT_WBMP) {}\r
+\r
+// bool Load(const TCHAR * imageFileName){ return CxImage::Load(imageFileName,CXIMAGE_FORMAT_WBMP);}\r
+// bool Save(const TCHAR * imageFileName){ return CxImage::Save(imageFileName,CXIMAGE_FORMAT_WBMP);}\r
+ bool Decode(CxFile * hFile);\r
+ bool Decode(FILE *hFile) { CxIOFile file(hFile); return Decode(&file); }\r
+protected:\r
+ bool ReadOctet(CxFile * hFile, DWORD *data);\r
+\r
+public:\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+protected:\r
+ bool WriteOctet(CxFile * hFile, const DWORD data);\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+};\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*\r
+*********************************************************************\r
+ * File: ximawmf.cpp\r
+ * Purpose: Windows Metafile Class Loader and Writer\r
+ * Author: Volker Horch - vhorch@gmx.de\r
+ * created: 13-Jun-2002\r
+ *\r
+ * Note: If the code below works, i wrote it.\r
+ * If it doesn't work, i don't know who wrote it.\r
+*********************************************************************\r
+ */\r
+\r
+/*\r
+*********************************************************************\r
+ Note by Author:\r
+*********************************************************************\r
+\r
+ Metafile Formats:\r
+ =================\r
+\r
+ There are 2 kinds of Windows Metafiles:\r
+ - Standard Windows Metafile\r
+ - Placeable Windows Metafile\r
+\r
+ A StandardWindows Metafile looks like:\r
+ - Metafile Header (MEATAHEADER)\r
+ - Metafile Records \r
+\r
+ A Placeable Metafile looks like:\r
+ - Aldus Header (METAFILEHEADER)\r
+ - Metafile Header (METAHEADER)\r
+ - Metafile Records\r
+\r
+ The "Metafile Header" and the "Metafile Records" are the same\r
+ for both formats. However, the Standard Metafile does not contain any\r
+ information about the original dimensions or x/y ratio of the Metafile.\r
+\r
+ I decided, to allow only placeable Metafiles here. If you also want to\r
+ enable Standard Metafiles, you will have to guess the dimensions of\r
+ the image.\r
+\r
+*********************************************************************\r
+ Limitations: see ximawmf.h\r
+ you may configure some stuff there\r
+*********************************************************************\r
+*/\r
+\r
+#include "ximawmf.h"\r
+\r
+#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+bool CxImageWMF::Decode(CxFile *hFile, long nForceWidth, long nForceHeight)\r
+{\r
+ if (hFile == NULL) return false;\r
+\r
+ HENHMETAFILE hMeta;\r
+ HDC hDC;\r
+ int cx,cy;\r
+\r
+ //save the current position of the file\r
+ long pos = hFile->Tell();\r
+\r
+ // Read the Metafile and convert to an Enhanced Metafile\r
+ METAFILEHEADER mfh;\r
+ hMeta = ConvertWmfFiletoEmf(hFile, &mfh);\r
+ if (hMeta) { // ok, it's a WMF\r
+\r
+/////////////////////////////////////////////////////////////////////\r
+// We use the original WMF size information, because conversion to\r
+// EMF adjusts the Metafile to Full Screen or does not set rclBounds at all\r
+// ENHMETAHEADER emh;\r
+// UINT uRet;\r
+// uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile \r
+// sizeof(ENHMETAHEADER), // size of buffer, in bytes \r
+// &emh); // address of buffer to receive data \r
+// if (!uRet){\r
+// DeleteEnhMetaFile(hMeta);\r
+// return false;\r
+// }\r
+// // calculate size\r
+// cx = emh.rclBounds.right - emh.rclBounds.left;\r
+// cy = emh.rclBounds.bottom - emh.rclBounds.top;\r
+/////////////////////////////////////////////////////////////////////\r
+\r
+ // calculate size\r
+ // scale the metafile (pixels/inch of metafile => pixels/inch of display)\r
+ // mfh.inch already checked to be <> 0\r
+\r
+ hDC = ::GetDC(0);\r
+ int cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);\r
+ int cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);\r
+ ::ReleaseDC(0, hDC);\r
+\r
+ cx = (mfh.inch/2 + (mfh.bbox.right - mfh.bbox.left) * cx1) / mfh.inch;\r
+ cy = (mfh.inch/2 + (mfh.bbox.bottom - mfh.bbox.top) * cy1) / mfh.inch;\r
+\r
+ } else { // maybe it's an EMF...\r
+\r
+ hFile->Seek(pos,SEEK_SET);\r
+\r
+ ENHMETAHEADER emh;\r
+ hMeta = ConvertEmfFiletoEmf(hFile, &emh);\r
+\r
+ if (!hMeta){\r
+ strcpy(info.szLastError,"corrupted WMF");\r
+ return false; // definitively give up\r
+ }\r
+\r
+ // ok, it's an EMF; calculate canvas size\r
+ cx = emh.rclBounds.right - emh.rclBounds.left;\r
+ cy = emh.rclBounds.bottom - emh.rclBounds.top;\r
+\r
+ // alternative methods, sometime not so reliable... [DP]\r
+ //cx = emh.szlDevice.cx;\r
+ //cy = emh.szlDevice.cy;\r
+ //\r
+ //hDC = ::GetDC(0);\r
+ //float hscale = (float)GetDeviceCaps(hDC, HORZRES)/(100.0f * GetDeviceCaps(hDC, HORZSIZE));\r
+ //float vscale = (float)GetDeviceCaps(hDC, VERTRES)/(100.0f * GetDeviceCaps(hDC, VERTSIZE));\r
+ //::ReleaseDC(0, hDC);\r
+ //cx = (long)((emh.rclFrame.right - emh.rclFrame.left) * hscale);\r
+ //cy = (long)((emh.rclFrame.bottom - emh.rclFrame.top) * vscale);\r
+ }\r
+\r
+ if (info.nEscape == -1) { // Check if cancelled\r
+ head.biWidth = cx;\r
+ head.biHeight= cy;\r
+ info.dwType = CXIMAGE_FORMAT_WMF;\r
+ DeleteEnhMetaFile(hMeta);\r
+ strcpy(info.szLastError,"output dimensions returned");\r
+ return true;\r
+ }\r
+\r
+ if (!cx || !cy) {\r
+ DeleteEnhMetaFile(hMeta);\r
+ strcpy(info.szLastError,"empty WMF");\r
+ return false;\r
+ }\r
+\r
+ if (nForceWidth) cx=nForceWidth;\r
+ if (nForceHeight) cy=nForceHeight;\r
+ ShrinkMetafile(cx, cy); // !! Otherwise Bitmap may have bombastic size\r
+\r
+ HDC hDC0 = ::GetDC(0); // DC of screen\r
+ HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display\r
+ hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen\r
+ ::ReleaseDC(0, hDC0); // don't need anymore. get rid of it.\r
+\r
+ if (hDC){\r
+ if (hBitmap){\r
+ RECT rc = {0,0,cx,cy};\r
+ int bpp = ::GetDeviceCaps(hDC, BITSPIXEL);\r
+\r
+ HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);\r
+\r
+ // clear out the entire bitmap with windows background\r
+ // because the MetaFile may not contain background information\r
+ DWORD dwBack = XMF_COLOR_BACK;\r
+#if XMF_SUPPORT_TRANSPARENCY\r
+ if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT;\r
+#endif\r
+ DWORD OldColor = SetBkColor(hDC, dwBack);\r
+ ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);\r
+ SetBkColor(hDC, OldColor);\r
+\r
+ //retrieves optional palette entries from the specified enhanced metafile\r
+ PLOGPALETTE plogPal;\r
+ PBYTE pjTmp; \r
+ HPALETTE hPal; \r
+ int iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL);\r
+ if (iEntries) { \r
+ if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, \r
+ sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) { \r
+ DeleteObject(hBitmap);\r
+ DeleteDC(hDC);\r
+ DeleteEnhMetaFile(hMeta);\r
+ strcpy(info.szLastError,"Cancelled");\r
+ return false;\r
+ } \r
+\r
+ plogPal->palVersion = 0x300; \r
+ plogPal->palNumEntries = (WORD) iEntries; \r
+ pjTmp = (PBYTE) plogPal; \r
+ pjTmp += 4; \r
+\r
+ GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp); \r
+ hPal = CreatePalette(plogPal); \r
+ GlobalFree(plogPal); \r
+\r
+ SelectPalette(hDC, hPal, FALSE); \r
+ RealizePalette(hDC); \r
+ } \r
+ \r
+ // Play the Metafile into Memory DC\r
+ BOOL bRet = PlayEnhMetaFile(hDC, // handle to a device context \r
+ hMeta, // handle to an enhanced metafile \r
+ &rc); // pointer to bounding rectangle\r
+\r
+ SelectObject(hDC, hBitmapOld);\r
+ DeleteEnhMetaFile(hMeta); // we are done with this one\r
+\r
+ if (info.nEscape) { // Check if cancelled\r
+ DeleteObject(hBitmap);\r
+ DeleteDC(hDC);\r
+ strcpy(info.szLastError,"Cancelled");\r
+ return false;\r
+ }\r
+\r
+ // the Bitmap now has the image.\r
+ // Create our DIB and convert the DDB into DIB\r
+ if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) {\r
+ DeleteObject(hBitmap);\r
+ DeleteDC(hDC);\r
+ return false;\r
+ }\r
+\r
+#if XMF_SUPPORT_TRANSPARENCY\r
+ if (bpp == 24) {\r
+ RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT };\r
+ SetTransColor(rgbTrans);\r
+ }\r
+#endif\r
+ // We're finally ready to get the DIB. Call the driver and let\r
+ // it party on our bitmap. It will fill in the color table,\r
+ // and bitmap bits of our global memory block.\r
+ bRet = GetDIBits(hDC, hBitmap, 0,\r
+ (UINT)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS);\r
+\r
+ DeleteObject(hBitmap);\r
+ DeleteDC(hDC);\r
+\r
+ return (bRet!=0);\r
+ } else {\r
+ DeleteDC(hDC);\r
+ }\r
+ } else {\r
+ if (hBitmap) DeleteObject(hBitmap);\r
+ }\r
+\r
+ DeleteEnhMetaFile(hMeta);\r
+\r
+ return false;\r
+}\r
+\r
+/**********************************************************************\r
+ Function: CheckMetafileHeader\r
+ Purpose: Check if the Metafileheader of a file is valid\r
+**********************************************************************/\r
+BOOL CxImageWMF::CheckMetafileHeader(METAFILEHEADER *metafileheader)\r
+{\r
+ WORD *pw;\r
+ WORD cs;\r
+ int i;\r
+\r
+ // check magic #\r
+ if (metafileheader->key != 0x9ac6cdd7L) return false;\r
+\r
+ // test checksum of header\r
+ pw = (WORD *)metafileheader;\r
+ cs = *pw;\r
+ pw++;\r
+ for (i = 0; i < 9; i++) {\r
+ cs ^= *pw;\r
+ pw++;\r
+ }\r
+\r
+ if (cs != metafileheader->checksum) return false;\r
+\r
+ // check resolution\r
+ if ((metafileheader->inch <= 0) || (metafileheader->inch > 2540)) return false;\r
+\r
+ return true;\r
+}\r
+\r
+/**********************************************************************\r
+ Function: ConvertWmfFiletoEmf\r
+ Purpose: Converts a Windows Metafile into an Enhanced Metafile\r
+**********************************************************************/\r
+HENHMETAFILE CxImageWMF::ConvertWmfFiletoEmf(CxFile *fp, METAFILEHEADER *metafileheader)\r
+{\r
+ HENHMETAFILE hMeta;\r
+ long lenFile;\r
+ long len;\r
+ BYTE *p;\r
+ METAHEADER mfHeader;\r
+ DWORD seekpos;\r
+\r
+ hMeta = 0;\r
+\r
+ // get length of the file\r
+ lenFile = fp->Size();\r
+\r
+ // a placeable metafile starts with a METAFILEHEADER\r
+ // read it and check metafileheader\r
+ len = fp->Read(metafileheader, 1, sizeof(METAFILEHEADER));\r
+ if (len < sizeof(METAFILEHEADER)) return (hMeta);\r
+\r
+ if (CheckMetafileHeader(metafileheader)) {\r
+ // This is a placeable metafile \r
+ // Convert the placeable format into something that can\r
+ // be used with GDI metafile functions \r
+ seekpos = sizeof(METAFILEHEADER);\r
+ } else {\r
+ // Not a placeable wmf. A windows metafile?\r
+ // at least not scaleable.\r
+ // we could try to convert, but would loose ratio. don't allow this\r
+ return (hMeta);\r
+\r
+ //metafileheader->bbox.right = ?;\r
+ //metafileheader->bbox.left = ?;\r
+ //metafileheader->bbox.bottom = ?;\r
+ //metafileheader->bbox.top = ?;\r
+ //metafileheader->inch = ?;\r
+ //\r
+ //seekpos = 0;\r
+ // fp->Seek(0, SEEK_SET); // rewind\r
+ }\r
+\r
+ // At this point we have a metaheader regardless of whether\r
+ // the metafile was a windows metafile or a placeable metafile\r
+ // so check to see if it is valid. There is really no good\r
+ // way to do this so just make sure that the mtType is either\r
+ // 1 or 2 (memory or disk file) \r
+ // in addition we compare the length of the METAHEADER against\r
+ // the length of the file. if filelength < len => no Metafile\r
+\r
+ len = fp->Read(&mfHeader, 1, sizeof(METAHEADER));\r
+ if (len < sizeof(METAHEADER)) return (hMeta);\r
+\r
+ if ((mfHeader.mtType != 1) && (mfHeader.mtType != 2)) return (hMeta);\r
+\r
+ // Length in Bytes from METAHEADER\r
+ len = mfHeader.mtSize * 2;\r
+ if (len > lenFile) return (hMeta);\r
+\r
+ // Allocate memory for the metafile bits \r
+ p = (BYTE *)malloc(len);\r
+ if (!p) return (hMeta);\r
+\r
+ // seek back to METAHEADER and read all the stuff at once\r
+ fp->Seek(seekpos, SEEK_SET);\r
+ lenFile = fp->Read(p, 1, len);\r
+ if (lenFile != len) {\r
+ free(p);\r
+ return (hMeta);\r
+ }\r
+\r
+ // the following (commented code) works, but adjusts rclBound of the\r
+ // Enhanced Metafile to full screen.\r
+ // the METAFILEHEADER from above is needed to scale the image\r
+\r
+// hMeta = SetWinMetaFileBits(len, p, NULL, NULL);\r
+\r
+ // scale the metafile (pixels/inch of metafile => pixels/inch of display)\r
+\r
+ METAFILEPICT mfp;\r
+ int cx1, cy1;\r
+ HDC hDC;\r
+\r
+ hDC = ::GetDC(0);\r
+ cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);\r
+ cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);\r
+\r
+ memset(&mfp, 0, sizeof(mfp));\r
+\r
+ mfp.mm = MM_ANISOTROPIC;\r
+ mfp.xExt = 10000; //(metafileheader->bbox.right - metafileheader->bbox.left) * cx1 / metafileheader->inch;\r
+ mfp.yExt = 10000; //(metafileheader->bbox.bottom - metafileheader->bbox.top) * cy1 / metafileheader->inch;\r
+ mfp.hMF = 0;\r
+\r
+ // in MM_ANISOTROPIC mode xExt and yExt are in MM_HIENGLISH\r
+ // MM_HIENGLISH means: Each logical unit is converted to 0.001 inch\r
+ //mfp.xExt *= 1000;\r
+ //mfp.yExt *= 1000;\r
+ // ????\r
+ //int k = 332800 / ::GetSystemMetrics(SM_CXSCREEN);\r
+ //mfp.xExt *= k; mfp.yExt *= k;\r
+\r
+ // fix for Win9x\r
+ while ((mfp.xExt < 6554) && (mfp.yExt < 6554))\r
+ {\r
+ mfp.xExt *= 10;\r
+ mfp.yExt *= 10;\r
+ }\r
+\r
+ hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);\r
+\r
+ if (!hMeta){ //try 2nd conversion using a different mapping\r
+ mfp.mm = MM_TEXT;\r
+ hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);\r
+ }\r
+\r
+ ::ReleaseDC(0, hDC);\r
+\r
+ // Free Memory\r
+ free(p);\r
+\r
+ return (hMeta);\r
+}\r
+/////////////////////////////////////////////////////////////////////\r
+HENHMETAFILE CxImageWMF::ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh)\r
+{\r
+ HENHMETAFILE hMeta;\r
+ long iLen = pFile->Size();\r
+\r
+ // Check the header first: <km>\r
+ long pos = pFile->Tell();\r
+ long iLenRead = pFile->Read(pemfh, 1, sizeof(ENHMETAHEADER));\r
+ if (iLenRead < sizeof(ENHMETAHEADER)) return NULL;\r
+ if (pemfh->iType != EMR_HEADER) return NULL;\r
+ if (pemfh->dSignature != ENHMETA_SIGNATURE) return NULL;\r
+ //if (pemfh->nBytes != (DWORD)iLen) return NULL;\r
+ pFile->Seek(pos,SEEK_SET);\r
+\r
+ BYTE* pBuff = (BYTE *)malloc(iLen);\r
+ if (!pBuff) return (FALSE);\r
+\r
+ // Read the Enhanced Metafile\r
+ iLenRead = pFile->Read(pBuff, 1, iLen);\r
+ if (iLenRead != iLen) {\r
+ free(pBuff);\r
+ return NULL;\r
+ }\r
+\r
+ // Make it a Memory Metafile\r
+ hMeta = SetEnhMetaFileBits(iLen, pBuff);\r
+\r
+ free(pBuff); // finished with this one\r
+\r
+ if (!hMeta) return NULL; // oops.\r
+\r
+ // Get the Enhanced Metafile Header\r
+ UINT uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile \r
+ sizeof(ENHMETAHEADER), // size of buffer, in bytes \r
+ pemfh); // address of buffer to receive data \r
+ \r
+ if (!uRet) {\r
+ DeleteEnhMetaFile(hMeta);\r
+ return NULL;\r
+ }\r
+\r
+ return (hMeta);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_DECODE\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+/////////////////////////////////////////////////////////////////////\r
+bool CxImageWMF::Encode(CxFile * hFile)\r
+{\r
+ if (hFile == NULL) return false;\r
+ strcpy(info.szLastError, "Save WMF not supported");\r
+ return false;\r
+}\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+/////////////////////////////////////////////////////////////////////\r
+\r
+/**********************************************************************\r
+Function: ShrinkMetafile\r
+Purpose: Shrink the size of a metafile to be not larger than\r
+ the definition\r
+**********************************************************************/\r
+void CxImageWMF::ShrinkMetafile(int &cx, int &cy)\r
+{\r
+ int xScreen = XMF_MAXSIZE_CX;\r
+ int yScreen = XMF_MAXSIZE_CY;\r
+\r
+ if (cx > xScreen){\r
+ cy = cy * xScreen / cx;\r
+ cx = xScreen;\r
+ }\r
+\r
+ if (cy > yScreen){\r
+ cx = cx * yScreen / cy;\r
+ cy = yScreen;\r
+ }\r
+}\r
+\r
+#endif // CIMAGE_SUPPORT_WMF\r
+\r
--- /dev/null
+/*\r
+*********************************************************************\r
+ * File: ximawmf.h\r
+ * Purpose: Windows Metafile Class Loader and Writer\r
+ * Author: Volker Horch - vhorch@gmx.de\r
+ * created: 13-Jun-2002\r
+*********************************************************************\r
+ */\r
+\r
+/*\r
+*********************************************************************\r
+ Notes by Author:\r
+*********************************************************************\r
+\r
+ Limitations:\r
+ ============\r
+\r
+ a) Transparency:\r
+\r
+ A Metafile is vector graphics, which has transparency by design.\r
+ This class always converts into a Bitmap format. Transparency is\r
+ supported, but there is no good way to find out, which parts\r
+ of the Metafile are transparent. There are two ways how we can\r
+ handle this:\r
+\r
+ - Clear the Background of the Bitmap with the background color\r
+ you like (i have used COLOR_WINDOW) and don't support transparency.\r
+\r
+ below #define XMF_SUPPORT_TRANSPARENCY 0\r
+ #define XMF_COLOR_BACK RGB(Background color you like)\r
+\r
+ - Clear the Background of the Bitmap with a very unusual color\r
+ (which one ?) and use this color as the transparent color\r
+\r
+ below #define XMF_SUPPORT_TRANSPARENCY 1\r
+ #define XMF_COLOR_TRANSPARENT_R ...\r
+ #define XMF_COLOR_TRANSPARENT_G ...\r
+ #define XMF_COLOR_TRANSPARENT_B ...\r
+\r
+ b) Resolution\r
+\r
+ Once we have converted the Metafile into a Bitmap and we zoom in\r
+ or out, the image may not look very good. If we still had the\r
+ original Metafile, zooming would produce good results always.\r
+\r
+ c) Size\r
+\r
+ Although the filesize of a Metafile may be very small, it might\r
+ produce a Bitmap with a bombastic size. Assume you have a Metafile\r
+ with an image size of 6000*4000, which contains just one Metafile\r
+ record ((e.g. a line from (0,0) to (6000, 4000)). The filesize\r
+ of this Metafile would be let's say 100kB. If we convert it to\r
+ a 6000*4000 Bitmap with 24 Bits/Pixes, the Bitmap would consume\r
+ about 68MB of memory.\r
+\r
+ I have choosen, to limit the size of the Bitmap to max.\r
+ screensize, to avoid memory problems.\r
+\r
+ If you want something else,\r
+ modify #define XMF_MAXSIZE_CX / XMF_MAXSIZE_CY below\r
+\r
+*********************************************************************\r
+*/\r
+\r
+#ifndef _XIMAWMF_H\r
+#define _XIMAWMF_H\r
+\r
+#include "ximage.h"\r
+\r
+#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS\r
+\r
+class CxImageWMF: public CxImage\r
+{\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct tagRECT16\r
+{\r
+ short int left;\r
+ short int top;\r
+ short int right;\r
+ short int bottom;\r
+} RECT16;\r
+\r
+// taken from Windos 3.11 SDK Documentation (Programmer's Reference Volume 4: Resources)\r
+typedef struct tagMETAFILEHEADER\r
+{\r
+ DWORD key; // always 0x9ac6cdd7\r
+ WORD reserved1; // reserved = 0\r
+ RECT16 bbox; // bounding rectangle in metafile units as defined in "inch"\r
+ WORD inch; // number of metafile units per inch (should be < 1440)\r
+ DWORD reserved2; // reserved = 0\r
+ WORD checksum; // sum of the first 10 WORDS (using XOR operator)\r
+} METAFILEHEADER;\r
+\r
+#pragma pack()\r
+\r
+public:\r
+ CxImageWMF(): CxImage(CXIMAGE_FORMAT_WMF) { }\r
+\r
+ bool Decode(CxFile * hFile, long nForceWidth=0, long nForceHeight=0);\r
+ bool Decode(FILE *hFile, long nForceWidth=0, long nForceHeight=0)\r
+ { CxIOFile file(hFile); return Decode(&file,nForceWidth,nForceHeight); }\r
+\r
+#if CXIMAGE_SUPPORT_ENCODE\r
+ bool Encode(CxFile * hFile);\r
+ bool Encode(FILE *hFile) { CxIOFile file(hFile); return Encode(&file); }\r
+#endif // CXIMAGE_SUPPORT_ENCODE\r
+\r
+protected:\r
+ void ShrinkMetafile(int &cx, int &cy);\r
+ BOOL CheckMetafileHeader(METAFILEHEADER *pmetafileheader);\r
+ HENHMETAFILE ConvertWmfFiletoEmf(CxFile *pFile, METAFILEHEADER *pmetafileheader);\r
+ HENHMETAFILE ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh);\r
+\r
+};\r
+\r
+#define METAFILEKEY 0x9ac6cdd7L\r
+\r
+// Background color definition (if no transparency). see Notes above\r
+#define XMF_COLOR_BACK GetSysColor(COLOR_WINDOW)\r
+// alternatives\r
+//#define XMF_COLOR_BACK RGB(192, 192, 192) // lite gray\r
+//#define XMF_COLOR_BACK RGB( 0, 0, 0) // black\r
+//#define XMF_COLOR_BACK RGB(255, 255, 255) // white\r
+\r
+\r
+// transparency support. see Notes above\r
+#define XMF_SUPPORT_TRANSPARENCY 0\r
+#define XMF_COLOR_TRANSPARENT_R 211\r
+#define XMF_COLOR_TRANSPARENT_G 121\r
+#define XMF_COLOR_TRANSPARENT_B 112\r
+// don't change\r
+#define XMF_COLOR_TRANSPARENT RGB (XMF_COLOR_TRANSPARENT_R, \\r
+ XMF_COLOR_TRANSPARENT_G, \\r
+ XMF_COLOR_TRANSPARENT_B)\r
+// don't change\r
+#define XMF_RGBQUAD_TRANSPARENT XMF_COLOR_TRANSPARENT_B, \\r
+ XMF_COLOR_TRANSPARENT_G, \\r
+ XMF_COLOR_TRANSPARENT_R, \\r
+ 0\r
+// max. size. see Notes above\r
+// alternatives\r
+//#define XMF_MAXSIZE_CX (GetSystemMetrics(SM_CXSCREEN)-10)\r
+//#define XMF_MAXSIZE_CY (GetSystemMetrics(SM_CYSCREEN)-50)\r
+//#define XMF_MAXSIZE_CX (2*GetSystemMetrics(SM_CXSCREEN)/3)\r
+//#define XMF_MAXSIZE_CY (2*GetSystemMetrics(SM_CYSCREEN)/3)\r
+#define XMF_MAXSIZE_CX 4000\r
+#define XMF_MAXSIZE_CY 4000\r
+\r
+\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+// xImaWnd.cpp : Windows functions\r
+/* 07/08/2001 v1.00 - Davide Pizzolato - www.xdp.it\r
+ * CxImage version 6.0.0 02/Feb/2008\r
+ */\r
+\r
+#include "ximage.h"\r
+\r
+#include "ximaiter.h" \r
+#include "ximabmp.h"\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if defined (_WIN32_WCE)\r
+\r
+#ifndef DEFAULT_GUI_FONT\r
+#define DEFAULT_GUI_FONT 17\r
+#endif\r
+\r
+#ifndef PROOF_QUALITY\r
+#define PROOF_QUALITY 2\r
+#endif\r
+\r
+struct DIBINFO : public BITMAPINFO\r
+{\r
+ RGBQUAD arColors[255]; // Color table info - adds an extra 255 entries to palette\r
+ operator LPBITMAPINFO() { return (LPBITMAPINFO) this; }\r
+ operator LPBITMAPINFOHEADER() { return &bmiHeader; }\r
+ RGBQUAD* ColorTable() { return bmiColors; }\r
+};\r
+\r
+int BytesPerLine(int nWidth, int nBitsPerPixel)\r
+{\r
+ return ( (nWidth * nBitsPerPixel + 31) & (~31) ) / 8;\r
+}\r
+\r
+int NumColorEntries(int nBitsPerPixel, int nCompression, DWORD biClrUsed)\r
+{\r
+ int nColors = 0;\r
+ switch (nBitsPerPixel)\r
+ {\r
+ case 1:\r
+ nColors = 2; break;\r
+ case 2:\r
+ nColors = 4; break; // winCE only\r
+ case 4:\r
+ nColors = 16; break;\r
+ case 8:\r
+ nColors =256; break;\r
+ case 24:\r
+ nColors = 0; break;\r
+ case 16:\r
+ case 32:\r
+ nColors = 3; break; // I've found that PocketPCs need this regardless of BI_RGB or BI_BITFIELDS\r
+ default:\r
+ ASSERT(FALSE);\r
+ }\r
+ // If biClrUsed is provided, and it is a legal value, use it\r
+ if (biClrUsed > 0 && biClrUsed <= (DWORD)nColors)\r
+ return biClrUsed;\r
+ \r
+ return nColors;\r
+}\r
+\r
+int GetDIBits(\r
+ HDC hdc, // handle to DC\r
+ HBITMAP hbmp, // handle to bitmap\r
+ UINT uStartScan, // first scan line to set\r
+ UINT cScanLines, // number of scan lines to copy\r
+ LPVOID lpvBits, // array for bitmap bits\r
+ LPBITMAPINFO lpbi, // bitmap data buffer\r
+ UINT uUsage // RGB or palette index\r
+)\r
+{\r
+ UINT iColorTableSize = 0;\r
+\r
+ if (!hbmp)\r
+ return 0;\r
+\r
+ // Get dimensions of bitmap\r
+ BITMAP bm;\r
+ if (!::GetObject(hbmp, sizeof(bm),(LPVOID)&bm))\r
+ return 0;\r
+\r
+ //3. Creating new bitmap and receive pointer to it's bits.\r
+ HBITMAP hTargetBitmap;\r
+ void *pBuffer;\r
+ \r
+ //3.1 Initilize DIBINFO structure\r
+ DIBINFO dibInfo;\r
+ dibInfo.bmiHeader.biBitCount = 24;\r
+ dibInfo.bmiHeader.biClrImportant = 0;\r
+ dibInfo.bmiHeader.biClrUsed = 0;\r
+ dibInfo.bmiHeader.biCompression = 0;\r
+ dibInfo.bmiHeader.biHeight = bm.bmHeight;\r
+ dibInfo.bmiHeader.biPlanes = 1;\r
+ dibInfo.bmiHeader.biSize = 40;\r
+ dibInfo.bmiHeader.biSizeImage = bm.bmHeight*BytesPerLine(bm.bmWidth,24);\r
+ dibInfo.bmiHeader.biWidth = bm.bmWidth;\r
+ dibInfo.bmiHeader.biXPelsPerMeter = 3780;\r
+ dibInfo.bmiHeader.biYPelsPerMeter = 3780;\r
+ dibInfo.bmiColors[0].rgbBlue = 0;\r
+ dibInfo.bmiColors[0].rgbGreen = 0;\r
+ dibInfo.bmiColors[0].rgbRed = 0;\r
+ dibInfo.bmiColors[0].rgbReserved = 0;\r
+\r
+ //3.2 Create bitmap and receive pointer to points into pBuffer\r
+ HDC hDC = ::GetDC(NULL);\r
+ ASSERT(hDC);\r
+ hTargetBitmap = CreateDIBSection(\r
+ hDC,\r
+ (const BITMAPINFO*)dibInfo,\r
+ DIB_RGB_COLORS,\r
+ (void**)&pBuffer,\r
+ NULL,\r
+ 0);\r
+\r
+ ::ReleaseDC(NULL, hDC);\r
+\r
+ //4. Copy source bitmap into the target bitmap.\r
+\r
+ //4.1 Create 2 device contexts\r
+ HDC memDc = CreateCompatibleDC(NULL);\r
+ if (!memDc) {\r
+ ASSERT(FALSE);\r
+ }\r
+ \r
+ HDC targetDc = CreateCompatibleDC(NULL);\r
+ if (!targetDc) {\r
+ ASSERT(FALSE);\r
+ }\r
+\r
+ //4.2 Select source bitmap into one DC, target into another\r
+ HBITMAP hOldBitmap1 = (HBITMAP)::SelectObject(memDc, hbmp);\r
+ HBITMAP hOldBitmap2 = (HBITMAP)::SelectObject(targetDc, hTargetBitmap);\r
+\r
+ //4.3 Copy source bitmap into the target one\r
+ BitBlt(targetDc, 0, 0, bm.bmWidth, bm.bmHeight, memDc, 0, 0, SRCCOPY);\r
+\r
+ //4.4 Restore device contexts\r
+ ::SelectObject(memDc, hOldBitmap1);\r
+ ::SelectObject(targetDc, hOldBitmap2);\r
+ DeleteDC(memDc);\r
+ DeleteDC(targetDc);\r
+\r
+ //Here we can bitmap bits: pBuffer. Note:\r
+ // 1. pBuffer contains 3 bytes per point\r
+ // 2. Lines ane from the bottom to the top!\r
+ // 3. Points in the line are from the left to the right\r
+ // 4. Bytes in one point are BGR (blue, green, red) not RGB\r
+ // 5. Don't delete pBuffer, it will be automatically deleted\r
+ // when delete hTargetBitmap\r
+ lpvBits = pBuffer;\r
+\r
+ DeleteObject(hbmp);\r
+ //DeleteObject(hTargetBitmap);\r
+\r
+ return 1;\r
+}\r
+#endif \r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#if CXIMAGE_SUPPORT_WINDOWS\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::Blt(HDC pDC, long x, long y)\r
+{\r
+ if((pDib==0)||(pDC==0)||(!info.bEnabled)) return 0;\r
+\r
+ HBRUSH brImage = CreateDIBPatternBrushPt(pDib, DIB_RGB_COLORS);\r
+ POINT pt;\r
+ SetBrushOrgEx(pDC,x,y,&pt); //<RT>\r
+ HBRUSH brOld = (HBRUSH) SelectObject(pDC, brImage);\r
+ PatBlt(pDC, x, y, head.biWidth, head.biHeight, PATCOPY);\r
+ SelectObject(pDC, brOld);\r
+ SetBrushOrgEx(pDC,pt.x,pt.y,NULL);\r
+ DeleteObject(brImage);\r
+ return 1;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Transfer the image in a global bitmap handle (clipboard copy)\r
+ */\r
+HANDLE CxImage::CopyToHandle()\r
+{\r
+ HANDLE hMem=NULL;\r
+ if (pDib){\r
+ hMem= GlobalAlloc(GHND, GetSize());\r
+ if (hMem){\r
+ BYTE* pDst=(BYTE*)GlobalLock(hMem);\r
+ if (pDst){\r
+ memcpy(pDst,pDib,GetSize());\r
+ }\r
+ GlobalUnlock(hMem);\r
+ }\r
+ }\r
+ return hMem;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Global object (clipboard paste) constructor\r
+ * \param hMem: source bitmap object, the clipboard format must be CF_DIB\r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::CreateFromHANDLE(HANDLE hMem)\r
+{\r
+ if (!Destroy())\r
+ return false;\r
+\r
+ DWORD dwSize = GlobalSize(hMem);\r
+ if (!dwSize) return false;\r
+\r
+ BYTE *lpVoid; //pointer to the bitmap\r
+ lpVoid = (BYTE *)GlobalLock(hMem);\r
+ BITMAPINFOHEADER *pHead; //pointer to the bitmap header\r
+ pHead = (BITMAPINFOHEADER *)lpVoid;\r
+ if (lpVoid){\r
+\r
+ //CxMemFile hFile(lpVoid,dwSize);\r
+\r
+ //copy the bitmap header\r
+ memcpy(&head,pHead,sizeof(BITMAPINFOHEADER));\r
+ //check if it's a top-down bitmap\r
+ bool bTopDownDib = head.biHeight<0;\r
+ if (bTopDownDib) head.biHeight=-head.biHeight;\r
+ //create the image\r
+ if(!Create(head.biWidth,head.biHeight,head.biBitCount)){\r
+ GlobalUnlock(lpVoid);\r
+ return false;\r
+ }\r
+ //preserve DPI\r
+ SetXDPI((long)floor(head.biXPelsPerMeter * 254.0 / 10000.0 + 0.5));\r
+ SetYDPI((long)floor(head.biYPelsPerMeter * 254.0 / 10000.0 + 0.5));\r
+\r
+ /*//copy the pixels (old way)\r
+ if((pHead->biCompression != BI_RGB) || (pHead->biBitCount == 32)){ //<Jรถrgen Alfredsson>\r
+ // BITFIELD case\r
+ // set the internal header in the dib\r
+ memcpy(pDib,&head,sizeof(head));\r
+ // get the bitfield masks\r
+ DWORD bf[3];\r
+ memcpy(bf,lpVoid+pHead->biSize,12);\r
+ // transform into RGB\r
+ Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount);\r
+ } else { //normal bitmap\r
+ memcpy(pDib,lpVoid,GetSize());\r
+ }*/\r
+\r
+ // <Michael Gandyra>\r
+ // fill in color map\r
+ bool bIsOldBmp = (head.biSize == sizeof(BITMAPCOREHEADER));\r
+ RGBQUAD *pRgb = GetPalette();\r
+ if (pRgb) {\r
+ // number of colors to fill in\r
+ int nColors = DibNumColors(pHead);\r
+ if (bIsOldBmp) {\r
+ /* get pointer to BITMAPCOREINFO (old style 1.x) */\r
+ LPBITMAPCOREINFO lpbmc = (LPBITMAPCOREINFO)lpVoid;\r
+ for (int i = nColors - 1; i >= 0; i--) {\r
+ pRgb[i].rgbRed = lpbmc->bmciColors[i].rgbtRed;\r
+ pRgb[i].rgbGreen = lpbmc->bmciColors[i].rgbtGreen;\r
+ pRgb[i].rgbBlue = lpbmc->bmciColors[i].rgbtBlue;\r
+ pRgb[i].rgbReserved = (BYTE)0;\r
+ }\r
+ } else {\r
+ /* get pointer to BITMAPINFO (new style 3.x) */\r
+ LPBITMAPINFO lpbmi = (LPBITMAPINFO)lpVoid;\r
+ for (int i = nColors - 1; i >= 0; i--) {\r
+ pRgb[i].rgbRed = lpbmi->bmiColors[i].rgbRed;\r
+ pRgb[i].rgbGreen = lpbmi->bmiColors[i].rgbGreen;\r
+ pRgb[i].rgbBlue = lpbmi->bmiColors[i].rgbBlue;\r
+ pRgb[i].rgbReserved = (BYTE)0;\r
+ }\r
+ }\r
+ }\r
+\r
+ // <Michael Gandyra>\r
+ DWORD dwCompression = pHead->biCompression;\r
+ // compressed bitmap ?\r
+ if(dwCompression!=BI_RGB || pHead->biBitCount==32 || pHead->biBitCount ==16) {\r
+ // get the bitmap bits\r
+ LPSTR lpDIBBits = (LPSTR)((BYTE*)pHead + *(DWORD*)pHead + (WORD)(GetNumColors() * sizeof(RGBQUAD)));\r
+ // decode and copy them to our image\r
+ switch (pHead->biBitCount) {\r
+ case 32 :\r
+ {\r
+ // BITFIELD case\r
+ if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB) {\r
+ // get the bitfield masks\r
+ DWORD bf[3];\r
+ memcpy(bf,lpVoid+pHead->biSize,12);\r
+ // transform into RGB\r
+ Bitfield2RGB(lpVoid+pHead->biSize+12,bf[0],bf[1],bf[2],(BYTE)pHead->biBitCount);\r
+ } else {\r
+ // "unknown compression";\r
+ GlobalUnlock(lpVoid);\r
+ return false;\r
+ }\r
+ }\r
+ break;\r
+ case 16 :\r
+ {\r
+ // get the bitfield masks\r
+ long offset=0;\r
+ DWORD bf[3];\r
+ if (dwCompression == BI_BITFIELDS) {\r
+ memcpy(bf,lpVoid+pHead->biSize,12);\r
+ offset= 12;\r
+ } else {\r
+ bf[0] = 0x7C00;\r
+ bf[1] = 0x3E0;\r
+ bf[2] = 0x1F; // RGB555\r
+ }\r
+ // copy the pixels\r
+ memcpy(info.pImage, lpDIBBits + offset, head.biHeight*((head.biWidth+1)/2)*4);\r
+ // transform into RGB\r
+ Bitfield2RGB(info.pImage, bf[0], bf[1], bf[2], 16);\r
+ }\r
+ break;\r
+ case 8 :\r
+ case 4 :\r
+ case 1 :\r
+ {\r
+ switch (dwCompression) {\r
+ case BI_RLE4:\r
+ {\r
+ BYTE status_byte = 0;\r
+ BYTE second_byte = 0;\r
+ int scanline = 0;\r
+ int bits = 0;\r
+ BOOL low_nibble = FALSE;\r
+ CImageIterator iter(this);\r
+\r
+ for (BOOL bContinue = TRUE; bContinue; ) {\r
+ status_byte = *(lpDIBBits++);\r
+ switch (status_byte) {\r
+ case RLE_COMMAND :\r
+ status_byte = *(lpDIBBits++);\r
+ switch (status_byte) {\r
+ case RLE_ENDOFLINE :\r
+ bits = 0;\r
+ scanline++;\r
+ low_nibble = FALSE;\r
+ break;\r
+ case RLE_ENDOFBITMAP :\r
+ bContinue = FALSE;\r
+ break;\r
+ case RLE_DELTA :\r
+ {\r
+ // read the delta values\r
+ BYTE delta_x;\r
+ BYTE delta_y;\r
+ delta_x = *(lpDIBBits++);\r
+ delta_y = *(lpDIBBits++);\r
+ // apply them\r
+ bits += delta_x / 2;\r
+ scanline += delta_y;\r
+ break;\r
+ }\r
+ default :\r
+ second_byte = *(lpDIBBits++);\r
+ BYTE* sline = iter.GetRow(scanline);\r
+ for (int i = 0; i < status_byte; i++) {\r
+ if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){\r
+ if (low_nibble) {\r
+ if (i&1)\r
+ *(sline + bits) |= (second_byte & 0x0f);\r
+ else\r
+ *(sline + bits) |= (second_byte & 0xf0)>>4;\r
+ bits++;\r
+ } else {\r
+ if (i&1)\r
+ *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;\r
+ else\r
+ *(sline + bits) = (BYTE)(second_byte & 0xf0);\r
+ }\r
+ }\r
+\r
+ if ((i & 1) && (i != (status_byte - 1)))\r
+ second_byte = *(lpDIBBits++);\r
+\r
+ low_nibble = !low_nibble;\r
+ }\r
+ if ((((status_byte+1) >> 1) & 1 ) == 1)\r
+ second_byte = *(lpDIBBits++); \r
+ break;\r
+ };\r
+ break;\r
+ default :\r
+ {\r
+ BYTE* sline = iter.GetRow(scanline);\r
+ second_byte = *(lpDIBBits++);\r
+ for (unsigned i = 0; i < status_byte; i++) {\r
+ if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){\r
+ if (low_nibble) {\r
+ if (i&1)\r
+ *(sline + bits) |= (second_byte & 0x0f);\r
+ else\r
+ *(sline + bits) |= (second_byte & 0xf0)>>4;\r
+ bits++;\r
+ } else {\r
+ if (i&1)\r
+ *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;\r
+ else\r
+ *(sline + bits) = (BYTE)(second_byte & 0xf0);\r
+ }\r
+ }\r
+ low_nibble = !low_nibble;\r
+ }\r
+ }\r
+ break;\r
+ };\r
+ }\r
+ }\r
+ break;\r
+ case BI_RLE8 :\r
+ {\r
+ BYTE status_byte = 0;\r
+ BYTE second_byte = 0;\r
+ int scanline = 0;\r
+ int bits = 0;\r
+ CImageIterator iter(this);\r
+\r
+ for (BOOL bContinue = TRUE; bContinue; ) {\r
+ status_byte = *(lpDIBBits++);\r
+ if (status_byte==RLE_COMMAND) {\r
+ status_byte = *(lpDIBBits++);\r
+ switch (status_byte) {\r
+ case RLE_ENDOFLINE :\r
+ bits = 0;\r
+ scanline++;\r
+ break;\r
+ case RLE_ENDOFBITMAP :\r
+ bContinue = FALSE;\r
+ break;\r
+ case RLE_DELTA :\r
+ {\r
+ // read the delta values\r
+ BYTE delta_x;\r
+ BYTE delta_y;\r
+ delta_x = *(lpDIBBits++);\r
+ delta_y = *(lpDIBBits++);\r
+ // apply them\r
+ bits += delta_x;\r
+ scanline += delta_y;\r
+ }\r
+ break;\r
+ default :\r
+ int nNumBytes = sizeof(BYTE) * status_byte;\r
+ memcpy((void *)(iter.GetRow(scanline) + bits), lpDIBBits, nNumBytes);\r
+ lpDIBBits += nNumBytes;\r
+ // align run length to even number of bytes \r
+ if ((status_byte & 1) == 1)\r
+ second_byte = *(lpDIBBits++);\r
+ bits += status_byte;\r
+ break;\r
+ };\r
+ } else {\r
+ BYTE *sline = iter.GetRow(scanline);\r
+ second_byte = *(lpDIBBits++);\r
+ for (unsigned i = 0; i < status_byte; i++) {\r
+ if ((DWORD)bits<info.dwEffWidth){\r
+ *(sline + bits) = second_byte;\r
+ bits++;\r
+ } else {\r
+ bContinue = FALSE; //don't delete: we are in memory, it is not as with files\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ break;\r
+ default :\r
+ {\r
+ // "compression type not supported";\r
+ GlobalUnlock(lpVoid);\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ //normal bitmap (not compressed)\r
+ memcpy(pDib,lpVoid,GetSize());\r
+ }\r
+\r
+ GlobalUnlock(lpVoid);\r
+\r
+ if (bTopDownDib) Flip();\r
+\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Transfer the image in a bitmap handle\r
+ * \param hdc: target device context (the screen, usually)\r
+ * \return bitmap handle, or NULL if an error occurs.\r
+ */\r
+HBITMAP CxImage::MakeBitmap(HDC hdc)\r
+{\r
+ if (!pDib)\r
+ return NULL;\r
+\r
+ if (!hdc){\r
+ // this call to CreateBitmap doesn't create a DIB <jaslet>\r
+ // // Create a device-independent bitmap <CSC>\r
+ // return CreateBitmap(head.biWidth,head.biHeight, 1, head.biBitCount, GetBits());\r
+ // use instead this code\r
+ HDC hMemDC = CreateCompatibleDC(NULL);\r
+ LPVOID pBit32;\r
+ HBITMAP bmp = CreateDIBSection(hMemDC,(LPBITMAPINFO)pDib,DIB_RGB_COLORS, &pBit32, NULL, 0);\r
+ if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage);\r
+ DeleteDC(hMemDC);\r
+ return bmp;\r
+ }\r
+\r
+ // this single line seems to work very well\r
+ //HBITMAP bmp = CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)pDib, CBM_INIT,\r
+ // GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS);\r
+ // this alternative works also with _WIN32_WCE\r
+ LPVOID pBit32;\r
+ HBITMAP bmp = CreateDIBSection(hdc, (LPBITMAPINFO)pDib, DIB_RGB_COLORS, &pBit32, NULL, 0);\r
+ if (pBit32) memcpy(pBit32, GetBits(), head.biSizeImage);\r
+\r
+ return bmp;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Bitmap resource constructor\r
+ * \param hbmp : bitmap resource handle\r
+ * \param hpal : (optional) palette, useful for 8bpp DC \r
+ * \return true if everything is ok\r
+ */\r
+bool CxImage::CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal)\r
+{\r
+ if (!Destroy())\r
+ return false;\r
+\r
+ if (hbmp) { \r
+ BITMAP bm;\r
+ // get informations about the bitmap\r
+ GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm);\r
+ // create the image\r
+ if (!Create(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0))\r
+ return false;\r
+ // create a device context for the bitmap\r
+ HDC dc = ::GetDC(NULL);\r
+ if (!dc)\r
+ return false;\r
+\r
+ if (hpal){\r
+ SelectObject(dc,hpal); //the palette you should get from the user or have a stock one\r
+ RealizePalette(dc);\r
+ }\r
+\r
+ // copy the pixels\r
+ if (GetDIBits(dc, hbmp, 0, head.biHeight, info.pImage,\r
+ (LPBITMAPINFO)pDib, DIB_RGB_COLORS) == 0){ //replace &head with pDib <Wil Stark>\r
+ strcpy(info.szLastError,"GetDIBits failed");\r
+ ::ReleaseDC(NULL, dc);\r
+ return false;\r
+ }\r
+ ::ReleaseDC(NULL, dc);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * icon resource constructor\r
+ * \param hico : icon resource handle\r
+ * \return true if everything is ok\r
+ * \author []; changes [Arlen Albert Keshabian]\r
+ */\r
+#if !defined (_WIN32_WCE)\r
+bool CxImage::CreateFromHICON(HICON hico)\r
+{\r
+ if (!Destroy() || !hico)\r
+ return false;\r
+\r
+ bool l_bResult = true;\r
+\r
+ ICONINFO iinfo;\r
+ GetIconInfo(hico,&iinfo);\r
+\r
+ BITMAP l_Bitmap;\r
+ GetObject(iinfo.hbmColor, sizeof(BITMAP), &l_Bitmap);\r
+\r
+ if(l_Bitmap.bmBitsPixel == 32)\r
+ {\r
+ BITMAPINFO l_BitmapInfo;\r
+ l_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
+ l_BitmapInfo.bmiHeader.biWidth = l_Bitmap.bmWidth;\r
+ l_BitmapInfo.bmiHeader.biHeight = l_Bitmap.bmHeight;\r
+ l_BitmapInfo.bmiHeader.biPlanes = l_Bitmap.bmPlanes;\r
+ l_BitmapInfo.bmiHeader.biBitCount = l_Bitmap.bmBitsPixel;\r
+ l_BitmapInfo.bmiHeader.biCompression = BI_RGB;\r
+\r
+ RGBQUAD *l_pRawBytes = new RGBQUAD[l_Bitmap.bmWidth * l_Bitmap.bmHeight];\r
+\r
+ HDC dc = ::GetDC(NULL);\r
+\r
+ if(dc)\r
+ {\r
+ if(GetDIBits(dc, iinfo.hbmColor, 0, l_Bitmap.bmHeight, l_pRawBytes, &l_BitmapInfo, DIB_RGB_COLORS))\r
+ l_bResult = CreateFromArray((BYTE*)l_pRawBytes, l_Bitmap.bmWidth, l_Bitmap.bmHeight, l_Bitmap.bmBitsPixel, l_Bitmap.bmWidthBytes, false);\r
+ else\r
+ l_bResult = false;\r
+\r
+ ::ReleaseDC(NULL, dc);\r
+ }\r
+ else\r
+ l_bResult = false;\r
+\r
+ delete [] l_pRawBytes;\r
+ }\r
+ else\r
+ {\r
+ l_bResult = CreateFromHBITMAP(iinfo.hbmColor);\r
+#if CXIMAGE_SUPPORT_ALPHA\r
+ if(l_bResult)\r
+ {\r
+ CxImage mask;\r
+ mask.CreateFromHBITMAP(iinfo.hbmMask);\r
+ mask.GrayScale();\r
+ mask.Negative();\r
+ AlphaSet(mask);\r
+ }\r
+#endif\r
+ }\r
+\r
+ DeleteObject(iinfo.hbmColor); //<Sims>\r
+ DeleteObject(iinfo.hbmMask); //<Sims>\r
+ \r
+ return l_bResult;\r
+}\r
+#endif //_WIN32_WCE\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::Draw(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth)\r
+{\r
+ return Draw(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Draws the image in the specified device context, with support for alpha channel, alpha palette, transparency, opacity.\r
+ * \param hdc : destination device context\r
+ * \param x,y : (optional) offset\r
+ * \param cx,cy : (optional) size.\r
+ * - If cx or cy are not specified (or less than 0), the normal width or height will be used\r
+ * - If cx or cy are different than width or height, the image will be stretched\r
+ *\r
+ * \param pClipRect : limit the drawing operations inside a given rectangle in the output device context.\r
+ * \param bSmooth : activates a bilinear filter that will enhance the appearence for zommed pictures.\r
+ * Quite slow. Needs CXIMAGE_SUPPORT_INTERPOLATION.\r
+ * \return true if everything is ok\r
+ */\r
+long CxImage::Draw(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth)\r
+{\r
+ if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0;\r
+\r
+ if (cx < 0) cx = head.biWidth;\r
+ if (cy < 0) cy = head.biHeight;\r
+ bool bTransparent = info.nBkgndIndex >= 0;\r
+ bool bAlpha = pAlpha != 0;\r
+\r
+ //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield]\r
+ int hdc_Restore = ::SaveDC(hdc);\r
+ if (!hdc_Restore) \r
+ return 0;\r
+\r
+#if !defined (_WIN32_WCE)\r
+ RECT mainbox; // (experimental) \r
+ if (pClipRect){\r
+ GetClipBox(hdc,&mainbox);\r
+ HRGN rgn = CreateRectRgnIndirect(pClipRect);\r
+ ExtSelectClipRgn(hdc,rgn,RGN_AND);\r
+ DeleteObject(rgn);\r
+ }\r
+#endif\r
+\r
+ //find the smallest area to paint\r
+ RECT clipbox,paintbox;\r
+ GetClipBox(hdc,&clipbox);\r
+\r
+ paintbox.top = min(clipbox.bottom,max(clipbox.top,y));\r
+ paintbox.left = min(clipbox.right,max(clipbox.left,x));\r
+ paintbox.right = max(clipbox.left,min(clipbox.right,x+cx));\r
+ paintbox.bottom = max(clipbox.top,min(clipbox.bottom,y+cy));\r
+\r
+ long destw = paintbox.right - paintbox.left;\r
+ long desth = paintbox.bottom - paintbox.top;\r
+\r
+ if (!(bTransparent || bAlpha || info.bAlphaPaletteEnabled)){\r
+ if (cx==head.biWidth && cy==head.biHeight){ //NORMAL\r
+#if !defined (_WIN32_WCE)\r
+ SetStretchBltMode(hdc,COLORONCOLOR);\r
+#endif\r
+ SetDIBitsToDevice(hdc, x, y, cx, cy, 0, 0, 0, cy,\r
+ info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS);\r
+ } else { //STRETCH\r
+ //pixel informations\r
+ RGBQUAD c={0,0,0,0};\r
+ //Preparing Bitmap Info\r
+ BITMAPINFO bmInfo;\r
+ memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));\r
+ bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);\r
+ bmInfo.bmiHeader.biWidth=destw;\r
+ bmInfo.bmiHeader.biHeight=desth;\r
+ bmInfo.bmiHeader.biPlanes=1;\r
+ bmInfo.bmiHeader.biBitCount=24;\r
+ BYTE *pbase; //points to the final dib\r
+ BYTE *pdst; //current pixel from pbase\r
+ BYTE *ppix; //current pixel from image\r
+ //get the background\r
+ HDC TmpDC=CreateCompatibleDC(hdc);\r
+ HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);\r
+ HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);\r
+\r
+ if (pbase){\r
+ long xx,yy;\r
+ long sx,sy;\r
+ float dx,dy;\r
+ BYTE *psrc;\r
+\r
+ long ew = ((((24 * destw) + 31) / 32) * 4);\r
+ long ymax = paintbox.bottom;\r
+ long xmin = paintbox.left;\r
+ float fx=(float)head.biWidth/(float)cx;\r
+ float fy=(float)head.biHeight/(float)cy;\r
+\r
+ for(yy=0;yy<desth;yy++){\r
+ dy = head.biHeight-(ymax-yy-y)*fy;\r
+ sy = max(0L,(long)floor(dy));\r
+ psrc = info.pImage+sy*info.dwEffWidth;\r
+ pdst = pbase+yy*ew;\r
+ for(xx=0;xx<destw;xx++){\r
+ dx = (xx+xmin-x)*fx;\r
+ sx = max(0L,(long)floor(dx));\r
+#if CXIMAGE_SUPPORT_INTERPOLATION\r
+ if (bSmooth){\r
+ if (fx > 1 && fy > 1) { \r
+ c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); \r
+ } else { \r
+ c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); \r
+ } \r
+ } else\r
+#endif //CXIMAGE_SUPPORT_INTERPOLATION\r
+ {\r
+ if (head.biClrUsed){\r
+ c=GetPaletteColor(GetPixelIndex(sx,sy));\r
+ } else {\r
+ ppix = psrc + sx*3;\r
+ c.rgbBlue = *ppix++;\r
+ c.rgbGreen= *ppix++;\r
+ c.rgbRed = *ppix;\r
+ }\r
+ }\r
+ *pdst++=c.rgbBlue;\r
+ *pdst++=c.rgbGreen;\r
+ *pdst++=c.rgbRed;\r
+ }\r
+ }\r
+ }\r
+ //paint the image & cleanup\r
+ SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0);\r
+ DeleteObject(SelectObject(TmpDC,TmpObj));\r
+ DeleteDC(TmpDC);\r
+ }\r
+ } else { // draw image with transparent/alpha blending\r
+ //////////////////////////////////////////////////////////////////\r
+ //Alpha blend - Thanks to Florian Egel\r
+\r
+ //pixel informations\r
+ RGBQUAD c={0,0,0,0};\r
+ RGBQUAD ct = GetTransColor();\r
+ long* pc = (long*)&c;\r
+ long* pct= (long*)&ct;\r
+ long cit = GetTransIndex();\r
+ long ci = 0;\r
+\r
+ //Preparing Bitmap Info\r
+ BITMAPINFO bmInfo;\r
+ memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));\r
+ bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);\r
+ bmInfo.bmiHeader.biWidth=destw;\r
+ bmInfo.bmiHeader.biHeight=desth;\r
+ bmInfo.bmiHeader.biPlanes=1;\r
+ bmInfo.bmiHeader.biBitCount=24;\r
+\r
+ BYTE *pbase; //points to the final dib\r
+ BYTE *pdst; //current pixel from pbase\r
+ BYTE *ppix; //current pixel from image\r
+\r
+ //get the background\r
+ HDC TmpDC=CreateCompatibleDC(hdc);\r
+ HBITMAP TmpBmp=CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);\r
+ HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);\r
+ BitBlt(TmpDC,0,0,destw,desth,hdc,paintbox.left,paintbox.top,SRCCOPY);\r
+\r
+ if (pbase){\r
+ long xx,yy,alphaoffset,ix,iy;\r
+ BYTE a,a1,*psrc;\r
+ long ew = ((((24 * destw) + 31) / 32) * 4);\r
+ long ymax = paintbox.bottom;\r
+ long xmin = paintbox.left;\r
+\r
+ if (cx!=head.biWidth || cy!=head.biHeight){\r
+ //STRETCH\r
+ float fx=(float)head.biWidth/(float)cx;\r
+ float fy=(float)head.biHeight/(float)cy;\r
+ float dx,dy;\r
+ long sx,sy;\r
+ \r
+ for(yy=0;yy<desth;yy++){\r
+ dy = head.biHeight-(ymax-yy-y)*fy;\r
+ sy = max(0L,(long)floor(dy));\r
+\r
+ alphaoffset = sy*head.biWidth;\r
+ pdst = pbase + yy*ew;\r
+ psrc = info.pImage + sy*info.dwEffWidth;\r
+\r
+ for(xx=0;xx<destw;xx++){\r
+ dx = (xx+xmin-x)*fx;\r
+ sx = max(0L,(long)floor(dx));\r
+\r
+ if (bAlpha) a=pAlpha[alphaoffset+sx]; else a=255;\r
+ a =(BYTE)((a*(1+info.nAlphaMax))>>8);\r
+\r
+ if (head.biClrUsed){\r
+ ci = GetPixelIndex(sx,sy);\r
+#if CXIMAGE_SUPPORT_INTERPOLATION\r
+ if (bSmooth){\r
+ if (fx > 1 && fy > 1) { \r
+ c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); \r
+ } else { \r
+ c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); \r
+ } \r
+ } else\r
+#endif //CXIMAGE_SUPPORT_INTERPOLATION\r
+ {\r
+ c = GetPaletteColor(GetPixelIndex(sx,sy));\r
+ }\r
+ if (info.bAlphaPaletteEnabled){\r
+ a = (BYTE)((a*(1+c.rgbReserved))>>8);\r
+ }\r
+ } else {\r
+#if CXIMAGE_SUPPORT_INTERPOLATION\r
+ if (bSmooth){\r
+ if (fx > 1 && fy > 1) { \r
+ c = GetAreaColorInterpolated(dx - 0.5f, dy - 0.5f, fx, fy, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); \r
+ } else { \r
+ c = GetPixelColorInterpolated(dx - 0.5f, dy - 0.5f, CxImage::IM_BILINEAR, CxImage::OM_REPEAT); \r
+ } \r
+ } else\r
+#endif //CXIMAGE_SUPPORT_INTERPOLATION\r
+ {\r
+ ppix = psrc + sx*3;\r
+ c.rgbBlue = *ppix++;\r
+ c.rgbGreen= *ppix++;\r
+ c.rgbRed = *ppix;\r
+ }\r
+ }\r
+ //if (*pc!=*pct || !bTransparent){\r
+ //if ((head.biClrUsed && ci!=cit) || ((!head.biClrUsed||bSmooth) && *pc!=*pct) || !bTransparent){\r
+ if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){\r
+ // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication\r
+ if (a == 0) { // Transparent, retain dest \r
+ pdst+=3; \r
+ } else if (a == 255) { // opaque, ignore dest \r
+ *pdst++= c.rgbBlue; \r
+ *pdst++= c.rgbGreen; \r
+ *pdst++= c.rgbRed; \r
+ } else { // semi transparent \r
+ a1=(BYTE)~a;\r
+ *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); \r
+ *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); \r
+ *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); \r
+ } \r
+ } else {\r
+ pdst+=3;\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ //NORMAL\r
+ iy=head.biHeight-ymax+y;\r
+ for(yy=0;yy<desth;yy++,iy++){\r
+ alphaoffset=iy*head.biWidth;\r
+ ix=xmin-x;\r
+ pdst=pbase+yy*ew;\r
+ ppix=info.pImage+iy*info.dwEffWidth+ix*3;\r
+ for(xx=0;xx<destw;xx++,ix++){\r
+\r
+ if (bAlpha) a=pAlpha[alphaoffset+ix]; else a=255;\r
+ a = (BYTE)((a*(1+info.nAlphaMax))>>8);\r
+\r
+ if (head.biClrUsed){\r
+ ci = GetPixelIndex(ix,iy);\r
+ c = GetPaletteColor((BYTE)ci);\r
+ if (info.bAlphaPaletteEnabled){\r
+ a = (BYTE)((a*(1+c.rgbReserved))>>8);\r
+ }\r
+ } else {\r
+ c.rgbBlue = *ppix++;\r
+ c.rgbGreen= *ppix++;\r
+ c.rgbRed = *ppix++;\r
+ }\r
+\r
+ //if (*pc!=*pct || !bTransparent){\r
+ if ((head.biClrUsed && ci!=cit) || (!head.biClrUsed && *pc!=*pct) || !bTransparent){\r
+ // DJT, assume many pixels are fully transparent or opaque and thus avoid multiplication\r
+ if (a == 0) { // Transparent, retain dest \r
+ pdst+=3; \r
+ } else if (a == 255) { // opaque, ignore dest \r
+ *pdst++= c.rgbBlue; \r
+ *pdst++= c.rgbGreen; \r
+ *pdst++= c.rgbRed; \r
+ } else { // semi transparent \r
+ a1=(BYTE)~a;\r
+ *pdst++=(BYTE)((*pdst * a1 + a * c.rgbBlue)>>8); \r
+ *pdst++=(BYTE)((*pdst * a1 + a * c.rgbGreen)>>8); \r
+ *pdst++=(BYTE)((*pdst * a1 + a * c.rgbRed)>>8); \r
+ } \r
+ } else {\r
+ pdst+=3;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ //paint the image & cleanup\r
+ SetDIBitsToDevice(hdc,paintbox.left,paintbox.top,destw,desth,0,0,0,desth,pbase,&bmInfo,0);\r
+ DeleteObject(SelectObject(TmpDC,TmpObj));\r
+ DeleteDC(TmpDC);\r
+ }\r
+\r
+#if !defined (_WIN32_WCE)\r
+ if (pClipRect){ // (experimental)\r
+ HRGN rgn = CreateRectRgnIndirect(&mainbox);\r
+ ExtSelectClipRgn(hdc,rgn,RGN_OR);\r
+ DeleteObject(rgn);\r
+ }\r
+#endif\r
+\r
+ ::RestoreDC(hdc,hdc_Restore);\r
+ return 1;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::Draw2(HDC hdc, const RECT& rect)\r
+{\r
+ return Draw2(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Draws (stretch) the image with single transparency support\r
+ * \param hdc : destination device context\r
+ * \param x,y : (optional) offset\r
+ * \param cx,cy : (optional) size.\r
+ * - If cx or cy are not specified (or less than 0), the normal width or height will be used\r
+ * - If cx or cy are different than width or height, the image will be stretched\r
+ *\r
+ * \return true if everything is ok\r
+ */\r
+long CxImage::Draw2(HDC hdc, long x, long y, long cx, long cy)\r
+{\r
+ if((pDib==0)||(hdc==0)||(cx==0)||(cy==0)||(!info.bEnabled)) return 0;\r
+ if (cx < 0) cx = head.biWidth;\r
+ if (cy < 0) cy = head.biHeight;\r
+ bool bTransparent = (info.nBkgndIndex >= 0);\r
+\r
+ //required for MM_ANISOTROPIC, MM_HIENGLISH, and similar modes [Greg Peatfield]\r
+ int hdc_Restore = ::SaveDC(hdc);\r
+ if (!hdc_Restore) \r
+ return 0;\r
+\r
+ if (!bTransparent){\r
+#if !defined (_WIN32_WCE)\r
+ SetStretchBltMode(hdc,COLORONCOLOR); \r
+#endif\r
+ StretchDIBits(hdc, x, y, cx, cy, 0, 0, head.biWidth, head.biHeight,\r
+ info.pImage,(BITMAPINFO*)pDib, DIB_RGB_COLORS,SRCCOPY);\r
+ } else {\r
+ // draw image with transparent background\r
+ const int safe = 0; // or else GDI fails in the following - sometimes \r
+ RECT rcDst = {x+safe, y+safe, x+cx, y+cy};\r
+ if (RectVisible(hdc, &rcDst)){\r
+ /////////////////////////////////////////////////////////////////\r
+ // True Mask Method - Thanks to Paul Reynolds and Ron Gery\r
+ int nWidth = head.biWidth;\r
+ int nHeight = head.biHeight;\r
+ // Create two memory dcs for the image and the mask\r
+ HDC dcImage=CreateCompatibleDC(hdc);\r
+ HDC dcTrans=CreateCompatibleDC(hdc);\r
+ // Select the image into the appropriate dc\r
+ HBITMAP bm = CreateCompatibleBitmap(hdc, nWidth, nHeight);\r
+ HBITMAP pOldBitmapImage = (HBITMAP)SelectObject(dcImage,bm);\r
+#if !defined (_WIN32_WCE)\r
+ SetStretchBltMode(dcImage,COLORONCOLOR);\r
+#endif\r
+ StretchDIBits(dcImage, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,\r
+ info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,SRCCOPY);\r
+\r
+ // Create the mask bitmap\r
+ HBITMAP bitmapTrans = CreateBitmap(nWidth, nHeight, 1, 1, NULL);\r
+ // Select the mask bitmap into the appropriate dc\r
+ HBITMAP pOldBitmapTrans = (HBITMAP)SelectObject(dcTrans, bitmapTrans);\r
+ // Build mask based on transparent colour\r
+ RGBQUAD rgbBG;\r
+ if (head.biBitCount<24) rgbBG = GetPaletteColor((BYTE)info.nBkgndIndex);\r
+ else rgbBG = info.nBkgndColor;\r
+ COLORREF crColour = RGB(rgbBG.rgbRed, rgbBG.rgbGreen, rgbBG.rgbBlue);\r
+ COLORREF crOldBack = SetBkColor(dcImage,crColour);\r
+ BitBlt(dcTrans,0, 0, nWidth, nHeight, dcImage, 0, 0, SRCCOPY);\r
+\r
+ // Do the work - True Mask method - cool if not actual display\r
+ StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT);\r
+ StretchBlt(hdc,x, y,cx,cy, dcTrans, 0, 0, nWidth, nHeight, SRCAND);\r
+ StretchBlt(hdc,x, y,cx,cy, dcImage, 0, 0, nWidth, nHeight, SRCINVERT);\r
+\r
+ // Restore settings\r
+ SelectObject(dcImage,pOldBitmapImage);\r
+ SelectObject(dcTrans,pOldBitmapTrans);\r
+ SetBkColor(hdc,crOldBack);\r
+ DeleteObject( bitmapTrans ); // RG 29/01/2002\r
+ DeleteDC(dcImage);\r
+ DeleteDC(dcTrans);\r
+ DeleteObject(bm);\r
+ }\r
+ }\r
+ ::RestoreDC(hdc,hdc_Restore);\r
+ return 1;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::Stretch(HDC hdc, const RECT& rect, DWORD dwRop)\r
+{\r
+ return Stretch(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, dwRop);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Stretch the image. Obsolete: use Draw() or Draw2()\r
+ * \param hdc : destination device context\r
+ * \param xoffset,yoffset : (optional) offset\r
+ * \param xsize,ysize : size.\r
+ * \param dwRop : raster operation code (see BitBlt documentation)\r
+ * \return true if everything is ok\r
+ */\r
+long CxImage::Stretch(HDC hdc, long xoffset, long yoffset, long xsize, long ysize, DWORD dwRop)\r
+{\r
+ if((pDib)&&(hdc)) {\r
+ //palette must be correctly filled\r
+#if !defined (_WIN32_WCE)\r
+ SetStretchBltMode(hdc,COLORONCOLOR); \r
+#endif\r
+ StretchDIBits(hdc, xoffset, yoffset,\r
+ xsize, ysize, 0, 0, head.biWidth, head.biHeight,\r
+ info.pImage,(BITMAPINFO*)pDib,DIB_RGB_COLORS,dwRop);\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+/**\r
+ * Tiles the device context in the specified rectangle with the image.\r
+ * \param hdc : destination device context\r
+ * \param rc : tiled rectangle in the output device context\r
+ * \return true if everything is ok\r
+ */\r
+long CxImage::Tile(HDC hdc, RECT *rc)\r
+{\r
+ if((pDib)&&(hdc)&&(rc)) {\r
+ int w = rc->right - rc->left;\r
+ int h = rc->bottom - rc->top;\r
+ int x,y,z;\r
+ int bx=head.biWidth;\r
+ int by=head.biHeight;\r
+ for (y = 0 ; y < h ; y += by){\r
+ if ((y+by)>h) by=h-y;\r
+ z=bx;\r
+ for (x = 0 ; x < w ; x += z){\r
+ if ((x+z)>w) z=w-x;\r
+ RECT r = {rc->left + x,rc->top + y,rc->left + x + z,rc->top + y + by};\r
+ Draw(hdc,rc->left + x, rc->top + y,-1,-1,&r);\r
+ }\r
+ }\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// For UNICODE support: char -> TCHAR\r
+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)\r
+//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)\r
+{\r
+ if (IsValid()){\r
+ //get the background\r
+ HDC pDC;\r
+ if (hdc) pDC=hdc; else pDC = ::GetDC(0);\r
+ if (pDC==NULL) return 0;\r
+ HDC TmpDC=CreateCompatibleDC(pDC);\r
+ if (hdc==NULL) ::ReleaseDC(0, pDC);\r
+ if (TmpDC==NULL) return 0;\r
+ //choose the font\r
+ HFONT m_Font;\r
+ LOGFONT* m_pLF;\r
+ m_pLF=(LOGFONT*)calloc(1,sizeof(LOGFONT));\r
+ _tcsncpy(m_pLF->lfFaceName,font,31); // For UNICODE support\r
+ //strncpy(m_pLF->lfFaceName,font,31);\r
+ m_pLF->lfHeight=lSize;\r
+ m_pLF->lfWeight=lWeight;\r
+ m_pLF->lfItalic=bItalic;\r
+ m_pLF->lfUnderline=bUnderline;\r
+ m_Font=CreateFontIndirect(m_pLF);\r
+ //select the font in the dc\r
+ HFONT pOldFont=NULL;\r
+ if (m_Font)\r
+ pOldFont = (HFONT)SelectObject(TmpDC,m_Font);\r
+ else\r
+ pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT));\r
+\r
+ //Set text color\r
+ SetTextColor(TmpDC,RGB(255,255,255));\r
+ SetBkColor(TmpDC,RGB(0,0,0));\r
+ //draw the text\r
+ SetBkMode(TmpDC,OPAQUE);\r
+ //Set text position;\r
+ RECT pos = {0,0,0,0};\r
+ //long len = (long)strlen(text);\r
+ long len = (long)_tcslen(text); // For UNICODE support\r
+ ::DrawText(TmpDC,text,len,&pos,DT_CALCRECT);\r
+ pos.right+=pos.bottom; //for italics\r
+\r
+ //Preparing Bitmap Info\r
+ long width=pos.right;\r
+ long height=pos.bottom;\r
+ BITMAPINFO bmInfo;\r
+ memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));\r
+ bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);\r
+ bmInfo.bmiHeader.biWidth=width;\r
+ bmInfo.bmiHeader.biHeight=height;\r
+ bmInfo.bmiHeader.biPlanes=1;\r
+ bmInfo.bmiHeader.biBitCount=24;\r
+ BYTE *pbase; //points to the final dib\r
+\r
+ HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);\r
+ HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);\r
+ memset(pbase,0,height*((((24 * width) + 31) / 32) * 4));\r
+\r
+ ::DrawText(TmpDC,text,len,&pos,0);\r
+\r
+ CxImage itext;\r
+ itext.CreateFromHBITMAP(TmpBmp);\r
+\r
+ y=head.biHeight-y-1;\r
+ for (long ix=0;ix<width;ix++){\r
+ for (long iy=0;iy<height;iy++){\r
+ if (itext.GetPixelColor(ix,iy).rgbBlue) SetPixelColor(x+ix,y+iy,color,bSetAlpha);\r
+ }\r
+ }\r
+\r
+ //cleanup\r
+ if (pOldFont) SelectObject(TmpDC,pOldFont);\r
+ DeleteObject(m_Font);\r
+ free(m_pLF);\r
+ DeleteObject(SelectObject(TmpDC,TmpObj));\r
+ DeleteDC(TmpDC);\r
+ }\r
+\r
+ return 1;\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+// <VATI>\r
+long CxImage::DrawStringEx(HDC hdc, long x, long y, CXTEXTINFO *pTextType, bool bSetAlpha )\r
+{\r
+ if (!IsValid())\r
+ return -1;\r
+ \r
+ //get the background\r
+ HDC pDC;\r
+ if (hdc) pDC=hdc; else pDC = ::GetDC(0);\r
+ if (pDC==NULL) return 0;\r
+ HDC TmpDC=CreateCompatibleDC(pDC);\r
+ if (hdc==NULL) ::ReleaseDC(0, pDC);\r
+ if (TmpDC==NULL) return 0;\r
+\r
+ //choose the font\r
+ HFONT m_Font;\r
+ m_Font=CreateFontIndirect( &pTextType->lfont );\r
+ \r
+ // get colors in RGBQUAD\r
+ RGBQUAD p_forecolor = RGBtoRGBQUAD(pTextType->fcolor);\r
+ RGBQUAD p_backcolor = RGBtoRGBQUAD(pTextType->bcolor);\r
+\r
+ // check alignment and re-set default if necessary\r
+ if ( pTextType->align != DT_CENTER &&\r
+ pTextType->align != DT_LEFT &&\r
+ pTextType->align != DT_RIGHT )\r
+ pTextType->align = DT_CENTER;\r
+\r
+ // check rounding radius and re-set default if necessary\r
+ if ( pTextType->b_round > 50 )\r
+ pTextType->b_round = 10;\r
+\r
+ // check opacity and re-set default if necessary\r
+ if ( pTextType->b_opacity > 1. || pTextType->b_opacity < .0 )\r
+ pTextType->b_opacity = 0.;\r
+\r
+ //select the font in the dc\r
+ HFONT pOldFont=NULL;\r
+ if (m_Font)\r
+ pOldFont = (HFONT)SelectObject(TmpDC,m_Font);\r
+ else\r
+ pOldFont = (HFONT)SelectObject(TmpDC,GetStockObject(DEFAULT_GUI_FONT));\r
+\r
+ //Set text color\r
+ SetTextColor(TmpDC,RGB(255,255,255));\r
+ SetBkColor(TmpDC,RGB(0,0,0));\r
+ SetBkMode(TmpDC,OPAQUE);\r
+ //Set text position;\r
+ RECT pos = {0,0,0,0};\r
+ \r
+ // get text length and number of lines\r
+ long i=0, numlines=1, len=(long)_tcsclen(pTextType->text);\r
+ while (i<len)\r
+ {\r
+ if ( pTextType->text[i++]==13 )\r
+ numlines++;\r
+ }\r
+\r
+ ::DrawText(TmpDC, pTextType->text, len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX | DT_CALCRECT );\r
+\r
+ // increase only if it's really italics, and only one line height\r
+ if ( pTextType->lfont.lfItalic ) \r
+ pos.right += pos.bottom/2/numlines; \r
+\r
+ // background frame and rounding radius\r
+ int frame = 0, roundR = 0;\r
+ if ( pTextType->opaque )\r
+ {\r
+ roundR= (int)(pos.bottom/numlines * pTextType->b_round / 100 ) ;\r
+ frame = (int)(/*3.5 + */0.29289*roundR ) ;\r
+ pos.right += pos.bottom/numlines/3 ; // JUST FOR BEAUTY\r
+ }\r
+\r
+ //Preparing Bitmap Info\r
+ long width=pos.right +frame*2;\r
+ long height=pos.bottom +frame*2;\r
+ BITMAPINFO bmInfo;\r
+ memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER));\r
+ bmInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);\r
+ bmInfo.bmiHeader.biWidth=width;\r
+ bmInfo.bmiHeader.biHeight=height;\r
+ bmInfo.bmiHeader.biPlanes=1;\r
+ bmInfo.bmiHeader.biBitCount=24;\r
+ BYTE *pbase; //points to the final dib\r
+\r
+ HBITMAP TmpBmp=CreateDIBSection(TmpDC,&bmInfo,DIB_RGB_COLORS,(void**)&pbase,0,0);\r
+ HGDIOBJ TmpObj=SelectObject(TmpDC,TmpBmp);\r
+ memset(pbase,0,height*((((24 * width) + 31) / 32) * 4));\r
+\r
+ ::DrawText(TmpDC,pTextType->text,len, &pos, /*DT_EDITCONTROL|DT_EXTERNALLEADING|*/DT_NOPREFIX| pTextType->align );\r
+ \r
+ CxImage itext;\r
+ itext.CreateFromHBITMAP(TmpBmp);\r
+ y=head.biHeight-y-1;\r
+\r
+ itext.Negative();\r
+\r
+ if (pTextType->smooth==FALSE){\r
+ itext.Threshold(128);\r
+ } else {\r
+ //itext.TextBlur();\r
+ }\r
+\r
+ //move the insertion point according to alignment type\r
+ // DT_CENTER: cursor points to the center of text rectangle\r
+ // DT_RIGHT: cursor points to right side end of text rectangle\r
+ // DT_LEFT: cursor points to left end of text rectangle\r
+ if ( pTextType->align == DT_CENTER )\r
+ x -= width/2;\r
+ else if ( pTextType->align == DT_RIGHT )\r
+ x -= width;\r
+ if (x<0) x=0;\r
+ \r
+ //draw the background first, if it exists\r
+ long ix,iy;\r
+ if ( pTextType->opaque )\r
+ {\r
+ int ixf=0; \r
+ for (ix=0;ix<width;ix++)\r
+ {\r
+ if ( ix<=roundR )\r
+ ixf = (int)(.5+roundR-sqrt((float)(roundR*roundR-(ix-roundR)*(ix-roundR))));\r
+ else if ( ix>=width-roundR-1 )\r
+ ixf = (int)(.5+roundR-sqrt((float)(roundR*roundR-(width-1-ix-roundR)*(width-1-ix-roundR))));\r
+ else\r
+ ixf=0;\r
+\r
+ for (iy=0;iy<height;iy++)\r
+ {\r
+ if ( (ix<=roundR && ( iy > height-ixf-1 || iy < ixf )) ||\r
+ (ix>=width-roundR-1 && ( iy > height-ixf-1 || iy < ixf )) )\r
+ continue;\r
+ else\r
+ if ( pTextType->b_opacity > 0.0 && pTextType->b_opacity < 1.0 )\r
+ {\r
+ RGBQUAD bcolor, pcolor;\r
+ // calculate a transition color from original image to background color:\r
+ pcolor = GetPixelColor(x+ix,y+iy);\r
+ bcolor.rgbBlue = (unsigned char)(pTextType->b_opacity * pcolor.rgbBlue + (1.0-pTextType->b_opacity) * p_backcolor.rgbBlue );\r
+ bcolor.rgbRed = (unsigned char)(pTextType->b_opacity * pcolor.rgbRed + (1.0-pTextType->b_opacity) * p_backcolor.rgbRed ) ;\r
+ bcolor.rgbGreen = (unsigned char)(pTextType->b_opacity * pcolor.rgbGreen + (1.0-pTextType->b_opacity) * p_backcolor.rgbGreen ) ;\r
+ bcolor.rgbReserved = 0;\r
+ SetPixelColor(x+ix,y+iy,bcolor,bSetAlpha);\r
+ }\r
+ else\r
+ SetPixelColor(x+ix,y+iy,p_backcolor,bSetAlpha);\r
+ }\r
+ }\r
+ }\r
+\r
+ // draw the text itself\r
+ for (ix=0;ix<width;ix++)\r
+ {\r
+ for (iy=0;iy<height;iy++)\r
+ {\r
+ RGBQUAD pcolor = GetPixelColor(x+ix,y+iy);\r
+ RGBQUAD tcolor = itext.GetPixelColor(ix,iy);\r
+ if (tcolor.rgbBlue!=255){\r
+ float a = tcolor.rgbBlue/255.0f;\r
+ pcolor.rgbBlue = (unsigned char)(a * (pcolor.rgbBlue - p_forecolor.rgbBlue) + p_forecolor.rgbBlue );\r
+ pcolor.rgbRed = (unsigned char)(a * (pcolor.rgbRed - p_forecolor.rgbRed) + p_forecolor.rgbRed ) ;\r
+ pcolor.rgbGreen = (unsigned char)(a * (pcolor.rgbGreen - p_forecolor.rgbGreen) + p_forecolor.rgbGreen );\r
+ pcolor.rgbReserved = 0;\r
+ SetPixelColor(x+ix+frame,y+iy-frame,pcolor,bSetAlpha);\r
+ //SetPixelColor(x+ix+frame,y+iy-frame,p_forecolor,bSetAlpha);\r
+ }\r
+ }\r
+ }\r
+\r
+ //cleanup\r
+ if (pOldFont) SelectObject(TmpDC,pOldFont);\r
+ DeleteObject(m_Font);\r
+ DeleteObject(SelectObject(TmpDC,TmpObj));\r
+ DeleteDC(TmpDC);\r
+ return 1;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+void CxImage::InitTextInfo( CXTEXTINFO *txt )\r
+{\r
+\r
+ memset( txt, 0, sizeof(CXTEXTINFO));\r
+ \r
+ // LOGFONT defaults\r
+ txt->lfont.lfHeight = -36; \r
+ txt->lfont.lfCharSet = EASTEUROPE_CHARSET; // just for Central-European users \r
+ txt->lfont.lfWeight = FW_NORMAL;\r
+ txt->lfont.lfWidth = 0; \r
+ txt->lfont.lfEscapement = 0; \r
+ txt->lfont.lfOrientation = 0; \r
+ txt->lfont.lfItalic = FALSE; \r
+ txt->lfont.lfUnderline = FALSE; \r
+ txt->lfont.lfStrikeOut = FALSE; \r
+ txt->lfont.lfOutPrecision = OUT_DEFAULT_PRECIS; \r
+ txt->lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; \r
+ txt->lfont.lfQuality = PROOF_QUALITY; \r
+ txt->lfont.lfPitchAndFamily= DEFAULT_PITCH | FF_DONTCARE ; \r
+ _stprintf( txt->lfont.lfFaceName, _T("Arial")); //use TCHAR mappings <Cesar M>\r
+\r
+ // initial colors\r
+ txt->fcolor = RGB( 255,255,160 ); // default foreground: light goldyellow\r
+ txt->bcolor = RGB( 0, 80,160 ); // default background: light blue\r
+\r
+ // background\r
+ txt->opaque = TRUE; // text has a non-transparent background;\r
+ txt->smooth = TRUE;\r
+ txt->b_opacity = 0.0; // default: opaque background\r
+ txt->b_outline = 0; // default: no outline (OUTLINE NOT IMPLEMENTED AT THIS TIME)\r
+ txt->b_round = 20; // default: rounding radius is 20% of the rectangle height\r
+ // the text \r
+ _stprintf( txt->text, _T("Sample Text 01234รตรป")); // text use TCHAR mappings <Cesar M>\r
+ txt->align = DT_CENTER;\r
+ return;\r
+}\r
+\r
+#if CXIMAGE_SUPPORT_LAYERS\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::LayerDrawAll(HDC hdc, const RECT& rect, RECT* pClipRect, bool bSmooth)\r
+{\r
+ return LayerDrawAll(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pClipRect,bSmooth);\r
+}\r
+////////////////////////////////////////////////////////////////////////////////\r
+long CxImage::LayerDrawAll(HDC hdc, long x, long y, long cx, long cy, RECT* pClipRect, bool bSmooth)\r
+{\r
+ long n=0;\r
+ CxImage* pLayer;\r
+ while(pLayer=GetLayer(n++)){\r
+ if (pLayer->Draw(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0)\r
+ return 0;\r
+ if (pLayer->LayerDrawAll(hdc,x+pLayer->info.xOffset,y+pLayer->info.yOffset,cx,cy,pClipRect,bSmooth)==0)\r
+ return 0;\r
+ }\r
+ return 1;\r
+}\r
+#endif //CXIMAGE_SUPPORT_LAYERS\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+#endif //CXIMAGE_SUPPORT_WINDOWS\r
+////////////////////////////////////////////////////////////////////////////////\r
--- /dev/null
+#if !defined(__xiofile_h)\r
+#define __xiofile_h\r
+\r
+#include "xfile.h"\r
+//#include <TCHAR.h>\r
+\r
+class DLL_EXP CxIOFile : public CxFile\r
+ {\r
+public:\r
+ CxIOFile(FILE* fp = NULL)\r
+ {\r
+ m_fp = fp;\r
+ m_bCloseFile = (bool)(fp==0);\r
+ }\r
+\r
+ ~CxIOFile()\r
+ {\r
+ Close();\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ bool Open(LPCTSTR filename, LPCTSTR mode)\r
+ {\r
+ if (m_fp) return false; // Can't re-open without closing first\r
+\r
+ m_fp = _tfopen(filename, mode);\r
+ if (!m_fp) return false;\r
+\r
+ m_bCloseFile = true;\r
+\r
+ return true;\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual bool Close()\r
+ {\r
+ int iErr = 0;\r
+ if ( (m_fp) && (m_bCloseFile) ){ \r
+ iErr = fclose(m_fp);\r
+ m_fp = NULL;\r
+ }\r
+ return (bool)(iErr==0);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual size_t Read(void *buffer, size_t size, size_t count)\r
+ {\r
+ if (!m_fp) return 0;\r
+ return fread(buffer, size, count, m_fp);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual size_t Write(const void *buffer, size_t size, size_t count)\r
+ {\r
+ if (!m_fp) return 0;\r
+ return fwrite(buffer, size, count, m_fp);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual bool Seek(long offset, int origin)\r
+ {\r
+ if (!m_fp) return false;\r
+ return (bool)(fseek(m_fp, offset, origin) == 0);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual long Tell()\r
+ {\r
+ if (!m_fp) return 0;\r
+ return ftell(m_fp);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual long Size()\r
+ {\r
+ if (!m_fp) return -1;\r
+ long pos,size;\r
+ pos = ftell(m_fp);\r
+ fseek(m_fp, 0, SEEK_END);\r
+ size = ftell(m_fp);\r
+ fseek(m_fp, pos,SEEK_SET);\r
+ return size;\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual bool Flush()\r
+ {\r
+ if (!m_fp) return false;\r
+ return (bool)(fflush(m_fp) == 0);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual bool Eof()\r
+ {\r
+ if (!m_fp) return true;\r
+ return (bool)(feof(m_fp) != 0);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual long Error()\r
+ {\r
+ if (!m_fp) return -1;\r
+ return ferror(m_fp);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual bool PutC(unsigned char c)\r
+ {\r
+ if (!m_fp) return false;\r
+ return (bool)(fputc(c, m_fp) == c);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual long GetC()\r
+ {\r
+ if (!m_fp) return EOF;\r
+ return getc(m_fp);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual char * GetS(char *string, int n)\r
+ {\r
+ if (!m_fp) return NULL;\r
+ return fgets(string,n,m_fp);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+ virtual long Scanf(const char *format, void* output)\r
+ {\r
+ if (!m_fp) return EOF;\r
+ return fscanf(m_fp, format, output);\r
+ }\r
+//////////////////////////////////////////////////////////\r
+protected:\r
+ FILE *m_fp;\r
+ bool m_bCloseFile;\r
+ };\r
+\r
+#endif\r
--- /dev/null
+#include "xmemfile.h"\r
+\r
+//////////////////////////////////////////////////////////\r
+CxMemFile::CxMemFile(BYTE* pBuffer, DWORD size)\r
+{\r
+ m_pBuffer = pBuffer;\r
+ m_Position = 0;\r
+ m_Size = m_Edge = size;\r
+ m_bFreeOnClose = (bool)(pBuffer==0);\r
+}\r
+//////////////////////////////////////////////////////////\r
+CxMemFile::~CxMemFile()\r
+{\r
+ Close();\r
+}\r
+//////////////////////////////////////////////////////////\r
+bool CxMemFile::Close()\r
+{\r
+ if ( (m_pBuffer) && (m_bFreeOnClose) ){\r
+ free(m_pBuffer);\r
+ m_pBuffer = NULL;\r
+ m_Size = 0;\r
+ }\r
+ return true;\r
+}\r
+//////////////////////////////////////////////////////////\r
+bool CxMemFile::Open()\r
+{\r
+ if (m_pBuffer) return false; // Can't re-open without closing first\r
+\r
+ m_Position = m_Size = m_Edge = 0;\r
+ m_pBuffer=(BYTE*)malloc(1);\r
+ m_bFreeOnClose = true;\r
+\r
+ return (m_pBuffer!=0);\r
+}\r
+//////////////////////////////////////////////////////////\r
+BYTE* CxMemFile::GetBuffer(bool bDetachBuffer)\r
+{\r
+ //can only detach, avoid inadvertantly attaching to\r
+ // memory that may not be ours [Jason De Arte]\r
+ if( bDetachBuffer )\r
+ m_bFreeOnClose = false;\r
+ return m_pBuffer;\r
+}\r
+//////////////////////////////////////////////////////////\r
+size_t CxMemFile::Read(void *buffer, size_t size, size_t count)\r
+{\r
+ if (buffer==NULL) return 0;\r
+\r
+ if (m_pBuffer==NULL) return 0;\r
+ if (m_Position >= (long)m_Size) return 0;\r
+\r
+ long nCount = (long)(count*size);\r
+ if (nCount == 0) return 0;\r
+\r
+ long nRead;\r
+ if (m_Position + nCount > (long)m_Size)\r
+ nRead = (m_Size - m_Position);\r
+ else\r
+ nRead = nCount;\r
+\r
+ memcpy(buffer, m_pBuffer + m_Position, nRead);\r
+ m_Position += nRead;\r
+\r
+ return (size_t)(nRead/size);\r
+}\r
+//////////////////////////////////////////////////////////\r
+size_t CxMemFile::Write(const void *buffer, size_t size, size_t count)\r
+{\r
+ if (m_pBuffer==NULL) return 0;\r
+ if (buffer==NULL) return 0;\r
+\r
+ long nCount = (long)(count*size);\r
+ if (nCount == 0) return 0;\r
+\r
+ if (m_Position + nCount > m_Edge){\r
+ if (!Alloc(m_Position + nCount)){\r
+ return false;\r
+ }\r
+ }\r
+\r
+ memcpy(m_pBuffer + m_Position, buffer, nCount);\r
+\r
+ m_Position += nCount;\r
+\r
+ if (m_Position > (long)m_Size) m_Size = m_Position;\r
+ \r
+ return count;\r
+}\r
+//////////////////////////////////////////////////////////\r
+bool CxMemFile::Seek(long offset, int origin)\r
+{\r
+ if (m_pBuffer==NULL) return false;\r
+ long lNewPos = m_Position;\r
+\r
+ if (origin == SEEK_SET) lNewPos = offset;\r
+ else if (origin == SEEK_CUR) lNewPos += offset;\r
+ else if (origin == SEEK_END) lNewPos = m_Size + offset;\r
+ else return false;\r
+\r
+ if (lNewPos < 0) lNewPos = 0;\r
+\r
+ m_Position = lNewPos;\r
+ return true;\r
+}\r
+//////////////////////////////////////////////////////////\r
+long CxMemFile::Tell()\r
+{\r
+ if (m_pBuffer==NULL) return -1;\r
+ return m_Position;\r
+}\r
+//////////////////////////////////////////////////////////\r
+long CxMemFile::Size()\r
+{\r
+ if (m_pBuffer==NULL) return -1;\r
+ return m_Size;\r
+}\r
+//////////////////////////////////////////////////////////\r
+bool CxMemFile::Flush()\r
+{\r
+ if (m_pBuffer==NULL) return false;\r
+ return true;\r
+}\r
+//////////////////////////////////////////////////////////\r
+bool CxMemFile::Eof()\r
+{\r
+ if (m_pBuffer==NULL) return true;\r
+ return (m_Position >= (long)m_Size);\r
+}\r
+//////////////////////////////////////////////////////////\r
+long CxMemFile::Error()\r
+{\r
+ if (m_pBuffer==NULL) return -1;\r
+ return (m_Position > (long)m_Size);\r
+}\r
+//////////////////////////////////////////////////////////\r
+bool CxMemFile::PutC(unsigned char c)\r
+{\r
+ if (m_pBuffer==NULL) return false;\r
+\r
+ if (m_Position >= m_Edge){\r
+ if (!Alloc(m_Position + 1)){\r
+ return false;\r
+ }\r
+ }\r
+\r
+ m_pBuffer[m_Position++] = c;\r
+\r
+ if (m_Position > (long)m_Size) m_Size = m_Position;\r
+ \r
+ return true;\r
+}\r
+//////////////////////////////////////////////////////////\r
+long CxMemFile::GetC()\r
+{\r
+ if (Eof()) return EOF;\r
+ return *(BYTE*)((BYTE*)m_pBuffer + m_Position++);\r
+}\r
+//////////////////////////////////////////////////////////\r
+char * CxMemFile::GetS(char *string, int n)\r
+{\r
+ n--;\r
+ long c,i=0;\r
+ while (i<n){\r
+ c = GetC();\r
+ if (c == EOF) return 0;\r
+ string[i++] = (char)c;\r
+ if (c == '\n') break;\r
+ }\r
+ string[i] = 0;\r
+ return string;\r
+}\r
+//////////////////////////////////////////////////////////\r
+long CxMemFile::Scanf(const char *format, void* output)\r
+{\r
+ return 0;\r
+}\r
+//////////////////////////////////////////////////////////\r
+bool CxMemFile::Alloc(DWORD dwNewLen)\r
+{\r
+ if (dwNewLen > (DWORD)m_Edge)\r
+ {\r
+ // find new buffer size\r
+ DWORD dwNewBufferSize = (DWORD)(((dwNewLen>>16)+1)<<16);\r
+\r
+ // allocate new buffer\r
+ if (m_pBuffer == NULL) m_pBuffer = (BYTE*)malloc(dwNewBufferSize);\r
+ else m_pBuffer = (BYTE*)realloc(m_pBuffer, dwNewBufferSize);\r
+ // I own this buffer now (caller knows nothing about it)\r
+ m_bFreeOnClose = true;\r
+\r
+ m_Edge = dwNewBufferSize;\r
+ }\r
+ return (m_pBuffer!=0);\r
+}\r
+//////////////////////////////////////////////////////////\r
+void CxMemFile::Free()\r
+{\r
+ Close();\r
+}\r
+//////////////////////////////////////////////////////////\r
--- /dev/null
+#if !defined(__xmemfile_h)\r
+#define __xmemfile_h\r
+\r
+#include "xfile.h"\r
+\r
+//////////////////////////////////////////////////////////\r
+class DLL_EXP CxMemFile : public CxFile\r
+{\r
+public:\r
+ CxMemFile(BYTE* pBuffer = NULL, DWORD size = 0);\r
+ ~CxMemFile();\r
+\r
+ bool Open();\r
+ BYTE* GetBuffer(bool bDetachBuffer = true);\r
+\r
+ virtual bool Close();\r
+ virtual size_t Read(void *buffer, size_t size, size_t count);\r
+ virtual size_t Write(const void *buffer, size_t size, size_t count);\r
+ virtual bool Seek(long offset, int origin);\r
+ virtual long Tell();\r
+ virtual long Size();\r
+ virtual bool Flush();\r
+ virtual bool Eof();\r
+ virtual long Error();\r
+ virtual bool PutC(unsigned char c);\r
+ virtual long GetC();\r
+ virtual char * GetS(char *string, int n);\r
+ virtual long Scanf(const char *format, void* output);\r
+\r
+protected:\r
+ bool Alloc(DWORD nBytes);\r
+ void Free();\r
+\r
+ BYTE* m_pBuffer;\r
+ DWORD m_Size;\r
+ bool m_bFreeOnClose;\r
+ long m_Position; //current position\r
+ long m_Edge; //buffer size\r
+};\r
+\r
+#endif\r