diff --git a/.gitignore b/.gitignore index 335fbb4..15cc979 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,9 @@ Release _release *__Win32_* /innosetup/installs +/#Intermediate +/#Build +*.vcxproj.user +*.VC.db +*.VC.opendb +/ipch \ No newline at end of file diff --git a/.vs/BlitzNext/v14/.suo b/.vs/BlitzNext/v14/.suo new file mode 100644 index 0000000..93af6e7 Binary files /dev/null and b/.vs/BlitzNext/v14/.suo differ diff --git a/BlitzNext.sln b/BlitzNext.sln new file mode 100644 index 0000000..1868d5d --- /dev/null +++ b/BlitzNext.sln @@ -0,0 +1,644 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asm_makeinsts", "asm_makeinsts\asm_makeinsts.vcxproj", "{E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bblaunch", "bblaunch\bblaunch.vcxproj", "{C74A383E-81B0-4679-AAC9-535C94C92EA5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbruntime", "bbruntime\bbruntime.vcxproj", "{DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbruntime_dll", "bbruntime_dll\bbruntime_dll.vcxproj", "{5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blitz", "blitz\blitz.vcxproj", "{C23AF61E-9509-411F-933E-17DB18884B21}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blitz3d", "blitz3d\blitz3d.vcxproj", "{BE0BA538-6215-4836-9227-1D3627E40D61}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blitzide", "blitzide\blitzide.vcxproj", "{B61D8348-B715-42B8-A759-C7BBB0C8CD4D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compiler", "compiler\compiler.vcxproj", "{D884A075-E3B8-44E1-838D-74F28B33391B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "config", "config\config.vcxproj", "{3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debugger", "debugger\debugger.vcxproj", "{4132C330-95D9-4F68-A51A-3B90381587C5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gxruntime", "gxruntime\gxruntime.vcxproj", "{FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "linker", "linker\linker.vcxproj", "{0B629BA3-D138-407A-801D-DBE7C8DC4324}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "linker_dll", "linker_dll\linker_dll.vcxproj", "{778BCC7F-40F9-4309-9A88-C0F60D9B364D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stdutil", "stdutil\stdutil.vcxproj", "{6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + AppStore|Any CPU = AppStore|Any CPU + AppStore|ARM = AppStore|ARM + AppStore|iPhone = AppStore|iPhone + AppStore|iPhoneSimulator = AppStore|iPhoneSimulator + AppStore|x86 = AppStore|x86 + Blitz2DRelease|Any CPU = Blitz2DRelease|Any CPU + Blitz2DRelease|ARM = Blitz2DRelease|ARM + Blitz2DRelease|iPhone = Blitz2DRelease|iPhone + Blitz2DRelease|iPhoneSimulator = Blitz2DRelease|iPhoneSimulator + Blitz2DRelease|x86 = Blitz2DRelease|x86 + Blitz3DRelease|Any CPU = Blitz3DRelease|Any CPU + Blitz3DRelease|ARM = Blitz3DRelease|ARM + Blitz3DRelease|iPhone = Blitz3DRelease|iPhone + Blitz3DRelease|iPhoneSimulator = Blitz3DRelease|iPhoneSimulator + Blitz3DRelease|x86 = Blitz3DRelease|x86 + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Release|x86 = Release|x86 + Template|Any CPU = Template|Any CPU + Template|ARM = Template|ARM + Template|iPhone = Template|iPhone + Template|iPhoneSimulator = Template|iPhoneSimulator + Template|x86 = Template|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|Any CPU.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|Any CPU.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|ARM.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|ARM.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|iPhone.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|iPhone.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|iPhoneSimulator.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|x86.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.AppStore|x86.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|Any CPU.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|Any CPU.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|ARM.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|ARM.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|iPhone.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|iPhone.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|iPhoneSimulator.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|x86.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz2DRelease|x86.Build.0 = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|Any CPU.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|Any CPU.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|ARM.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|ARM.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|iPhone.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|iPhone.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|iPhoneSimulator.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|x86.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Blitz3DRelease|x86.Build.0 = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Debug|ARM.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Debug|iPhone.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Debug|x86.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Debug|x86.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Release|Any CPU.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Release|ARM.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Release|iPhone.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Release|x86.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Release|x86.Build.0 = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|Any CPU.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|Any CPU.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|ARM.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|ARM.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|iPhone.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|iPhone.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|iPhoneSimulator.ActiveCfg = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|iPhoneSimulator.Build.0 = Debug|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|x86.ActiveCfg = Release|Win32 + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E}.Template|x86.Build.0 = Release|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|Any CPU.Build.0 = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|ARM.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|ARM.Build.0 = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|iPhone.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|iPhone.Build.0 = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|x86.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.AppStore|x86.Build.0 = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Debug|ARM.ActiveCfg = Debug|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Debug|iPhone.ActiveCfg = Debug|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Debug|x86.ActiveCfg = Debug|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Debug|x86.Build.0 = Debug|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Release|Any CPU.ActiveCfg = Release|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Release|ARM.ActiveCfg = Release|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Release|iPhone.ActiveCfg = Release|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Release|x86.ActiveCfg = Release|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Release|x86.Build.0 = Release|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Template|Any CPU.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Template|ARM.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Template|iPhone.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Template|x86.ActiveCfg = Template|Win32 + {C74A383E-81B0-4679-AAC9-535C94C92EA5}.Template|x86.Build.0 = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|Any CPU.Build.0 = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|ARM.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|ARM.Build.0 = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|iPhone.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|iPhone.Build.0 = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|x86.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.AppStore|x86.Build.0 = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Debug|ARM.ActiveCfg = Debug|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Debug|iPhone.ActiveCfg = Debug|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Debug|x86.ActiveCfg = Debug|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Debug|x86.Build.0 = Debug|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Release|Any CPU.ActiveCfg = Release|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Release|ARM.ActiveCfg = Release|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Release|iPhone.ActiveCfg = Release|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Release|x86.ActiveCfg = Release|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Release|x86.Build.0 = Release|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Template|Any CPU.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Template|ARM.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Template|iPhone.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Template|x86.ActiveCfg = Template|Win32 + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354}.Template|x86.Build.0 = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|Any CPU.Build.0 = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|ARM.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|ARM.Build.0 = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|iPhone.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|iPhone.Build.0 = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|x86.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.AppStore|x86.Build.0 = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Debug|ARM.ActiveCfg = Debug|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Debug|iPhone.ActiveCfg = Debug|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Debug|x86.ActiveCfg = Debug|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Debug|x86.Build.0 = Debug|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Release|Any CPU.ActiveCfg = Release|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Release|ARM.ActiveCfg = Release|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Release|iPhone.ActiveCfg = Release|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Release|x86.ActiveCfg = Release|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Release|x86.Build.0 = Release|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Template|Any CPU.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Template|ARM.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Template|iPhone.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Template|x86.ActiveCfg = Template|Win32 + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3}.Template|x86.Build.0 = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|Any CPU.Build.0 = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|ARM.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|ARM.Build.0 = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|iPhone.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|iPhone.Build.0 = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|x86.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.AppStore|x86.Build.0 = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Debug|ARM.ActiveCfg = Debug|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Debug|iPhone.ActiveCfg = Debug|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Debug|x86.ActiveCfg = Debug|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Debug|x86.Build.0 = Debug|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Release|Any CPU.ActiveCfg = Release|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Release|ARM.ActiveCfg = Release|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Release|iPhone.ActiveCfg = Release|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Release|x86.ActiveCfg = Release|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Release|x86.Build.0 = Release|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Template|Any CPU.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Template|ARM.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Template|iPhone.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Template|x86.ActiveCfg = Template|Win32 + {C23AF61E-9509-411F-933E-17DB18884B21}.Template|x86.Build.0 = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|Any CPU.Build.0 = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|ARM.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|ARM.Build.0 = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|iPhone.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|iPhone.Build.0 = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|x86.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.AppStore|x86.Build.0 = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Debug|ARM.ActiveCfg = Debug|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Debug|iPhone.ActiveCfg = Debug|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Debug|x86.ActiveCfg = Debug|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Debug|x86.Build.0 = Debug|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Release|Any CPU.ActiveCfg = Release|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Release|ARM.ActiveCfg = Release|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Release|iPhone.ActiveCfg = Release|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Release|x86.ActiveCfg = Release|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Release|x86.Build.0 = Release|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Template|Any CPU.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Template|ARM.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Template|iPhone.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Template|x86.ActiveCfg = Template|Win32 + {BE0BA538-6215-4836-9227-1D3627E40D61}.Template|x86.Build.0 = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|Any CPU.Build.0 = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|ARM.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|ARM.Build.0 = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|iPhone.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|iPhone.Build.0 = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|x86.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.AppStore|x86.Build.0 = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Debug|ARM.ActiveCfg = Debug|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Debug|iPhone.ActiveCfg = Debug|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Debug|x86.ActiveCfg = Debug|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Debug|x86.Build.0 = Debug|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Release|Any CPU.ActiveCfg = Release|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Release|ARM.ActiveCfg = Release|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Release|iPhone.ActiveCfg = Release|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Release|x86.ActiveCfg = Release|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Release|x86.Build.0 = Release|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Template|Any CPU.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Template|ARM.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Template|iPhone.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Template|x86.ActiveCfg = Template|Win32 + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D}.Template|x86.Build.0 = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|Any CPU.Build.0 = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|ARM.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|ARM.Build.0 = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|iPhone.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|iPhone.Build.0 = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|x86.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.AppStore|x86.Build.0 = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Debug|ARM.ActiveCfg = Debug|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Debug|iPhone.ActiveCfg = Debug|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Debug|x86.ActiveCfg = Debug|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Debug|x86.Build.0 = Debug|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Release|Any CPU.ActiveCfg = Release|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Release|ARM.ActiveCfg = Release|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Release|iPhone.ActiveCfg = Release|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Release|x86.ActiveCfg = Release|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Release|x86.Build.0 = Release|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Template|Any CPU.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Template|ARM.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Template|iPhone.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Template|x86.ActiveCfg = Template|Win32 + {D884A075-E3B8-44E1-838D-74F28B33391B}.Template|x86.Build.0 = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|Any CPU.Build.0 = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|ARM.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|ARM.Build.0 = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|iPhone.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|iPhone.Build.0 = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|x86.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.AppStore|x86.Build.0 = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Debug|ARM.ActiveCfg = Debug|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Debug|iPhone.ActiveCfg = Debug|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Debug|x86.ActiveCfg = Debug|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Debug|x86.Build.0 = Debug|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Release|Any CPU.ActiveCfg = Release|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Release|ARM.ActiveCfg = Release|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Release|iPhone.ActiveCfg = Release|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Release|x86.ActiveCfg = Release|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Release|x86.Build.0 = Release|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Template|Any CPU.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Template|ARM.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Template|iPhone.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Template|x86.ActiveCfg = Template|Win32 + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA}.Template|x86.Build.0 = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|Any CPU.Build.0 = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|ARM.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|ARM.Build.0 = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|iPhone.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|iPhone.Build.0 = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|x86.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.AppStore|x86.Build.0 = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Debug|ARM.ActiveCfg = Debug|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Debug|iPhone.ActiveCfg = Debug|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Debug|x86.ActiveCfg = Debug|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Debug|x86.Build.0 = Debug|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Release|Any CPU.ActiveCfg = Release|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Release|ARM.ActiveCfg = Release|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Release|iPhone.ActiveCfg = Release|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Release|x86.ActiveCfg = Release|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Release|x86.Build.0 = Release|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Template|Any CPU.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Template|ARM.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Template|iPhone.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Template|x86.ActiveCfg = Template|Win32 + {4132C330-95D9-4F68-A51A-3B90381587C5}.Template|x86.Build.0 = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|Any CPU.Build.0 = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|ARM.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|ARM.Build.0 = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|iPhone.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|iPhone.Build.0 = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|x86.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.AppStore|x86.Build.0 = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Debug|ARM.ActiveCfg = Debug|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Debug|iPhone.ActiveCfg = Debug|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Debug|x86.ActiveCfg = Debug|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Debug|x86.Build.0 = Debug|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Release|Any CPU.ActiveCfg = Release|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Release|ARM.ActiveCfg = Release|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Release|iPhone.ActiveCfg = Release|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Release|x86.ActiveCfg = Release|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Release|x86.Build.0 = Release|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Template|Any CPU.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Template|ARM.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Template|iPhone.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Template|x86.ActiveCfg = Template|Win32 + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18}.Template|x86.Build.0 = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|Any CPU.Build.0 = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|ARM.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|ARM.Build.0 = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|iPhone.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|iPhone.Build.0 = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|x86.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.AppStore|x86.Build.0 = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Debug|ARM.ActiveCfg = Debug|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Debug|iPhone.ActiveCfg = Debug|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Debug|x86.ActiveCfg = Debug|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Debug|x86.Build.0 = Debug|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Release|Any CPU.ActiveCfg = Release|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Release|ARM.ActiveCfg = Release|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Release|iPhone.ActiveCfg = Release|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Release|x86.ActiveCfg = Release|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Release|x86.Build.0 = Release|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Template|Any CPU.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Template|ARM.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Template|iPhone.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Template|x86.ActiveCfg = Template|Win32 + {0B629BA3-D138-407A-801D-DBE7C8DC4324}.Template|x86.Build.0 = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|Any CPU.Build.0 = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|ARM.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|ARM.Build.0 = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|iPhone.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|iPhone.Build.0 = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|x86.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.AppStore|x86.Build.0 = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Debug|ARM.ActiveCfg = Debug|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Debug|iPhone.ActiveCfg = Debug|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Debug|x86.ActiveCfg = Debug|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Debug|x86.Build.0 = Debug|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Release|Any CPU.ActiveCfg = Release|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Release|ARM.ActiveCfg = Release|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Release|iPhone.ActiveCfg = Release|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Release|x86.ActiveCfg = Release|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Release|x86.Build.0 = Release|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Template|Any CPU.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Template|ARM.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Template|iPhone.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Template|x86.ActiveCfg = Template|Win32 + {778BCC7F-40F9-4309-9A88-C0F60D9B364D}.Template|x86.Build.0 = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|Any CPU.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|Any CPU.Build.0 = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|ARM.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|ARM.Build.0 = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|iPhone.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|iPhone.Build.0 = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|iPhoneSimulator.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|iPhoneSimulator.Build.0 = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|x86.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.AppStore|x86.Build.0 = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz2DRelease|Any CPU.ActiveCfg = Blitz2DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz2DRelease|ARM.ActiveCfg = Blitz2DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz2DRelease|iPhone.ActiveCfg = Blitz2DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz2DRelease|iPhoneSimulator.ActiveCfg = Blitz2DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz2DRelease|x86.ActiveCfg = Blitz2DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz2DRelease|x86.Build.0 = Blitz2DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz3DRelease|Any CPU.ActiveCfg = Blitz3DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz3DRelease|ARM.ActiveCfg = Blitz3DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz3DRelease|iPhone.ActiveCfg = Blitz3DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz3DRelease|iPhoneSimulator.ActiveCfg = Blitz3DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz3DRelease|x86.ActiveCfg = Blitz3DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Blitz3DRelease|x86.Build.0 = Blitz3DRelease|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Debug|ARM.ActiveCfg = Debug|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Debug|iPhone.ActiveCfg = Debug|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Debug|x86.ActiveCfg = Debug|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Debug|x86.Build.0 = Debug|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Release|Any CPU.ActiveCfg = Release|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Release|ARM.ActiveCfg = Release|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Release|iPhone.ActiveCfg = Release|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Release|iPhoneSimulator.ActiveCfg = Release|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Release|x86.ActiveCfg = Release|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Release|x86.Build.0 = Release|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Template|Any CPU.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Template|ARM.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Template|iPhone.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Template|iPhoneSimulator.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Template|x86.ActiveCfg = Template|Win32 + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E}.Template|x86.Build.0 = Template|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 0000000..109ec9d Binary files /dev/null and b/UpgradeLog.htm differ diff --git a/asm_makeinsts/asm_makeinsts.vcxproj b/asm_makeinsts/asm_makeinsts.vcxproj new file mode 100644 index 0000000..426d4b2 --- /dev/null +++ b/asm_makeinsts/asm_makeinsts.vcxproj @@ -0,0 +1,133 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + {E85F5BD3-FEA3-4342-885E-2C00AFBFE12E} + 10.0.10586.0 + + + + Application + v140 + false + MultiByte + + + Application + v140 + false + MultiByte + + + + + + + + + + + + + + + .\Release\ + .\Release\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + + MultiThreaded + AnySuitable + true + MaxSpeed + true + Level3 + true + Size + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + .\Release\ + .\Release\asm_makeinsts.pch + .\Release\ + .\Release\ + + + .\Release\asm_makeinsts.tlb + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\asm_makeinsts.bsc + + + true + Console + .\Release\asm_makeinsts.exe + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\asm_makeinsts.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + .\Debug\asm_makeinsts.tlb + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\asm_makeinsts.bsc + + + true + true + Console + .\Debug\asm_makeinsts.exe + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + \ No newline at end of file diff --git a/bblaunch/bblaunch.vcxproj b/bblaunch/bblaunch.vcxproj new file mode 100644 index 0000000..af9a1d3 --- /dev/null +++ b/bblaunch/bblaunch.vcxproj @@ -0,0 +1,323 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {C74A383E-81B0-4679-AAC9-535C94C92EA5} + 10.0.10586.0 + + + + Application + v140 + + + Application + v140 + false + MultiByte + + + Application + v140 + false + MultiByte + + + Application + v140 + false + MultiByte + + + Application + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\bblaunch___Win32_Blitz2DRelease\ + .\bblaunch___Win32_Blitz2DRelease\ + false + + + .\bblaunch___Win32_Blitz3DRelease\ + .\bblaunch___Win32_Blitz3DRelease\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + false + + + .\Release\ + .\Release\ + false + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\bblaunch___Win32_Blitz2DRelease\ + .\bblaunch___Win32_Blitz2DRelease\bblaunch.pch + .\bblaunch___Win32_Blitz2DRelease\ + .\bblaunch___Win32_Blitz2DRelease\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\bblaunch___Win32_Blitz2DRelease\bblaunch.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\bblaunch___Win32_Blitz2DRelease\bblaunch.bsc + + + true + Windows + ..\..\release\blitz2drelease\BlitzBasic.exe + dxguid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _WINDOWS;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\bblaunch___Win32_Blitz3DRelease\ + .\bblaunch___Win32_Blitz3DRelease\bblaunch.pch + .\bblaunch___Win32_Blitz3DRelease\ + .\bblaunch___Win32_Blitz3DRelease\ + StdCall + + + true + NDEBUG;%(PreprocessorDefinitions) + .\bblaunch___Win32_Blitz3DRelease\bblaunch.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\bblaunch___Win32_Blitz3DRelease\bblaunch.bsc + + + true + Windows + ../_release/Blitz3D.exe + dxguid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\bblaunch.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\bblaunch.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\bblaunch.bsc + + + true + true + Windows + ..\blitzbasic\blitzbasic.exe + /FIXED:NO + dxguid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + AnySuitable + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Release\ + .\Release\bblaunch.pch + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\bblaunch.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\bblaunch.bsc + + + true + Windows + ..\blitzbasic\blitzbasic.exe + dxguid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + {df8caa9d-7154-4d5f-bccc-0d7bb57c7354} + false + + + {5fa2fd4a-f9a4-41ba-9484-07c3a57a87e3} + false + + + {be0ba538-6215-4836-9227-1d3627e40d61} + false + + + {b61d8348-b715-42b8-a759-c7bbb0c8cd4d} + false + + + {c23af61e-9509-411f-933e-17db18884b21} + false + + + {d884a075-e3b8-44e1-838d-74f28b33391b} + false + + + {3e355353-96d8-4aaf-bf95-8e6ca0d4b1ba} + false + + + {4132c330-95d9-4f68-a51a-3b90381587c5} + false + + + {ff2d8bf7-1930-4cab-bc48-05cd33b7dc18} + false + + + {0b629ba3-d138-407a-801d-dbe7c8dc4324} + false + + + {778bcc7f-40f9-4309-9a88-c0f60d9b364d} + false + + + {6bcfc5ca-ea71-4ae9-8b96-28b8701f939e} + false + + + + + + \ No newline at end of file diff --git a/bbruntime/bbblitz3d.cpp b/bbruntime/bbblitz3d.cpp index bf36a5e..8a458c9 100644 --- a/bbruntime/bbblitz3d.cpp +++ b/bbruntime/bbblitz3d.cpp @@ -1,8 +1,6 @@ #include "std.h" -#ifdef PRO - #include "bbblitz3d.h" #include "bbgraphics.h" #include "../blitz3d/blitz3d.h" @@ -1855,7 +1853,7 @@ void bbPointEntity( Entity *e,Entity *t,float roll ){ void bbAlignToVector( Entity *e,float nx,float ny,float nz,int axis,float rate ){ Vector ax( nx,ny,nz ); float l=ax.length(); - if( l<=EPSILON ) return; + if( l<=FLT_EPSILON ) return; ax/=l; Quat q=e->getWorldRotation(); @@ -1863,9 +1861,9 @@ void bbAlignToVector( Entity *e,float nx,float ny,float nz,int axis,float rate float dp=ax.dot( tv ); - if( dp>=1-EPSILON ) return; + if( dp>=1-FLT_EPSILON ) return; - if( dp<=-1+EPSILON ){ + if( dp<=-1+FLT_EPSILON ){ float an=PI*rate/2; Vector cp=(axis==1) ? q.j() : (axis==2 ? q.k() : q.i()); e->setWorldRotation( Quat( cosf(an),cp*sinf(an) ) * q ); @@ -2225,6 +2223,4 @@ void blitz3d_link( void (*rtSym)( const char *sym,void *pc ) ){ rtSym( "NameEntity%entity$name",bbNameEntity ); rtSym( "$EntityName%entity",bbEntityName ); rtSym( "$EntityClass%entity",bbEntityClass ); -} - -#endif +} \ No newline at end of file diff --git a/bbruntime/bbruntime.vcxproj b/bbruntime/bbruntime.vcxproj new file mode 100644 index 0000000..5136ee9 --- /dev/null +++ b/bbruntime/bbruntime.vcxproj @@ -0,0 +1,285 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {DF8CAA9D-7154-4D5F-BCCC-0D7BB57C7354} + 10.0.10586.0 + + + + Application + v140 + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + .\bbruntime___Win32_Blitz2DRelease\ + .\bbruntime___Win32_Blitz2DRelease\ + false + + + .\bbruntime___Win32_Blitz3DRelease\ + .\bbruntime___Win32_Blitz3DRelease\ + false + + + .\Release\ + .\Release\ + false + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\bbruntime.pch + Use + std.h + .\Debug\ + .\Debug\ + EnableFastChecks + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\bbruntime.bsc + + + true + .\Debug\bbruntime.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\bbruntime___Win32_Blitz2DRelease\ + .\bbruntime___Win32_Blitz2DRelease\bbruntime.pch + Use + std.h + .\bbruntime___Win32_Blitz2DRelease\ + .\bbruntime___Win32_Blitz2DRelease\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\bbruntime___Win32_Blitz2DRelease\bbruntime.bsc + + + true + .\bbruntime___Win32_Blitz2DRelease\bbruntime.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + _LIB;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\bbruntime___Win32_Blitz3DRelease\ + .\bbruntime___Win32_Blitz3DRelease\bbruntime.pch + + .\bbruntime___Win32_Blitz3DRelease\ + .\bbruntime___Win32_Blitz3DRelease\ + StdCall + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\bbruntime___Win32_Blitz3DRelease\bbruntime.bsc + + + true + .\bbruntime___Win32_Blitz3DRelease\bbruntime.lib + + + + + MultiThreaded + AnySuitable + true + MaxSpeed + true + Level3 + true + Size + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\bbruntime.pch + Use + std.h + .\Release\ + .\Release\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\bbruntime.bsc + + + true + .\Release\bbruntime.lib + + + + + Use + + + + + + + + + + Use + std.h + + + + + + + + + Create + std.h + Create + std.h + Create + std.h + Create + std.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bbruntime/bbruntime.vcxproj.filters b/bbruntime/bbruntime.vcxproj.filters new file mode 100644 index 0000000..86c5100 --- /dev/null +++ b/bbruntime/bbruntime.vcxproj.filters @@ -0,0 +1,127 @@ + + + + + {2be14919-a9d3-4029-97d0-c02d529d1a8e} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {2a5eb825-a520-433a-88ff-a2f0408189ac} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/bbruntime/bbsockets.cpp b/bbruntime/bbsockets.cpp index 9d0cbe7..15f2eaa 100644 --- a/bbruntime/bbsockets.cpp +++ b/bbruntime/bbsockets.cpp @@ -8,12 +8,12 @@ static int recv_timeout; static int read_timeout; static int accept_timeout; -static void close( SOCKET sock,int e ){ - if( e<0 ){ - int opt=1; - setsockopt( sock,SOL_SOCKET,SO_DONTLINGER,(char*)&opt,sizeof(opt) ); +static void close(SOCKET sock, int e) { + if (e < 0) { + int opt = 1; + setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (char*)&opt, sizeof(opt)); } - closesocket( sock ); + closesocket(sock); } class UDPStream; @@ -24,18 +24,18 @@ static set udp_set; static set tcp_set; static set server_set; -class UDPStream : public bbStream{ +class UDPStream : public bbStream { public: - UDPStream( SOCKET s ); + UDPStream(SOCKET s); ~UDPStream(); - int read( char *buff,int size ); - int write( const char *buff,int size ); + int read(char *buff, int size); + int write(const char *buff, int size); int avail(); int eof(); int recv(); - int send( int ip,int port ); + int send(int ip, int port); int getIP(); int getPort(); int getMsgIP(); @@ -43,108 +43,108 @@ public: private: SOCKET sock; - vector in_buf,out_buf; - sockaddr_in addr,in_addr,out_addr; - int in_get,e; + vector in_buf, out_buf; + sockaddr_in addr, in_addr, out_addr; + int in_get, e; }; -UDPStream::UDPStream( SOCKET s ):sock(s),in_get(0),e(0){ - int len=sizeof(addr); - getsockname( s,(sockaddr*)&addr,&len ); - in_addr=out_addr=addr; +UDPStream::UDPStream(SOCKET s) :sock(s), in_get(0), e(0) { + int len = sizeof(addr); + getsockname(s, (sockaddr*)&addr, &len); + in_addr = out_addr = addr; } -UDPStream::~UDPStream(){ - close( sock,e ); +UDPStream::~UDPStream() { + close(sock, e); } -int UDPStream::read( char *buff,int size ){ - if( e ) return 0; - int n=in_buf.size()-in_get; - if( ngetMilliSecs()+recv_timeout; - for(;;){ - int dt=0; - if( recv_timeout ){ - dt=tout-gx_runtime->getMilliSecs(); - if( dt<0 ) dt=0; + if (recv_timeout) tout = gx_runtime->getMilliSecs() + recv_timeout; + for (;;) { + int dt = 0; + if (recv_timeout) { + dt = tout - gx_runtime->getMilliSecs(); + if (dt < 0) dt = 0; } - fd_set fd={ 1,sock }; - timeval tv={ dt/1000,(dt%1000)*1000 }; - int n=::select( 0,&fd,0,0,&tv ); - if( !n ) return 0; - if( n!=1 ){ e=-1;return 0; } - unsigned long sz=-1; - if( ioctlsocket( sock,FIONREAD,&sz ) ){ e=-1;return 0; } - in_buf.resize( sz );in_get=0; - int len=sizeof(in_addr); - n=::recvfrom( sock,in_buf.begin(),sz,0,(sockaddr*)&in_addr,&len ); - if( n==SOCKET_ERROR ) continue; //{ e=-1;return 0; } - in_buf.resize( n ); + fd_set fd = { 1,sock }; + timeval tv = { dt / 1000,(dt % 1000) * 1000 }; + int n = ::select(0, &fd, 0, 0, &tv); + if (!n) return 0; + if (n != 1) { e = -1; return 0; } + unsigned long sz = -1; + if (ioctlsocket(sock, FIONREAD, &sz)) { e = -1; return 0; } + in_buf.resize(sz); in_get = 0; + int len = sizeof(in_addr); + n = ::recvfrom(sock, &(in_buf.begin())[0], sz, 0, (sockaddr*)&in_addr, &len); + if (n == SOCKET_ERROR) continue; //{ e=-1;return 0; } + in_buf.resize(n); return getMsgIP(); } return 0; } //send, empty buffer -int UDPStream::send( int ip,int port ){ - if( e ) return 0; - int sz=out_buf.size(); - out_addr.sin_addr.S_un.S_addr=htonl( ip ); - out_addr.sin_port=htons( port ? port : addr.sin_port ); - int n=::sendto( sock,out_buf.begin(),sz,0,(sockaddr*)&out_addr,sizeof(out_addr) ); - if( n!=sz ) return e=-1; +int UDPStream::send(int ip, int port) { + if (e) return 0; + int sz = out_buf.size(); + out_addr.sin_addr.S_un.S_addr = htonl(ip); + out_addr.sin_port = htons(port ? port : addr.sin_port); + int n = ::sendto(sock, &(out_buf.begin())[0], sz, 0, (sockaddr*)&out_addr, sizeof(out_addr)); + if (n != sz) return e = -1; out_buf.clear(); return sz; } -int UDPStream::getIP(){ - return ntohl( addr.sin_addr.S_un.S_addr ); +int UDPStream::getIP() { + return ntohl(addr.sin_addr.S_un.S_addr); } -int UDPStream::getPort(){ - return ntohs( addr.sin_port ); +int UDPStream::getPort() { + return ntohs(addr.sin_port); } -int UDPStream::getMsgIP(){ - return ntohl( in_addr.sin_addr.S_un.S_addr ); +int UDPStream::getMsgIP() { + return ntohl(in_addr.sin_addr.S_un.S_addr); } -int UDPStream::getMsgPort(){ - return ntohs( in_addr.sin_port ); +int UDPStream::getMsgPort() { + return ntohs(in_addr.sin_port); } -class TCPStream : public bbStream{ +class TCPStream : public bbStream { public: - TCPStream( SOCKET s,TCPServer *t ); + TCPStream(SOCKET s, TCPServer *t); ~TCPStream(); - int read( char *buff,int size ); - int write( const char *buff,int size ); + int read(char *buff, int size); + int write(const char *buff, int size); int avail(); int eof(); @@ -154,17 +154,17 @@ public: private: SOCKET sock; TCPServer *server; - int e,ip,port; + int e, ip, port; }; -class TCPServer{ +class TCPServer { public: - TCPServer( SOCKET S ); + TCPServer(SOCKET S); ~TCPServer(); TCPStream *accept(); - void remove( TCPStream *s ); + void remove(TCPStream *s); private: int e; @@ -172,258 +172,258 @@ private: set accepted_set; }; -TCPStream::TCPStream( SOCKET s,TCPServer *t ):sock(s),server(t),e(0){ +TCPStream::TCPStream(SOCKET s, TCPServer *t) :sock(s), server(t), e(0) { sockaddr_in addr; - int len=sizeof(addr); - if( getpeername( s,(sockaddr*)&addr,&len ) ){ - ip=port=0; + int len = sizeof(addr); + if (getpeername(s, (sockaddr*)&addr, &len)) { + ip = port = 0; return; } - ip=ntohl(addr.sin_addr.S_un.S_addr); - port=ntohs(addr.sin_port); + ip = ntohl(addr.sin_addr.S_un.S_addr); + port = ntohs(addr.sin_port); } -TCPStream::~TCPStream(){ - if( server ) server->remove( this ); - close( sock,e ); +TCPStream::~TCPStream() { + if (server) server->remove(this); + close(sock, e); } -int TCPStream::read( char *buff,int size ){ - if( e ) return 0; - char *b=buff,*l=buff+size; +int TCPStream::read(char *buff, int size) { + if (e) return 0; + char *b = buff, *l = buff + size; int tout; - if( read_timeout ) tout=gx_runtime->getMilliSecs()+read_timeout; - while( bgetMilliSecs(); - if( dt<0 ) dt=0; + if (read_timeout) tout = gx_runtime->getMilliSecs() + read_timeout; + while (b < l) { + int dt = 0; + if (read_timeout) { + dt = tout - gx_runtime->getMilliSecs(); + if (dt < 0) dt = 0; } - fd_set fd={ 1,sock }; - timeval tv={ dt/1000,(dt%1000)*1000 }; - int n=::select( 0,&fd,0,0,&tv ); - if( n!=1 ){ e=-1;break; } - n=::recv( sock,b,l-b,0 ); - if( n==0 ){ e=1;break; } - if( n==SOCKET_ERROR ){ e=-1;break; } - b+=n; + fd_set fd = { 1,sock }; + timeval tv = { dt / 1000,(dt % 1000) * 1000 }; + int n = ::select(0, &fd, 0, 0, &tv); + if (n != 1) { e = -1; break; } + n = ::recv(sock, b, l - b, 0); + if (n == 0) { e = 1; break; } + if (n == SOCKET_ERROR) { e = -1; break; } + b += n; } - return b-buff; + return b - buff; } -int TCPStream::write( const char *buff,int size ){ - if( e ) return 0; - int n=::send( sock,buff,size,0 ); - if( n==SOCKET_ERROR ){ e=-1;return 0; } +int TCPStream::write(const char *buff, int size) { + if (e) return 0; + int n = ::send(sock, buff, size, 0); + if (n == SOCKET_ERROR) { e = -1; return 0; } return n; } -int TCPStream::avail(){ +int TCPStream::avail() { unsigned long t; - int n=::ioctlsocket( sock,FIONREAD,&t ); - if( n==SOCKET_ERROR ){ e=-1;return 0; } + int n = ::ioctlsocket(sock, FIONREAD, &t); + if (n == SOCKET_ERROR) { e = -1; return 0; } return t; } -int TCPStream::eof(){ - if( e ) return e; - fd_set fd={ 1,sock }; - timeval tv={ 0,0 }; - switch( ::select( 0,&fd,0,0,&tv ) ){ +int TCPStream::eof() { + if (e) return e; + fd_set fd = { 1,sock }; + timeval tv = { 0,0 }; + switch (::select(0, &fd, 0, 0, &tv)) { case 0:break; - case 1:if( !avail() ) e=1;break; - default:e=-1; + case 1:if (!avail()) e = 1; break; + default:e = -1; } return e; } -int TCPStream::getIP(){ +int TCPStream::getIP() { return ip; } -int TCPStream::getPort(){ +int TCPStream::getPort() { return port; } -TCPServer::TCPServer( SOCKET s ):sock(s),e(0){ +TCPServer::TCPServer(SOCKET s) :sock(s), e(0) { } -TCPServer::~TCPServer(){ - while( accepted_set.size() ) delete *accepted_set.begin(); - close( sock,e ); +TCPServer::~TCPServer() { + while (accepted_set.size()) delete *accepted_set.begin(); + close(sock, e); } -TCPStream *TCPServer::accept(){ - if( e ) return 0; - fd_set fd={ 1,sock }; - timeval tv={ accept_timeout/1000,(accept_timeout%1000)*1000 }; - int n=::select( 0,&fd,0,0,&tv ); - if( n==0 ) return 0; - if( n!=1 ){ e=-1;return 0; } - SOCKET t=::accept( sock,0,0 ); - if( t==INVALID_SOCKET ){ e=-1;return 0; } - TCPStream *s=d_new TCPStream( t,this ); - accepted_set.insert( s ); +TCPStream *TCPServer::accept() { + if (e) return 0; + fd_set fd = { 1,sock }; + timeval tv = { accept_timeout / 1000,(accept_timeout % 1000) * 1000 }; + int n = ::select(0, &fd, 0, 0, &tv); + if (n == 0) return 0; + if (n != 1) { e = -1; return 0; } + SOCKET t = ::accept(sock, 0, 0); + if (t == INVALID_SOCKET) { e = -1; return 0; } + TCPStream *s = d_new TCPStream(t, this); + accepted_set.insert(s); return s; } -void TCPServer::remove( TCPStream *s ){ - accepted_set.erase( s ); +void TCPServer::remove(TCPStream *s) { + accepted_set.erase(s); } -static inline void debugUDPStream( UDPStream *p ){ - if( debug && !udp_set.count(p) ){ - RTEX( "UDP Stream does not exist" ); +static inline void debugUDPStream(UDPStream *p) { + if (debug && !udp_set.count(p)) { + RTEX("UDP Stream does not exist"); } } -static inline void debugTCPStream( TCPStream *p ){ - if( debug && !tcp_set.count(p) ){ - RTEX( "TCP Stream does not exist" ); +static inline void debugTCPStream(TCPStream *p) { + if (debug && !tcp_set.count(p)) { + RTEX("TCP Stream does not exist"); } } -static inline void debugTCPServer( TCPServer *p ){ - if( debug && !server_set.count(p) ){ - RTEX( "TCP Server does not exist" ); +static inline void debugTCPServer(TCPServer *p) { + if (debug && !server_set.count(p)) { + RTEX("TCP Server does not exist"); } } static vector host_ips; -int bbCountHostIPs( BBStr *host ){ +int bbCountHostIPs(BBStr *host) { host_ips.clear(); - HOSTENT *h=gethostbyname( host->c_str() ); - delete host;if( !h ) return 0; - char **p=h->h_addr_list; - while( char *t=*p++ ) host_ips.push_back( ntohl(*(int*)t) ); + HOSTENT *h = gethostbyname(host->c_str()); + delete host; if (!h) return 0; + char **p = h->h_addr_list; + while (char *t = *p++) host_ips.push_back(ntohl(*(int*)t)); return host_ips.size(); } -int bbHostIP( int index ){ - if( debug ){ - if( index<1 || index>host_ips.size() ){ - RTEX( "Host index out of range" ); +int bbHostIP(int index) { + if (debug) { + if (index<1 || index>host_ips.size()) { + RTEX("Host index out of range"); } } - return host_ips[index-1]; + return host_ips[index - 1]; } -UDPStream *bbCreateUDPStream( int port ){ - if( !socks_ok ) return 0; - SOCKET s=::socket( AF_INET,SOCK_DGRAM,0 ); - if( s!=INVALID_SOCKET ){ - sockaddr_in addr={AF_INET,htons(port)}; - if( !::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ - UDPStream *p=d_new UDPStream( s ); - udp_set.insert( p ); +UDPStream *bbCreateUDPStream(int port) { + if (!socks_ok) return 0; + SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0); + if (s != INVALID_SOCKET) { + sockaddr_in addr = { AF_INET,htons(port) }; + if (!::bind(s, (sockaddr*)&addr, sizeof(addr))) { + UDPStream *p = d_new UDPStream(s); + udp_set.insert(p); return p; } - ::closesocket( s ); + ::closesocket(s); } return 0; } -void bbCloseUDPStream( UDPStream *p ){ - debugUDPStream( p ); - udp_set.erase( p ); +void bbCloseUDPStream(UDPStream *p) { + debugUDPStream(p); + udp_set.erase(p); delete p; } -int bbRecvUDPMsg( UDPStream *p ){ - debugUDPStream( p ); +int bbRecvUDPMsg(UDPStream *p) { + debugUDPStream(p); return p->recv(); } -void bbSendUDPMsg( UDPStream *p,int ip,int port ){ - debugUDPStream( p ); - p->send( ip,port ); +void bbSendUDPMsg(UDPStream *p, int ip, int port) { + debugUDPStream(p); + p->send(ip, port); } -int bbUDPStreamIP( UDPStream *p ){ - debugUDPStream( p ); +int bbUDPStreamIP(UDPStream *p) { + debugUDPStream(p); return p->getIP(); } -int bbUDPStreamPort( UDPStream *p ){ - debugUDPStream( p ); +int bbUDPStreamPort(UDPStream *p) { + debugUDPStream(p); return p->getPort(); } -int bbUDPMsgIP( UDPStream *p ){ - debugUDPStream( p ); +int bbUDPMsgIP(UDPStream *p) { + debugUDPStream(p); return p->getMsgIP(); } -int bbUDPMsgPort( UDPStream *p ){ - debugUDPStream( p ); +int bbUDPMsgPort(UDPStream *p) { + debugUDPStream(p); return p->getMsgPort(); } -void bbUDPTimeouts( int rt ){ - recv_timeout=rt; +void bbUDPTimeouts(int rt) { + recv_timeout = rt; } -BBStr *bbDottedIP( int ip ){ +BBStr *bbDottedIP(int ip) { return d_new BBStr( - itoa((ip>>24)&255)+"."+itoa((ip>>16)&255)+"."+ - itoa((ip>>8)&255)+"."+itoa(ip&255) ); + itoa((ip >> 24) & 255) + "." + itoa((ip >> 16) & 255) + "." + + itoa((ip >> 8) & 255) + "." + itoa(ip & 255)); } -static int findHostIP( const string &t ){ - int ip=inet_addr( t.c_str() ); - if( ip!=INADDR_NONE ) return ip; - HOSTENT *h=gethostbyname( t.c_str() ); - if( !h ) return -1; +static int findHostIP(const string &t) { + int ip = inet_addr(t.c_str()); + if (ip != INADDR_NONE) return ip; + HOSTENT *h = gethostbyname(t.c_str()); + if (!h) return -1; char *p; - for( char **list=h->h_addr_list;p=*list;++list ){ + for (char **list = h->h_addr_list; p = *list; ++list) { return *(int*)p; } return 0; } -TCPStream *bbOpenTCPStream( BBStr *server,int port,int local_port ){ - if( !socks_ok ){ +TCPStream *bbOpenTCPStream(BBStr *server, int port, int local_port) { + if (!socks_ok) { delete server; return 0; } - int ip=findHostIP( *server );delete server; - if( ip==-1 ) return 0; - SOCKET s=::socket( AF_INET,SOCK_STREAM,0 ); - if( s!=INVALID_SOCKET ){ - if( local_port ){ - sockaddr_in addr={AF_INET,htons(local_port)}; - if( ::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ - ::closesocket( s ); + int ip = findHostIP(*server); delete server; + if (ip == -1) return 0; + SOCKET s = ::socket(AF_INET, SOCK_STREAM, 0); + if (s != INVALID_SOCKET) { + if (local_port) { + sockaddr_in addr = { AF_INET,htons(local_port) }; + if (::bind(s, (sockaddr*)&addr, sizeof(addr))) { + ::closesocket(s); return 0; } } - sockaddr_in addr={AF_INET,htons(port)}; - addr.sin_addr.S_un.S_addr=ip; - if( !::connect( s,(sockaddr*)&addr,sizeof(addr) ) ){ - TCPStream *p=d_new TCPStream( s,0 ); - tcp_set.insert( p ); + sockaddr_in addr = { AF_INET,htons(port) }; + addr.sin_addr.S_un.S_addr = ip; + if (!::connect(s, (sockaddr*)&addr, sizeof(addr))) { + TCPStream *p = d_new TCPStream(s, 0); + tcp_set.insert(p); return p; } - ::closesocket( s ); + ::closesocket(s); } return 0; } -void bbCloseTCPStream( TCPStream *p ){ - debugTCPStream( p ); - tcp_set.erase( p ); +void bbCloseTCPStream(TCPStream *p) { + debugTCPStream(p); + tcp_set.erase(p); delete p; } -TCPServer * bbCreateTCPServer( int port ){ - SOCKET s=::socket( AF_INET,SOCK_STREAM,0 ); - if( s!=INVALID_SOCKET ){ - sockaddr_in addr={AF_INET,htons(port)}; - if( !::bind( s,(sockaddr*)&addr,sizeof(addr) ) ){ - if( !::listen( s,SOMAXCONN ) ){ - TCPServer *p=d_new TCPServer( s ); - server_set.insert( p ); +TCPServer * bbCreateTCPServer(int port) { + SOCKET s = ::socket(AF_INET, SOCK_STREAM, 0); + if (s != INVALID_SOCKET) { + sockaddr_in addr = { AF_INET,htons(port) }; + if (!::bind(s, (sockaddr*)&addr, sizeof(addr))) { + if (!::listen(s, SOMAXCONN)) { + TCPServer *p = d_new TCPServer(s); + server_set.insert(p); return p; } } @@ -432,74 +432,74 @@ TCPServer * bbCreateTCPServer( int port ){ return 0; } -void bbCloseTCPServer( TCPServer *p ){ - debugTCPServer( p ); - server_set.erase( p ); +void bbCloseTCPServer(TCPServer *p) { + debugTCPServer(p); + server_set.erase(p); delete p; } -TCPStream * bbAcceptTCPStream( TCPServer *server ){ - debugTCPServer( server ); - if( !gx_runtime->idle() ) RTEX( 0 ); - if( TCPStream *tcp=server->accept() ){ - tcp_set.insert( tcp ); +TCPStream * bbAcceptTCPStream(TCPServer *server) { + debugTCPServer(server); + if (!gx_runtime->idle()) RTEX(0); + if (TCPStream *tcp = server->accept()) { + tcp_set.insert(tcp); return tcp; } return 0; } -int bbTCPStreamIP( TCPStream *p ){ - debugTCPStream( p ); +int bbTCPStreamIP(TCPStream *p) { + debugTCPStream(p); return p->getIP(); } -int bbTCPStreamPort( TCPStream *p ){ - debugTCPStream( p ); +int bbTCPStreamPort(TCPStream *p) { + debugTCPStream(p); return p->getPort(); } -void bbTCPTimeouts( int rt,int at ){ - read_timeout=rt; - accept_timeout=at; +void bbTCPTimeouts(int rt, int at) { + read_timeout = rt; + accept_timeout = at; } -bool sockets_create(){ - socks_ok=WSAStartup( 0x0101,&wsadata )==0; - recv_timeout=0; - read_timeout=10000; - accept_timeout=0; +bool sockets_create() { + socks_ok = WSAStartup(0x0101, &wsadata) == 0; + recv_timeout = 0; + read_timeout = 10000; + accept_timeout = 0; return true; } -bool sockets_destroy(){ - while( udp_set.size() ) bbCloseUDPStream( *udp_set.begin() ); - while( tcp_set.size() ) bbCloseTCPStream( *tcp_set.begin() ); - while( server_set.size() ) bbCloseTCPServer( *server_set.begin() ); - if( socks_ok ) WSACleanup(); +bool sockets_destroy() { + while (udp_set.size()) bbCloseUDPStream(*udp_set.begin()); + while (tcp_set.size()) bbCloseTCPStream(*tcp_set.begin()); + while (server_set.size()) bbCloseTCPServer(*server_set.begin()); + if (socks_ok) WSACleanup(); return true; } -void sockets_link( void(*rtSym)(const char*,void*) ){ - rtSym( "$DottedIP%IP",bbDottedIP ); - rtSym( "%CountHostIPs$host_name",bbCountHostIPs ); - rtSym( "%HostIP%host_index",bbHostIP ); +void sockets_link(void(*rtSym)(const char*, void*)) { + rtSym("$DottedIP%IP", bbDottedIP); + rtSym("%CountHostIPs$host_name", bbCountHostIPs); + rtSym("%HostIP%host_index", bbHostIP); - rtSym( "%CreateUDPStream%port=0",bbCreateUDPStream ); - rtSym( "CloseUDPStream%udp_stream",bbCloseUDPStream ); - rtSym( "SendUDPMsg%udp_stream%dest_ip%dest_port=0",bbSendUDPMsg ); - rtSym( "%RecvUDPMsg%udp_stream",bbRecvUDPMsg ); - rtSym( "%UDPStreamIP%udp_stream",bbUDPStreamIP ); - rtSym( "%UDPStreamPort%udp_stream",bbUDPStreamPort ); - rtSym( "%UDPMsgIP%udp_stream",bbUDPMsgIP ); - rtSym( "%UDPMsgPort%udp_stream",bbUDPMsgPort ); - rtSym( "UDPTimeouts%recv_timeout",bbUDPTimeouts ); + rtSym("%CreateUDPStream%port=0", bbCreateUDPStream); + rtSym("CloseUDPStream%udp_stream", bbCloseUDPStream); + rtSym("SendUDPMsg%udp_stream%dest_ip%dest_port=0", bbSendUDPMsg); + rtSym("%RecvUDPMsg%udp_stream", bbRecvUDPMsg); + rtSym("%UDPStreamIP%udp_stream", bbUDPStreamIP); + rtSym("%UDPStreamPort%udp_stream", bbUDPStreamPort); + rtSym("%UDPMsgIP%udp_stream", bbUDPMsgIP); + rtSym("%UDPMsgPort%udp_stream", bbUDPMsgPort); + rtSym("UDPTimeouts%recv_timeout", bbUDPTimeouts); - rtSym( "%OpenTCPStream$server%server_port%local_port=0",bbOpenTCPStream ); - rtSym( "CloseTCPStream%tcp_stream",bbCloseTCPStream ); - rtSym( "%CreateTCPServer%port",bbCreateTCPServer ); - rtSym( "CloseTCPServer%tcp_server",bbCloseTCPServer ); - rtSym( "%AcceptTCPStream%tcp_server",bbAcceptTCPStream ); - rtSym( "%TCPStreamIP%tcp_stream",bbTCPStreamIP ); - rtSym( "%TCPStreamPort%tcp_stream",bbTCPStreamPort ); - rtSym( "TCPTimeouts%read_millis%accept_millis",bbTCPTimeouts ); + rtSym("%OpenTCPStream$server%server_port%local_port=0", bbOpenTCPStream); + rtSym("CloseTCPStream%tcp_stream", bbCloseTCPStream); + rtSym("%CreateTCPServer%port", bbCreateTCPServer); + rtSym("CloseTCPServer%tcp_server", bbCloseTCPServer); + rtSym("%AcceptTCPStream%tcp_server", bbAcceptTCPStream); + rtSym("%TCPStreamIP%tcp_stream", bbTCPStreamIP); + rtSym("%TCPStreamPort%tcp_stream", bbTCPStreamPort); + rtSym("TCPTimeouts%read_millis%accept_millis", bbTCPTimeouts); } diff --git a/bbruntime/multiplay.cpp b/bbruntime/multiplay.cpp index 1535b68..8d56364 100644 --- a/bbruntime/multiplay.cpp +++ b/bbruntime/multiplay.cpp @@ -9,301 +9,301 @@ #include "multiplay.h" #include "multiplay_setup.h" -struct Player; - -static bool host; - -static map player_map; -static list players,new_players; - -static int msg_type; -static string msg_data; -static DPID msg_from,msg_to; - -static char *recv_buff; -static int recv_buff_sz; - -static char *send_buff; -static int send_buff_sz; - -#pragma pack( push,1 ) -struct bbMsg{ - DPID from,to; - char type; -}; -#pragma pack( pop ) - -struct Player{ - DPID id; - string name; - bool remote; - - Player( DPID i,const string &n,bool r ):id(i),name(n),remote(r){ - players.push_back( this ); - if( remote ) new_players.push_back( this ); - player_map.clear(); - } - - Player::~Player(){ - new_players.remove( this ); - players.remove( this ); - player_map.clear(); - } -}; - -static void chk(){ - if( !dirPlay ){ - RTEX( "Multiplayer game not started" ); - } -} - -static void clearPlayers(){ - while( players.size() ) delete players.back(); - new_players.clear(); - player_map.clear(); -} - -static Player *findPlayer( DPID id ){ - if( !player_map.size() ){ - list::iterator it; - for( it=players.begin();it!=players.end();++it ){ - player_map.insert( pair( (*it)->id,(*it) ) ); - } - } - map::iterator it=player_map.find( id ); - return it==player_map.end() ? 0 : it->second; -} - -static BOOL FAR PASCAL enumPlayer( DPID id,DWORD type,LPCDPNAME name,DWORD flags,LPVOID context ){ - Player *p=findPlayer( id );if( p ) return TRUE; - p=d_new Player( id,string( name->lpszShortNameA ),true ); - return TRUE; -} - -void multiplay_link( void(*rtSym)(const char*,void*) ){ - rtSym( "%StartNetGame",bbStartNetGame ); - rtSym( "%HostNetGame$game_name",bbHostNetGame ); - rtSym( "%JoinNetGame$game_name$ip_address",bbJoinNetGame ); - rtSym( "StopNetGame",bbStopNetGame ); - - rtSym( "%CreateNetPlayer$name",bbCreateNetPlayer ); - rtSym( "DeleteNetPlayer%player",bbDeleteNetPlayer ); - rtSym( "$NetPlayerName%player",bbNetPlayerName ); - rtSym( "%NetPlayerLocal%player",bbNetPlayerLocal ); - - rtSym( "%SendNetMsg%type$msg%from_player%to_player=0%reliable=1",bbSendNetMsg ); - - rtSym( "%RecvNetMsg",bbRecvNetMsg ); - rtSym( "%NetMsgType",bbNetMsgType ); - rtSym( "%NetMsgFrom",bbNetMsgFrom ); - rtSym( "%NetMsgTo",bbNetMsgTo ); - rtSym( "$NetMsgData",bbNetMsgData ); -} - -bool multiplay_create(){ - - recv_buff_sz=send_buff_sz=1024; - recv_buff=d_new char[recv_buff_sz]; - send_buff=d_new char[send_buff_sz]; - - multiplay_setup_create(); - - return true; -} - -bool multiplay_destroy(){ - - bbStopNetGame(); - - multiplay_setup_destroy(); - - delete[] recv_buff;recv_buff=0; - delete[] send_buff;send_buff=0; - - return true; -} - -static int startGame( int n ){ - clearPlayers(); - if( !n ) return 0; - if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )>=0 ){ - host=n==2; - return n; - } - multiplay_setup_close(); - return 0; -} - -int bbStartNetGame(){ - if( dirPlay ){ - RTEX( "Multiplayer game already started" ); - } - return startGame( multiplay_setup_open() ); -} - -int bbHostNetGame( BBStr *name ){ - if( dirPlay ){ - RTEX( "Multiplayer game already started" ); - } - string n=*name;delete name; - return startGame( multiplay_setup_host( n ) ); -} - -int bbJoinNetGame( BBStr *name,BBStr *address ){ - if( dirPlay ){ - RTEX( "Multiplayer game already started" ); - } - string n=*name,a=*address;delete name;delete address; - return startGame( multiplay_setup_join( n,a ) ); -} - -void bbStopNetGame(){ - multiplay_setup_close(); - clearPlayers(); -} - -DPID bbCreateNetPlayer( BBStr *nm ){ - chk(); - - string t=*nm; - string t0=t+'\0'; - delete nm; - - DPID id; - DPNAME name; - memset( &name,0,sizeof( name ) ); - name.dwSize=sizeof(name);name.lpszShortNameA=(char*)t0.data(); - - if( dirPlay->CreatePlayer( &id,&name,0,0,0,0 )<0 ) return 0; - - Player *p=d_new Player( id,t,false ); - - if( players.size()==1 ){ - if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )<0 ){ - dirPlay->DestroyPlayer( id ); - delete p; - return 0; - } - } - return id; -} - -void bbDeleteNetPlayer( DPID player ){ - chk(); - - if( Player *p=findPlayer( player ) ){ - dirPlay->DestroyPlayer( player ); - delete p; - } -} - -BBStr *bbNetPlayerName( DPID player ){ - if( !player ) return d_new BBStr( "" ); - Player *p=findPlayer( player ); - return d_new BBStr( p ? p->name : "" ); -} - -int bbNetPlayerLocal( DPID player ){ - if( Player *p=findPlayer( player ) ) return p->remote ? 0 : 1; - return 0; -} - -int bbRecvNetMsg(){ - chk(); - - msg_type=0; - msg_data.resize(0); - msg_from=DPID_UNKNOWN;msg_to=DPID_ALLPLAYERS; - - while( !msg_type ){ - - if( new_players.size() ){ - msg_from=new_players.front()->id; - new_players.pop_front(); - msg_type=100; - return 1; - } - - DPID from,to; - DWORD sz=recv_buff_sz; - int n=dirPlay->Receive( &from,&to,0,recv_buff,&sz ); - - if( n==DPERR_BUFFERTOOSMALL ){ - sz=recv_buff_sz=sz/2+sz; - delete[] recv_buff;recv_buff=d_new char[recv_buff_sz]; - n=dirPlay->Receive( &from,&to,0,recv_buff,&sz ); - } - - if( n!=DP_OK ) return 0; - - if( from==DPID_SYSMSG ){ - switch( *(DWORD*)recv_buff ){ - case DPSYS_CREATEPLAYERORGROUP: - if( DPMSG_CREATEPLAYERORGROUP *msg=(DPMSG_CREATEPLAYERORGROUP*)recv_buff ){ - if( findPlayer( from=msg->dpId ) ) continue; - d_new Player( from,string( msg->dpnName.lpszShortNameA ),true ); - continue; - } - break; - case DPSYS_DESTROYPLAYERORGROUP: - if( DPMSG_DESTROYPLAYERORGROUP *msg=(DPMSG_DESTROYPLAYERORGROUP*)recv_buff ){ - Player *p=findPlayer( msg->dpId );if( !p ) continue; - delete p;msg_from=msg->dpId;msg_type=101; - } - break; - case DPSYS_HOST: - if( !host ){ - host=true;msg_type=102; - } - break; - case DPSYS_SESSIONLOST: - msg_type=200; - break; - } - }else{ - bbMsg *m=(bbMsg*)recv_buff; - Player *p=findPlayer( m->from ); - if( p && !p->remote ) continue; - msg_data=string( (char*)(m+1),sz-sizeof(bbMsg) ); - msg_from=m->from;msg_to=m->to; - msg_type=m->type; - } - } - return 1; -} - -int bbNetMsgType(){ - return msg_type; -} - -BBStr *bbNetMsgData(){ - return d_new BBStr( msg_data ); -} - -DPID bbNetMsgFrom(){ - return msg_from; -} - -DPID bbNetMsgTo(){ - return msg_to; -} - -int bbSendNetMsg( int type,BBStr *msg,DPID from,DPID to,int reliable ){ - chk(); - - int sz=msg->size()+sizeof(bbMsg); - if( sz>send_buff_sz ){ - send_buff_sz=sz/2+sz; - delete send_buff;send_buff=d_new char[send_buff_sz]; - } - bbMsg *m=(bbMsg*)send_buff; - m->type=type;m->from=from;m->to=to; - - memcpy( m+1,msg->data(),msg->size() ); - - if( !to ) to=DPID_ALLPLAYERS; - int n=dirPlay->Send( from,to,reliable ? DPSEND_GUARANTEED : 0,send_buff,sz ); - delete msg; - - return n>=0; -} +//struct Player; +// +//static bool host; +// +//static map player_map; +//static list players,new_players; +// +//static int msg_type; +//static string msg_data; +//static DPID msg_from,msg_to; +// +//static char *recv_buff; +//static int recv_buff_sz; +// +//static char *send_buff; +//static int send_buff_sz; +// +//#pragma pack( push,1 ) +//struct bbMsg{ +// DPID from,to; +// char type; +//}; +//#pragma pack( pop ) +// +//struct Player{ +// DPID id; +// string name; +// bool remote; +// +// Player( DPID i,const string &n,bool r ):id(i),name(n),remote(r){ +// players.push_back( this ); +// if( remote ) new_players.push_back( this ); +// player_map.clear(); +// } +// +// Player::~Player(){ +// new_players.remove( this ); +// players.remove( this ); +// player_map.clear(); +// } +//}; +// +//static void chk(){ +// if( !dirPlay ){ +// RTEX( "Multiplayer game not started" ); +// } +//} +// +//static void clearPlayers(){ +// while( players.size() ) delete players.back(); +// new_players.clear(); +// player_map.clear(); +//} +// +//static Player *findPlayer( DPID id ){ +// if( !player_map.size() ){ +// list::iterator it; +// for( it=players.begin();it!=players.end();++it ){ +// player_map.insert( pair( (*it)->id,(*it) ) ); +// } +// } +// map::iterator it=player_map.find( id ); +// return it==player_map.end() ? 0 : it->second; +//} +// +//static BOOL FAR PASCAL enumPlayer( DPID id,DWORD type,LPCDPNAME name,DWORD flags,LPVOID context ){ +// Player *p=findPlayer( id );if( p ) return TRUE; +// p=d_new Player( id,string( name->lpszShortNameA ),true ); +// return TRUE; +//} +// +//void multiplay_link( void(*rtSym)(const char*,void*) ){ +// rtSym( "%StartNetGame",bbStartNetGame ); +// rtSym( "%HostNetGame$game_name",bbHostNetGame ); +// rtSym( "%JoinNetGame$game_name$ip_address",bbJoinNetGame ); +// rtSym( "StopNetGame",bbStopNetGame ); +// +// rtSym( "%CreateNetPlayer$name",bbCreateNetPlayer ); +// rtSym( "DeleteNetPlayer%player",bbDeleteNetPlayer ); +// rtSym( "$NetPlayerName%player",bbNetPlayerName ); +// rtSym( "%NetPlayerLocal%player",bbNetPlayerLocal ); +// +// rtSym( "%SendNetMsg%type$msg%from_player%to_player=0%reliable=1",bbSendNetMsg ); +// +// rtSym( "%RecvNetMsg",bbRecvNetMsg ); +// rtSym( "%NetMsgType",bbNetMsgType ); +// rtSym( "%NetMsgFrom",bbNetMsgFrom ); +// rtSym( "%NetMsgTo",bbNetMsgTo ); +// rtSym( "$NetMsgData",bbNetMsgData ); +//} +// +//bool multiplay_create(){ +// +// recv_buff_sz=send_buff_sz=1024; +// recv_buff=d_new char[recv_buff_sz]; +// send_buff=d_new char[send_buff_sz]; +// +// multiplay_setup_create(); +// +// return true; +//} +// +//bool multiplay_destroy(){ +// +// bbStopNetGame(); +// +// multiplay_setup_destroy(); +// +// delete[] recv_buff;recv_buff=0; +// delete[] send_buff;send_buff=0; +// +// return true; +//} +// +//static int startGame( int n ){ +// clearPlayers(); +// if( !n ) return 0; +// if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )>=0 ){ +// host=n==2; +// return n; +// } +// multiplay_setup_close(); +// return 0; +//} +// +//int bbStartNetGame(){ +// if( dirPlay ){ +// RTEX( "Multiplayer game already started" ); +// } +// return startGame( multiplay_setup_open() ); +//} +// +//int bbHostNetGame( BBStr *name ){ +// if( dirPlay ){ +// RTEX( "Multiplayer game already started" ); +// } +// string n=*name;delete name; +// return startGame( multiplay_setup_host( n ) ); +//} +// +//int bbJoinNetGame( BBStr *name,BBStr *address ){ +// if( dirPlay ){ +// RTEX( "Multiplayer game already started" ); +// } +// string n=*name,a=*address;delete name;delete address; +// return startGame( multiplay_setup_join( n,a ) ); +//} +// +//void bbStopNetGame(){ +// multiplay_setup_close(); +// clearPlayers(); +//} +// +//DPID bbCreateNetPlayer( BBStr *nm ){ +// chk(); +// +// string t=*nm; +// string t0=t+'\0'; +// delete nm; +// +// DPID id; +// DPNAME name; +// memset( &name,0,sizeof( name ) ); +// name.dwSize=sizeof(name);name.lpszShortNameA=(char*)t0.data(); +// +// if( dirPlay->CreatePlayer( &id,&name,0,0,0,0 )<0 ) return 0; +// +// Player *p=d_new Player( id,t,false ); +// +// if( players.size()==1 ){ +// if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )<0 ){ +// dirPlay->DestroyPlayer( id ); +// delete p; +// return 0; +// } +// } +// return id; +//} +// +//void bbDeleteNetPlayer( DPID player ){ +// chk(); +// +// if( Player *p=findPlayer( player ) ){ +// dirPlay->DestroyPlayer( player ); +// delete p; +// } +//} +// +//BBStr *bbNetPlayerName( DPID player ){ +// if( !player ) return d_new BBStr( "" ); +// Player *p=findPlayer( player ); +// return d_new BBStr( p ? p->name : "" ); +//} +// +//int bbNetPlayerLocal( DPID player ){ +// if( Player *p=findPlayer( player ) ) return p->remote ? 0 : 1; +// return 0; +//} +// +//int bbRecvNetMsg(){ +// chk(); +// +// msg_type=0; +// msg_data.resize(0); +// msg_from=DPID_UNKNOWN;msg_to=DPID_ALLPLAYERS; +// +// while( !msg_type ){ +// +// if( new_players.size() ){ +// msg_from=new_players.front()->id; +// new_players.pop_front(); +// msg_type=100; +// return 1; +// } +// +// DPID from,to; +// DWORD sz=recv_buff_sz; +// int n=dirPlay->Receive( &from,&to,0,recv_buff,&sz ); +// +// if( n==DPERR_BUFFERTOOSMALL ){ +// sz=recv_buff_sz=sz/2+sz; +// delete[] recv_buff;recv_buff=d_new char[recv_buff_sz]; +// n=dirPlay->Receive( &from,&to,0,recv_buff,&sz ); +// } +// +// if( n!=DP_OK ) return 0; +// +// if( from==DPID_SYSMSG ){ +// switch( *(DWORD*)recv_buff ){ +// case DPSYS_CREATEPLAYERORGROUP: +// if( DPMSG_CREATEPLAYERORGROUP *msg=(DPMSG_CREATEPLAYERORGROUP*)recv_buff ){ +// if( findPlayer( from=msg->dpId ) ) continue; +// d_new Player( from,string( msg->dpnName.lpszShortNameA ),true ); +// continue; +// } +// break; +// case DPSYS_DESTROYPLAYERORGROUP: +// if( DPMSG_DESTROYPLAYERORGROUP *msg=(DPMSG_DESTROYPLAYERORGROUP*)recv_buff ){ +// Player *p=findPlayer( msg->dpId );if( !p ) continue; +// delete p;msg_from=msg->dpId;msg_type=101; +// } +// break; +// case DPSYS_HOST: +// if( !host ){ +// host=true;msg_type=102; +// } +// break; +// case DPSYS_SESSIONLOST: +// msg_type=200; +// break; +// } +// }else{ +// bbMsg *m=(bbMsg*)recv_buff; +// Player *p=findPlayer( m->from ); +// if( p && !p->remote ) continue; +// msg_data=string( (char*)(m+1),sz-sizeof(bbMsg) ); +// msg_from=m->from;msg_to=m->to; +// msg_type=m->type; +// } +// } +// return 1; +//} +// +//int bbNetMsgType(){ +// return msg_type; +//} +// +//BBStr *bbNetMsgData(){ +// return d_new BBStr( msg_data ); +//} +// +//DPID bbNetMsgFrom(){ +// return msg_from; +//} +// +//DPID bbNetMsgTo(){ +// return msg_to; +//} +// +//int bbSendNetMsg( int type,BBStr *msg,DPID from,DPID to,int reliable ){ +// chk(); +// +// int sz=msg->size()+sizeof(bbMsg); +// if( sz>send_buff_sz ){ +// send_buff_sz=sz/2+sz; +// delete send_buff;send_buff=d_new char[send_buff_sz]; +// } +// bbMsg *m=(bbMsg*)send_buff; +// m->type=type;m->from=from;m->to=to; +// +// memcpy( m+1,msg->data(),msg->size() ); +// +// if( !to ) to=DPID_ALLPLAYERS; +// int n=dirPlay->Send( from,to,reliable ? DPSEND_GUARANTEED : 0,send_buff,sz ); +// delete msg; +// +// return n>=0; +//} diff --git a/bbruntime/multiplay.h b/bbruntime/multiplay.h index 25c83f3..839d726 100644 --- a/bbruntime/multiplay.h +++ b/bbruntime/multiplay.h @@ -3,28 +3,28 @@ #define MULTIPLAY_H #include "bbsys.h" -#include +//#include -void multiplay_link(); -bool multiplay_create(); -bool multiplay_destroy(); - -int bbStartNetGame(); -int bbHostNetGame( BBStr *name ); -int bbJoinNetGame( BBStr *name,BBStr *address ); -void bbStopNetGame(); - -DPID bbCreateNetPlayer( BBStr *name ); -void bbDeleteNetPlayer( DPID player ); -BBStr * bbNetPlayerName( DPID player ); -int bbNetPlayerLocal( DPID player ); - -int bbSendNetMsg( int type,BBStr *msg,DPID from,DPID to,int reliable ); - -int bbRecvNetMsg(); -int bbNetMsgType(); -BBStr * bbNetMsgData(); -DPID bbNetMsgFrom(); -DPID bbNetMsgTo(); +//void multiplay_link(); +//bool multiplay_create(); +//bool multiplay_destroy(); +// +//int bbStartNetGame(); +//int bbHostNetGame( BBStr *name ); +//int bbJoinNetGame( BBStr *name,BBStr *address ); +//void bbStopNetGame(); +// +//DPID bbCreateNetPlayer( BBStr *name ); +//void bbDeleteNetPlayer( DPID player ); +//BBStr * bbNetPlayerName( DPID player ); +//int bbNetPlayerLocal( DPID player ); +// +//int bbSendNetMsg( int type,BBStr *msg,DPID from,DPID to,int reliable ); +// +//int bbRecvNetMsg(); +//int bbNetMsgType(); +//BBStr * bbNetMsgData(); +//DPID bbNetMsgFrom(); +//DPID bbNetMsgTo(); #endif diff --git a/bbruntime/multiplay_setup.cpp b/bbruntime/multiplay_setup.cpp index b6e6baa..d51f31d 100644 --- a/bbruntime/multiplay_setup.cpp +++ b/bbruntime/multiplay_setup.cpp @@ -4,378 +4,378 @@ #include "resource.h" #include "multiplay_setup.h" -IDirectPlay4 *dirPlay; - -struct Connection{ - GUID guid; - string name; - void *data; - - Connection( const GUID &g,const string &n,void *d,int sz ):guid(g),name(n){ - data=d_new char[sz];memcpy( data,d,sz ); - } - - ~Connection(){ - delete[] data; - } -}; - -struct Session{ - GUID guid; - string name; - int max_players,curr_players,data1,data2; - - Session( const DPSESSIONDESC2 *desc ){ - guid=desc->guidInstance; - name=string( desc->lpszSessionNameA ); - max_players=desc->dwMaxPlayers; - curr_players=desc->dwCurrentPlayers; - data1=desc->dwUser1;data2=desc->dwUser2; - } -}; - -static int timer; -static vector connections; -static vector sessions; - -static void clearSessions(){ - for( ;sessions.size();sessions.pop_back() ) delete sessions.back(); -} - -static void clearConnections(){ - for( ;connections.size();connections.pop_back() ) delete connections.back(); -} - -static bool openDirPlay( HWND hwnd ){ - if( dirPlay ) return true; - if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ) return true; - MessageBox( hwnd,"Error opening DirectPlay","DirectPlay Error",MB_ICONWARNING ); - return false; -} - -static bool closeDirPlay( HWND hwnd ){ - if( hwnd && timer ) KillTimer( hwnd,timer ); - timer=0;if( !dirPlay ) return true; - dirPlay->Close(); - int n=dirPlay->Release(); - dirPlay=0;return n==0; -} - -static BOOL FAR PASCAL enumConnection( LPCGUID guid,LPVOID conn,DWORD size,LPCDPNAME name,DWORD flags,LPVOID context ){ - IDirectPlay4 *dp; - if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dp )<0 ) return FALSE; - int n=dp->InitializeConnection( conn,0 ); - dp->Release();if( n<0 ) return TRUE; - - Connection *c=d_new Connection( *guid,string( strdup( name->lpszShortNameA ) ),conn,size ); - connections.push_back( c ); - - return TRUE; -} - -static BOOL FAR PASCAL enumSession( LPCDPSESSIONDESC2 desc,LPDWORD timeout,DWORD flags,LPVOID lpContext ){ - - if( !desc ) return FALSE; - sessions.push_back( d_new Session( desc ) ); - return TRUE; -} - -static bool startGame( HWND hwnd ){ - if( !dirPlay ) return false; - - char buff[MAX_PATH]; - int n=GetWindowText( GetDlgItem( hwnd,IDC_GAMENAME ),buff,MAX_PATH ); - if( !n ){ - MessageBox( hwnd,"Please enter a name for the new game","DirectPlay Request",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONINFORMATION|MB_OK ); - return false; - } - - string name=string( buff )+'\0'; - - DPSESSIONDESC2 desc; - memset(&desc,0,sizeof(desc)); - desc.dwSize=sizeof(desc); - desc.guidApplication=GUID_NULL; - desc.dwFlags= - DPSESSION_KEEPALIVE| - DPSESSION_MIGRATEHOST| - DPSESSION_NOMESSAGEID| - DPSESSION_OPTIMIZELATENCY| - DPSESSION_DIRECTPLAYPROTOCOL; - desc.lpszSessionNameA=(char*)name.data(); - - if( dirPlay->Open( &desc,DPOPEN_CREATE )<0 ){ - MessageBox( hwnd,"Unable to create new game","DirPlay Error",MB_ICONWARNING ); - return false; - } - return true; -} - -static bool joinGame( HWND hwnd ){ - if( !dirPlay ) return false; - - int ses=SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_GETCURSEL,0,0 ); - if( ses<0 || ses>=sessions.size() ) return false; - - DPSESSIONDESC2 desc; - memset(&desc,0,sizeof(desc)); - desc.dwSize=sizeof(desc); - desc.guidInstance=sessions[ses]->guid; - - if( dirPlay->Open( &desc,DPOPEN_JOIN )<0 ){ - MessageBox( hwnd,"Unable to join game","DirPlay Error",MB_ICONWARNING ); - return false; - } - return true; -} - -static bool enumSessions( HWND hwnd ){ - if( !dirPlay ) return false; - - clearSessions(); - EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),true ); - SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_RESETCONTENT,0,0 ); - - DPSESSIONDESC2 desc; - memset(&desc,0,sizeof(desc)); - desc.dwSize=sizeof(desc); - desc.guidApplication=GUID_NULL; - - int n=dirPlay->EnumSessions( &desc,0,enumSession,0,DPENUMSESSIONS_ASYNC ); - if( n>=0 ){ - if( !timer ) SetTimer( hwnd,timer=1,1000,0 ); - for( int k=0;kname.c_str() ) ); - } - if( !sessions.size() ){ - SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_ADDSTRING,0,(LPARAM)"" ); - EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),false ); - } - return true; - } - closeDirPlay( hwnd ); - if( n==DPERR_USERCANCEL ) return false; - MessageBox( hwnd,"Unable to enumerate sessions","DirPlay Error",MB_ICONWARNING ); - return false; -} - -static bool connect( HWND hwnd ){ - int con=SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_GETCURSEL,0,0 ); - if( con<1 || con>=connections.size() ) return false; - - closeDirPlay( hwnd ); - if( openDirPlay( hwnd ) ){ - int n=dirPlay->InitializeConnection( connections[con]->data,0 ); - if( n>=0 ){ - if( enumSessions( hwnd ) ) return true; - }else{ - if( n!=DPERR_USERCANCEL ){ - string t="Unable to open "+connections[con]->name; - MessageBox( hwnd,t.c_str(),"DirPlay Error",MB_ICONWARNING ); - } - } - closeDirPlay( hwnd ); - } - return false; -} - -static void endDialog( HWND hwnd,int rc ){ - if( timer ) KillTimer( hwnd,timer ); - timer=0; - if( !rc ) closeDirPlay( hwnd ); - EndDialog( hwnd,rc ); -} - -static BOOL CALLBACK dialogProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ){ - - int k,lo=LOWORD(wparam),hi=HIWORD(wparam); - - bool reset=false; - - switch( msg ){ - case WM_INITDIALOG: - SetForegroundWindow( hwnd ); - clearConnections(); - connections.push_back( d_new Connection( GUID_NULL,"","",0 ) ); - if( openDirPlay( hwnd ) ){ - if( dirPlay->EnumConnections( 0,enumConnection,0,0 )<0 ){ - MessageBox( hwnd,"Failed to enumerate connections","DirectPlay Error",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONWARNING|MB_OK ); - } - closeDirPlay( hwnd ); - } - for( k=0;kname; - SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_ADDSTRING,0,(LPARAM)t.c_str() ); - } - timer=0; - reset=true; - break; - case WM_TIMER: //refresh sessions list! - if( timer && wparam==timer && !enumSessions( hwnd ) ) reset=true; - break; - case WM_CLOSE: - endDialog( hwnd,0 ); - break; - case WM_COMMAND: - switch( hi ){ - case BN_CLICKED: - switch( lo ){ - case IDC_CANCEL: - endDialog( hwnd,0 ); - break; - case IDC_GAMENAME:case IDC_HOSTGAME: - if( startGame( hwnd ) ){ - endDialog( hwnd,2 ); - } - break; - } - break; - case LBN_DBLCLK: - switch( lo ){ - case IDC_GAMELIST: - if( joinGame( hwnd ) ){ - endDialog( hwnd,1 ); - } - break; - } - break; - case CBN_SELCHANGE: - switch( lo ){ - case IDC_CONNECTIONS: - if( connect( hwnd ) ){ - EnableWindow( GetDlgItem( hwnd,IDC_GAMENAME ),true ); - EnableWindow( GetDlgItem( hwnd,IDC_HOSTGAME ),true ); - break; - }else{ - reset=true; - } - break; - } - break; - } - break; - default: - return 0; - } - - if( reset ){ - closeDirPlay( hwnd ); - SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_SETCURSEL,0,0 ); - EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),false ); - EnableWindow( GetDlgItem( hwnd,IDC_HOSTGAME ),false ); - EnableWindow( GetDlgItem( hwnd,IDC_GAMENAME ),false ); - SetWindowText( GetDlgItem( hwnd,IDC_GAMENAME ),"" ); - SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_RESETCONTENT,0,0 ); - } - return 1; -} - -void multiplay_setup_create(){ - dirPlay=0; -} - -void multiplay_setup_destroy(){ - multiplay_setup_close(); -} - -int multiplay_setup_open(){ - gx_runtime->idle(); - - int n=DialogBox( GetModuleHandle( "runtime" ),MAKEINTRESOURCE( IDD_MULTIPLAYER ),GetDesktopWindow(),dialogProc ); - - if( n!=1 && n!=2 ) n=0; - - clearSessions(); - clearConnections(); - - //NAUGHTY! - gx_runtime->asyncRun(); - gx_runtime->idle(); - return n; -} - -void multiplay_setup_close(){ - closeDirPlay( 0 ); -} - -int multiplay_setup_host( const string &game_name ){ - int ret=0; - IDirectPlayLobby *lobby; - IDirectPlayLobby3 *lobby3; - if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ){ - if( DirectPlayLobbyCreate( 0,&lobby,0,0,0 )>=0 ){ - if( lobby->QueryInterface( IID_IDirectPlayLobby3,(void**)&lobby3 )>=0 ){ - //ok, create an address for initializeconnection - string ip( "\0" ); - char address[256];DWORD sz=256; - if( lobby3->CreateAddress( DPSPGUID_TCPIP,DPAID_INet,ip.data(),ip.size(),address,&sz )>=0 ){ - if( dirPlay->InitializeConnection( address,0 )>=0 ){ - string name=game_name+'\0'; - DPSESSIONDESC2 desc; - memset(&desc,0,sizeof(desc)); - desc.dwSize=sizeof(desc); - desc.guidApplication=GUID_NULL; - desc.dwFlags= - DPSESSION_KEEPALIVE| - DPSESSION_MIGRATEHOST| - DPSESSION_NOMESSAGEID| - DPSESSION_OPTIMIZELATENCY| - DPSESSION_DIRECTPLAYPROTOCOL; - desc.lpszSessionNameA=(char*)name.data(); - if( dirPlay->Open( &desc,DPOPEN_CREATE )>=0 ){ - ret=2; - } - } - } - lobby3->Release(); - } - lobby->Release(); - } - if( !ret ){ - dirPlay->Release(); - dirPlay=0; - } - } - return ret; -} - -int multiplay_setup_join( const string &game_name,const string &ip_add ){ - int ret=0; - IDirectPlayLobby *lobby; - IDirectPlayLobby3 *lobby3; - if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ){ - if( DirectPlayLobbyCreate( 0,&lobby,0,0,0 )>=0 ){ - if( lobby->QueryInterface( IID_IDirectPlayLobby3,(void**)&lobby3 )>=0 ){ - //ok, create an address for initializeconnection - string ip=ip_add+'\0'; - char address[256];DWORD sz=256; - if( lobby3->CreateAddress( DPSPGUID_TCPIP,DPAID_INet,ip.data(),ip.size(),address,&sz )>=0 ){ - if( dirPlay->InitializeConnection( address,0 )>=0 ){ - DPSESSIONDESC2 desc; - memset(&desc,0,sizeof(desc)); - desc.dwSize=sizeof(desc); - desc.guidApplication=GUID_NULL; - if( dirPlay->EnumSessions( &desc,0,enumSession,0,0 )>=0 ){ - for( int k=0;kname!=game_name ) continue; - desc.guidInstance=sessions[k]->guid; - if( dirPlay->Open( &desc,DPOPEN_JOIN )>=0 ){ - ret=1; - } - break; - } - } - clearSessions(); - } - } - lobby3->Release(); - } - lobby->Release(); - } - if( !ret ){ - dirPlay->Release(); - dirPlay=0; - } - } - return ret; -} +//IDirectPlay4 *dirPlay; +// +//struct Connection{ +// GUID guid; +// string name; +// void *data; +// +// Connection( const GUID &g,const string &n,void *d,int sz ):guid(g),name(n){ +// data=d_new char[sz];memcpy( data,d,sz ); +// } +// +// ~Connection(){ +// delete[] data; +// } +//}; +// +//struct Session{ +// GUID guid; +// string name; +// int max_players,curr_players,data1,data2; +// +// Session( const DPSESSIONDESC2 *desc ){ +// guid=desc->guidInstance; +// name=string( desc->lpszSessionNameA ); +// max_players=desc->dwMaxPlayers; +// curr_players=desc->dwCurrentPlayers; +// data1=desc->dwUser1;data2=desc->dwUser2; +// } +//}; +// +//static int timer; +//static vector connections; +//static vector sessions; +// +//static void clearSessions(){ +// for( ;sessions.size();sessions.pop_back() ) delete sessions.back(); +//} +// +//static void clearConnections(){ +// for( ;connections.size();connections.pop_back() ) delete connections.back(); +//} +// +//static bool openDirPlay( HWND hwnd ){ +// if( dirPlay ) return true; +// if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ) return true; +// MessageBox( hwnd,"Error opening DirectPlay","DirectPlay Error",MB_ICONWARNING ); +// return false; +//} +// +//static bool closeDirPlay( HWND hwnd ){ +// if( hwnd && timer ) KillTimer( hwnd,timer ); +// timer=0;if( !dirPlay ) return true; +// dirPlay->Close(); +// int n=dirPlay->Release(); +// dirPlay=0;return n==0; +//} +// +//static BOOL FAR PASCAL enumConnection( LPCGUID guid,LPVOID conn,DWORD size,LPCDPNAME name,DWORD flags,LPVOID context ){ +// IDirectPlay4 *dp; +// if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dp )<0 ) return FALSE; +// int n=dp->InitializeConnection( conn,0 ); +// dp->Release();if( n<0 ) return TRUE; +// +// Connection *c=d_new Connection( *guid,string( strdup( name->lpszShortNameA ) ),conn,size ); +// connections.push_back( c ); +// +// return TRUE; +//} +// +//static BOOL FAR PASCAL enumSession( LPCDPSESSIONDESC2 desc,LPDWORD timeout,DWORD flags,LPVOID lpContext ){ +// +// if( !desc ) return FALSE; +// sessions.push_back( d_new Session( desc ) ); +// return TRUE; +//} +// +//static bool startGame( HWND hwnd ){ +// if( !dirPlay ) return false; +// +// char buff[MAX_PATH]; +// int n=GetWindowText( GetDlgItem( hwnd,IDC_GAMENAME ),buff,MAX_PATH ); +// if( !n ){ +// MessageBox( hwnd,"Please enter a name for the new game","DirectPlay Request",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONINFORMATION|MB_OK ); +// return false; +// } +// +// string name=string( buff )+'\0'; +// +// DPSESSIONDESC2 desc; +// memset(&desc,0,sizeof(desc)); +// desc.dwSize=sizeof(desc); +// desc.guidApplication=GUID_NULL; +// desc.dwFlags= +// DPSESSION_KEEPALIVE| +// DPSESSION_MIGRATEHOST| +// DPSESSION_NOMESSAGEID| +// DPSESSION_OPTIMIZELATENCY| +// DPSESSION_DIRECTPLAYPROTOCOL; +// desc.lpszSessionNameA=(char*)name.data(); +// +// if( dirPlay->Open( &desc,DPOPEN_CREATE )<0 ){ +// MessageBox( hwnd,"Unable to create new game","DirPlay Error",MB_ICONWARNING ); +// return false; +// } +// return true; +//} +// +//static bool joinGame( HWND hwnd ){ +// if( !dirPlay ) return false; +// +// int ses=SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_GETCURSEL,0,0 ); +// if( ses<0 || ses>=sessions.size() ) return false; +// +// DPSESSIONDESC2 desc; +// memset(&desc,0,sizeof(desc)); +// desc.dwSize=sizeof(desc); +// desc.guidInstance=sessions[ses]->guid; +// +// if( dirPlay->Open( &desc,DPOPEN_JOIN )<0 ){ +// MessageBox( hwnd,"Unable to join game","DirPlay Error",MB_ICONWARNING ); +// return false; +// } +// return true; +//} +// +//static bool enumSessions( HWND hwnd ){ +// if( !dirPlay ) return false; +// +// clearSessions(); +// EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),true ); +// SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_RESETCONTENT,0,0 ); +// +// DPSESSIONDESC2 desc; +// memset(&desc,0,sizeof(desc)); +// desc.dwSize=sizeof(desc); +// desc.guidApplication=GUID_NULL; +// +// int n=dirPlay->EnumSessions( &desc,0,enumSession,0,DPENUMSESSIONS_ASYNC ); +// if( n>=0 ){ +// if( !timer ) SetTimer( hwnd,timer=1,1000,0 ); +// for( int k=0;kname.c_str() ) ); +// } +// if( !sessions.size() ){ +// SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_ADDSTRING,0,(LPARAM)"" ); +// EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),false ); +// } +// return true; +// } +// closeDirPlay( hwnd ); +// if( n==DPERR_USERCANCEL ) return false; +// MessageBox( hwnd,"Unable to enumerate sessions","DirPlay Error",MB_ICONWARNING ); +// return false; +//} +// +//static bool connect( HWND hwnd ){ +// int con=SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_GETCURSEL,0,0 ); +// if( con<1 || con>=connections.size() ) return false; +// +// closeDirPlay( hwnd ); +// if( openDirPlay( hwnd ) ){ +// int n=dirPlay->InitializeConnection( connections[con]->data,0 ); +// if( n>=0 ){ +// if( enumSessions( hwnd ) ) return true; +// }else{ +// if( n!=DPERR_USERCANCEL ){ +// string t="Unable to open "+connections[con]->name; +// MessageBox( hwnd,t.c_str(),"DirPlay Error",MB_ICONWARNING ); +// } +// } +// closeDirPlay( hwnd ); +// } +// return false; +//} +// +//static void endDialog( HWND hwnd,int rc ){ +// if( timer ) KillTimer( hwnd,timer ); +// timer=0; +// if( !rc ) closeDirPlay( hwnd ); +// EndDialog( hwnd,rc ); +//} +// +//static BOOL CALLBACK dialogProc( HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam ){ +// +// int k,lo=LOWORD(wparam),hi=HIWORD(wparam); +// +// bool reset=false; +// +// switch( msg ){ +// case WM_INITDIALOG: +// SetForegroundWindow( hwnd ); +// clearConnections(); +// connections.push_back( d_new Connection( GUID_NULL,"","",0 ) ); +// if( openDirPlay( hwnd ) ){ +// if( dirPlay->EnumConnections( 0,enumConnection,0,0 )<0 ){ +// MessageBox( hwnd,"Failed to enumerate connections","DirectPlay Error",MB_SETFOREGROUND|MB_TOPMOST|MB_ICONWARNING|MB_OK ); +// } +// closeDirPlay( hwnd ); +// } +// for( k=0;kname; +// SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_ADDSTRING,0,(LPARAM)t.c_str() ); +// } +// timer=0; +// reset=true; +// break; +// case WM_TIMER: //refresh sessions list! +// if( timer && wparam==timer && !enumSessions( hwnd ) ) reset=true; +// break; +// case WM_CLOSE: +// endDialog( hwnd,0 ); +// break; +// case WM_COMMAND: +// switch( hi ){ +// case BN_CLICKED: +// switch( lo ){ +// case IDC_CANCEL: +// endDialog( hwnd,0 ); +// break; +// case IDC_GAMENAME:case IDC_HOSTGAME: +// if( startGame( hwnd ) ){ +// endDialog( hwnd,2 ); +// } +// break; +// } +// break; +// case LBN_DBLCLK: +// switch( lo ){ +// case IDC_GAMELIST: +// if( joinGame( hwnd ) ){ +// endDialog( hwnd,1 ); +// } +// break; +// } +// break; +// case CBN_SELCHANGE: +// switch( lo ){ +// case IDC_CONNECTIONS: +// if( connect( hwnd ) ){ +// EnableWindow( GetDlgItem( hwnd,IDC_GAMENAME ),true ); +// EnableWindow( GetDlgItem( hwnd,IDC_HOSTGAME ),true ); +// break; +// }else{ +// reset=true; +// } +// break; +// } +// break; +// } +// break; +// default: +// return 0; +// } +// +// if( reset ){ +// closeDirPlay( hwnd ); +// SendDlgItemMessage( hwnd,IDC_CONNECTIONS,CB_SETCURSEL,0,0 ); +// EnableWindow( GetDlgItem( hwnd,IDC_GAMELIST ),false ); +// EnableWindow( GetDlgItem( hwnd,IDC_HOSTGAME ),false ); +// EnableWindow( GetDlgItem( hwnd,IDC_GAMENAME ),false ); +// SetWindowText( GetDlgItem( hwnd,IDC_GAMENAME ),"" ); +// SendDlgItemMessage( hwnd,IDC_GAMELIST,LB_RESETCONTENT,0,0 ); +// } +// return 1; +//} +// +//void multiplay_setup_create(){ +// dirPlay=0; +//} +// +//void multiplay_setup_destroy(){ +// multiplay_setup_close(); +//} +// +//int multiplay_setup_open(){ +// gx_runtime->idle(); +// +// int n=DialogBox( GetModuleHandle( "runtime" ),MAKEINTRESOURCE( IDD_MULTIPLAYER ),GetDesktopWindow(),dialogProc ); +// +// if( n!=1 && n!=2 ) n=0; +// +// clearSessions(); +// clearConnections(); +// +// //NAUGHTY! +// gx_runtime->asyncRun(); +// gx_runtime->idle(); +// return n; +//} +// +//void multiplay_setup_close(){ +// closeDirPlay( 0 ); +//} +// +//int multiplay_setup_host( const string &game_name ){ +// int ret=0; +// IDirectPlayLobby *lobby; +// IDirectPlayLobby3 *lobby3; +// if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ){ +// if( DirectPlayLobbyCreate( 0,&lobby,0,0,0 )>=0 ){ +// if( lobby->QueryInterface( IID_IDirectPlayLobby3,(void**)&lobby3 )>=0 ){ +// //ok, create an address for initializeconnection +// string ip( "\0" ); +// char address[256];DWORD sz=256; +// if( lobby3->CreateAddress( DPSPGUID_TCPIP,DPAID_INet,ip.data(),ip.size(),address,&sz )>=0 ){ +// if( dirPlay->InitializeConnection( address,0 )>=0 ){ +// string name=game_name+'\0'; +// DPSESSIONDESC2 desc; +// memset(&desc,0,sizeof(desc)); +// desc.dwSize=sizeof(desc); +// desc.guidApplication=GUID_NULL; +// desc.dwFlags= +// DPSESSION_KEEPALIVE| +// DPSESSION_MIGRATEHOST| +// DPSESSION_NOMESSAGEID| +// DPSESSION_OPTIMIZELATENCY| +// DPSESSION_DIRECTPLAYPROTOCOL; +// desc.lpszSessionNameA=(char*)name.data(); +// if( dirPlay->Open( &desc,DPOPEN_CREATE )>=0 ){ +// ret=2; +// } +// } +// } +// lobby3->Release(); +// } +// lobby->Release(); +// } +// if( !ret ){ +// dirPlay->Release(); +// dirPlay=0; +// } +// } +// return ret; +//} +// +//int multiplay_setup_join( const string &game_name,const string &ip_add ){ +// int ret=0; +// IDirectPlayLobby *lobby; +// IDirectPlayLobby3 *lobby3; +// if( CoCreateInstance( CLSID_DirectPlay,0,CLSCTX_ALL,IID_IDirectPlay4A,(void**)&dirPlay )>=0 ){ +// if( DirectPlayLobbyCreate( 0,&lobby,0,0,0 )>=0 ){ +// if( lobby->QueryInterface( IID_IDirectPlayLobby3,(void**)&lobby3 )>=0 ){ +// //ok, create an address for initializeconnection +// string ip=ip_add+'\0'; +// char address[256];DWORD sz=256; +// if( lobby3->CreateAddress( DPSPGUID_TCPIP,DPAID_INet,ip.data(),ip.size(),address,&sz )>=0 ){ +// if( dirPlay->InitializeConnection( address,0 )>=0 ){ +// DPSESSIONDESC2 desc; +// memset(&desc,0,sizeof(desc)); +// desc.dwSize=sizeof(desc); +// desc.guidApplication=GUID_NULL; +// if( dirPlay->EnumSessions( &desc,0,enumSession,0,0 )>=0 ){ +// for( int k=0;kname!=game_name ) continue; +// desc.guidInstance=sessions[k]->guid; +// if( dirPlay->Open( &desc,DPOPEN_JOIN )>=0 ){ +// ret=1; +// } +// break; +// } +// } +// clearSessions(); +// } +// } +// lobby3->Release(); +// } +// lobby->Release(); +// } +// if( !ret ){ +// dirPlay->Release(); +// dirPlay=0; +// } +// } +// return ret; +//} diff --git a/bbruntime/multiplay_setup.h b/bbruntime/multiplay_setup.h index c64ee32..709476a 100644 --- a/bbruntime/multiplay_setup.h +++ b/bbruntime/multiplay_setup.h @@ -2,17 +2,17 @@ #ifndef MULTIPLAY_SETUP_H #define MULTIPLAY_SETUP_H -#include -#include +//#include +//#include +// +//extern IDirectPlay4 *dirPlay; -extern IDirectPlay4 *dirPlay; - -void multiplay_setup_create(); -void multiplay_setup_destroy(); - -int multiplay_setup_open(); -int multiplay_setup_host( const string &game_name ); -int multiplay_setup_join( const string &game_name,const string &ip_add ); -void multiplay_setup_close(); +//void multiplay_setup_create(); +//void multiplay_setup_destroy(); +// +//int multiplay_setup_open(); +//int multiplay_setup_host( const string &game_name ); +//int multiplay_setup_join( const string &game_name,const string &ip_add ); +//void multiplay_setup_close(); #endif diff --git a/bbruntime_dll/bbruntime_dll.vcxproj b/bbruntime_dll/bbruntime_dll.vcxproj new file mode 100644 index 0000000..b28ecf0 --- /dev/null +++ b/bbruntime_dll/bbruntime_dll.vcxproj @@ -0,0 +1,304 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {5FA2FD4A-F9A4-41BA-9484-07C3A57A87E3} + 10.0.10586.0 + + + + Application + v140 + + + DynamicLibrary + v140 + false + MultiByte + + + DynamicLibrary + v140 + false + MultiByte + + + DynamicLibrary + v140 + false + MultiByte + + + DynamicLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + false + + + .\Release\ + .\Release\ + false + + + .\bbruntime_dll___Win32_Blitz2DRelease\ + .\bbruntime_dll___Win32_Blitz2DRelease\ + false + + + .\bbruntime_dll___Win32_Blitz3DRelease\ + .\bbruntime_dll___Win32_Blitz3DRelease\ + false + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_WINDOWS;_USRDLL;BBRUNTIME_DLL_EXPORTS;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\bbruntime_dll.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\bbruntime_dll.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\bbruntime_dll.bsc + + + true + true + true + Console + ..\blitzbasic\bin\runtime.dll + .\Debug\runtime.lib + /FIXED:NO + wsock32.lib;winmm.lib;dxguid.lib;d3dxof.lib;dplayx.lib;ddraw.lib;dinput.lib;dsound.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;BBRUNTIME_DLL_EXPORTS;%(PreprocessorDefinitions) + AssemblyCode + .\Release\ + .\Release\bbruntime_dll.pch + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\bbruntime_dll.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\bbruntime_dll.bsc + + + true + true + Console + ..\blitzbasic\bin\runtime.dll + .\Release\runtime.lib + wsock32.lib;winmm.lib;dxguid.lib;d3dxof.lib;dplayx.lib;ddraw.lib;dinput.lib;dsound.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;BBRUNTIME_DLL_EXPORTS;%(PreprocessorDefinitions) + AssemblyCode + .\bbruntime_dll___Win32_Blitz2DRelease\ + .\bbruntime_dll___Win32_Blitz2DRelease\bbruntime_dll.pch + .\bbruntime_dll___Win32_Blitz2DRelease\ + .\bbruntime_dll___Win32_Blitz2DRelease\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\bbruntime_dll___Win32_Blitz2DRelease\bbruntime_dll.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\bbruntime_dll___Win32_Blitz2DRelease\bbruntime_dll.bsc + + + true + true + Console + ..\..\release\blitz2drelease\bin\runtime.dll + .\bbruntime_dll___Win32_Blitz2DRelease\runtime.lib + wsock32.lib;winmm.lib;dxguid.lib;d3dxof.lib;dplayx.lib;ddraw.lib;dinput.lib;dsound.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _WINDOWS;_USRDLL;BBRUNTIME_DLL_EXPORTS;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + AssemblyCode + .\bbruntime_dll___Win32_Blitz3DRelease\ + .\bbruntime_dll___Win32_Blitz3DRelease\bbruntime_dll.pch + .\bbruntime_dll___Win32_Blitz3DRelease\ + .\bbruntime_dll___Win32_Blitz3DRelease\ + StdCall + + + true + NDEBUG;%(PreprocessorDefinitions) + .\bbruntime_dll___Win32_Blitz3DRelease\bbruntime_dll.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\bbruntime_dll___Win32_Blitz3DRelease\bbruntime_dll.bsc + + + true + true + Console + ../_release/bin/runtime.dll + .\bbruntime_dll___Win32_Blitz3DRelease\runtime.lib + wsock32.lib;amstrmid.lib;winmm.lib;dxguid.lib;d3dxof.lib;dplayx.lib;ddraw.lib;dinput.lib;dsound.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + {df8caa9d-7154-4d5f-bccc-0d7bb57c7354} + false + + + {be0ba538-6215-4836-9227-1d3627e40d61} + false + + + {ff2d8bf7-1930-4cab-bc48-05cd33b7dc18} + false + + + {6bcfc5ca-ea71-4ae9-8b96-28b8701f939e} + false + + + + + + \ No newline at end of file diff --git a/bbruntime_dll/bbruntime_dll.vcxproj.filters b/bbruntime_dll/bbruntime_dll.vcxproj.filters new file mode 100644 index 0000000..6637178 --- /dev/null +++ b/bbruntime_dll/bbruntime_dll.vcxproj.filters @@ -0,0 +1,44 @@ + + + + + {a65b2e3f-fc88-4d53-91dd-eb0642bee121} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {aca80be8-67eb-4554-af3e-500c319542c5} + h;hpp;hxx;hm;inl + + + {09c1e929-5d9c-4e04-ab45-9a6a24fdd23c} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + + + \ No newline at end of file diff --git a/blitz/blitz.vcxproj b/blitz/blitz.vcxproj new file mode 100644 index 0000000..d2ae9b2 --- /dev/null +++ b/blitz/blitz.vcxproj @@ -0,0 +1,258 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {C23AF61E-9509-411F-933E-17DB18884B21} + 10.0.10586.0 + + + + Application + v140 + + + Application + v140 + false + MultiByte + + + Application + v140 + false + MultiByte + + + Application + v140 + false + MultiByte + + + Application + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + .\blitz___Win32_Blitz2DRelease\ + .\blitz___Win32_Blitz2DRelease\ + false + + + .\blitz___Win32_Blitz3DRelease\ + .\blitz___Win32_Blitz3DRelease\ + false + + + .\Release\ + .\Release\ + false + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\blitz.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + .\Debug\blitz.tlb + + + 0x1409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\blitz.bsc + + + true + true + Console + .\Debug\blitz.exe + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + .\blitz___Win32_Blitz2DRelease\ + .\blitz___Win32_Blitz2DRelease\blitz.pch + .\blitz___Win32_Blitz2DRelease\ + .\blitz___Win32_Blitz2DRelease\ + + + .\blitz___Win32_Blitz2DRelease\blitz.tlb + + + 0x1409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\blitz___Win32_Blitz2DRelease\blitz.bsc + + + true + Console + ..\..\release\blitz2drelease\bin\blitzcc.exe + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _CONSOLE;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\blitz___Win32_Blitz3DRelease\ + .\blitz___Win32_Blitz3DRelease\blitz.pch + .\blitz___Win32_Blitz3DRelease\ + .\blitz___Win32_Blitz3DRelease\ + StdCall + + + .\blitz___Win32_Blitz3DRelease\blitz.tlb + + + 0x1409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\blitz___Win32_Blitz3DRelease\blitz.bsc + + + true + Console + ../_release/bin/blitzcc.exe + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + .\Release\ + .\Release\blitz.pch + .\Release\ + .\Release\ + + + .\Release\blitz.tlb + + + 0x1409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\blitz.bsc + + + true + Console + ..\blitzbasic\bin\blitzcc.exe + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + {d884a075-e3b8-44e1-838d-74f28b33391b} + false + + + {6bcfc5ca-ea71-4ae9-8b96-28b8701f939e} + false + + + + + + \ No newline at end of file diff --git a/blitz3d.dsw b/blitz3d.dsw deleted file mode 100644 index ad5fc10..0000000 --- a/blitz3d.dsw +++ /dev/null @@ -1,266 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "asm_makeinsts"=.\asm_makeinsts\asm_makeinsts.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "bblaunch"=.\bblaunch\bblaunch.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name blitzide - End Project Dependency - Begin Project Dependency - Project_Dep_Name compiler - End Project Dependency - Begin Project Dependency - Project_Dep_Name config - End Project Dependency - Begin Project Dependency - Project_Dep_Name linker_dll - End Project Dependency - Begin Project Dependency - Project_Dep_Name stdutil - End Project Dependency - Begin Project Dependency - Project_Dep_Name linker - End Project Dependency - Begin Project Dependency - Project_Dep_Name bbruntime - End Project Dependency - Begin Project Dependency - Project_Dep_Name bbruntime_dll - End Project Dependency - Begin Project Dependency - Project_Dep_Name gxruntime - End Project Dependency - Begin Project Dependency - Project_Dep_Name debugger - End Project Dependency - Begin Project Dependency - Project_Dep_Name blitz - End Project Dependency - Begin Project Dependency - Project_Dep_Name blitz3d - End Project Dependency -}}} - -############################################################################### - -Project: "bbruntime"=.\bbruntime\bbruntime.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "bbruntime_dll"=.\bbruntime_dll\bbruntime_dll.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name bbruntime - End Project Dependency - Begin Project Dependency - Project_Dep_Name gxruntime - End Project Dependency - Begin Project Dependency - Project_Dep_Name stdutil - End Project Dependency - Begin Project Dependency - Project_Dep_Name blitz3d - End Project Dependency -}}} - -############################################################################### - -Project: "blitz"=.\blitz\blitz.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name compiler - End Project Dependency - Begin Project Dependency - Project_Dep_Name stdutil - End Project Dependency -}}} - -############################################################################### - -Project: "blitz3d"=.\blitz3d\blitz3d.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "blitzide"=.\blitzide\blitzide.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name config - End Project Dependency -}}} - -############################################################################### - -Project: "compiler"=.\compiler\compiler.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name config - End Project Dependency - Begin Project Dependency - Project_Dep_Name stdutil - End Project Dependency -}}} - -############################################################################### - -Project: "config"=.\config\config.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "debugger"=.\debugger\debugger.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "gxruntime"=.\gxruntime\gxruntime.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "linker"=.\linker\linker.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name config - End Project Dependency - Begin Project Dependency - Project_Dep_Name stdutil - End Project Dependency -}}} - -############################################################################### - -Project: "linker_dll"=.\linker_dll\linker_dll.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name linker - End Project Dependency - Begin Project Dependency - Project_Dep_Name stdutil - End Project Dependency - Begin Project Dependency - Project_Dep_Name config - End Project Dependency -}}} - -############################################################################### - -Project: "stdutil"=.\stdutil\stdutil.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name config - End Project Dependency -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/blitz3d/blitz3d.vcxproj b/blitz3d/blitz3d.vcxproj new file mode 100644 index 0000000..56058c7 --- /dev/null +++ b/blitz3d/blitz3d.vcxproj @@ -0,0 +1,308 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {BE0BA538-6215-4836-9227-1D3627E40D61} + 10.0.10586.0 + + + + Application + v140 + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\Release\ + .\Release\ + false + + + .\blitz3d___Win32_Blitz2DRelease\ + .\blitz3d___Win32_Blitz2DRelease\ + false + + + .\blitz3d___Win32_Blitz3DRelease\ + .\blitz3d___Win32_Blitz3DRelease\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\blitz3d.pch + Use + std.h + .\Release\ + .\Release\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\blitz3d.bsc + + + true + .\Release\blitz3d.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\blitz3d___Win32_Blitz2DRelease\ + .\blitz3d___Win32_Blitz2DRelease\blitz3d.pch + Use + std.h + .\blitz3d___Win32_Blitz2DRelease\ + .\blitz3d___Win32_Blitz2DRelease\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\blitz3d___Win32_Blitz2DRelease\blitz3d.bsc + + + true + .\blitz3d___Win32_Blitz2DRelease\blitz3d.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + _LIB;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\blitz3d___Win32_Blitz3DRelease\ + .\blitz3d___Win32_Blitz3DRelease\blitz3d.pch + + .\blitz3d___Win32_Blitz3DRelease\ + .\blitz3d___Win32_Blitz3DRelease\ + StdCall + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\blitz3d___Win32_Blitz3DRelease\blitz3d.bsc + + + true + .\blitz3d___Win32_Blitz3DRelease\blitz3d.lib + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\blitz3d.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\blitz3d.bsc + + + true + .\Debug\blitz3d.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + std.h + Create + std.h + Create + std.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/blitz3d/blitz3d.vcxproj.filters b/blitz3d/blitz3d.vcxproj.filters new file mode 100644 index 0000000..7b85dea --- /dev/null +++ b/blitz3d/blitz3d.vcxproj.filters @@ -0,0 +1,233 @@ + + + + + {962a947f-b247-4138-9efd-8b71759b7a57} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {8867a7d7-3bbe-4ef6-a38a-cd4e1a7180d9} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/blitz3d/collision.cpp b/blitz3d/collision.cpp index 9ec2baf..db48723 100644 --- a/blitz3d/collision.cpp +++ b/blitz3d/collision.cpp @@ -2,7 +2,7 @@ #include "std.h" #include "collision.h" -const float COLLISION_EPSILON=.001f; +const float COLLISION_FLT_EPSILON=.001f; /* // @@ -202,7 +202,7 @@ bool Collision::update( const Line &line,float t,const Vector &n ){ if( t>time ) return false; Plane p(line*t,n); if( p.n.dot( line.d )>=0 ) return false; - if( p.distance(line.o)<-COLLISION_EPSILON ) return false; + if( p.distance(line.o)<-COLLISION_FLT_EPSILON ) return false; time=t; normal=n; diff --git a/blitz3d/collision.h b/blitz3d/collision.h index da7ad33..36219f5 100644 --- a/blitz3d/collision.h +++ b/blitz3d/collision.h @@ -4,7 +4,7 @@ #include "geom.h" -extern const float COLLISION_EPSILON; +extern const float COLLISION_FLT_EPSILON; struct Collision{ float time; diff --git a/blitz3d/geom.h b/blitz3d/geom.h index c0e2dbe..4e6fbb8 100644 --- a/blitz3d/geom.h +++ b/blitz3d/geom.h @@ -10,549 +10,549 @@ class Plane; class Matrix; class Transform; -const float PI=3.14159265359f; //180 degrees -const float TWOPI=PI*2.0f; //360 degrees -const float HALFPI=PI*.5f; //90 degrees -const float QUARTERPI=PI*.25f; //45 degrees -const float EPSILON=.000001f; //small value -const float INFINITY=10000000.0f; //big value +static float PI = 3.14159265359f; //180 degrees +static float TWOPI = PI*2.0f; //360 degrees +static float HALFPI = PI*.5f; //90 degrees +static float QUARTERPI = PI*.25f; //45 degrees +//static float FLT_EPSILON=.000001f; //small value +//static float INFINITY=10000000.0f; //big value -class Vector{ +class Vector { public: - float x,y,z; + float x, y, z; - Vector():x(0),y(0),z(0){ + Vector() :x(0), y(0), z(0) { } - Vector( float x,float y,float z ):x(x),y(y),z(z){ + Vector(float x, float y, float z) :x(x), y(y), z(z) { } - operator float*(){ + operator float*() { return &x; } - operator const float *(){ + operator const float *() { return &x; } - float &operator[]( int n ){ - return (&x)[n]; + float &operator[](int n) { + return (&x)[n]; } - float operator[]( int n )const{ - return (&x)[n]; + float operator[](int n)const { + return (&x)[n]; } - Vector operator-()const{ - return Vector( -x,-y,-z ); + Vector operator-()const { + return Vector(-x, -y, -z); } - Vector operator*( float scale )const{ - return Vector( x*scale,y*scale,z*scale ); + Vector operator*(float scale)const { + return Vector(x*scale, y*scale, z*scale); } - Vector operator*( const Vector &q )const{ - return Vector( x*q.x,y*q.y,z*q.z ); + Vector operator*(const Vector &q)const { + return Vector(x*q.x, y*q.y, z*q.z); } - Vector operator/( float scale )const{ - return Vector( x/scale,y/scale,z/scale ); + Vector operator/(float scale)const { + return Vector(x / scale, y / scale, z / scale); } - Vector operator/( const Vector &q )const{ - return Vector( x/q.x,y/q.y,z/q.z ); + Vector operator/(const Vector &q)const { + return Vector(x / q.x, y / q.y, z / q.z); } - Vector operator+( const Vector &q )const{ - return Vector( x+q.x,y+q.y,z+q.z ); + Vector operator+(const Vector &q)const { + return Vector(x + q.x, y + q.y, z + q.z); } - Vector operator-( const Vector &q )const{ - return Vector( x-q.x,y-q.y,z-q.z ); + Vector operator-(const Vector &q)const { + return Vector(x - q.x, y - q.y, z - q.z); } - Vector &operator*=( float scale ){ - x*=scale;y*=scale;z*=scale;return *this; + Vector &operator*=(float scale) { + x *= scale; y *= scale; z *= scale; return *this; } - Vector &operator*=( const Vector &q ){ - x*=q.x;y*=q.y;z*=q.z;return *this; + Vector &operator*=(const Vector &q) { + x *= q.x; y *= q.y; z *= q.z; return *this; } - Vector &operator/=( float scale ){ - x/=scale;y/=scale;z/=scale;return *this; + Vector &operator/=(float scale) { + x /= scale; y /= scale; z /= scale; return *this; } - Vector &operator/=( const Vector &q ){ - x/=q.x;y/=q.y;z/=q.z;return *this; + Vector &operator/=(const Vector &q) { + x /= q.x; y /= q.y; z /= q.z; return *this; } - Vector &operator+=( const Vector &q ){ - x+=q.x;y+=q.y;z+=q.z;return *this; + Vector &operator+=(const Vector &q) { + x += q.x; y += q.y; z += q.z; return *this; } - Vector &operator-=( const Vector &q ){ - x-=q.x;y-=q.y;z-=q.z;return *this; + Vector &operator-=(const Vector &q) { + x -= q.x; y -= q.y; z -= q.z; return *this; } - bool operator<( const Vector &q )const{ - if( fabs(x-q.x)>EPSILON ) return xEPSILON ) return yEPSILON && z FLT_FLT_EPSILON) return x < q.x ? true : false; + if (fabs(y - q.y) > FLT_FLT_EPSILON) return y < q.y ? true : false; + return fabs(z - q.z) > FLT_FLT_EPSILON && z < q.z; } - bool operator==( const Vector &q )const{ - return fabs(x-q.x)<=EPSILON && fabs(y-q.y)<=EPSILON && fabs(z-q.z)<=EPSILON; + bool operator==(const Vector &q)const { + return fabs(x - q.x) <= FLT_FLT_EPSILON && fabs(y - q.y) <= FLT_FLT_EPSILON && fabs(z - q.z) <= FLT_FLT_EPSILON; } - bool operator!=( const Vector &q )const{ - return fabs(x-q.x)>EPSILON || fabs(y-q.y)>EPSILON || fabs(z-q.z)>EPSILON; + bool operator!=(const Vector &q)const { + return fabs(x - q.x) > FLT_FLT_EPSILON || fabs(y - q.y) > FLT_FLT_EPSILON || fabs(z - q.z) > FLT_FLT_EPSILON; } - float dot( const Vector &q )const{ - return x*q.x+y*q.y+z*q.z; + float dot(const Vector &q)const { + return x*q.x + y*q.y + z*q.z; } - Vector cross( const Vector &q )const{ - return Vector( y*q.z-z*q.y,z*q.x-x*q.z,x*q.y-y*q.x ); + Vector cross(const Vector &q)const { + return Vector(y*q.z - z*q.y, z*q.x - x*q.z, x*q.y - y*q.x); } - float length()const{ - return sqrtf(x*x+y*y+z*z); + float length()const { + return sqrtf(x*x + y*y + z*z); } - float distance( const Vector &q )const{ - float dx=x-q.x,dy=y-q.y,dz=z-q.z;return sqrtf(dx*dx+dy*dy+dz*dz); + float distance(const Vector &q)const { + float dx = x - q.x, dy = y - q.y, dz = z - q.z; return sqrtf(dx*dx + dy*dy + dz*dz); } - Vector normalized()const{ - float l=length();return Vector( x/l,y/l,z/l ); + Vector normalized()const { + float l = length(); return Vector(x / l, y / l, z / l); } - void normalize(){ - float l=length();x/=l;y/=l;z/=l; + void normalize() { + float l = length(); x /= l; y /= l; z /= l; } - float yaw()const{ - return -atan2f( x,z ); + float yaw()const { + return -atan2f(x, z); } - float pitch()const{ - return -atan2f( y,sqrtf( x*x+z*z ) ); + float pitch()const { + return -atan2f(y, sqrtf(x*x + z*z)); } - void clear(){ - x=y=z=0; + void clear() { + x = y = z = 0; } }; -class Line{ +class Line { public: - Vector o,d; - Line(){ + Vector o, d; + Line() { } - Line( const Vector &o,const Vector &d ):o(o),d(d){ + Line(const Vector &o, const Vector &d) :o(o), d(d) { } - Line operator+( const Vector &q )const{ - return Line( o+q,d ); + Line operator+(const Vector &q)const { + return Line(o + q, d); } - Line operator-( const Vector &q )const{ - return Line( o-q,d ); + Line operator-(const Vector &q)const { + return Line(o - q, d); } - Vector operator*( float q )const{ - return o+d*q; + Vector operator*(float q)const { + return o + d*q; } - Vector nearest( const Vector &q )const{ - return o+d*(d.dot(q-o)/d.dot(d)); + Vector nearest(const Vector &q)const { + return o + d*(d.dot(q - o) / d.dot(d)); } }; -class Plane{ +class Plane { public: Vector n; float d; - Plane():d(0){ + Plane() :d(0) { } //normal/offset form - Plane( const Vector &n,float d ):n(n),d(d){ + Plane(const Vector &n, float d) :n(n), d(d) { } //point/normal form - Plane( const Vector &p,const Vector &n ):n(n),d(-n.dot(p)){ + Plane(const Vector &p, const Vector &n) :n(n), d(-n.dot(p)) { } //create plane from tri - Plane( const Vector &v0,const Vector &v1,const Vector &v2 ){ - n=(v1-v0).cross(v2-v0).normalized();d=-n.dot(v0); + Plane(const Vector &v0, const Vector &v1, const Vector &v2) { + n = (v1 - v0).cross(v2 - v0).normalized(); d = -n.dot(v0); } - Plane operator-()const{ - return Plane( -n,-d ); + Plane operator-()const { + return Plane(-n, -d); } - float t_intersect( const Line &q )const{ - return -distance(q.o)/n.dot(q.d); + float t_intersect(const Line &q)const { + return -distance(q.o) / n.dot(q.d); } - Vector intersect( const Line &q )const{ + Vector intersect(const Line &q)const { return q*t_intersect(q); } - Line intersect( const Plane &q )const{ - Vector lv=n.cross( q.n ).normalized(); - return Line( q.intersect( Line( nearest( n*-d ),n.cross(lv) ) ),lv ); + Line intersect(const Plane &q)const { + Vector lv = n.cross(q.n).normalized(); + return Line(q.intersect(Line(nearest(n*-d), n.cross(lv))), lv); } - Vector nearest( const Vector &q )const{ - return q-n*distance(q); + Vector nearest(const Vector &q)const { + return q - n*distance(q); } - void negate(){ - n=-n;d=-d; + void negate() { + n = -n; d = -d; } - float distance( const Vector &q )const{ - return n.dot(q)+d; + float distance(const Vector &q)const { + return n.dot(q) + d; } }; -struct Quat{ +struct Quat { float w; Vector v; - Quat():w(1){ + Quat() :w(1) { } - Quat( float w,const Vector &v ):w(w),v(v){ + Quat(float w, const Vector &v) :w(w), v(v) { } - Quat operator-()const{ - return Quat( w,-v ); + Quat operator-()const { + return Quat(w, -v); } - Quat operator+( const Quat &q )const{ - return Quat( w+q.w,v+q.v ); + Quat operator+(const Quat &q)const { + return Quat(w + q.w, v + q.v); } - Quat operator-( const Quat &q )const{ - return Quat( w-q.w,v-q.v ); + Quat operator-(const Quat &q)const { + return Quat(w - q.w, v - q.v); } - Quat operator*( const Quat &q )const{ - return Quat( w*q.w-v.dot(q.v),q.v.cross(v)+q.v*w+v*q.w ); + Quat operator*(const Quat &q)const { + return Quat(w*q.w - v.dot(q.v), q.v.cross(v) + q.v*w + v*q.w); } - Vector operator*( const Vector &q )const{ - return (*this * Quat(0,q) * -*this).v; + Vector operator*(const Vector &q)const { + return (*this * Quat(0, q) * -*this).v; } - Quat operator*( float q )const{ - return Quat( w*q,v*q ); + Quat operator*(float q)const { + return Quat(w*q, v*q); } - Quat operator/( float q )const{ - return Quat( w/q,v/q ); + Quat operator/(float q)const { + return Quat(w / q, v / q); } - float dot( const Quat &q )const{ - return v.x*q.v.x+v.y*q.v.y+v.z*q.v.z+w*q.w; + float dot(const Quat &q)const { + return v.x*q.v.x + v.y*q.v.y + v.z*q.v.z + w*q.w; } - float length()const{ - return sqrtf( w*w+v.x*v.x+v.y*v.y+v.z*v.z ); + float length()const { + return sqrtf(w*w + v.x*v.x + v.y*v.y + v.z*v.z); } - void normalize(){ - *this=*this/length(); + void normalize() { + *this = *this / length(); } - Quat normalized()const{ - return *this/length(); + Quat normalized()const { + return *this / length(); } - Quat slerpTo( const Quat &q,float a )const{ - Quat t=q; - float d=dot(q),b=1-a; - if( d<0 ){ t.w=-t.w;t.v=-t.v;d=-d; } - if( d<1-EPSILON ){ - float om=acosf( d ); - float si=sinf( om ); - a=sinf( a*om )/si; - b=sinf( b*om )/si; + Quat slerpTo(const Quat &q, float a)const { + Quat t = q; + float d = dot(q), b = 1 - a; + if (d < 0) { t.w = -t.w; t.v = -t.v; d = -d; } + if (d < 1 - FLT_FLT_EPSILON) { + float om = acosf(d); + float si = sinf(om); + a = sinf(a*om) / si; + b = sinf(b*om) / si; } return *this*b + t*a; } - Vector i()const{ - float xz=v.x*v.z,wy=w*v.y; - float xy=v.x*v.y,wz=w*v.z; - float yy=v.y*v.y,zz=v.z*v.z; - return Vector( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ); + Vector i()const { + float xz = v.x*v.z, wy = w*v.y; + float xy = v.x*v.y, wz = w*v.z; + float yy = v.y*v.y, zz = v.z*v.z; + return Vector(1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy)); } - Vector j()const{ - float yz=v.y*v.z,wx=w*v.x; - float xy=v.x*v.y,wz=w*v.z; - float xx=v.x*v.x,zz=v.z*v.z; - return Vector( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ); + Vector j()const { + float yz = v.y*v.z, wx = w*v.x; + float xy = v.x*v.y, wz = w*v.z; + float xx = v.x*v.x, zz = v.z*v.z; + return Vector(2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx)); } - Vector k()const{ - float xz=v.x*v.z,wy=w*v.y; - float yz=v.y*v.z,wx=w*v.x; - float xx=v.x*v.x,yy=v.y*v.y; - return Vector( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ); + Vector k()const { + float xz = v.x*v.z, wy = w*v.y; + float yz = v.y*v.z, wx = w*v.x; + float xx = v.x*v.x, yy = v.y*v.y; + return Vector(2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy)); } }; -class Matrix{ +class Matrix { static Matrix tmps[64]; - static Matrix &alloc_tmp(){ static int tmp=0;return tmps[tmp++&63]; } + static Matrix &alloc_tmp() { static int tmp = 0; return tmps[tmp++ & 63]; } friend class Transform; public: - Vector i,j,k; + Vector i, j, k; - Matrix():i(Vector(1,0,0)),j(Vector(0,1,0)),k(Vector(0,0,1)){ + Matrix() :i(Vector(1, 0, 0)), j(Vector(0, 1, 0)), k(Vector(0, 0, 1)) { } - Matrix( const Vector &i,const Vector &j,const Vector &k ):i(i),j(j),k(k){ + Matrix(const Vector &i, const Vector &j, const Vector &k) :i(i), j(j), k(k) { } - Matrix( const Quat &q ){ - float xx=q.v.x*q.v.x,yy=q.v.y*q.v.y,zz=q.v.z*q.v.z; - float xy=q.v.x*q.v.y,xz=q.v.x*q.v.z,yz=q.v.y*q.v.z; - float wx=q.w*q.v.x,wy=q.w*q.v.y,wz=q.w*q.v.z; - i=Vector( 1-2*(yy+zz),2*(xy-wz),2*(xz+wy) ), - j=Vector( 2*(xy+wz),1-2*(xx+zz),2*(yz-wx) ), - k=Vector( 2*(xz-wy),2*(yz+wx),1-2*(xx+yy) ); + Matrix(const Quat &q) { + float xx = q.v.x*q.v.x, yy = q.v.y*q.v.y, zz = q.v.z*q.v.z; + float xy = q.v.x*q.v.y, xz = q.v.x*q.v.z, yz = q.v.y*q.v.z; + float wx = q.w*q.v.x, wy = q.w*q.v.y, wz = q.w*q.v.z; + i = Vector(1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy)), + j = Vector(2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx)), + k = Vector(2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy)); } - Matrix( float angle,const Vector &axis ){ - const Vector &u=axis; - float c=cosf(angle),s=sinf(angle); - float x2=axis.x*axis.x,y2=axis.y*axis.y,z2=axis.z*axis.z; - i=Vector( x2+c*(1-x2),u.x*u.y*(1-c)-u.z*s,u.z*u.x*(1-c)+u.y*s ); - j=Vector( u.x*u.y*(1-c)+u.z*s,y2+c*(1-y2),u.y*u.z*(1-c)-u.x*s ); - k=Vector( u.z*u.x*(1-c)-u.y*s,u.y*u.z*(1-c)+u.x*s,z2+c*(1-z2) ); + Matrix(float angle, const Vector &axis) { + const Vector &u = axis; + float c = cosf(angle), s = sinf(angle); + float x2 = axis.x*axis.x, y2 = axis.y*axis.y, z2 = axis.z*axis.z; + i = Vector(x2 + c*(1 - x2), u.x*u.y*(1 - c) - u.z*s, u.z*u.x*(1 - c) + u.y*s); + j = Vector(u.x*u.y*(1 - c) + u.z*s, y2 + c*(1 - y2), u.y*u.z*(1 - c) - u.x*s); + k = Vector(u.z*u.x*(1 - c) - u.y*s, u.y*u.z*(1 - c) + u.x*s, z2 + c*(1 - z2)); } - Vector &operator[]( int n ){ - return (&i)[n]; - } - const Vector &operator[]( int n )const{ + Vector &operator[](int n) { return (&i)[n]; } - Matrix &operator~()const{ - Matrix &m=alloc_tmp(); - m.i.x=i.x;m.i.y=j.x;m.i.z=k.x; - m.j.x=i.y;m.j.y=j.y;m.j.z=k.y; - m.k.x=i.z;m.k.y=j.z;m.k.z=k.z; + const Vector &operator[](int n)const { + return (&i)[n]; + } + Matrix &operator~()const { + Matrix &m = alloc_tmp(); + m.i.x = i.x; m.i.y = j.x; m.i.z = k.x; + m.j.x = i.y; m.j.y = j.y; m.j.z = k.y; + m.k.x = i.z; m.k.y = j.z; m.k.z = k.z; return m; } - float determinant()const{ - return i.x*(j.y*k.z-j.z*k.y )-i.y*(j.x*k.z-j.z*k.x )+i.z*(j.x*k.y-j.y*k.x ); + float determinant()const { + return i.x*(j.y*k.z - j.z*k.y) - i.y*(j.x*k.z - j.z*k.x) + i.z*(j.x*k.y - j.y*k.x); } - Matrix &operator-()const{ - Matrix &m=alloc_tmp(); - float t=1.0f/determinant(); - m.i.x= t*(j.y*k.z-j.z*k.y);m.i.y=-t*(i.y*k.z-i.z*k.y);m.i.z= t*(i.y*j.z-i.z*j.y); - m.j.x=-t*(j.x*k.z-j.z*k.x);m.j.y= t*(i.x*k.z-i.z*k.x);m.j.z=-t*(i.x*j.z-i.z*j.x); - m.k.x= t*(j.x*k.y-j.y*k.x);m.k.y=-t*(i.x*k.y-i.y*k.x);m.k.z= t*(i.x*j.y-i.y*j.x); + Matrix &operator-()const { + Matrix &m = alloc_tmp(); + float t = 1.0f / determinant(); + m.i.x = t*(j.y*k.z - j.z*k.y); m.i.y = -t*(i.y*k.z - i.z*k.y); m.i.z = t*(i.y*j.z - i.z*j.y); + m.j.x = -t*(j.x*k.z - j.z*k.x); m.j.y = t*(i.x*k.z - i.z*k.x); m.j.z = -t*(i.x*j.z - i.z*j.x); + m.k.x = t*(j.x*k.y - j.y*k.x); m.k.y = -t*(i.x*k.y - i.y*k.x); m.k.z = t*(i.x*j.y - i.y*j.x); return m; } - Matrix &cofactor()const{ - Matrix &m=alloc_tmp(); - m.i.x= (j.y*k.z-j.z*k.y);m.i.y=-(j.x*k.z-j.z*k.x);m.i.z= (j.x*k.y-j.y*k.x); - m.j.x=-(i.y*k.z-i.z*k.y);m.j.y= (i.x*k.z-i.z*k.x);m.j.z=-(i.x*k.y-i.y*k.x); - m.k.x= (i.y*j.z-i.z*j.y);m.k.y=-(i.x*j.z-i.z*j.x);m.k.z= (i.x*j.y-i.y*j.x); + Matrix &cofactor()const { + Matrix &m = alloc_tmp(); + m.i.x = (j.y*k.z - j.z*k.y); m.i.y = -(j.x*k.z - j.z*k.x); m.i.z = (j.x*k.y - j.y*k.x); + m.j.x = -(i.y*k.z - i.z*k.y); m.j.y = (i.x*k.z - i.z*k.x); m.j.z = -(i.x*k.y - i.y*k.x); + m.k.x = (i.y*j.z - i.z*j.y); m.k.y = -(i.x*j.z - i.z*j.x); m.k.z = (i.x*j.y - i.y*j.x); return m; } - bool operator==( const Matrix &q )const{ - return i==q.i && j==q.j && k==q.k; + bool operator==(const Matrix &q)const { + return i == q.i && j == q.j && k == q.k; } - bool operator!=( const Matrix &q )const{ - return i!=q.i || j!=q.j || k!=q.k; + bool operator!=(const Matrix &q)const { + return i != q.i || j != q.j || k != q.k; } - Vector operator*( const Vector &q )const{ - return Vector( i.x*q.x+j.x*q.y+k.x*q.z,i.y*q.x+j.y*q.y+k.y*q.z,i.z*q.x+j.z*q.y+k.z*q.z ); + Vector operator*(const Vector &q)const { + return Vector(i.x*q.x + j.x*q.y + k.x*q.z, i.y*q.x + j.y*q.y + k.y*q.z, i.z*q.x + j.z*q.y + k.z*q.z); } - Matrix &operator*( const Matrix &q )const{ - Matrix &m=alloc_tmp(); - m.i.x=i.x*q.i.x+j.x*q.i.y+k.x*q.i.z;m.i.y=i.y*q.i.x+j.y*q.i.y+k.y*q.i.z;m.i.z=i.z*q.i.x+j.z*q.i.y+k.z*q.i.z; - m.j.x=i.x*q.j.x+j.x*q.j.y+k.x*q.j.z;m.j.y=i.y*q.j.x+j.y*q.j.y+k.y*q.j.z;m.j.z=i.z*q.j.x+j.z*q.j.y+k.z*q.j.z; - m.k.x=i.x*q.k.x+j.x*q.k.y+k.x*q.k.z;m.k.y=i.y*q.k.x+j.y*q.k.y+k.y*q.k.z;m.k.z=i.z*q.k.x+j.z*q.k.y+k.z*q.k.z; + Matrix &operator*(const Matrix &q)const { + Matrix &m = alloc_tmp(); + m.i.x = i.x*q.i.x + j.x*q.i.y + k.x*q.i.z; m.i.y = i.y*q.i.x + j.y*q.i.y + k.y*q.i.z; m.i.z = i.z*q.i.x + j.z*q.i.y + k.z*q.i.z; + m.j.x = i.x*q.j.x + j.x*q.j.y + k.x*q.j.z; m.j.y = i.y*q.j.x + j.y*q.j.y + k.y*q.j.z; m.j.z = i.z*q.j.x + j.z*q.j.y + k.z*q.j.z; + m.k.x = i.x*q.k.x + j.x*q.k.y + k.x*q.k.z; m.k.y = i.y*q.k.x + j.y*q.k.y + k.y*q.k.z; m.k.z = i.z*q.k.x + j.z*q.k.y + k.z*q.k.z; return m; } - void orthogonalize(){ + void orthogonalize() { k.normalize(); - i=j.cross( k ).normalized(); - j=k.cross( i ); + i = j.cross(k).normalized(); + j = k.cross(i); } - Matrix &orthogonalized()const{ - Matrix &m=alloc_tmp(); - m=*this;m.orthogonalize(); + Matrix &orthogonalized()const { + Matrix &m = alloc_tmp(); + m = *this; m.orthogonalize(); return m; } }; -class Box{ +class Box { public: - Vector a,b; - Box():a( Vector(INFINITY,INFINITY,INFINITY) ),b( Vector(-INFINITY,-INFINITY,-INFINITY) ){ + Vector a, b; + Box() :a(Vector(INFINITY, INFINITY, INFINITY)), b(Vector(-INFINITY, -INFINITY, -INFINITY)) { } - Box( const Vector &q ):a(q),b(q){ + Box(const Vector &q) :a(q), b(q) { } - Box( const Vector &a,const Vector &b ):a(a),b(b){ + Box(const Vector &a, const Vector &b) :a(a), b(b) { } - Box( const Line &l ):a(l.o),b(l.o){ - update( l.o+l.d ); + Box(const Line &l) :a(l.o), b(l.o) { + update(l.o + l.d); } - void clear(){ - a.x=a.y=a.z=INFINITY; - b.x=b.y=b.z=-INFINITY; + void clear() { + a.x = a.y = a.z = INFINITY; + b.x = b.y = b.z = -INFINITY; } - bool empty()const{ - return b.xb.x ) b.x=q.x;if( q.y>b.y ) b.y=q.y;if( q.z>b.z ) b.z=q.z; + void update(const Vector &q) { + if (q.x < a.x) a.x = q.x; if (q.y < a.y) a.y = q.y; if (q.z < a.z) a.z = q.z; + if (q.x > b.x) b.x = q.x; if (q.y > b.y) b.y = q.y; if (q.z > b.z) b.z = q.z; } - void update( const Box &q ){ - if( q.a.xb.x ) b.x=q.b.x;if( q.b.y>b.y ) b.y=q.b.y;if( q.b.z>b.z ) b.z=q.b.z; + void update(const Box &q) { + if (q.a.x < a.x) a.x = q.a.x; if (q.a.y < a.y) a.y = q.a.y; if (q.a.z < a.z) a.z = q.a.z; + if (q.b.x > b.x) b.x = q.b.x; if (q.b.y > b.y) b.y = q.b.y; if (q.b.z > b.z) b.z = q.b.z; } - bool overlaps( const Box &q )const{ + bool overlaps(const Box &q)const { return - (b.x=(a.x>q.a.x?a.x:q.a.x) && - (b.y=(a.y>q.a.y?a.y:q.a.y) && - (b.z=(a.z>q.a.z?a.z:q.a.z); + (b.x < q.b.x ? b.x : q.b.x) >= (a.x > q.a.x ? a.x : q.a.x) && + (b.y < q.b.y ? b.y : q.b.y) >= (a.y > q.a.y ? a.y : q.a.y) && + (b.z < q.b.z ? b.z : q.b.z) >= (a.z > q.a.z ? a.z : q.a.z); } - void expand( float n ){ - a.x-=n;a.y-=n;a.z-=n;b.x+=n;b.y+=n;b.z+=n; + void expand(float n) { + a.x -= n; a.y -= n; a.z -= n; b.x += n; b.y += n; b.z += n; } - float width()const{ - return b.x-a.x; + float width()const { + return b.x - a.x; } - float height()const{ - return b.y-a.y; + float height()const { + return b.y - a.y; } - float depth()const{ - return b.z-a.z; + float depth()const { + return b.z - a.z; } - bool contains( const Vector &q ){ - return q.x>=a.x && q.x<=b.x && q.y>=a.y && q.y<=b.y && q.z>=a.z && q.z<=b.z; + bool contains(const Vector &q) { + return q.x >= a.x && q.x <= b.x && q.y >= a.y && q.y <= b.y && q.z >= a.z && q.z <= b.z; } }; -class Transform{ +class Transform { static Transform tmps[64]; - static Transform &alloc_tmp(){ static int tmp=0;return tmps[tmp++&63]; } + static Transform &alloc_tmp() { static int tmp = 0; return tmps[tmp++ & 63]; } public: Matrix m; Vector v; - Transform(){ + Transform() { } - Transform( const Matrix &m ):m(m){ + Transform(const Matrix &m) :m(m) { } - Transform( const Vector &v ):v(v){ + Transform(const Vector &v) :v(v) { } - Transform( const Matrix &m,const Vector &v ):m(m),v(v){ + Transform(const Matrix &m, const Vector &v) :m(m), v(v) { } - Transform &operator-()const{ - Transform &t=alloc_tmp(); - t.m=-m;t.v=t.m*-v; + Transform &operator-()const { + Transform &t = alloc_tmp(); + t.m = -m; t.v = t.m*-v; return t; } - Transform &operator~()const{ - Transform &t=alloc_tmp(); - t.m=~m;t.v=t.m*-v; + Transform &operator~()const { + Transform &t = alloc_tmp(); + t.m = ~m; t.v = t.m*-v; return t; } - Vector operator*( const Vector &q )const{ - return m*q+v; + Vector operator*(const Vector &q)const { + return m*q + v; } - Line operator*( const Line &q )const{ - Vector t=(*this)*q.o; - return Line( t,(*this)*(q.o+q.d)-t ); + Line operator*(const Line &q)const { + Vector t = (*this)*q.o; + return Line(t, (*this)*(q.o + q.d) - t); } - Box operator*( const Box &q )const{ - Box t( (*this*q.corner(0) ) ); - for( int k=1;k<8;++k ) t.update( *this*q.corner(k) ); + Box operator*(const Box &q)const { + Box t((*this*q.corner(0))); + for (int k = 1; k < 8; ++k) t.update(*this*q.corner(k)); return t; } - Transform &operator*( const Transform &q )const{ - Transform &t=alloc_tmp(); - t.m=m*q.m;t.v=m*q.v+v; + Transform &operator*(const Transform &q)const { + Transform &t = alloc_tmp(); + t.m = m*q.m; t.v = m*q.v + v; return t; } - bool operator==( const Transform &q )const{ - return m==q.m && v==q.v; + bool operator==(const Transform &q)const { + return m == q.m && v == q.v; } - bool operator!=( const Transform &q )const{ - return !operator==( q ); + bool operator!=(const Transform &q)const { + return !operator==(q); } }; -inline float transformRadius( float r,const Matrix &t ){ - static const float sq_3=sqrtf(1.0f/3.0f); - return (t * Vector( sq_3,sq_3,sq_3 )).length()*r; +inline float transformRadius(float r, const Matrix &t) { + static const float sq_3 = sqrtf(1.0f / 3.0f); + return (t * Vector(sq_3, sq_3, sq_3)).length()*r; } -inline Matrix pitchMatrix( float q ){ - return Matrix( Vector(1,0,0),Vector(0,cosf(q),sinf(q)),Vector(0,-sinf(q),cosf(q)) ); +inline Matrix pitchMatrix(float q) { + return Matrix(Vector(1, 0, 0), Vector(0, cosf(q), sinf(q)), Vector(0, -sinf(q), cosf(q))); } -inline Matrix yawMatrix( float q ){ - return Matrix( Vector(cosf(q),0,sinf(q)),Vector(0,1,0),Vector(-sinf(q),0,cosf(q)) ); +inline Matrix yawMatrix(float q) { + return Matrix(Vector(cosf(q), 0, sinf(q)), Vector(0, 1, 0), Vector(-sinf(q), 0, cosf(q))); } -inline Matrix rollMatrix( float q ){ - return Matrix( Vector(cosf(q),sinf(q),0),Vector(-sinf(q),cosf(q),0),Vector(0,0,1) ); +inline Matrix rollMatrix(float q) { + return Matrix(Vector(cosf(q), sinf(q), 0), Vector(-sinf(q), cosf(q), 0), Vector(0, 0, 1)); } -inline float matrixPitch( const Matrix &m ){ +inline float matrixPitch(const Matrix &m) { return m.k.pitch(); -// return asinf( -m.k.y ); + // return asinf( -m.k.y ); } -inline float matrixYaw( const Matrix &m ){ +inline float matrixYaw(const Matrix &m) { return m.k.yaw(); //return atan2f( -m.k.x,m.k.z ); } -inline float matrixRoll( const Matrix &m ){ - return atan2f( m.i.y,m.j.y ); +inline float matrixRoll(const Matrix &m) { + return atan2f(m.i.y, m.j.y); //Matrix t=pitchMatrix( -matrixPitch(m) )*yawMatrix( -matrixYaw(m) )*m; //return atan2f( t.i.y,t.i.x ); } -inline Matrix scaleMatrix( float x,float y,float z ){ - return Matrix( Vector( x,0,0 ),Vector( 0,y,0 ),Vector( 0,0,z ) ); +inline Matrix scaleMatrix(float x, float y, float z) { + return Matrix(Vector(x, 0, 0), Vector(0, y, 0), Vector(0, 0, z)); } -inline Matrix scaleMatrix( const Vector &scale ){ - return Matrix( Vector( scale.x,0,0 ),Vector( 0,scale.y,0 ),Vector( 0,0,scale.z ) ); +inline Matrix scaleMatrix(const Vector &scale) { + return Matrix(Vector(scale.x, 0, 0), Vector(0, scale.y, 0), Vector(0, 0, scale.z)); } -inline Quat pitchQuat( float p ){ - return Quat( cosf(p/-2),Vector( sinf(p/-2),0,0 ) ); +inline Quat pitchQuat(float p) { + return Quat(cosf(p / -2), Vector(sinf(p / -2), 0, 0)); } -inline Quat yawQuat( float y ){ - return Quat( cosf(y/2),Vector( 0,sinf(y/2),0 ) ); +inline Quat yawQuat(float y) { + return Quat(cosf(y / 2), Vector(0, sinf(y / 2), 0)); } -inline Quat rollQuat( float r ){ - return Quat( cosf(r/-2),Vector( 0,0,sinf(r/-2) ) ); +inline Quat rollQuat(float r) { + return Quat(cosf(r / -2), Vector(0, 0, sinf(r / -2))); } //inline Quat rotationQuat( float p,float y,float r ){ // return yawQuat(y)*pitchQuat(p)*rollQuat(r); //} -Quat rotationQuat( float p,float y,float r ); +Quat rotationQuat(float p, float y, float r); -inline Matrix rotationMatrix( float p,float y,float r ){ +inline Matrix rotationMatrix(float p, float y, float r) { return yawMatrix(y)*pitchMatrix(p)*rollMatrix(r); } -inline Matrix rotationMatrix( const Vector &rot ){ +inline Matrix rotationMatrix(const Vector &rot) { return yawMatrix(rot.y)*pitchMatrix(rot.x)*rollMatrix(rot.z); } -inline float quatPitch( const Quat &q ){ +inline float quatPitch(const Quat &q) { return q.k().pitch(); } -inline float quatYaw( const Quat &q ){ +inline float quatYaw(const Quat &q) { return q.k().yaw(); } -inline float quatRoll( const Quat &q ){ -// Vector i=q.i(),j=q.j(); -// return atan2f( i.y,j.y ); - return matrixRoll( q ); +inline float quatRoll(const Quat &q) { + // Vector i=q.i(),j=q.j(); + // return atan2f( i.y,j.y ); + return matrixRoll(q); } -inline Quat matrixQuat( const Matrix &p ){ - Matrix m=p; +inline Quat matrixQuat(const Matrix &p) { + Matrix m = p; m.orthogonalize(); - float t=m.i.x+m.j.y+m.k.z,w,x,y,z; - if( t>EPSILON ){ - t=sqrtf( t+1 )*2; - x=(m.k.y-m.j.z)/t; - y=(m.i.z-m.k.x)/t; - z=(m.j.x-m.i.y)/t; - w=t/4; - }else if( m.i.x>m.j.y && m.i.x>m.k.z ){ - t=sqrtf( m.i.x-m.j.y-m.k.z+1 )*2; - x=t/4; - y=(m.j.x+m.i.y)/t; - z=(m.i.z+m.k.x)/t; - w=(m.k.y-m.j.z)/t; - }else if( m.j.y>m.k.z ){ - t=sqrtf( m.j.y-m.k.z-m.i.x+1 )*2; - x=(m.j.x+m.i.y)/t; - y=t/4; - z=(m.k.y+m.j.z)/t; - w=(m.i.z-m.k.x)/t; - }else{ - t=sqrtf( m.k.z-m.j.y-m.i.x+1 )*2; - x=(m.i.z+m.k.x)/t; - y=(m.k.y+m.j.z)/t; - z=t/4; - w=(m.j.x-m.i.y)/t; + float t = m.i.x + m.j.y + m.k.z, w, x, y, z; + if (t > FLT_FLT_EPSILON) { + t = sqrtf(t + 1) * 2; + x = (m.k.y - m.j.z) / t; + y = (m.i.z - m.k.x) / t; + z = (m.j.x - m.i.y) / t; + w = t / 4; + } else if (m.i.x > m.j.y && m.i.x > m.k.z) { + t = sqrtf(m.i.x - m.j.y - m.k.z + 1) * 2; + x = t / 4; + y = (m.j.x + m.i.y) / t; + z = (m.i.z + m.k.x) / t; + w = (m.k.y - m.j.z) / t; + } else if (m.j.y > m.k.z) { + t = sqrtf(m.j.y - m.k.z - m.i.x + 1) * 2; + x = (m.j.x + m.i.y) / t; + y = t / 4; + z = (m.k.y + m.j.z) / t; + w = (m.i.z - m.k.x) / t; + } else { + t = sqrtf(m.k.z - m.j.y - m.i.x + 1) * 2; + x = (m.i.z + m.k.x) / t; + y = (m.k.y + m.j.z) / t; + z = t / 4; + w = (m.j.x - m.i.y) / t; } - return Quat( w,Vector( x,y,z ) ); + return Quat(w, Vector(x, y, z)); } #endif \ No newline at end of file diff --git a/blitz3d/loader_3ds.cpp b/blitz3d/loader_3ds.cpp index 7576a5f..6c0413f 100644 --- a/blitz3d/loader_3ds.cpp +++ b/blitz3d/loader_3ds.cpp @@ -343,7 +343,7 @@ static void parseAnimKeys( Animation *anim,int type ){ in.sgetn( (char*)&angle,4 ); in.sgetn( (char*)&axis,12 ); // _log( "ROT_KEY: time="+itoa(time)+" angle="+ftoa(angle)+" axis="+ftoa(axis.x)+","+ftoa(axis.y)+","+ftoa(axis.z) ); - if( axis.length()>EPSILON ){ + if( axis.length()>FLT_EPSILON ){ if( flip_tris ) angle=-angle; if( conv ) axis=conv_tform.m*axis; quat=Quat( cosf( angle/2 ),axis.normalized()*sinf( angle/2 ) )*quat; @@ -394,8 +394,8 @@ static void parseMeshInfo( MeshModel *root,float curr_time ){ _log( "PIVOT: "+ftoa(pivot.x)+","+ftoa(pivot.y)+","+ftoa(pivot.z) ); break; case 0xb014: //BOUNDBOX - in.sgetn( (char*)&box.a,12 ); - in.sgetn( (char*)&box.b,12 ); + in.sgetn( (char*)&(box.a),12 ); + in.sgetn( (char*)&(box.b),12 ); box_centre=box.centre(); if( conv ) box_centre=conv_tform * box_centre; _log( "BOUNDBOX: min="+ftoa(box.a.x)+","+ftoa(box.a.y)+","+ftoa(box.a.z)+" max="+ftoa(box.b.x)+","+ftoa(box.b.y)+","+ftoa(box.b.z) ); diff --git a/blitz3d/loader_x.cpp b/blitz3d/loader_x.cpp index 0a3adfa..18e48be 100644 --- a/blitz3d/loader_x.cpp +++ b/blitz3d/loader_x.cpp @@ -34,7 +34,7 @@ static void parseAnimKey( IDirectXFileData *fileData,MeshModel *e ){ if( n==4 ){ Quat rot=*(Quat*)data; if( conv ){ - if( fabs(rot.w)<1-EPSILON ){ + if( fabs(rot.w)<1-FLT_EPSILON ){ rot.normalize(); //quat-to-axis/angle float half=acosf( rot.w ); diff --git a/blitz3d/md2rep.cpp b/blitz3d/md2rep.cpp index ef6709c..1cd8255 100644 --- a/blitz3d/md2rep.cpp +++ b/blitz3d/md2rep.cpp @@ -6,164 +6,164 @@ extern gxRuntime *gx_runtime; extern gxGraphics *gx_graphics; -static Vector *normals=0; -static float tex_coords[2][2]={{0,0},{0,0}}; +static Vector *normals = 0; +static float tex_coords[2][2] = { {0,0},{0,0} }; #pragma pack( push,1 ) -struct md2_header{ - int magic; - int version; - int skinWidth; - int skinHeight; - int frameSize; - int numSkins; - int numVertices; - int numTexCoords; - int numTriangles; - int numGlCommands; - int numFrames; - int offsetSkins; - int offsetTexCoords; - int offsetTriangles; - int offsetFrames; - int offsetGlCommands; +struct md2_header { + int magic; + int version; + int skinWidth; + int skinHeight; + int frameSize; + int numSkins; + int numVertices; + int numTexCoords; + int numTriangles; + int numGlCommands; + int numFrames; + int offsetSkins; + int offsetTexCoords; + int offsetTriangles; + int offsetFrames; + int offsetGlCommands; int offsetEnd; }; -struct md2_uv{ - short u,v; +struct md2_uv { + short u, v; }; -struct md2_vert{ - unsigned char x,y,z,n; +struct md2_vert { + unsigned char x, y, z, n; }; -struct md2_tri{ - unsigned short verts[3],uvs[3]; +struct md2_tri { + unsigned short verts[3], uvs[3]; }; #pragma pack( pop ) -struct t_vert{ - unsigned short i,uv; - bool operator<( const t_vert &t )const{ - return memcmp( &i,&t.i,4 )<0; +struct t_vert { + unsigned short i, uv; + bool operator<(const t_vert &t)const { + return memcmp(&i, &t.i, 4) < 0; } }; -struct t_tri{ +struct t_tri { unsigned short verts[3]; }; -MD2Rep::MD2Rep( const string &f ): -mesh(0),n_verts(0),n_tris(0),n_frames(0){ +MD2Rep::MD2Rep(const string &f) : + mesh(0), n_verts(0), n_tris(0), n_frames(0) { filebuf in; md2_header header; - if( !in.open( f.c_str(),ios_base::in|ios_base::binary ) ) return; - if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ) return; - if( header.magic!='2PDI' || header.version!=8 ) return; + if (!in.open(f.c_str(), ios_base::in | ios_base::binary)) return; + if (in.sgetn((char*)&header, sizeof(header)) != sizeof(header)) return; + if (header.magic != '2PDI' || header.version != 8) return; - n_frames=header.numFrames; - n_tris=header.numTriangles; + n_frames = header.numFrames; + n_tris = header.numTriangles; //read in tex coords vector md2_uvs; - md2_uvs.resize( header.numTexCoords ); - in.pubseekpos( header.offsetTexCoords ); - in.sgetn( (char*)md2_uvs.begin(),header.numTexCoords*sizeof(md2_uv) ); + md2_uvs.resize(header.numTexCoords); + in.pubseekpos(header.offsetTexCoords); + in.sgetn((char*)(&md2_uvs.begin()[0]), header.numTexCoords * sizeof(md2_uv)); //read in triangles vector md2_tris; - md2_tris.resize( n_tris ); - in.pubseekpos( header.offsetTriangles ); - in.sgetn( (char*)md2_tris.begin(),n_tris*sizeof(md2_tri) ); + md2_tris.resize(n_tris); + in.pubseekpos(header.offsetTriangles); + in.sgetn((char*)(&md2_tris.begin()[0]), n_tris * sizeof(md2_tri)); vector t_tris; vector t_verts; - map t_map; + map t_map; int k; - for( k=0;k::iterator it=t_map.find( t ); - if( it==t_map.end() ){ + t.i = md2_tris[k].verts[j]; + t.uv = md2_tris[k].uvs[j]; + map::iterator it = t_map.find(t); + if (it == t_map.end()) { //create new vert - tr.verts[j]=t_map[t]=t_verts.size(); - t_verts.push_back( t ); + tr.verts[j] = t_map[t] = t_verts.size(); + t_verts.push_back(t); //add UVs VertexUV uv; - uv.u=md2_uvs[t.uv].u/(float)(header.skinWidth); - uv.v=md2_uvs[t.uv].v/(float)(header.skinHeight); - uvs.push_back( uv ); - }else{ + uv.u = md2_uvs[t.uv].u / (float)(header.skinWidth); + uv.v = md2_uvs[t.uv].v / (float)(header.skinHeight); + uvs.push_back(uv); + } else { //reuse vert - tr.verts[j]=it->second; + tr.verts[j] = it->second; } } - t_tris.push_back( tr ); + t_tris.push_back(tr); } - n_verts=t_verts.size(); + n_verts = t_verts.size(); - frames.resize( n_frames ); - in.pubseekpos( header.offsetFrames ); + frames.resize(n_frames); + in.pubseekpos(header.offsetFrames); vector md2_verts; - md2_verts.resize( header.numVertices ); + md2_verts.resize(header.numVertices); //read in frames - for( k=0;kscale,12 ); - in.sgetn( (char*)&fr->trans,12 ); - in.sgetn( t_buff,16 ); + Frame *fr = &frames[k]; + in.sgetn((char*)&fr->scale, 12); + in.sgetn((char*)&fr->trans, 12); + in.sgetn(t_buff, 16); - fr->scale=Vector( fr->scale.y,fr->scale.z,fr->scale.x ); - fr->trans=Vector( fr->trans.y,fr->trans.z,fr->trans.x ); + fr->scale = Vector(fr->scale.y, fr->scale.z, fr->scale.x); + fr->trans = Vector(fr->trans.y, fr->trans.z, fr->trans.x); //read vertices - in.sgetn( (char*)md2_verts.begin(),header.numVertices*sizeof(md2_vert) ); + in.sgetn((char*)&md2_verts.begin()[0], header.numVertices * sizeof(md2_vert)); - fr->verts.resize( n_verts ); - for( int j=0;jverts[j]; - const t_vert &tv=t_verts[j]; - const md2_vert &mv=md2_verts[tv.i]; - v->x=mv.y; - v->y=mv.z; - v->z=mv.x; - v->n=mv.n; - box.update( Vector( v->x,v->y,v->z ) * fr->scale + fr->trans ); + fr->verts.resize(n_verts); + for (int j = 0; j < n_verts; ++j) { + Vertex *v = &fr->verts[j]; + const t_vert &tv = t_verts[j]; + const md2_vert &mv = md2_verts[tv.i]; + v->x = mv.y; + v->y = mv.z; + v->z = mv.x; + v->n = mv.n; + box.update(Vector(v->x, v->y, v->z) * fr->scale + fr->trans); } } //create mesh and setup tris - mesh=gx_graphics->createMesh( n_verts,n_tris,0 ); - mesh->lock( true ); - for( k=0;ksetTriangle( k,t.verts[0],t.verts[2],t.verts[1] ); + mesh = gx_graphics->createMesh(n_verts, n_tris, 0); + mesh->lock(true); + for (k = 0; k < n_tris; ++k) { + const t_tri &t = t_tris[k]; + mesh->setTriangle(k, t.verts[0], t.verts[2], t.verts[1]); } mesh->unlock(); //build normals - if( !normals ){ - normals=(Vector*)md2norms; - for( int k=0;kfreeMesh( mesh ); +MD2Rep::~MD2Rep() { + if (mesh) gx_graphics->freeMesh(mesh); } /* @@ -180,41 +180,41 @@ void MD2Rep::render( Vert *v,int frame ){ } */ -void MD2Rep::render( Vert *v,int frame,float time ){ +void MD2Rep::render(Vert *v, int frame, float time) { - const Frame &frame_b=frames[frame]; - const Vertex *v_b=frame_b.verts.begin(); - const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + const Frame &frame_b = frames[frame]; + const Vertex *v_b = (Vertex*)(&frame_b.verts.begin()[0]); + const Vector scale_b = frame_b.scale, trans_b = frame_b.trans; - for( int k=0;kx*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); - const Vector &n_b=normals[ v_b->n ]; + const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z); + const Vector &n_b = normals[v_b->n]; - v->coords+=(t_b-v->coords)*time; - v->normal+=(n_b-v->normal)*time; + v->coords += (t_b - v->coords)*time; + v->normal += (n_b - v->normal)*time; } } -void MD2Rep::render( Vert *v,int render_a,int render_b,float render_t ){ - const Frame &frame_a=frames[render_a]; - const Vector scale_a=frame_a.scale,trans_a=frame_a.trans; +void MD2Rep::render(Vert *v, int render_a, int render_b, float render_t) { + const Frame &frame_a = frames[render_a]; + const Vector scale_a = frame_a.scale, trans_a = frame_a.trans; - const Frame &frame_b=frames[render_b]; - const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + const Frame &frame_b = frames[render_b]; + const Vector scale_b = frame_b.scale, trans_b = frame_b.trans; - const Vertex *v_a=frame_a.verts.begin(); - const Vertex *v_b=frame_b.verts.begin(); + const Vertex *v_a = (Vertex*)(&frame_a.verts.begin()[0]); + const Vertex *v_b = (Vertex*)(&frame_b.verts.begin()[0]); - for( int k=0;kx*scale_a.x+trans_a.x,v_a->y*scale_a.y+trans_a.y,v_a->z*scale_a.z+trans_a.z ); - const Vector t_b( v_b->x*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); - v->coords=(t_b-t_a)*render_t+t_a; + const Vector t_a(v_a->x*scale_a.x + trans_a.x, v_a->y*scale_a.y + trans_a.y, v_a->z*scale_a.z + trans_a.z); + const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z); + v->coords = (t_b - t_a)*render_t + t_a; - const Vector &n_a=normals[v_a->n]; - const Vector &n_b=normals[v_b->n]; - v->normal=(n_b-n_a)*render_t+n_a; + const Vector &n_a = normals[v_a->n]; + const Vector &n_b = normals[v_b->n]; + v->normal = (n_b - n_a)*render_t + n_a; } } @@ -227,36 +227,36 @@ void MD2Rep::render( Vert *v,const Vert *v_a,const Vert *v_b,float render_t ){ } */ -void MD2Rep::render( Model *model,int render_a,int render_b,float render_t ){ - const Frame &frame_a=frames[render_a]; - const Vector scale_a=frame_a.scale,trans_a=frame_a.trans; +void MD2Rep::render(Model *model, int render_a, int render_b, float render_t) { + const Frame &frame_a = frames[render_a]; + const Vector scale_a = frame_a.scale, trans_a = frame_a.trans; - const Frame &frame_b=frames[render_b]; - const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + const Frame &frame_b = frames[render_b]; + const Vector scale_b = frame_b.scale, trans_b = frame_b.trans; - const VertexUV *uv=uvs.begin(); - const Vertex *v_a=frame_a.verts.begin(); - const Vertex *v_b=frame_b.verts.begin(); + const VertexUV *uv = (VertexUV*)&uvs.begin()[0]; + const Vertex *v_a = (Vertex*)(&frame_a.verts.begin()[0]); + const Vertex *v_b = (Vertex*)(&frame_b.verts.begin()[0]); - mesh->lock( true ); - for( int k=0;klock(true); + for (int k = 0; k < n_verts; ++uv, ++v_a, ++v_b, ++k) { - const Vector t_a( v_a->x*scale_a.x+trans_a.x,v_a->y*scale_a.y+trans_a.y,v_a->z*scale_a.z+trans_a.z ); - const Vector t_b( v_b->x*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); - const Vector t( (t_b-t_a)*render_t+t_a ); + const Vector t_a(v_a->x*scale_a.x + trans_a.x, v_a->y*scale_a.y + trans_a.y, v_a->z*scale_a.z + trans_a.z); + const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z); + const Vector t((t_b - t_a)*render_t + t_a); - const Vector &n_a=normals[v_a->n]; - const Vector &n_b=normals[v_b->n]; - const Vector n( (n_b-n_a)*render_t+n_a ); + const Vector &n_a = normals[v_a->n]; + const Vector &n_b = normals[v_b->n]; + const Vector n((n_b - n_a)*render_t + n_a); - tex_coords[0][0]=uv->u; - tex_coords[0][1]=uv->v; + tex_coords[0][0] = uv->u; + tex_coords[0][1] = uv->v; - mesh->setVertex( k,&t.x,&n.x,tex_coords ); + mesh->setVertex(k, &t.x, &n.x, tex_coords); } mesh->unlock(); - model->enqueue( mesh,0,n_verts,0,n_tris ); + model->enqueue(mesh, 0, n_verts, 0, n_tris); } /* void MD2Rep::render( Model *model,const Vert *v_a,const Vert *v_b,float render_t ){ @@ -280,30 +280,30 @@ void MD2Rep::render( Model *model,const Vert *v_a,const Vert *v_b,float render_t } */ -void MD2Rep::render( Model *model,const Vert *v_a,int render_b,float render_t ){ +void MD2Rep::render(Model *model, const Vert *v_a, int render_b, float render_t) { - const Frame &frame_b=frames[render_b]; - const Vector scale_b=frame_b.scale,trans_b=frame_b.trans; + const Frame &frame_b = frames[render_b]; + const Vector scale_b = frame_b.scale, trans_b = frame_b.trans; - const VertexUV *uv=uvs.begin(); - const Vertex *v_b=frame_b.verts.begin(); + const VertexUV *uv = (VertexUV*)&uvs.begin()[0]; + const Vertex *v_b = (Vertex*)&frame_b.verts.begin()[0]; - mesh->lock( true ); - for( int k=0;klock(true); + for (int k = 0; k < n_verts; ++uv, ++v_a, ++v_b, ++k) { - const Vector t_b( v_b->x*scale_b.x+trans_b.x,v_b->y*scale_b.y+trans_b.y,v_b->z*scale_b.z+trans_b.z ); - const Vector t( (t_b-v_a->coords)*render_t+v_a->coords ); + const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z); + const Vector t((t_b - v_a->coords)*render_t + v_a->coords); - const Vector &n_b=normals[v_b->n]; - const Vector n( (n_b-v_a->normal)*render_t+v_a->normal ); + const Vector &n_b = normals[v_b->n]; + const Vector n((n_b - v_a->normal)*render_t + v_a->normal); - tex_coords[0][0]=uv->u; - tex_coords[0][1]=uv->v; + tex_coords[0][0] = uv->u; + tex_coords[0][1] = uv->v; - mesh->setVertex( k,&t.x,&n.x,tex_coords ); + mesh->setVertex(k, &t.x, &n.x, tex_coords); } mesh->unlock(); - model->enqueue( mesh,0,n_verts,0,n_tris ); + model->enqueue(mesh, 0, n_verts, 0, n_tris); } diff --git a/blitz3d/q3bsprep.cpp b/blitz3d/q3bsprep.cpp index 7efefda..59b1419 100644 --- a/blitz3d/q3bsprep.cpp +++ b/blitz3d/q3bsprep.cpp @@ -166,11 +166,11 @@ Vector static tf( const Vector &v ){ } #ifdef BETA -static log( const string &t ){ +static int log( const string &t ){ gx_runtime->debugLog( t.c_str() ); } #else -static log( const string &t ){} +static int log( const string &t ){} #endif static Surf *findSurf( q3_face *f ){ diff --git a/blitz3d/surface.cpp b/blitz3d/surface.cpp index e2b8f9a..d74879d 100644 --- a/blitz3d/surface.cpp +++ b/blitz3d/surface.cpp @@ -69,7 +69,7 @@ void Surface::updateNormals(){ const Vector &v1=vertices[t.verts[1]].coords; const Vector &v2=vertices[t.verts[2]].coords; Vector n=(v1-v0).cross(v2-v0); - if( n.length()<=EPSILON ) continue; + if( n.length()<= FLT_FLT_EPSILON ) continue; n.normalize(); norm_map[v0]+=n; norm_map[v1]+=n; diff --git a/blitz3d/terrainrep.cpp b/blitz3d/terrainrep.cpp index f42a562..218a6f5 100644 --- a/blitz3d/terrainrep.cpp +++ b/blitz3d/terrainrep.cpp @@ -15,7 +15,7 @@ static const TerrainRep *curr; static Frustum frustum; static int out_cnt,proc_cnt,clip_cnt; -static float proj_epsilon=EPSILON; //.01f; +static float proj_epsilon= FLT_FLT_EPSILON; //.01f; struct TerrainRep::Cell{ unsigned char height; @@ -259,7 +259,7 @@ void TerrainRep::insert( Tri *t ){ Vector v=Vector( verts[t->v1].v+verts[t->v2].v )/2; // float d=eye_plane.distance( v ); float d=eye_vec.distance( v ); - if( dproj_err=errors[t->id].error/d; if( t->proj_err>proj_epsilon ){ tri_que.push( t ); @@ -344,7 +344,7 @@ TerrainRep::Error TerrainRep::calcErr( int id,const Vert &v0,const Vert &v1,cons Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 ); float e=fabs(tv.v.y-(v1.v.y+v2.v.y)/2); - et.error= e>=1 ? 255 : ceil( (e-EPSILON)*255.0f ); + et.error= e>=1 ? 255 : ceil( (e- FLT_FLT_EPSILON)*255.0f ); Error el=calcErr( id*2,tv,v2,v0 ); Error er=calcErr( id*2+1,tv,v0,v1 ); @@ -382,7 +382,7 @@ TerrainRep::Error TerrainRep::calcErr( int id,int x,int z,const Vert &v0,const V Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 ); float e=fabs(tv.v.y-(v1.v.y+v2.v.y)/2); - et.error= e>=1 ? 255 : ceil( (e-EPSILON)*255.0f ); + et.error= e>=1 ? 255 : ceil( (e- FLT_FLT_EPSILON)*255.0f ); Error el=calcErr( id*2,x,z,tv,v2,v0 ); Error er=calcErr( id*2+1,x,z,tv,v0,v1 ); diff --git a/blitz3d/world.cpp b/blitz3d/world.cpp index d24302a..ac09812 100644 --- a/blitz3d/world.cpp +++ b/blitz3d/world.cpp @@ -234,10 +234,10 @@ void World::collide( Object *src ){ Plane coll_plane( coll_line*coll.time,coll.normal ); - coll_plane.d-=COLLISION_EPSILON; + coll_plane.d-=COLLISION_FLT_EPSILON; coll.time=coll_plane.t_intersect( coll_line ); - if( coll.time>0 ){// && fabs(coll.normal.dot( coll_line.d ))>EPSILON ){ + if( coll.time>0 ){// && fabs(coll.normal.dot( coll_line.d ))>FLT_EPSILON ){ //update source position - ONLY IF AHEAD! sv=coll_line*coll.time; td*=1-coll.time; @@ -257,7 +257,7 @@ void World::collide( Object *src ){ }else if( n_hit==1 ){ if( planes[0].distance(nv)>=0 ){ dv=nv;n_hit=0; - }else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-EPSILON ){ + }else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-FLT_FLT_EPSILON ){ dv=coll_plane.intersect( planes[0] ).nearest( dv ); }else{ //SQUISHED! @@ -277,11 +277,11 @@ void World::collide( Object *src ){ if( coll_info->response==COLLISION_RESPONSE_SLIDE ){ float d=dd.length(); - if( d<=EPSILON ){ dv=sv;break; } + if( d<= FLT_FLT_EPSILON ){ dv=sv;break; } if( d>td ) dd*=td/d; }else if( coll_info->response==COLLISION_RESPONSE_SLIDEXZ ){ float d=Vector( dd.x,0,dd.z ).length(); - if( d<=EPSILON ){ dv=sv;break; } + if( d<= FLT_FLT_EPSILON ){ dv=sv;break; } if( d>td_xz ) dd*=td_xz/d; } @@ -396,7 +396,7 @@ void World::collide( Object *src ){ //move plane out a bit (cough) coll_plane.d-=.001f; - if( fabs(coll.normal.dot( coll_line.d ))>EPSILON ){ + if( fabs(coll.normal.dot( coll_line.d ))>FLT_EPSILON ){ float t=coll_plane.t_intersect( coll_line ); //update source position - ONLY IF AHEAD! if( t>0 ){ @@ -421,7 +421,7 @@ void World::collide( Object *src ){ }else if( n_hit==1 ){ if( planes[0].distance(nv)>=0 ){ dv=nv;n_hit=0; - }else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-EPSILON ){ + }else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-FLT_EPSILON ){ dv=coll_plane.intersect( planes[0] ).nearest( dv ); }else{ hits=MAX_HITS;break; @@ -439,11 +439,11 @@ void World::collide( Object *src ){ if( coll_info->response==COLLISION_RESPONSE_SLIDE ){ float d=dd.length(); - if( d<=EPSILON ){ dv=sv;break; } + if( d<=FLT_EPSILON ){ dv=sv;break; } if( d>td ) dd*=td/d; }else if( coll_info->response==COLLISION_RESPONSE_SLIDEXZ ){ float d=Vector( dd.x,0,dd.z ).length(); - if( d<=EPSILON ){ dv=sv;break; } + if( d<=FLT_EPSILON ){ dv=sv;break; } if( d>td_xz ) dd*=td_xz/d; } diff --git a/blitzbasic/bin/debugger.dll b/blitzbasic/bin/debugger.dll new file mode 100644 index 0000000..2ae3e95 Binary files /dev/null and b/blitzbasic/bin/debugger.dll differ diff --git a/blitzide/blitzide.vcxproj b/blitzide/blitzide.vcxproj new file mode 100644 index 0000000..6006d5a --- /dev/null +++ b/blitzide/blitzide.vcxproj @@ -0,0 +1,320 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + MFCProj + {B61D8348-B715-42B8-A759-C7BBB0C8CD4D} + 10.0.10586.0 + + + + Application + v140 + + + Application + v140 + Static + MultiByte + + + Application + v140 + Static + MultiByte + + + Application + v140 + Static + MultiByte + + + Application + v140 + Static + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\blitzide___Win32_Blitz2DRelease\ + .\blitzide___Win32_Blitz2DRelease\ + false + + + .\blitzide___Win32_Blitz3DRelease\ + .\blitzide___Win32_Blitz3DRelease\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + false + + + .\Release\ + .\Release\ + false + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\blitzide___Win32_Blitz2DRelease\ + .\blitzide___Win32_Blitz2DRelease\blitzide.pch + Use + stdafx.h + .\blitzide___Win32_Blitz2DRelease\ + .\blitzide___Win32_Blitz2DRelease\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\blitzide___Win32_Blitz2DRelease\blitzide.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\blitzide___Win32_Blitz2DRelease\blitzide.bsc + + + true + false + Windows + false + ..\..\release\blitz2drelease\bin\ide.exe + winmm.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _WINDOWS;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\blitzide___Win32_Blitz3DRelease\ + .\blitzide___Win32_Blitz3DRelease\blitzide.pch + + .\blitzide___Win32_Blitz3DRelease\ + .\blitzide___Win32_Blitz3DRelease\ + StdCall + + + true + NDEBUG;%(PreprocessorDefinitions) + .\blitzide___Win32_Blitz3DRelease\blitzide.tlb + true + Win32 + + + 0x0409 + NDEBUG;PRO;%(PreprocessorDefinitions) + + + true + .\blitzide___Win32_Blitz3DRelease\blitzide.bsc + + + true + false + Windows + false + ../_release/bin/ide.exe + winmm.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\blitzide.pch + Use + stdafx.h + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\blitzide.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\blitzide.bsc + + + true + true + Windows + afxmem.obj;%(IgnoreSpecificDefaultLibraries) + ..\blitzbasic\bin\ide.exe + /FIXED:NO + ddraw.lib;dinput.lib;dsound.lib;dplayx.lib;dxguid.lib;winmm.lib;%(AdditionalDependencies) + + + + + MultiThreaded + AnySuitable + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + .\Release\ + .\Release\blitzide.pch + Use + stdafx.h + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\blitzide.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\blitzide.bsc + + + true + false + Windows + false + ..\blitzbasic\bin\ide.exe + winmm.lib;%(AdditionalDependencies) + + + + + + + + + + + + + Create + stdafx.h + Create + stdafx.h + Create + stdafx.h + Create + stdafx.h + + + + + + + + + + + + + + + + + + + + + + + + + + {3e355353-96d8-4aaf-bf95-8e6ca0d4b1ba} + false + + + + + + \ No newline at end of file diff --git a/blitzide/blitzide.vcxproj.filters b/blitzide/blitzide.vcxproj.filters new file mode 100644 index 0000000..37d85ba --- /dev/null +++ b/blitzide/blitzide.vcxproj.filters @@ -0,0 +1,87 @@ + + + + + {9c2049a6-f32f-4502-857f-a4ae3ffa8d7d} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {a084b10a-802f-4ff7-b0fa-c89f7b661e28} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + + + \ No newline at end of file diff --git a/blitzide/mainframe.h b/blitzide/mainframe.h index 069cb35..2cda8fe 100644 --- a/blitzide/mainframe.h +++ b/blitzide/mainframe.h @@ -74,8 +74,8 @@ private: CToolBar toolBar; CStatusBar statusBar; - map editors; - map helps; + std::map editors; + std::map helps; string last_quick_help; diff --git a/compiler/compiler.vcxproj b/compiler/compiler.vcxproj new file mode 100644 index 0000000..55b4b9e --- /dev/null +++ b/compiler/compiler.vcxproj @@ -0,0 +1,334 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {D884A075-E3B8-44E1-838D-74F28B33391B} + 10.0.10586.0 + + + + Application + v140 + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\compiler___Win32_Blitz2DRelease\ + .\compiler___Win32_Blitz2DRelease\ + false + + + .\compiler___Win32_Blitz3DRelease\ + .\compiler___Win32_Blitz3DRelease\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + .\Release\ + .\Release\ + false + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\compiler___Win32_Blitz2DRelease\ + .\compiler___Win32_Blitz2DRelease\compiler.pch + Use + std.h + .\compiler___Win32_Blitz2DRelease\ + .\compiler___Win32_Blitz2DRelease\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\compiler___Win32_Blitz2DRelease\compiler.bsc + + + true + .\compiler___Win32_Blitz2DRelease\compiler.lib + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _LIB;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\compiler___Win32_Blitz3DRelease\ + .\compiler___Win32_Blitz3DRelease\compiler.pch + + .\compiler___Win32_Blitz3DRelease\ + .\compiler___Win32_Blitz3DRelease\ + StdCall + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\compiler___Win32_Blitz3DRelease\compiler.bsc + + + true + .\compiler___Win32_Blitz3DRelease\compiler.lib + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\compiler.pch + Use + std.h + .\Debug\ + .\Debug\ + EnableFastChecks + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\compiler.bsc + + + true + .\Debug\compiler.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\compiler.pch + Use + std.h + .\Release\ + .\Release\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\compiler.bsc + + + true + .\Release\compiler.lib + + + + + Use + ../std.h + Use + ../std.h + Use + ../std.h + Use + ../std.h + + + Use + ../std.h + Use + ../std.h + Use + ../std.h + Use + ../std.h + + + Use + ../std.h + Use + ../std.h + Use + ../std.h + Use + ../std.h + + + Use + ../std.h + Use + ../std.h + Use + ../std.h + Use + ../std.h + + + Use + ../std.h + Use + ../std.h + Use + ../std.h + Use + ../std.h + + + + + + + + + + Create + std.h + Create + std.h + Create + std.h + Create + std.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {3e355353-96d8-4aaf-bf95-8e6ca0d4b1ba} + false + + + {6bcfc5ca-ea71-4ae9-8b96-28b8701f939e} + false + + + + + + \ No newline at end of file diff --git a/compiler/compiler.vcxproj.filters b/compiler/compiler.vcxproj.filters new file mode 100644 index 0000000..41cf75e --- /dev/null +++ b/compiler/compiler.vcxproj.filters @@ -0,0 +1,141 @@ + + + + + {0b6321df-3a3e-4216-9d78-49d53be3c776} + + + {7504da95-9f66-48b8-a5a8-18b4ea7e3f61} + + + {bd57d294-2c5f-436a-b0ea-611753bab52a} + + + {2d9d1b9e-3980-46dc-8780-4acfc27cdfe1} + + + {a3cafe0f-afd9-403e-9b3d-4274d9934b74} + + + {780f6104-16ed-450b-870a-be4469b42eb9} + + + {3990d4b7-2d61-49b0-b1dd-019167e36b1d} + + + + + nodes + + + nodes + + + nodes + + + nodes + + + nodes + + + nodes + + + environ + + + environ + + + environ + + + parser + + + parser + + + codegen\codegen_x86 + + + codegen\codegen_x86 + + + assem\assem_x86 + + + assem\assem_x86 + + + assem\assem_x86 + + + + + + nodes + + + nodes + + + nodes + + + nodes + + + nodes + + + nodes + + + nodes + + + environ + + + environ + + + environ + + + environ + + + parser + + + parser + + + codegen\codegen_x86 + + + codegen\codegen_x86 + + + codegen + + + assem\assem_x86 + + + assem\assem_x86 + + + assem\assem_x86 + + + assem + + + + + \ No newline at end of file diff --git a/config/config.h b/config/config.h index 134ebfd..d5af680 100644 --- a/config/config.h +++ b/config/config.h @@ -4,6 +4,7 @@ #define BASE_VER 1108 +#define PRO #ifdef PRO #define PRO_F 0x010000 #else diff --git a/config/config.vcxproj b/config/config.vcxproj new file mode 100644 index 0000000..558ab43 --- /dev/null +++ b/config/config.vcxproj @@ -0,0 +1,225 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {3E355353-96D8-4AAF-BF95-8E6CA0D4B1BA} + 10.0.10586.0 + + + + Application + v140 + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\config___Win32_Blitz2DRelease\ + .\config___Win32_Blitz2DRelease\ + false + + + .\config___Win32_Blitz3DRelease\ + .\config___Win32_Blitz3DRelease\ + false + + + .\Release\ + .\Release\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\config___Win32_Blitz2DRelease\ + .\config___Win32_Blitz2DRelease\config.pch + .\config___Win32_Blitz2DRelease\ + .\config___Win32_Blitz2DRelease\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\config___Win32_Blitz2DRelease\config.bsc + + + true + .\config___Win32_Blitz2DRelease\config.lib + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _LIB;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\config___Win32_Blitz3DRelease\ + .\config___Win32_Blitz3DRelease\config.pch + .\config___Win32_Blitz3DRelease\ + .\config___Win32_Blitz3DRelease\ + StdCall + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\config___Win32_Blitz3DRelease\config.bsc + + + true + .\config___Win32_Blitz3DRelease\config.lib + + + + + MultiThreaded + AnySuitable + true + MaxSpeed + true + Level3 + true + Size + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\config.pch + .\Release\ + .\Release\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\config.bsc + + + true + .\Release\config.lib + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\config.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\config.bsc + + + true + .\Debug\config.lib + + + + + + + + + \ No newline at end of file diff --git a/debugger/debugger.vcxproj b/debugger/debugger.vcxproj new file mode 100644 index 0000000..5069918 --- /dev/null +++ b/debugger/debugger.vcxproj @@ -0,0 +1,293 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + MFCProj + {4132C330-95D9-4F68-A51A-3B90381587C5} + 10.0.10586.0 + + + + Application + v140 + + + DynamicLibrary + v140 + Static + MultiByte + + + DynamicLibrary + v140 + Static + MultiByte + + + DynamicLibrary + v140 + Static + MultiByte + + + DynamicLibrary + v140 + Static + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\Release\ + .\Release\ + false + + + .\debugger___Win32_Blitz2DRelease\ + .\debugger___Win32_Blitz2DRelease\ + false + + + .\debugger___Win32_Blitz3DRelease\ + .\debugger___Win32_Blitz3DRelease\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + false + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;DEBUGGER_EXPORTS;%(PreprocessorDefinitions) + .\Release\ + .\Release\debugger.pch + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\debugger.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\debugger.bsc + + + true + true + Windows + ..\blitzbasic\bin\debugger.dll + .\Release\debugger.lib + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;DEBUGGER_EXPORTS;%(PreprocessorDefinitions) + .\debugger___Win32_Blitz2DRelease\ + .\debugger___Win32_Blitz2DRelease\debugger.pch + .\debugger___Win32_Blitz2DRelease\ + .\debugger___Win32_Blitz2DRelease\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\debugger___Win32_Blitz2DRelease\debugger.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\debugger___Win32_Blitz2DRelease\debugger.bsc + + + true + true + Windows + ..\..\release\blitz2drelease\bin\debugger.dll + .\debugger___Win32_Blitz2DRelease\debugger.lib + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _WINDOWS;_USRDLL;DEBUGGER_EXPORTS;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\debugger___Win32_Blitz3DRelease\ + .\debugger___Win32_Blitz3DRelease\debugger.pch + .\debugger___Win32_Blitz3DRelease\ + .\debugger___Win32_Blitz3DRelease\ + StdCall + + + true + NDEBUG;%(PreprocessorDefinitions) + .\debugger___Win32_Blitz3DRelease\debugger.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\debugger___Win32_Blitz3DRelease\debugger.bsc + + + true + true + Windows + ../_release/bin/debugger.dll + .\debugger___Win32_Blitz3DRelease\debugger.lib + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUGGER_EXPORTS;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\debugger.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\debugger.tlb + true + Win32 + + + 0x1409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\debugger.bsc + + + true + true + true + Console + ..\blitzbasic\bin\debugger.dll + .\Debug\debugger.lib + /FIXED:NO + + + + + + + + + + + + + Create + stdafx.h + Create + stdafx.h + Create + stdafx.h + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/debugger/debugger.vcxproj.filters b/debugger/debugger.vcxproj.filters new file mode 100644 index 0000000..0f5a34c --- /dev/null +++ b/debugger/debugger.vcxproj.filters @@ -0,0 +1,70 @@ + + + + + {e724ef2d-96f4-4a45-850b-146498babe2e} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {5b254165-41b7-415b-bb46-4ff914fc5a5f} + h;hpp;hxx;hm;inl + + + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/debugger/mainframe.cpp b/debugger/mainframe.cpp index d3aa9ce..77bbc3c 100644 --- a/debugger/mainframe.cpp +++ b/debugger/mainframe.cpp @@ -285,8 +285,8 @@ SourceFile *MainFrame::sourceFile(const char *file){ file_tabs.insert( make_pair(file,tab) ); - if( char *p=strrchr(file,'/') ) file=p+1; - if( char *p=strrchr(file,'\\') ) file=p+1; + if(const char *p=strrchr(file,'/') ) file=p+1; + if(const char *p=strrchr(file,'\\') ) file=p+1; tabber.insert( tab,t,file ); tabber.setCurrent( tab ); diff --git a/fmodapi375win/README.TXT b/fmodapi375win/README.TXT new file mode 100644 index 0000000..2262f1d --- /dev/null +++ b/fmodapi375win/README.TXT @@ -0,0 +1,100 @@ +---------------------------------------------------------------------------- + FMOD 3.75 + Copyright (c) Firelight Technologies Pty, Ltd, + 1994 - 2004 +---------------------------------------------------------------------------- + + http://www.fmod.org + + +---------------------------------------------------------------------------- +WIN32 specific issues. +---------------------------------------------------------------------------- + +Remember to use the correct import library! + +MSVC Users - use FMODVC.LIB +METROWERKS/CODEWARRIOR Users - use FMODVC.LIB +WATCOM Users - use FMODWC.LIB +BORLAND Users - use FMODBC.LIB +LCC-WIN32 Users - use FMODLCC.LIB +DEV-C++, MINGW AND CYGWIN Users - use LIBFMOD.A + +Linux users - link with libfmod-3.75.so (i.e. gcc file.c -lfmod-3.75) +Delphi Users - use FMOD.PAS +Visual Basic Users - use FMOD.BAS + +---------------------------------------------------------------------------- +ASIO Config +---------------------------------------------------------------------------- +FMOD ignores FSOUND_SetBufferSize in ASIO mode. It relies on settings +provided by the ASIO control panel supplied with the driver. In the tools +directory of the FMOD api, you will find an asioconfig.exe tool which allows +you to configure the ASIO driver by doubleclicking on the appropriate driver. + +---------------------------------------------------------------------------- +FMOD End User License Agreement +---------------------------------------------------------------------------- + +FMOD's names, sources, documentation and binaries contained within the +distributed archive are copyright © Firelight Technologies, Pty, Ltd. +1994-2004. + +The contents of the FMOD distribution archive may not be redistributed, +reproduced, modified, transmitted, broadcast, published or adapted in any +way, shape or form, without the prior written consent of the owner, +Firelight Technologies, be it by tangible or non tangible media. + +The fmod.dll file may be redistributed without the authors prior permission, +and must remain unmodified. The use of dll 'static linking' tools that aim +to hide the fmod library are forbidden. + +FMOD may not be used in a commercial product, or product that directly or +indirectly receives income with the aid of the FMOD sound library, without +a commercial license from Firelight Technologies. Releasing a product +without a commercial license in this instance is a breach of the FMOD EULA +and parties who violate this license will be prosecuted under the full +extent of the law. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------------- +Ogg Vorbis License +---------------------------------------------------------------------------- +Portions Copyright (c) 2001, Xiphophorus + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of the Xiphophorus nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/fmodapi375win/api/delphi/fmod.dcu b/fmodapi375win/api/delphi/fmod.dcu new file mode 100644 index 0000000..30216cc Binary files /dev/null and b/fmodapi375win/api/delphi/fmod.dcu differ diff --git a/fmodapi375win/api/delphi/fmod.pas b/fmodapi375win/api/delphi/fmod.pas new file mode 100644 index 0000000..93dbfc8 --- /dev/null +++ b/fmodapi375win/api/delphi/fmod.pas @@ -0,0 +1,783 @@ +{ =============================================================================================== } +{ FMOD Main header file. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004. } +{ =============================================================================================== } +{ + NOTE: For the demos to run you must have either fmod.dll (in Windows) + or libfmod-3.75.so (in Linux) installed. + + In Windows, copy the fmod.dll file found in the api directory to either of + the following locations (in order of preference) + - your application directory + - Windows\System (95/98) or WinNT\System32 (NT/2000/XP) + + In Linux, make sure you are signed in as root and copy the libfmod-3.75.so + file from the api directory to your /usr/lib/ directory. + Then via a command line, navigate to the /usr/lib/ directory and create + a symbolic link between libfmod-3.75.so and libfmod.so. This is done with + the following command (assuming you are in /usr/lib/)... + ln -s libfmod-3.75.so libfmod.so. +} +{ =============================================================================================== } + +{$IFDEF FPC} + {$MODE DELPHI} + {$IFDEF WIN32} + {$DEFINE MSWINDOWS} + {$ENDIF} +{$ENDIF} + +unit fmod; + +interface + +uses +{$IFDEF MSWINDOWS} + Windows, +{$ENDIF} + fmodtypes; + +{ + Disable warning for unsafe types in Delphi 7 +} +{$IFDEF VER150} +{$WARN UNSAFE_TYPE OFF} +{$ENDIF} + +//=============================================================================================== +// FUNCTION PROTOTYPES +//=============================================================================================== + +{ ================================== } +{ Library load/unload functions. } +{ ================================== } + +{ + If no library name is passed to FMOD_Load, then the default library name + used. These are stub functions. +} + +function FMOD_Load(LibName: PChar): Boolean; +procedure FMOD_Unload; + +{ ================================== } +{ Initialization / Global functions. } +{ ================================== } + +{ + PRE - FSOUND_Init functions. These can't be called after FSOUND_Init is + called (they will fail). They set up FMOD system functionality. +} + +function FSOUND_SetOutput(OutputType: TFSoundOutputTypes): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetDriver(Driver: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetMixer(Mixer: TFSoundMixerTypes): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetBufferSize(LenMs: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetHWND(Hwnd: THandle): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetMinHardwareChannels(Min: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetMaxHardwareChannels(Max: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetMemorySystem(Pool: Pointer; PoolLen: Integer; + UserAlloc: TFSoundAllocCallback; + UserRealloc: TFSoundReallocCallback; + UserFree: TFSoundFreeCallback): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Main initialization / closedown functions. + Note : Use FSOUND_INIT_USEDEFAULTMIDISYNTH with FSOUND_Init for software override + with MIDI playback. + : Use FSOUND_INIT_GLOBALFOCUS with FSOUND_Init to make sound audible no matter + which window is in focus. (FSOUND_OUTPUT_DSOUND only) +} + +function FSOUND_Init(MixRate: Integer; MaxSoftwareChannels: Integer; Flags: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_Close; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Runtime system level functions +} + +procedure FSOUND_Update; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; // This is called to update 3d sound / non-realtime output + +procedure FSOUND_SetSpeakerMode(SpeakerMode: Cardinal); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_SetSFXMasterVolume(Volume: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_SetPanSeperation(PanSep: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_File_SetCallbacks(OpenCallback: TFSoundOpenCallback; + CloseCallback: TFSoundCloseCallback; + ReadCallback: TFSoundReadCallback; + SeekCallback: TFSoundSeekCallback; + TellCallback: TFSoundTellCallback); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + System information functions +} + +function FSOUND_GetError: TFModErrors; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetVersion: Single; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetOutput: TFSoundOutputTypes; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetOutputHandle: Pointer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetDriver: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetMixer: TFSoundMixerTypes; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetNumDrivers: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetDriverName(Id: Integer): PChar; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetDriverCaps(Id: Integer; var Caps: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetOutputRate: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetMaxChannels: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetMaxSamples: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetSpeakerMode: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetSFXMasterVolume: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetNumHWChannels(var num2d: Integer; var num3d: Integer; var total: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetChannelsPlaying: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetCPUUsage: Single; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_GetMemoryStats(var CurrentAlloced: Cardinal; var MaxAlloced: Cardinal); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================================== } +{ Sample management / load functions. } +{ =================================== } + +{ + Sample creation and management functions + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Sample_Load to load from memory. + Use FSOUND_LOADRAW flag with FSOUND_Sample_Load to treat as as raw pcm data. +} + +function FSOUND_Sample_Load(Index: Integer; const NameOrData: PChar; Mode: Cardinal; Offset: Integer; Length: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_Alloc(Index: Integer; Length: Integer; Mode: Cardinal; DefFreq: Integer; DefVol: Integer; DefPan: Integer; DefPri: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_Sample_Free(Sptr: PFSoundSample); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_Upload(Sptr: PFSoundSample; SrcData: Pointer; Mode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_Lock(Sptr: PFSoundSample; Offset: Integer; Length: Integer; var Ptr1: Pointer; var Ptr2: Pointer; var Len1: Cardinal; var Len2: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_Unlock(Sptr: PFSoundSample; Ptr1: Pointer; Ptr2: Pointer; Len1: Cardinal; Len2: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Sample control functions +} + +function FSOUND_Sample_SetMode(Sptr: PFSoundSample; Mode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_SetLoopPoints(Sptr: PFSoundSample; LoopStart, LoopEnd: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_SetDefaults(Sptr: PFSoundSample; DefFreq, DefVol, DefPan, DefPri: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_SetDefaultsEx(Sptr: PFSoundSample; DefFreq, DefVol, DefPan, DefPri, VarFreq, VarVol, VarPan: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_SetMinMaxDistance(Sptr: PFSoundSample; Min, Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_SetMaxPlaybacks(Sptr: PFSoundSample; Max: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Sample information functions +} + +function FSOUND_Sample_Get(SampNo: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_GetName(Sptr: PFSoundSample): PCHAR; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_GetLength(Sptr: PFSoundSample): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_GetLoopPoints(Sptr: PFSoundSample; var LoopStart: Integer; var LoopEnd: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_GetDefaults(Sptr: PFSoundSample; var DefFreq: Integer; var DefVol: Integer; var DefPan: Integer; var DefPri: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_GetDefaultsEx(Sptr: PFSoundSample; var DefFreq: Integer; var DefVol: Integer; var DefPan: Integer; var DefPri: Integer;var VarFreq: Integer; var VarVol: Integer; var VarPan: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_GetMode(Sptr: PFSoundSample): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Sample_GetMinMaxDistance(Sptr: PFSoundSample; var Min: Single; var Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ============================ } +{ Channel control functions. } +{ ============================ } + +{ + Playing and stopping sounds. + Note : Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. + Use FSOUND_ALL as the 'channel' variable to control ALL channels with one function call! +} + +function FSOUND_PlaySound(Channel: Integer; Sptr: PFSoundSample): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_PlaySoundEx(Channel: Integer; Sptr: PFSoundSample; Dsp: PFSoundDSPUnit; StartPaused: ByteBool): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_StopSound(Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Functions to control playback of a channel. + Note : FSOUND_ALL can be used on most of these functions as a channel value. +} + +function FSOUND_SetFrequency(Channel: Integer; Freq: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetVolume(Channel: Integer; Vol: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetVolumeAbsolute(Channel: Integer; Vol: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetPan(Channel: Integer; Pan: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetSurround(Channel: Integer; Surround: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetMute(Channel: Integer; Mute: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetPriority(Channel: Integer; Priority: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetReserved(Channel: Integer; Reserved: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetPaused(Channel: Integer; Paused: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetLoopMode(Channel: Integer; LoopMode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_SetCurrentPosition(Channel: Integer; Offset: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_3D_SetAttributes(Channel: Integer; Pos: PFSoundVector; Vel: PFSoundVector): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_3D_SetMinMaxDistance(Channel: Integer; Min: Single; Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Channel information functions +} + +function FSOUND_IsPlaying(Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetFrequency(Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetVolume(Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetAmplitude(Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetPan(Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetSurround(Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetMute(Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetPriority(Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetReserved(Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetPaused(Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetLoopMode(Channel: Integer): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetCurrentPosition(Channel: Integer): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetCurrentSample(Channel: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetCurrentLevels(Channel: Integer; l, r: PSingle): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetNumSubChannels(Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_GetSubChannel(Channel: Integer; SubChannel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_3D_GetAttributes(Channel: Integer; Pos: PFSoundVector; Vel: PFSoundVector): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_3D_GetMinMaxDistance(Channel: Integer; var Min: Single; var Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================== } +{ 3D sound functions. } +{ =================== } + +{ + See also 3d sample and channel based functions above. + Call FSOUND_Update once a frame to process 3d information. +} + +procedure FSOUND_3D_Listener_SetCurrent(current: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_3D_Listener_SetAttributes(Pos: PFSoundVector; Vel: PFSoundVector; + fx: Single; fy: Single; fz: Single; + tx: Single; ty: Single; tz: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_3D_Listener_GetAttributes(Pos: PFSoundVector; Vel: PFSoundVector; + fx: PSingle; fy: PSingle; fz: PSingle; + tx: PSingle; ty: PSingle; tz: PSingle); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_3D_SetDopplerFactor(Scale: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_3D_SetDistanceFactor(Scale: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_3D_SetRolloffFactor(Scale: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================== } +{ FX functions. } +{ =================== } + +{ + Functions to control DX8 only effects processing. + + - FX enabled samples can only be played once at a time, not multiple times at once. + - Sounds have to be created with FSOUND_HW2D or FSOUND_HW3D for this to work. + - FSOUND_INIT_ENABLESYSTEMCHANNELFX can be used to apply hardware effect processing to the + global mixed output of FMOD's software channels. + - FSOUND_FX_Enable returns an FX handle that you can use to alter fx parameters. + - FSOUND_FX_Enable can be called multiple times in a row, even on the same FX type, + it will return a unique handle for each FX. + - FSOUND_FX_Enable cannot be called if the sound is playing or locked. + - FSOUND_FX_Disable must be called to reset/clear the FX from a channel. +} + +function FSOUND_FX_Enable(Channel: Integer; Fx: TFSoundFXModes): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_Disable(Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_FX_SetChorus(FXId: Integer; WetDryMix, Depth, Feedback, Frequency: Single; Waveform: Integer; Delay: Single; Phase: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetCompressor(FXId: Integer; Gain, Attack, Release, Threshold, Ratio, Predelay: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetDistortion(FXId: Integer; Gain, Edge, PostEQCenterFrequency, PostEQBandwidth, PreLowpassCutoff: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetEcho(FXId: Integer; WetDryMix, Feedback, LeftDelay, RightDelay: Single; PanDelay: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetFlanger(FXId: Integer; WetDryMix, Depth, Feedback, Frequency: Single; Waveform: Integer; Delay: Single; Phase: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetGargle(FXId, RateHz, WaveShape: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetI3DL2Reverb(FXId, Room, RoomHF: Integer; RoomRolloffFactor, DecayTime, DecayHFRatio: Single; Reflections: Integer; ReflectionsDelay: Single; Reverb: Integer; ReverbDelay, Diffusion, Density, HFReference: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetParamEQ(FXId: Integer; Center, Bandwidth, Gain: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_FX_SetWavesReverb(FXId: Integer; InGain, ReverbMix, ReverbTime, HighFreqRTRatio: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ========================= } +{ File Streaming functions. } +{ ========================= } + +{ + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Stream_Open to stream from memory. + Use FSOUND_LOADRAW flag with FSOUND_Stream_Open to treat stream as raw pcm data. + Use FSOUND_MPEGACCURATE flag with FSOUND_Stream_Open to open mpegs in 'accurate mode' for settime/gettime/getlengthms. + Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. +} + +function FSOUND_Stream_SetBufferSize(Ms: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_Open(const name_or_data: PChar; Mode: Cardinal; Offset: Integer; Length: Integer): PFSoundStream; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Create(Callback: TFSoundStreamCallback; Length: Integer; Mode: Cardinal; SampleRate: Integer; UserData: Integer): PFSoundStream; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Close(Stream: PFSoundStream): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_Play(Channel: Integer; Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_PlayEx(Channel: Integer; Stream: PFSoundStream; Dsp: PFSoundDSPUnit; StartPaused: ByteBool): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Stop(Stream: PFSoundStream): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_SetPosition(Stream: PFSoundStream; Position: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetPosition(Stream: PFSoundStream): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_SetTime(Stream: PFSoundStream; Ms: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetTime(Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetLength(Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetLengthMs(Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_SetMode(Stream: PFSoundStream; mode: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetMode(Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_SetLoopPoints(Stream: PFSoundStream; LoopStartPCM, LoopEndPCM: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_SetLoopCount(Stream: PFSoundStream; Count: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetOpenState(Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetSample(Stream: PFSoundStream): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_CreateDSP(Stream: PFSoundStream; Callback: TFSoundDSPCallback; Priority: Integer; Param: Integer): PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_SetEndCallback(Stream: PFSoundStream; Callback: TFSoundStreamCallback; UserData: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_SetSyncCallback(Stream: PFSoundStream; Callback: TFSoundStreamCallback; UserData: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_AddSyncPoint(Stream: PFSoundStream; PCMOffset: Cardinal; Name: PChar): PFSyncPoint; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_DeleteSyncPoint(Point: PFSyncPoint): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetNumSyncPoints(Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetSyncPoint(Stream: PFSoundStream; Index: Integer): PFSyncPoint; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetSyncPointInfo(Point: PFSyncPoint; var PCMOffset: Cardinal): PCHAR; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_SetSubStream(Stream: PFSoundStream; Index: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetNumSubStreams(Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_SetSubStreamSentence(Stream: PFSoundStream; var SentenceList: Cardinal; NumItems: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_Stream_GetNumTagFields(Stream: PFSoundStream; var Num: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_GetTagField(Stream: PFSoundStream; Num: Integer; var TagType: TFSoundTagFieldType; var Name: PChar; var Value: Pointer; var Length: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_FindTagField(Stream: PFSoundStream; TagType: TFSoundTagFieldType; Name: PChar; var Value: Pointer; var Length: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Internet streaming functions +} + +function FSOUND_Stream_Net_SetProxy(Proxy: PChar): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Net_GetLastServerStatus(): PChar; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Net_SetBufferProperties(BufferSize: Integer; PreBuffer_Percent: Integer; ReBuffer_Percent: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Net_GetBufferProperties(var Buffersize: Integer; var PreBuffer_Percent: Integer; var ReBuffer_Percent: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Net_SetMetadataCallback(Stream: PFSoundStream; Callback: TFMetaDataCallback; UserData: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Stream_Net_GetStatus(Stream: PFSoundStream; var Status: TFSoundStreamNetStatus; var BufferPercentUsed: Integer; var BitRate: Integer; var Flags: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================== } +{ CD audio functions. } +{ =================== } + +{ + Note : 0 = default cdrom. Otherwise specify the drive letter, for example. 'D'. +} + +function FSOUND_CD_Play(Drive: Byte; Track: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_CD_SetPlayMode(Drive: Byte; Mode: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_Stop(Drive: Byte): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_SetPaused(Drive: Byte; Paused: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_SetVolume(Drive: Byte; Volume: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_SetTrackTime(Drive: Byte; ms: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_OpenTray(Drive: Byte; Open: Byte): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FSOUND_CD_GetPaused(Drive: Byte): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_GetTrack(Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_GetNumTracks(Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_GetVolume(Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_GetTrackLength(Drive: Byte; Track: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_CD_GetTrackTime(Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ============== } +{ DSP functions. } +{ ============== } + + +{ + DSP Unit control and information functions. +} + +function FSOUND_DSP_Create(Callback: TFSoundDSPCallback; Priority: Integer; Param: Integer): PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_DSP_Free(DSPUnit: PFSoundDSPUnit); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_DSP_SetPriority(DSPUnit: PFSoundDSPUnit; Priority: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_DSP_GetPriority(DSPUnit: PFSoundDSPUnit): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_DSP_SetActive(DSPUnit: PFSoundDSPUnit; Active: ByteBool); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_DSP_GetActive(DSPUnit: PFSoundDSPUnit): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Functions to get hold of FSOUND 'system DSP unit' handles. +} + +function FSOUND_DSP_GetClearUnit: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_DSP_GetSFXUnit: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_DSP_GetMusicUnit: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_DSP_GetFFTUnit: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_DSP_GetClipAndCopyUnit: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Miscellaneous DSP functions + Note for the spectrum analysis function to work, you have to enable the FFT DSP unit with + the following code FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); + It is off by default to save cpu usage. +} + +function FSOUND_DSP_MixBuffers(DestBuffer: Pointer; SrcBuffer: Pointer; Len: Integer; Freq: Integer; Vol: Integer; Pan: Integer; Mode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FSOUND_DSP_ClearMixBuffer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_DSP_GetBufferLength: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Length of each DSP update } +function FSOUND_DSP_GetBufferLengthTotal: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Total buffer length due to FSOUND_SetBufferSize } +function FSOUND_DSP_GetSpectrum: PSingle; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. } + +{ ========================================================================== } +{ Reverb functions. (eax2/3 reverb) (NOT SUPPORTED IN LINUX/CE) } +{ ========================================================================== } + +{ + See structures above for definitions and information on the reverb parameters. +} + +function FSOUND_Reverb_SetProperties(var Prop: TFSoundReverbProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Reverb_GetProperties(var Prop: TFSoundReverbProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Reverb_SetChannelProperties(Channel: Integer; var Prop: TFSoundReverbChannelProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Reverb_GetChannelProperties(Channel: Integer; var Prop: TFSoundReverbChannelProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ================================================ } +{ Recording functions (NOT SUPPORTED IN LINUX/MAC) } +{ ================================================ } + +{ + Recording initialization functions +} + +function FSOUND_Record_SetDriver(OutputType: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Record_GetNumDrivers: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Record_GetDriverName(Id: Integer): PChar; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Record_GetDriver: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Recording functionality. Only one recording session will work at a time. +} + +function FSOUND_Record_StartSample(Sptr: PFSoundSample; Loop: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Record_Stop: ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FSOUND_Record_GetPosition: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ============================================================================================= } +{ FMUSIC API (MOD,S3M,XM,IT,MIDI PLAYBACK) } +{ ============================================================================================= } + +{ + Song management / playback functions. +} + +function FMUSIC_LoadSong(const Name: PChar): PFMusicModule; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_LoadSongEx(Name_Or_Data: Pointer; Offset: Integer; Length: Integer; Mode: Cardinal; var SampleList: Integer; SampleListNum: Integer): PFMusicModule; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetOpenState(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_FreeSong(Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_PlaySong(Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_StopSong(Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +procedure FMUSIC_StopAllSongs; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FMUSIC_SetZxxCallback(Module: PFMusicModule; Callback: TFMusicCallback): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetRowCallback(Module: PFMusicModule; Callback: TFMusicCallback; RowStep: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetOrderCallback(Module: PFMusicModule; Callback: TFMusicCallback; OrderStep: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetInstCallback(Module: PFMusicModule; Callback: TFMusicCallback; Instrument: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +function FMUSIC_SetSample(Module: PFMusicModule; SampNo: Integer; Sptr: PFSoundSample): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetUserData(Module: PFMusicModule; userdata: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_OptimizeChannels(Module: PFMusicModule; MaxChannels: Integer; MinVolume: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Runtime song functions. +} + +function FMUSIC_SetReverb(Reverb: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetLooping(Module: PFMusicModule; Looping: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetOrder(Module: PFMusicModule; Order: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetPaused(Module: PFMusicModule; Pause: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetMasterVolume(Module: PFMusicModule; Volume: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetMasterSpeed(Module: PFMusicModule; speed: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_SetPanSeperation(Module: PFMusicModule; PanSep: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Static song information functions. +} + +function FMUSIC_GetName(Module: PFMusicModule): PCHAR; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetType(Module: PFMusicModule): TFMusicTypes; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetNumOrders(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetNumPatterns(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetNumInstruments(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetNumSamples(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetNumChannels(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetSample(Module: PFMusicModule; SampNo: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetPatternLength(Module: PFMusicModule; OrderNo: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Runtime song information. +} + +function FMUSIC_IsFinished(Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_IsPlaying(Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetMasterVolume(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetGlobalVolume(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetOrder(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetPattern(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetSpeed(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetBPM(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetRow(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetPaused(Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetTime(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetRealChannel(Module: PFMusicModule; modchannel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; +function FMUSIC_GetUserData(Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +implementation + +const +{$IFDEF LINUX} + FMOD_DLL = 'libfmod.so'; +{$ELSE} +{$IFDEF MSWINDOWS} + FMOD_DLL = 'fmod.dll'; +{$ENDIF} +{$ENDIF} + +{ + Stub functions to allow applications to swap between static and dynamic with + no code changes at all. +} +function FMOD_Load(LibName: PChar): Boolean; +begin + Result := True; +end; + +procedure FMOD_Unload; +begin +end; + +function FSOUND_SetOutput; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetOutput@4' {$ENDIF}; +function FSOUND_SetDriver; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetDriver@4' {$ENDIF}; +function FSOUND_SetMixer; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetMixer@4' {$ENDIF}; +function FSOUND_SetBufferSize; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetBufferSize@4' {$ENDIF}; +function FSOUND_SetHWND; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetHWND@4' {$ENDIF}; +function FSOUND_SetMinHardwareChannels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetMinHardwareChannels@4' {$ENDIF}; +function FSOUND_SetMaxHardwareChannels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetMaxHardwareChannels@4' {$ENDIF}; +function FSOUND_SetMemorySystem; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetMemorySystem@20' {$ENDIF}; +function FSOUND_Init; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Init@12' {$ENDIF}; +procedure FSOUND_Close; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Close@0' {$ENDIF}; +procedure FSOUND_Update; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Update@0' {$ENDIF}; +procedure FSOUND_SetSpeakerMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetSpeakerMode@4' {$ENDIF}; +procedure FSOUND_SetSFXMasterVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetSFXMasterVolume@4' {$ENDIF}; +procedure FSOUND_SetPanSeperation; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetPanSeperation@4' {$ENDIF}; +function FSOUND_GetError; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetError@0' {$ENDIF}; +function FSOUND_GetVersion; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetVersion@0' {$ENDIF}; +function FSOUND_GetOutput; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetOutput@0' {$ENDIF}; +function FSOUND_GetOutputHandle; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetOutputHandle@0' {$ENDIF}; +function FSOUND_GetDriver; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetDriver@0' {$ENDIF}; +function FSOUND_GetMixer; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetMixer@0' {$ENDIF}; +function FSOUND_GetNumDrivers; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetNumDrivers@0' {$ENDIF}; +function FSOUND_GetDriverName; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetDriverName@4' {$ENDIF}; +function FSOUND_GetDriverCaps; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetDriverCaps@8' {$ENDIF}; +function FSOUND_GetOutputRate; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetOutputRate@0' {$ENDIF}; +function FSOUND_GetMaxChannels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetMaxChannels@0' {$ENDIF}; +function FSOUND_GetMaxSamples; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetMaxSamples@0' {$ENDIF}; +function FSOUND_GetSpeakerMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetSpeakerMode@0' {$ENDIF}; +function FSOUND_GetSFXMasterVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetSFXMasterVolume@0' {$ENDIF}; +function FSOUND_GetNumHWChannels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetNumHWChannels@12' {$ENDIF}; +function FSOUND_GetChannelsPlaying; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetChannelsPlaying@0' {$ENDIF}; +function FSOUND_GetCPUUsage; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetCPUUsage@0' {$ENDIF}; +procedure FSOUND_GetMemoryStats; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetMemoryStats@8' {$ENDIF}; +function FSOUND_Sample_Load; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_Load@20' {$ENDIF}; +function FSOUND_Sample_Alloc; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_Alloc@28' {$ENDIF}; +procedure FSOUND_Sample_Free; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_Free@4' {$ENDIF}; +function FSOUND_Sample_Upload; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_Upload@12' {$ENDIF}; +function FSOUND_Sample_Lock; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_Lock@28' {$ENDIF}; +function FSOUND_Sample_Unlock; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_Unlock@20' {$ENDIF}; +function FSOUND_Sample_SetMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_SetMode@8' {$ENDIF}; +function FSOUND_Sample_SetLoopPoints; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_SetLoopPoints@12' {$ENDIF}; +function FSOUND_Sample_SetDefaults; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_SetDefaults@20' {$ENDIF}; +function FSOUND_Sample_SetDefaultsEx; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_SetDefaultsEx@32' {$ENDIF}; +function FSOUND_Sample_SetMinMaxDistance; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_SetMinMaxDistance@12' {$ENDIF}; +function FSOUND_Sample_SetMaxPlaybacks; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_SetMaxPlaybacks@8' {$ENDIF}; +function FSOUND_Sample_Get; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_Get@4' {$ENDIF}; +function FSOUND_Sample_GetName; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_GetName@4' {$ENDIF}; +function FSOUND_Sample_GetLength; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_GetLength@4' {$ENDIF}; +function FSOUND_Sample_GetLoopPoints; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_GetLoopPoints@12' {$ENDIF}; +function FSOUND_Sample_GetDefaults; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_GetDefaults@20' {$ENDIF}; +function FSOUND_Sample_GetDefaultsEx; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_GetDefaultsEx@32' {$ENDIF}; +function FSOUND_Sample_GetMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_GetMode@4' {$ENDIF}; +function FSOUND_Sample_GetMinMaxDistance; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Sample_GetMinMaxDistance@12' {$ENDIF}; +function FSOUND_PlaySound; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_PlaySound@8' {$ENDIF}; +function FSOUND_PlaySoundEx; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_PlaySoundEx@16' {$ENDIF}; +function FSOUND_StopSound; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_StopSound@4' {$ENDIF}; +function FSOUND_SetFrequency; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetFrequency@8' {$ENDIF}; +function FSOUND_SetVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetVolume@8' {$ENDIF}; +function FSOUND_SetVolumeAbsolute; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetVolumeAbsolute@8' {$ENDIF}; +function FSOUND_SetPan; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetPan@8' {$ENDIF}; +function FSOUND_SetSurround; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetSurround@8' {$ENDIF}; +function FSOUND_SetMute; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetMute@8' {$ENDIF}; +function FSOUND_SetPriority; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetPriority@8' {$ENDIF}; +function FSOUND_SetReserved; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetReserved@8' {$ENDIF}; +function FSOUND_SetPaused; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetPaused@8' {$ENDIF}; +function FSOUND_SetLoopMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetLoopMode@8' {$ENDIF}; +function FSOUND_SetCurrentPosition; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_SetCurrentPosition@8' {$ENDIF}; +function FSOUND_3D_SetAttributes; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_SetAttributes@12' {$ENDIF}; +function FSOUND_3D_SetMinMaxDistance; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_SetMinMaxDistance@12' {$ENDIF}; +function FSOUND_IsPlaying; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_IsPlaying@4' {$ENDIF}; +function FSOUND_GetFrequency; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetFrequency@4' {$ENDIF}; +function FSOUND_GetVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetVolume@4' {$ENDIF}; +function FSOUND_GetAmplitude; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetAmplitude@4' {$ENDIF}; +function FSOUND_GetPan; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetPan@4' {$ENDIF}; +function FSOUND_GetSurround; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetSurround@4' {$ENDIF}; +function FSOUND_GetMute; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetMute@4' {$ENDIF}; +function FSOUND_GetPriority; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetPriority@4' {$ENDIF}; +function FSOUND_GetReserved; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetReserved@4' {$ENDIF}; +function FSOUND_GetPaused; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetPaused@4' {$ENDIF}; +function FSOUND_GetLoopMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetLoopMode@4' {$ENDIF}; +function FSOUND_GetCurrentPosition; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetCurrentPosition@4' {$ENDIF}; +function FSOUND_GetCurrentSample; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetCurrentSample@4' {$ENDIF}; +function FSOUND_GetCurrentLevels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetCurrentLevels@12' {$ENDIF}; +function FSOUND_GetNumSubChannels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetNumSubChannels@4' {$ENDIF}; +function FSOUND_GetSubChannel; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_GetSubChannel@8' {$ENDIF}; +function FSOUND_3D_GetAttributes; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_GetAttributes@12' {$ENDIF}; +function FSOUND_3D_GetMinMaxDistance; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_GetMinMaxDistance@12' {$ENDIF}; +procedure FSOUND_3D_Listener_SetCurrent; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_Listener_SetCurrent@8' {$ENDIF}; +procedure FSOUND_3D_Listener_SetAttributes; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_Listener_SetAttributes@32' {$ENDIF}; +procedure FSOUND_3D_Listener_GetAttributes; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_Listener_GetAttributes@32' {$ENDIF}; +procedure FSOUND_3D_SetDopplerFactor; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_SetDopplerFactor@4' {$ENDIF}; +procedure FSOUND_3D_SetDistanceFactor; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_SetDistanceFactor@4' {$ENDIF}; +procedure FSOUND_3D_SetRolloffFactor; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_3D_SetRolloffFactor@4' {$ENDIF}; +function FSOUND_FX_Enable; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_Enable@8' {$ENDIF}; +function FSOUND_FX_Disable; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_Disable@4' {$ENDIF}; +function FSOUND_FX_SetChorus; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetChorus@32' {$ENDIF}; +function FSOUND_FX_SetCompressor; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetCompressor@28' {$ENDIF}; +function FSOUND_FX_SetDistortion; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetDistortion@24' {$ENDIF}; +function FSOUND_FX_SetEcho; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetEcho@24' {$ENDIF}; +function FSOUND_FX_SetFlanger; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetFlanger@32' {$ENDIF}; +function FSOUND_FX_SetGargle; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetGargle@12' {$ENDIF}; +function FSOUND_FX_SetI3DL2Reverb; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetI3DL2Reverb@52' {$ENDIF}; +function FSOUND_FX_SetParamEQ; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetParamEQ@16' {$ENDIF}; +function FSOUND_FX_SetWavesReverb; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_FX_SetWavesReverb@20' {$ENDIF}; +function FSOUND_Stream_Open; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Open@16' {$ENDIF}; +function FSOUND_Stream_Create; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Create@20' {$ENDIF}; +function FSOUND_Stream_Play; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Play@8' {$ENDIF}; +function FSOUND_Stream_PlayEx; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_PlayEx@16' {$ENDIF}; +function FSOUND_Stream_Stop; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Stop@4' {$ENDIF}; +function FSOUND_Stream_Close; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Close@4' {$ENDIF}; +function FSOUND_Stream_SetEndCallback; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetEndCallback@12' {$ENDIF}; +function FSOUND_Stream_SetSyncCallback; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetSyncCallback@12' {$ENDIF}; +function FSOUND_Stream_GetSample; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetSample@4' {$ENDIF}; +function FSOUND_Stream_CreateDSP; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_CreateDSP@16' {$ENDIF}; +function FSOUND_Stream_SetBufferSize; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetBufferSize@4' {$ENDIF}; +function FSOUND_Stream_SetPosition; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetPosition@8' {$ENDIF}; +function FSOUND_Stream_GetPosition; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetPosition@4' {$ENDIF}; +function FSOUND_Stream_SetTime; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetTime@8' {$ENDIF}; +function FSOUND_Stream_GetTime; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetTime@4' {$ENDIF}; +function FSOUND_Stream_GetLength; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetLength@4' {$ENDIF}; +function FSOUND_Stream_GetLengthMs; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetLengthMs@4' {$ENDIF}; +function FSOUND_Stream_SetMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetMode@8' {$ENDIF}; +function FSOUND_Stream_GetMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetMode@4' {$ENDIF}; +function FSOUND_Stream_SetLoopPoints; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetLoopPoints@12' {$ENDIF}; +function FSOUND_Stream_SetLoopCount; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetLoopCount@8' {$ENDIF}; +function FSOUND_Stream_AddSyncPoint; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_AddSyncPoint@12' {$ENDIF}; +function FSOUND_Stream_DeleteSyncPoint; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_DeleteSyncPoint@4' {$ENDIF}; +function FSOUND_Stream_GetNumSyncPoints; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetNumSyncPoints@4' {$ENDIF}; +function FSOUND_Stream_GetSyncPoint; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetSyncPoint@8' {$ENDIF}; +function FSOUND_Stream_GetSyncPointInfo; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetSyncPointInfo@8' {$ENDIF}; +function FSOUND_Stream_GetOpenState; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetOpenState@4' {$ENDIF}; +function FSOUND_Stream_SetSubStream; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetSubStream@8' {$ENDIF}; +function FSOUND_Stream_GetNumSubStreams; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetNumSubStreams@4' {$ENDIF}; +function FSOUND_Stream_SetSubStreamSentence; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_SetSubStreamSentence@12' {$ENDIF}; +function FSOUND_Stream_GetNumTagFields; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetNumTagFields@8' {$ENDIF}; +function FSOUND_Stream_GetTagField; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_GetTagField@24' {$ENDIF}; +function FSOUND_Stream_FindTagField; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_FindTagField@20' {$ENDIF}; +function FSOUND_Stream_Net_SetProxy; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Net_SetProxy@4' {$ENDIF}; +function FSOUND_Stream_Net_GetLastServerStatus; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Net_GetLastServerStatus@0' {$ENDIF}; +function FSOUND_Stream_Net_SetBufferProperties; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Net_SetBufferProperties@12' {$ENDIF}; +function FSOUND_Stream_Net_GetBufferProperties; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Net_GetBufferProperties@12' {$ENDIF}; +function FSOUND_Stream_Net_SetMetadataCallback; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Net_SetMetadataCallback@12' {$ENDIF}; +function FSOUND_Stream_Net_GetStatus; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Stream_Net_GetStatus@20' {$ENDIF}; +function FSOUND_CD_Play; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_Play@8' {$ENDIF}; +procedure FSOUND_CD_SetPlayMode; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_SetPlayMode@8' {$ENDIF}; +function FSOUND_CD_Stop; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_Stop@4' {$ENDIF}; +function FSOUND_CD_SetPaused; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_SetPaused@8' {$ENDIF}; +function FSOUND_CD_SetVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_SetVolume@8' {$ENDIF}; +function FSOUND_CD_SetTrackTime; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_SetTrackTime@8' {$ENDIF}; +function FSOUND_CD_OpenTray; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_OpenTray@8' {$ENDIF}; +function FSOUND_CD_GetPaused; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_GetPaused@4' {$ENDIF}; +function FSOUND_CD_GetTrack; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_GetTrack@4' {$ENDIF}; +function FSOUND_CD_GetNumTracks; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_GetNumTracks@4' {$ENDIF}; +function FSOUND_CD_GetVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_GetVolume@4' {$ENDIF}; +function FSOUND_CD_GetTrackLength; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_GetTrackLength@8' {$ENDIF}; +function FSOUND_CD_GetTrackTime; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_CD_GetTrackTime@4' {$ENDIF}; +function FSOUND_DSP_Create; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_Create@12' {$ENDIF}; +procedure FSOUND_DSP_Free; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_Free@4' {$ENDIF}; +procedure FSOUND_DSP_SetPriority; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_SetPriority@8' {$ENDIF}; +function FSOUND_DSP_GetPriority; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetPriority@4' {$ENDIF}; +procedure FSOUND_DSP_SetActive; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_SetActive@8' {$ENDIF}; +function FSOUND_DSP_GetActive; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetActive@4' {$ENDIF}; +function FSOUND_DSP_GetClearUnit; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetClearUnit@0' {$ENDIF}; +function FSOUND_DSP_GetSFXUnit; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetSFXUnit@0' {$ENDIF}; +function FSOUND_DSP_GetMusicUnit; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetMusicUnit@0' {$ENDIF}; +function FSOUND_DSP_GetClipAndCopyUnit; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetClipAndCopyUnit@0' {$ENDIF}; +function FSOUND_DSP_GetFFTUnit; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetFFTUnit@0' {$ENDIF}; +function FSOUND_DSP_MixBuffers; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_MixBuffers@28' {$ENDIF}; +procedure FSOUND_DSP_ClearMixBuffer; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_ClearMixBuffer@0' {$ENDIF}; +function FSOUND_DSP_GetBufferLength; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetBufferLength@0' {$ENDIF}; +function FSOUND_DSP_GetBufferLengthTotal; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetBufferLengthTotal@0' {$ENDIF}; +function FSOUND_DSP_GetSpectrum; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_DSP_GetSpectrum@0' {$ENDIF}; +function FSOUND_Reverb_SetProperties; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Reverb_SetProperties@4' {$ENDIF}; +function FSOUND_Reverb_GetProperties; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Reverb_GetProperties@4' {$ENDIF}; +function FSOUND_Reverb_SetChannelProperties; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Reverb_SetChannelProperties@8' {$ENDIF}; +function FSOUND_Reverb_GetChannelProperties; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Reverb_GetChannelProperties@8' {$ENDIF}; +function FSOUND_Record_SetDriver; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Record_SetDriver@4' {$ENDIF}; +function FSOUND_Record_GetNumDrivers; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Record_GetNumDrivers@0' {$ENDIF}; +function FSOUND_Record_GetDriverName; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Record_GetDriverName@4' {$ENDIF}; +function FSOUND_Record_GetDriver; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Record_GetDriver@0' {$ENDIF}; +function FSOUND_Record_StartSample; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Record_StartSample@8' {$ENDIF}; +function FSOUND_Record_Stop; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Record_Stop@0' {$ENDIF}; +function FSOUND_Record_GetPosition; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_Record_GetPosition@0' {$ENDIF}; +procedure FSOUND_File_SetCallbacks; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FSOUND_File_SetCallbacks@20' {$ENDIF}; +function FMUSIC_LoadSong; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_LoadSong@4' {$ENDIF}; +function FMUSIC_LoadSongEx; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_LoadSongEx@24' {$ENDIF}; +function FMUSIC_GetOpenState; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetOpenState@4' {$ENDIF}; +function FMUSIC_FreeSong; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_FreeSong@4' {$ENDIF}; +function FMUSIC_PlaySong; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_PlaySong@4' {$ENDIF}; +function FMUSIC_StopSong; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_StopSong@4' {$ENDIF}; +procedure FMUSIC_StopAllSongs; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_StopAllSongs@0' {$ENDIF}; +function FMUSIC_SetZxxCallback; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetZxxCallback@8' {$ENDIF}; +function FMUSIC_SetRowCallback; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetRowCallback@12' {$ENDIF}; +function FMUSIC_SetOrderCallback; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetOrderCallback@12' {$ENDIF}; +function FMUSIC_SetInstCallback; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetInstCallback@12' {$ENDIF}; +function FMUSIC_SetSample; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetSample@12' {$ENDIF}; +function FMUSIC_SetUserData; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetUserData@8' {$ENDIF}; +function FMUSIC_OptimizeChannels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_OptimizeChannels@12' {$ENDIF}; +function FMUSIC_SetReverb; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetReverb@4' {$ENDIF}; +function FMUSIC_SetLooping; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetLooping@8' {$ENDIF}; +function FMUSIC_SetOrder; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetOrder@8' {$ENDIF}; +function FMUSIC_SetPaused; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetPaused@8' {$ENDIF}; +function FMUSIC_SetMasterVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetMasterVolume@8' {$ENDIF}; +function FMUSIC_SetMasterSpeed; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetMasterSpeed@8' {$ENDIF}; +function FMUSIC_SetPanSeperation; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_SetPanSeperation@8' {$ENDIF}; +function FMUSIC_GetName; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetName@4' {$ENDIF}; +function FMUSIC_GetType; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetType@4' {$ENDIF}; +function FMUSIC_GetNumOrders; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetNumOrders@4' {$ENDIF}; +function FMUSIC_GetNumPatterns; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetNumPatterns@4' {$ENDIF}; +function FMUSIC_GetNumInstruments; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetNumInstruments@4' {$ENDIF}; +function FMUSIC_GetNumSamples; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetNumSamples@4' {$ENDIF}; +function FMUSIC_GetNumChannels; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetNumChannels@4' {$ENDIF}; +function FMUSIC_GetSample; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetSample@8' {$ENDIF}; +function FMUSIC_GetPatternLength; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetPatternLength@8' {$ENDIF}; +function FMUSIC_IsFinished; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_IsFinished@4' {$ENDIF}; +function FMUSIC_IsPlaying; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_IsPlaying@4' {$ENDIF}; +function FMUSIC_GetMasterVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetMasterVolume@4' {$ENDIF}; +function FMUSIC_GetGlobalVolume; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetGlobalVolume@4' {$ENDIF}; +function FMUSIC_GetOrder; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetOrder@4' {$ENDIF}; +function FMUSIC_GetPattern; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetPattern@4' {$ENDIF}; +function FMUSIC_GetSpeed; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetSpeed@4' {$ENDIF}; +function FMUSIC_GetBPM; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetBPM@4' {$ENDIF}; +function FMUSIC_GetRow; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetRow@4' {$ENDIF}; +function FMUSIC_GetPaused; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetPaused@4' {$ENDIF}; +function FMUSIC_GetTime; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetTime@4' {$ENDIF}; +function FMUSIC_GetRealChannel; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetRealChannel@8' {$ENDIF}; +function FMUSIC_GetUserData; external FMOD_DLL {$IFDEF MSWINDOWS} name '_FMUSIC_GetUserData@4' {$ENDIF}; + +var + Saved8087CW: Word; + +{$ifdef FPC} //FPC do not have this function in its RTL +const + Default8087CW = $1332; //according to the FPC site it's the value used in the + //startup code. +procedure Set8087CW( value :word ); Assembler; +asm + FLDCW value +end; +{$endif} + + +initialization + { Save the current FPU state and then disable FPU exceptions } + Saved8087CW := Default8087CW; + Set8087CW($133f); { Disable all fpu exceptions } + +finalization + { Reset the FPU to the previous state } + Set8087CW(Saved8087CW); + +end. diff --git a/fmodapi375win/api/delphi/fmoddyn.pas b/fmodapi375win/api/delphi/fmoddyn.pas new file mode 100644 index 0000000..9fbede2 --- /dev/null +++ b/fmodapi375win/api/delphi/fmoddyn.pas @@ -0,0 +1,864 @@ +{============================================================================================ } +{ FMOD Main header file. Copyright (c), FireLight Technologies Pty, Ltd. 1999-2003. } +{ =========================================================================================== } +{ + NOTE: For the demos to run you must have either fmod.dll (in Windows) + or libfmod-3.75.so (in Linux) installed. + + In Windows, copy the fmod.dll file found in the api directory to either of + the following locations (in order of preference) + - your application directory + - Windows\System (95/98) or WinNT\System32 (NT/2000/XP) + + In Linux, make sure you are signed in as root and copy the libfmod-3.75.so + file from the api directory to your /usr/lib/ directory. + Then via a command line, navigate to the /usr/lib/ directory and create + a symbolic link between libfmod-3.75.so and libfmod.so. This is done with + the following command (assuming you are in /usr/lib/)... + ln -s libfmod-3.75.so libfmod.so. +} +{ =============================================================================================== } + +unit fmoddyn; + +{ + Disable assertions by changing the following compiler directive to OFF. + Assertions are used to check the functions are correctly loaded when using + dynamic loading. +} +{$ASSERTIONS ON} + +interface + +uses +{$IFDEF MSWINDOWS} + Windows, +{$ENDIF} + fmodtypes; + +{ + Disable warning for unsafe types in Delphi 7 +} +{$IFDEF VER150} +{$WARN UNSAFE_TYPE OFF} +{$ENDIF} + +//=============================================================================================== +// FUNCTION PROTOTYPES +//=============================================================================================== + +{ ================================== } +{ Library load/unload functions. } +{ ================================== } + +{ + If no library name is passed to FMOD_Load, then the default library name + used. +} + +function FMOD_Load(LibName: PChar {$ifndef FPC}= nil{$endif}): Boolean; +procedure FMOD_Unload; + +{ ================================== } +{ Initialization / Global functions. } +{ ================================== } + +{ + Pre FSOUND_Init functions. These can't be called after FSOUND_Init is + called (they will fail). They set up FMOD system functionality. +} + +var + FSOUND_SetOutput: function (OutputType: TFSoundOutputTypes): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetDriver: function (Driver: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetMixer: function (Mixer: TFSoundMixerTypes): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetBufferSize: function (LenMs: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetHWND: function (Hwnd: THandle): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetMinHardwareChannels: function (Min: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetMaxHardwareChannels: function (Max: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetMemorySystem: function (Pool: Pointer; + PoolLen: Integer; + UserAlloc: TFSoundAllocCallback; + UserRealloc: TFSoundReallocCallback; + UserFree: TFSoundFreeCallback): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Main initialization / closedown functions + Note : Use FSOUND_INIT_USEDEFAULTMIDISYNTH with FSOUND_Init for software override with MIDI playback. + : Use FSOUND_INIT_GLOBALFOCUS with FSOUND_Init to make sound audible + no matter which window is in focus. (FSOUND_OUTPUT_DSOUND only) +} + +var + FSOUND_Init: function (MixRate: Integer; MaxSoftwareChannels: Integer; Flags: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Close: procedure; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Runtime system level functions +} + +var + FSOUND_Update: procedure; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; // This is called to update 3d sound / non-realtime output + FSOUND_SetSpeakerMode: procedure (SpeakerMode: Cardinal); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetSFXMasterVolume: procedure (Volume: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetPanSeperation: procedure (PanSep: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_File_SetCallbacks: procedure (OpenCallback: TFSoundOpenCallback; + CloseCallback: TFSoundCloseCallback; + ReadCallback: TFSoundReadCallback; + SeekCallback: TFSoundSeekCallback; + TellCallback: TFSoundTellCallback); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + System information functions +} + +var + FSOUND_GetError: function: TFModErrors; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetVersion: function: Single; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetOutput: function: TFSoundOutputTypes; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetOutputHandle: function: Pointer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetDriver: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetMixer: function: TFSoundMixerTypes; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetNumDrivers: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetDriverName: function (Id: Integer): PChar; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetDriverCaps: function (Id: Integer; var Caps: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +var + FSOUND_GetOutputRate: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetMaxChannels: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetMaxSamples: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetSpeakerMode: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetSFXMasterVolume: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetNumHWChannels: function (var Num2D: Integer; var Num3D: Integer; var Total: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetChannelsPlaying: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetCPUUsage: function: Single; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetMemoryStats: Procedure (var CurrentAlloced: Cardinal; var MaxAlloced: Cardinal); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================================== } +{ Sample management / load functions. } +{ =================================== } + +{ + Sample creation and management functions + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Sample_Load to load from memory. + Use FSOUND_LOADRAW flag with FSOUND_Sample_Load to treat as as raw pcm data. +} + +var + FSOUND_Sample_Load: function (Index: Integer; const NameOrData: PChar; Mode: Cardinal; Offset: Integer; Length: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_Alloc: function (Index: Integer; Length: Integer; Mode: Cardinal; DefFreq: Integer; DefVol: Integer; DefPan: Integer; DefPri: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_Free: procedure (Sptr: PFSoundSample); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_Upload: function (Sptr: PFSoundSample; SrcData: Pointer; Mode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_Lock: function (Sptr: PFSoundSample; Offset: Integer; Length: Integer; var Ptr1: Pointer; var Ptr2: Pointer; var Len1: Cardinal; var Len2: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_Unlock: function (Sptr: PFSoundSample; Ptr1: Pointer; Ptr2: Pointer; Len1: Cardinal; Len2: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Sample control functions +} + +var + FSOUND_Sample_SetMode: function (Sptr: PFSoundSample; Mode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_SetLoopPoints: function (Sptr: PFSoundSample; LoopStart, LoopEnd: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_SetDefaults: function (Sptr: PFSoundSample; DefFreq, DefVol, DefPan, DefPri: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_SetDefaultsEx: function (Sptr: PFSoundSample; DefFreq, DefVol, DefPan, DefPri, VarFreq, VarVol, VarPan: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_SetMinMaxDistance: function (Sptr: PFSoundSample; Min, Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_SetMaxPlaybacks: function (Sptr: PFSoundSample; Max: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Sample information functions +} + +var + FSOUND_Sample_Get: function (SampNo: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_GetName: function (Sptr: PFSoundSample): PCHAR; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_GetLength: function (Sptr: PFSoundSample): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_GetLoopPoints: function (Sptr: PFSoundSample; var LoopStart: Integer; var LoopEnd: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_GetDefaults: function (Sptr: PFSoundSample; var DefFreq: Integer; var DefVol: Integer; var DefPan: Integer; var DefPri: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_GetDefaultsEx: function (Sptr: PFSoundSample; var DefFreq: Integer; var DefVol: Integer; var DefPan: Integer; var DefPri: Integer; var VarFreq: Integer; var VarVol: Integer; var VarPan): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_GetMode: function (Sptr: PFSoundSample): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Sample_GetMinMaxDistance: function (Sptr: PFSoundSample; var Min: Single; var Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ============================ } +{ Channel control functions. } +{ ============================ } + +{ + Playing and stopping sounds. + Note : Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. + Use FSOUND_ALL as the 'channel' variable to control ALL channels with one function call! +} + +var + FSOUND_PlaySound: function (Channel: Integer; Sptr: PFSoundSample): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_PlaySoundEx: function (Channel: Integer; Sptr: PFSoundSample; Dsp: PFSoundDSPUnit; StartPaused: ByteBool): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_StopSound: function (Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Functions to control playback of a channel. +} + +var + FSOUND_SetFrequency: function (Channel: Integer; Freq: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetVolume: function (Channel: Integer; Vol: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetVolumeAbsolute: function (Channel: Integer; Vol: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetPan: function (Channel: Integer; Pan: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetSurround: function (Channel: Integer; Surround: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetMute: function (Channel: Integer; Mute: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetPriority: function (Channel: Integer; Priority: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetReserved: function (Channel: Integer; Reserved: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetPaused: function (Channel: Integer; Paused: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetLoopMode: function (Channel: Integer; LoopMode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_SetCurrentPosition: function (Channel: Integer; Offset: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_SetAttributes: function (Channel: Integer; Pos: PFSoundVector; Vel: PFSoundVector): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_SetMinMaxDistance: function (Channel: Integer; Min: Single; Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Channel information functions +} + +var + FSOUND_IsPlaying: function (Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetFrequency: function (Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetVolume: function (Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetAmplitude: function (Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetPan: function (Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetSurround: function (Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetMute: function (Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetPriority: function (Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetReserved: function (Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetPaused: function (Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetLoopMode: function (Channel: Integer): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetCurrentPosition: function (Channel: Integer): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetCurrentSample: function (Channel: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetCurrentLevels: function (Channel: Integer; L, R: PSingle): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetNumSubChannels: function (Channel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_GetSubChannel: function (Channel: Integer; SubChannel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_GetAttributes: function (Channel: Integer; Pos: PFSoundVector; Vel: PFSoundVector): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_GetMinMaxDistance: function (Channel: Integer; var Min: Single; var Max: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================== } +{ 3D sound functions. } +{ =================== } + +{ + See also 3d sample and channel based functions above. + Call FSOUND_Update once a frame to process 3d information. +} + +var + FSOUND_3D_Listener_SetCurrent: procedure (current: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_Listener_SetAttributes: procedure (Pos: PFSoundVector; Vel: PFSoundVector; + fx: Single; fy: Single; fz: Single; + tx: Single; ty: Single; tz: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_Listener_GetAttributes: procedure (Pos: PFSoundVector; Vel: PFSoundVector; + fx: PSingle; fy: PSingle; fz: PSingle; + tx: PSingle; ty: PSingle; tz: PSingle); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_SetDopplerFactor: procedure (Scale: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_SetDistanceFactor: procedure (Scale: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_3D_SetRolloffFactor: procedure (Scale: Single); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================== } +{ FX functions. } +{ =================== } + +{ + Functions to control DX8 only effects processing. + + - FX enabled samples can only be played once at a time, not multiple times at once. + - Sounds have to be created with FSOUND_HW2D or FSOUND_HW3D for this to work. + - FSOUND_INIT_ENABLESYSTEMCHANNELFX can be used to apply hardware effect processing to the + global mixed output of FMOD's software channels. + - FSOUND_FX_Enable returns an FX handle that you can use to alter fx parameters. + - FSOUND_FX_Enable can be called multiple times in a row, even on the same FX type, + it will return a unique handle for each FX. + - FSOUND_FX_Enable cannot be called if the sound is playing or locked. + - Stopping or starting a sound resets all FX and they must be re-enabled each time + if this happens. +} + +var + FSOUND_FX_Enable: function (Channel: Integer; Fx: TFSoundFXModes): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Set bits to enable following fx } + FSOUND_FX_Disable: function (Channel: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_FX_SetChorus: function (FXId: Integer; WetDryMix, Depth, Feedback, Frequency: Single; Waveform: Integer; Delay: Single; Phase: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetCompressor: function (FXId: Integer; Gain, Attack, Release, Threshold, Ratio, Predelay: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetDistortion: function (FXId: Integer; Gain, Edge, PostEQCenterFrequency, PostEQBandwidth, PreLowpassCutoff: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetEcho: function (FXId: Integer; WetDryMix, Feedback, LeftDelay, RightDelay: Single; PanDelay: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetFlanger: function (FXId: Integer; WetDryMix, Depth, Feedback, Frequency: Single; Waveform: Integer; Delay: Single; Phase: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetGargle: function (FXId, RateHz, WaveShape: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetI3DL2Reverb: function (FXId, Room, RoomHF: Integer; RoomRolloffFactor, DecayTime, DecayHFRatio: Single; Reflections: Integer; ReflectionsDelay: Single; Reverb: Integer; ReverbDelay, Diffusion, Density, HFReference: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetParamEQ: function (FXId: Integer; Center, Bandwidth, Gain: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_FX_SetWavesReverb: function (FXId: Integer; InGain, ReverbMix, ReverbTime, HighFreqRTRatio: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ========================= } +{ File Streaming functions. } +{ ========================= } + +{ + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Stream_Open to stream from memory. + Use FSOUND_LOADRAW flag with FSOUND_Stream_Open to treat stream as raw pcm data. + Use FSOUND_MPEGACCURATE flag with FSOUND_Stream_Open to open mpegs in 'accurate mode' for settime/gettime/getlengthms. + Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. +} + +var + // call this before opening streams, not after + FSOUND_Stream_SetBufferSize: function (Ms: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_Open: function(const name_or_data: PChar; Mode: Cardinal; Offset: Integer; Length: Integer): PFSoundStream; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Create: function (Callback: TFSoundStreamCallback; Length: Integer; Mode: Cardinal; SampleRate: Integer; UserData: Integer): PFSoundStream; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Close: function(Stream: PFSoundStream): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_Play: function(Channel: Integer; Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_PlayEx: function (Channel: Integer; Stream: PFSoundStream; Dsp: PFSoundDSPUnit; StartPaused: ByteBool): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Stop: function(Stream: PFSoundStream): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_SetPosition: function (Stream: PFSoundStream; Position: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetPosition: function (Stream: PFSoundStream): Cardinal; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_SetTime: function (Stream: PFSoundStream; Ms: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetTime: function (Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetLength: function (Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetLengthMs: function (Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_SetMode: function (Stream: PFSoundStream; mode: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetMode: function (Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_SetLoopPoints: function (Stream: PFSoundStream; LoopStartPCM, LoopEndPCM: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_SetLoopCount: function (Stream: PFSoundStream; Count: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetOpenState: function (Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetSample: function (Stream: PFSoundStream): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Every stream contains a sample to play back on } + FSOUND_Stream_CreateDSP: function (Stream: PFSoundStream; Callback: TFSoundDSPCallback; Priority: Integer; Param: Integer): PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_SetEndCallback: function (Stream: PFSoundStream; Callback: TFSoundStreamCallback; UserData: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_SetSyncCallback: function (Stream: PFSoundStream; Callback: TFSoundStreamCallback; UserData: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_AddSyncPoint: function (Stream: PFSoundStream; PCMOffset: Cardinal; Name: PChar): PFSyncPoint; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_DeleteSyncPoint: function (Point: PFSyncPoint): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetNumSyncPoints: function (Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetSyncPoint: function (Stream: PFSoundStream; Index: Integer): PFSyncPoint; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetSyncPointInfo: function (Point: PFSyncPoint; var PCMOffset: Cardinal): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_SetSubStream: function (Stream: PFSoundStream; Index: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetNumSubStreams: function (Stream: PFSoundStream): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_SetSubStreamSentence: function (Stream: PFSoundStream; var sentencelist: Cardinal; numitems: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_GetNumTagFields: function (Stream: PFSoundStream; var Num: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_GetTagField: function (Stream: PFSoundStream; Num: Integer; var _Type: TFSoundTagFieldType; var Name: PCHAR; var Value: Pointer; var Length: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_FindTagField: function (Stream: PFSoundStream; _Type: TFSoundTagFieldType; Name: PChar; var Value: Pointer; var Length: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + + FSOUND_Stream_Net_SetProxy: function (Proxy: PChar): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Net_GetLastServerStatus: function: PChar; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Net_SetBufferProperties: function (BufferSize: Integer; PreBuffer_Percent: Integer; ReBuffer_Percent: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Net_GetBufferProperties: function (var Buffersize: Integer; var PreBuffer_Percent: Integer; var ReBuffer_Percent: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Net_SetMetadataCallback: function (Stream: PFSoundStream; Callback: TFMetaDataCallback; UserData: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Stream_Net_GetStatus: function (Stream: PFSoundStream; var Status: TFSoundStreamNetStatus; var BufferPercentUsed: Integer; var BitRate: Integer; var Flags: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ =================== } +{ CD audio functions. } +{ =================== } + +{ + Note : 0 = default cdrom. Otherwise specify the drive letter, for example. 'D'. +} + +var + FSOUND_CD_Play: function (Drive: Byte; Track: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_SetPlayMode: procedure (Drive: Byte; Mode: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_Stop: function (Drive: Byte): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_SetPaused: function (Drive: Byte; Paused: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_SetVolume: function (Drive: Byte; Volume: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_SetTrackTime: function (Drive: Byte; ms: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_OpenTray: function (Drive: Byte; Open: Byte): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +var + FSOUND_CD_GetPaused: function (Drive: Byte): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_GetTrack: function (Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_GetNumTracks: function (Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_GetVolume: function (Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_GetTrackLength: function (Drive: Byte; Track: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_CD_GetTrackTime: function (Drive: Byte): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ============== } +{ DSP functions. } +{ ============== } + +{ + DSP Unit control and information functions. +} + +var + FSOUND_DSP_Create: function (Callback: TFSoundDSPCallback; Priority: Integer; Param: Integer): PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_Free: procedure (DSPUnit: PFSoundDSPUnit); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_SetPriority: procedure (DSPUnit: PFSoundDSPUnit; Priority: Integer); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_GetPriority: function (DSPUnit: PFSoundDSPUnit): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_SetActive: procedure (DSPUnit: PFSoundDSPUnit; Active: ByteBool); {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_GetActive: function (DSPUnit: PFSoundDSPUnit): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Functions to get hold of FSOUND 'system DSP unit' handles. +} + +var + FSOUND_DSP_GetClearUnit: function: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_GetSFXUnit: function: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_GetMusicUnit: function: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_GetClipAndCopyUnit: function: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_GetFFTUnit: function: PFSoundDSPUnit; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Miscellaneous DSP functions + Note for the spectrum analysis function to work, you have to enable the FFT DSP unit with + the following code FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); + It is off by default to save cpu usage. +} + +var + FSOUND_DSP_MixBuffers: function (DestBuffer: Pointer; SrcBuffer: Pointer; Len: Integer; Freq: Integer; Vol: Integer; Pan: Integer; Mode: Cardinal): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_ClearMixBuffer: procedure; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_DSP_GetBufferLength: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Length of each DSP update } + FSOUND_DSP_GetBufferLengthTotal: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Total buffer length due to FSOUND_SetBufferSize } + FSOUND_DSP_GetSpectrum: function: PSingle; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; { Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. } + +{ ========================================================================== } +{ Reverb functions. (eax2/eax3 reverb) (NOT SUPPORTED IN LINUX/CE) } +{ ========================================================================== } + +{ + See structures above for definitions and information on the reverb parameters. +} + +var + FSOUND_Reverb_SetProperties: function (const Prop: TFSoundReverbProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Reverb_GetProperties: function (var Prop: TFSoundReverbProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Reverb_SetChannelProperties: function (Channel: Integer; var Prop: TFSoundReverbChannelProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Reverb_GetChannelProperties: function (Channel: Integer; var Prop: TFSoundReverbChannelProperties): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ================================================ } +{ Recording functions (NOT SUPPORTED IN LINUX/MAC) } +{ ================================================ } + +{ + Recording initialization functions +} + +var + FSOUND_Record_SetDriver: function (OutputType: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Record_GetNumDrivers: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Record_GetDriverName: function (Id: Integer): PChar; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Record_GetDriver: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Recording functionality. Only one recording session will work at a time. +} + +var + FSOUND_Record_StartSample: function (Sptr: PFSoundSample; Loop: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Record_Stop: function: ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FSOUND_Record_GetPosition: function: Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ ============================================================================================= } +{ FMUSIC API (MOD,S3M,XM,IT,MIDI PLAYBACK) } +{ ============================================================================================= } + +{ + Song management / playback functions. +} + +var + FMUSIC_LoadSong: function (const Name: PChar): PFMusicModule; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_LoadSongEx: function (Name_Or_Data: Pointer; Offset: Integer; Length: Integer; Mode: Cardinal; var SampleList: Integer; SampleListNum: Integer): PFMusicModule; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetOpenState: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_FreeSong: function (Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_PlaySong: function (Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_StopSong: function (Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_StopAllSongs: procedure; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +var + FMUSIC_SetZxxCallback: function (Module: PFMusicModule; Callback: TFMusicCallback): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetRowCallback: function (Module: PFMusicModule; Callback: TFMusicCallback; RowStep: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetOrderCallback: function (Module: PFMusicModule; Callback: TFMusicCallback; OrderStep: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetInstCallback: function (Module: PFMusicModule; Callback: TFMusicCallback; Instrument: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +var + FMUSIC_SetSample: function (Module: PFMusicModule; SampNo: Integer; Sptr: PFSoundSample): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetUserData: function (Module: PFMusicModule; userdata: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_OptimizeChannels: function (Module: PFMusicModule; MaxChannels: Integer; MinVolume: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Runtime song functions. +} + +var + FMUSIC_SetReverb: function (Reverb: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetLooping: function (Module: PFMusicModule; Looping: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetOrder: function (Module: PFMusicModule; Order: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetPaused: function (Module: PFMusicModule; Pause: ByteBool): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetMasterVolume: function (Module: PFMusicModule; Volume: Integer): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetMasterSpeed: function (Module: PFMusicModule; Speed: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_SetPanSeperation: function (Module: PFMusicModule; PanSep: Single): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Static song information functions. +} + +var + FMUSIC_GetName: function (Module: PFMusicModule): PCHAR; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetType: function (Module: PFMusicModule): TFMusicTypes; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetNumOrders: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetNumPatterns: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetNumInstruments: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetNumSamples: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetNumChannels: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetSample: function (Module: PFMusicModule; SampNo: Integer): PFSoundSample; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetPatternLength: function (Module: PFMusicModule; OrderNo: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +{ + Runtime song information. +} + +var + FMUSIC_IsFinished: function (Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_IsPlaying: function (Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetMasterVolume: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetGlobalVolume: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetOrder: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetPattern: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetSpeed: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetBPM: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetRow: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetPaused: function (Module: PFMusicModule): ByteBool; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetTime: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetRealChannel: function (Module: PFMusicModule; ModChannel: Integer): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + FMUSIC_GetUserData: function (Module: PFMusicModule): Integer; {$IFDEF LINUX} cdecl {$ELSE} stdcall {$ENDIF}; + +implementation + +{$IFDEF LINUX} +uses + Libc; +{$ENDIF} + +const +{$IFDEF LINUX} + FMOD_DLL = 'libfmod.so'; +{$ELSE} +{$IFDEF MSWINDOWS} + FMOD_DLL = 'fmod.dll'; +{$ENDIF} +{$ENDIF} + +type +{$IFDEF LINUX} + TFMODModuleHandle = Pointer; +{$ELSE} + TFMODModuleHandle = HINST; +{$ENDIF} + +const +{$IFDEF LINUX} + INVALID_MODULEHANDLE_VALUE = TFMODModuleHandle(nil); +{$ELSE} + INVALID_MODULEHANDLE_VALUE = TFMODModuleHandle(0); +{$ENDIF} + +var + FMODHandle: TFMODModuleHandle; + +function GetAddress(Handle: TFMODModuleHandle; FuncName: PChar): Pointer; +begin +{$IFDEF MSWINDOWS} + Result := GetProcAddress(Handle, FuncName); +{$ELSE} + Result := dlsym(Handle, FuncName); +{$ENDIF} + Assert(Result <> nil, 'Failed to find ' + FuncName + ' in ' + FMOD_DLL); +end; + +function FMOD_Load(LibName: PChar): Boolean; +begin + Result := False; + + { Make sure the previous library is unloaded } + FMOD_Unload; + + { If no library name given, use the default library names } + if LibName = nil then + LibName := FMOD_DLL; + + { Load the library } +{$IFDEF MSWINDOWS} + FMODHandle := LoadLibrary(LibName); +{$ELSE} + FMODHandle := dlopen(LibName, RTLD_NOW); +{$ENDIF} + if FMODHandle = INVALID_MODULEHANDLE_VALUE then + Exit; + + { Get all the function addresses from the library } + FSOUND_SetOutput := GetAddress(FMODHandle, '_FSOUND_SetOutput@4'); + FSOUND_SetDriver := GetAddress(FMODHandle, '_FSOUND_SetDriver@4'); + FSOUND_SetMixer := GetAddress(FMODHandle, '_FSOUND_SetMixer@4'); + FSOUND_SetBufferSize := GetAddress(FMODHandle, '_FSOUND_SetBufferSize@4'); + FSOUND_SetHWND := GetAddress(FMODHandle, '_FSOUND_SetHWND@4'); + FSOUND_SetMinHardwareChannels := GetAddress(FMODHandle, '_FSOUND_SetMinHardwareChannels@4'); + FSOUND_SetMaxHardwareChannels := GetAddress(FMODHandle, '_FSOUND_SetMaxHardwareChannels@4'); + FSOUND_SetMemorySystem := GetAddress(FMODHandle, '_FSOUND_SetMemorySystem@20'); + FSOUND_Init := GetAddress(FMODHandle, '_FSOUND_Init@12'); + FSOUND_Close := GetAddress(FMODHandle, '_FSOUND_Close@0'); + FSOUND_Update := GetAddress(FMODHandle, '_FSOUND_Update@0'); + FSOUND_SetSpeakerMode := GetAddress(FMODHandle, '_FSOUND_SetSpeakerMode@4'); + FSOUND_SetSFXMasterVolume := GetAddress(FMODHandle, '_FSOUND_SetSFXMasterVolume@4'); + FSOUND_SetPanSeperation := GetAddress(FMODHandle, '_FSOUND_SetPanSeperation@4'); + FSOUND_GetError := GetAddress(FMODHandle, '_FSOUND_GetError@0'); + FSOUND_GetVersion := GetAddress(FMODHandle, '_FSOUND_GetVersion@0'); + FSOUND_GetOutput := GetAddress(FMODHandle, '_FSOUND_GetOutput@0'); + FSOUND_GetOutputHandle := GetAddress(FMODHandle, '_FSOUND_GetOutputHandle@0'); + FSOUND_GetDriver := GetAddress(FMODHandle, '_FSOUND_GetDriver@0'); + FSOUND_GetMixer := GetAddress(FMODHandle, '_FSOUND_GetMixer@0'); + FSOUND_GetNumDrivers := GetAddress(FMODHandle, '_FSOUND_GetNumDrivers@0'); + FSOUND_GetDriverName := GetAddress(FMODHandle, '_FSOUND_GetDriverName@4'); + FSOUND_GetDriverCaps := GetAddress(FMODHandle, '_FSOUND_GetDriverCaps@8'); + FSOUND_GetOutputRate := GetAddress(FMODHandle, '_FSOUND_GetOutputRate@0'); + FSOUND_GetMaxChannels := GetAddress(FMODHandle, '_FSOUND_GetMaxChannels@0'); + FSOUND_GetMaxSamples := GetAddress(FMODHandle, '_FSOUND_GetMaxSamples@0'); + FSOUND_GetSpeakerMode := GetAddress(FMODHandle, '_FSOUND_GetSpeakerMode@0'); + FSOUND_GetSFXMasterVolume := GetAddress(FMODHandle, '_FSOUND_GetSFXMasterVolume@0'); + FSOUND_GetNumHWChannels := GetAddress(FMODHandle, '_FSOUND_GetNumHWChannels@12'); + FSOUND_GetChannelsPlaying := GetAddress(FMODHandle, '_FSOUND_GetChannelsPlaying@0'); + FSOUND_GetCPUUsage := GetAddress(FMODHandle, '_FSOUND_GetCPUUsage@0'); + FSOUND_GetMemoryStats := GetAddress(FMODHandle, '_FSOUND_GetMemoryStats@8'); + FSOUND_Sample_Load := GetAddress(FMODHandle, '_FSOUND_Sample_Load@20'); + FSOUND_Sample_Alloc := GetAddress(FMODHandle, '_FSOUND_Sample_Alloc@28'); + FSOUND_Sample_Free := GetAddress(FMODHandle, '_FSOUND_Sample_Free@4'); + FSOUND_Sample_Upload := GetAddress(FMODHandle, '_FSOUND_Sample_Upload@12'); + FSOUND_Sample_Lock := GetAddress(FMODHandle, '_FSOUND_Sample_Lock@28'); + FSOUND_Sample_Unlock := GetAddress(FMODHandle, '_FSOUND_Sample_Unlock@20'); + FSOUND_Sample_SetMode := GetAddress(FMODHandle, '_FSOUND_Sample_SetMode@8'); + FSOUND_Sample_SetLoopPoints := GetAddress(FMODHandle, '_FSOUND_Sample_SetLoopPoints@12'); + FSOUND_Sample_SetDefaults := GetAddress(FMODHandle, '_FSOUND_Sample_SetDefaults@20'); + FSOUND_Sample_SetDefaultsEx := GetAddress(FMODHandle, '_FSOUND_Sample_SetDefaultsEx@32'); + FSOUND_Sample_SetMinMaxDistance := GetAddress(FMODHandle, '_FSOUND_Sample_SetMinMaxDistance@12'); + FSOUND_Sample_SetMaxPlaybacks := GetAddress(FMODHandle, '_FSOUND_Sample_SetMaxPlaybacks@8'); + FSOUND_Sample_Get := GetAddress(FMODHandle, '_FSOUND_Sample_Get@4'); + FSOUND_Sample_GetName := GetAddress(FMODHandle, '_FSOUND_Sample_GetName@4'); + FSOUND_Sample_GetLength := GetAddress(FMODHandle, '_FSOUND_Sample_GetLength@4'); + FSOUND_Sample_GetLoopPoints := GetAddress(FMODHandle, '_FSOUND_Sample_GetLoopPoints@12'); + FSOUND_Sample_GetDefaults := GetAddress(FMODHandle, '_FSOUND_Sample_GetDefaults@20'); + FSOUND_Sample_GetDefaultsEx := GetAddress(FMODHandle, '_FSOUND_Sample_GetDefaultsEx@32'); + FSOUND_Sample_GetMode := GetAddress(FMODHandle, '_FSOUND_Sample_GetMode@4'); + FSOUND_Sample_GetMinMaxDistance := GetAddress(FMODHandle, '_FSOUND_Sample_GetMinMaxDistance@12'); + FSOUND_PlaySound := GetAddress(FMODHandle, '_FSOUND_PlaySound@8'); + FSOUND_PlaySoundEx := GetAddress(FMODHandle, '_FSOUND_PlaySoundEx@16'); + FSOUND_StopSound := GetAddress(FMODHandle, '_FSOUND_StopSound@4'); + FSOUND_SetFrequency := GetAddress(FMODHandle, '_FSOUND_SetFrequency@8'); + FSOUND_SetVolume := GetAddress(FMODHandle, '_FSOUND_SetVolume@8'); + FSOUND_SetVolumeAbsolute := GetAddress(FMODHandle, '_FSOUND_SetVolumeAbsolute@8'); + FSOUND_SetPan := GetAddress(FMODHandle, '_FSOUND_SetPan@8'); + FSOUND_SetSurround := GetAddress(FMODHandle, '_FSOUND_SetSurround@8'); + FSOUND_SetMute := GetAddress(FMODHandle, '_FSOUND_SetMute@8'); + FSOUND_SetPriority := GetAddress(FMODHandle, '_FSOUND_SetPriority@8'); + FSOUND_SetReserved := GetAddress(FMODHandle, '_FSOUND_SetReserved@8'); + FSOUND_SetPaused := GetAddress(FMODHandle, '_FSOUND_SetPaused@8'); + FSOUND_SetLoopMode := GetAddress(FMODHandle, '_FSOUND_SetLoopMode@8'); + FSOUND_SetCurrentPosition := GetAddress(FMODHandle, '_FSOUND_SetCurrentPosition@8'); + FSOUND_3D_SetAttributes := GetAddress(FMODHandle, '_FSOUND_3D_SetAttributes@12'); + FSOUND_3D_SetMinMaxDistance := GetAddress(FMODHandle, '_FSOUND_3D_SetMinMaxDistance@12'); + FSOUND_IsPlaying := GetAddress(FMODHandle, '_FSOUND_IsPlaying@4'); + FSOUND_GetFrequency := GetAddress(FMODHandle, '_FSOUND_GetFrequency@4'); + FSOUND_GetVolume := GetAddress(FMODHandle, '_FSOUND_GetVolume@4'); + FSOUND_GetAmplitude := GetAddress(FMODHandle, '_FSOUND_GetAmplitude@4'); + FSOUND_GetPan := GetAddress(FMODHandle, '_FSOUND_GetPan@4'); + FSOUND_GetSurround := GetAddress(FMODHandle, '_FSOUND_GetSurround@4'); + FSOUND_GetMute := GetAddress(FMODHandle, '_FSOUND_GetMute@4'); + FSOUND_GetPriority := GetAddress(FMODHandle, '_FSOUND_GetPriority@4'); + FSOUND_GetReserved := GetAddress(FMODHandle, '_FSOUND_GetReserved@4'); + FSOUND_GetPaused := GetAddress(FMODHandle, '_FSOUND_GetPaused@4'); + FSOUND_GetLoopMode := GetAddress(FMODHandle, '_FSOUND_GetLoopMode@4'); + FSOUND_GetCurrentPosition := GetAddress(FMODHandle, '_FSOUND_GetCurrentPosition@4'); + FSOUND_GetCurrentSample := GetAddress(FMODHandle, '_FSOUND_GetCurrentSample@4'); + FSOUND_GetCurrentLevels := GetAddress(FMODHandle, '_FSOUND_GetCurrentLevels@12'); + FSOUND_GetNumSubChannels := GetAddress(FMODHandle, '_FSOUND_GetNumSubChannels@4'); + FSOUND_GetSubChannel := GetAddress(FMODHandle, '_FSOUND_GetSubChannel@8'); + FSOUND_3D_GetAttributes := GetAddress(FMODHandle, '_FSOUND_3D_GetAttributes@12'); + FSOUND_3D_GetMinMaxDistance := GetAddress(FMODHandle, '_FSOUND_3D_GetMinMaxDistance@12'); + FSOUND_3D_Listener_SetCurrent := GetAddress(FMODHandle, '_FSOUND_3D_Listener_SetCurrent@8'); + FSOUND_3D_Listener_SetAttributes := GetAddress(FMODHandle, '_FSOUND_3D_Listener_SetAttributes@32'); + FSOUND_3D_Listener_GetAttributes := GetAddress(FMODHandle, '_FSOUND_3D_Listener_GetAttributes@32'); + FSOUND_3D_SetDopplerFactor := GetAddress(FMODHandle, '_FSOUND_3D_SetDopplerFactor@4'); + FSOUND_3D_SetDistanceFactor := GetAddress(FMODHandle, '_FSOUND_3D_SetDistanceFactor@4'); + FSOUND_3D_SetRolloffFactor := GetAddress(FMODHandle, '_FSOUND_3D_SetRolloffFactor@4'); + FSOUND_FX_Enable := GetAddress(FMODHandle, '_FSOUND_FX_Enable@8'); + FSOUND_FX_SetChorus := GetAddress(FMODHandle, '_FSOUND_FX_SetChorus@32'); + FSOUND_FX_SetCompressor := GetAddress(FMODHandle, '_FSOUND_FX_SetCompressor@28'); + FSOUND_FX_SetDistortion := GetAddress(FMODHandle, '_FSOUND_FX_SetDistortion@24'); + FSOUND_FX_SetEcho := GetAddress(FMODHandle, '_FSOUND_FX_SetEcho@24'); + FSOUND_FX_SetFlanger := GetAddress(FMODHandle, '_FSOUND_FX_SetFlanger@32'); + FSOUND_FX_SetGargle := GetAddress(FMODHandle, '_FSOUND_FX_SetGargle@12'); + FSOUND_FX_SetI3DL2Reverb := GetAddress(FMODHandle, '_FSOUND_FX_SetI3DL2Reverb@52'); + FSOUND_FX_SetParamEQ := GetAddress(FMODHandle, '_FSOUND_FX_SetParamEQ@16'); + FSOUND_FX_SetWavesReverb := GetAddress(FMODHandle, '_FSOUND_FX_SetWavesReverb@20'); + FSOUND_Stream_Open := GetAddress(FMODHandle, '_FSOUND_Stream_Open@16'); + FSOUND_Stream_Create := GetAddress(FMODHandle, '_FSOUND_Stream_Create@20'); + FSOUND_Stream_Close := GetAddress(FMODHandle, '_FSOUND_Stream_Close@4'); + FSOUND_Stream_Play := GetAddress(FMODHandle, '_FSOUND_Stream_Play@8'); + FSOUND_Stream_PlayEx := GetAddress(FMODHandle, '_FSOUND_Stream_PlayEx@16'); + FSOUND_Stream_Stop := GetAddress(FMODHandle, '_FSOUND_Stream_Stop@4'); + FSOUND_Stream_SetEndCallback := GetAddress(FMODHandle, '_FSOUND_Stream_SetEndCallback@12'); + FSOUND_Stream_SetSyncCallback := GetAddress(FMODHandle, '_FSOUND_Stream_SetSyncCallback@12'); + FSOUND_Stream_GetSample := GetAddress(FMODHandle, '_FSOUND_Stream_GetSample@4'); + FSOUND_Stream_CreateDSP := GetAddress(FMODHandle, '_FSOUND_Stream_CreateDSP@16'); + FSOUND_Stream_SetBufferSize := GetAddress(FMODHandle, '_FSOUND_Stream_SetBufferSize@4'); + FSOUND_Stream_SetPosition := GetAddress(FMODHandle, '_FSOUND_Stream_SetPosition@8'); + FSOUND_Stream_GetPosition := GetAddress(FMODHandle, '_FSOUND_Stream_GetPosition@4'); + FSOUND_Stream_SetTime := GetAddress(FMODHandle, '_FSOUND_Stream_SetTime@8'); + FSOUND_Stream_GetTime := GetAddress(FMODHandle, '_FSOUND_Stream_GetTime@4'); + FSOUND_Stream_GetLength := GetAddress(FMODHandle, '_FSOUND_Stream_GetLength@4'); + FSOUND_Stream_GetLengthMs := GetAddress(FMODHandle, '_FSOUND_Stream_GetLengthMs@4'); + FSOUND_Stream_SetMode := GetAddress(FMODHandle, '_FSOUND_Stream_SetMode@8'); + FSOUND_Stream_GetMode := GetAddress(FMODHandle, '_FSOUND_Stream_GetMode@4'); + FSOUND_Stream_SetLoopPoints := GetAddress(FMODHandle, '_FSOUND_Stream_SetLoopPoints@12'); + FSOUND_Stream_SetLoopCount := GetAddress(FMODHandle, '_FSOUND_Stream_SetLoopCount@8'); + FSOUND_Stream_GetOpenState := GetAddress(FMODHandle, '_FSOUND_Stream_GetOpenState@4'); + FSOUND_Stream_AddSyncPoint := GetAddress(FMODHandle, '_FSOUND_Stream_AddSyncPoint@12'); + FSOUND_Stream_DeleteSyncPoint := GetAddress(FMODHandle, '_FSOUND_Stream_DeleteSyncPoint@4'); + FSOUND_Stream_GetNumSyncPoints := GetAddress(FMODHandle, '_FSOUND_Stream_GetNumSyncPoints@4'); + FSOUND_Stream_GetSyncPoint := GetAddress(FMODHandle, '_FSOUND_Stream_GetSyncPoint@8'); + FSOUND_Stream_GetSyncPointInfo := GetAddress(FMODHandle, '_FSOUND_Stream_GetSyncPointInfo@8'); + FSOUND_Stream_SetSubStream := GetAddress(FMODHandle, '_FSOUND_Stream_SetSubStream@8'); + FSOUND_Stream_GetNumSubStreams := GetAddress(FMODHandle, '_FSOUND_Stream_GetNumSubStreams@4'); + FSOUND_Stream_SetSubStreamSentence := GetAddress(FMODHandle, '_FSOUND_Stream_SetSubStreamSentence@12'); + FSOUND_Stream_GetNumTagFields := GetAddress(FMODHandle, '_FSOUND_Stream_GetNumTagFields@8'); + FSOUND_Stream_GetTagField := GetAddress(FMODHandle, '_FSOUND_Stream_GetTagField@24'); + FSOUND_Stream_FindTagField := GetAddress(FMODHandle, '_FSOUND_Stream_FindTagField@20'); + FSOUND_Stream_Net_SetProxy := GetAddress(FMODHandle, '_FSOUND_Stream_Net_SetProxy@4'); + FSOUND_Stream_Net_GetLastServerStatus := GetAddress(FMODHandle, '_FSOUND_Stream_Net_GetLastServerStatus@0'); + FSOUND_Stream_Net_SetBufferProperties := GetAddress(FMODHandle, '_FSOUND_Stream_Net_SetBufferProperties@12'); + FSOUND_Stream_Net_GetBufferProperties := GetAddress(FMODHandle, '_FSOUND_Stream_Net_GetBufferProperties@12'); + FSOUND_Stream_Net_SetMetadataCallback := GetAddress(FMODHandle, '_FSOUND_Stream_Net_SetMetadataCallback@12'); + FSOUND_Stream_Net_GetStatus := GetAddress(FMODHandle, '_FSOUND_Stream_Net_GetStatus@20'); + FSOUND_CD_Play := GetAddress(FMODHandle, '_FSOUND_CD_Play@8'); + FSOUND_CD_SetPlayMode := GetAddress(FMODHandle, '_FSOUND_CD_SetPlayMode@8'); + FSOUND_CD_Stop := GetAddress(FMODHandle, '_FSOUND_CD_Stop@4'); + FSOUND_CD_SetPaused := GetAddress(FMODHandle, '_FSOUND_CD_SetPaused@8'); + FSOUND_CD_SetVolume := GetAddress(FMODHandle, '_FSOUND_CD_SetVolume@8'); + FSOUND_CD_SetTrackTime := GetAddress(FMODHandle, '_FSOUND_CD_SetTrackTime@8'); + FSOUND_CD_OpenTray := GetAddress(FMODHandle, '_FSOUND_CD_OpenTray@8'); + FSOUND_CD_GetPaused := GetAddress(FMODHandle, '_FSOUND_CD_GetPaused@4'); + FSOUND_CD_GetTrack := GetAddress(FMODHandle, '_FSOUND_CD_GetTrack@4'); + FSOUND_CD_GetNumTracks := GetAddress(FMODHandle, '_FSOUND_CD_GetNumTracks@4'); + FSOUND_CD_GetVolume := GetAddress(FMODHandle, '_FSOUND_CD_GetVolume@4'); + FSOUND_CD_GetTrackLength := GetAddress(FMODHandle, '_FSOUND_CD_GetTrackLength@8'); + FSOUND_CD_GetTrackTime := GetAddress(FMODHandle, '_FSOUND_CD_GetTrackTime@4'); + FSOUND_DSP_Create := GetAddress(FMODHandle, '_FSOUND_DSP_Create@12'); + FSOUND_DSP_Free := GetAddress(FMODHandle, '_FSOUND_DSP_Free@4'); + FSOUND_DSP_SetPriority := GetAddress(FMODHandle, '_FSOUND_DSP_SetPriority@8'); + FSOUND_DSP_GetPriority := GetAddress(FMODHandle, '_FSOUND_DSP_GetPriority@4'); + FSOUND_DSP_SetActive := GetAddress(FMODHandle, '_FSOUND_DSP_SetActive@8'); + FSOUND_DSP_GetActive := GetAddress(FMODHandle, '_FSOUND_DSP_GetActive@4'); + FSOUND_DSP_GetClearUnit := GetAddress(FMODHandle, '_FSOUND_DSP_GetClearUnit@0'); + FSOUND_DSP_GetSFXUnit := GetAddress(FMODHandle, '_FSOUND_DSP_GetSFXUnit@0'); + FSOUND_DSP_GetMusicUnit := GetAddress(FMODHandle, '_FSOUND_DSP_GetMusicUnit@0'); + FSOUND_DSP_GetClipAndCopyUnit := GetAddress(FMODHandle, '_FSOUND_DSP_GetClipAndCopyUnit@0'); + FSOUND_DSP_GetFFTUnit := GetAddress(FMODHandle, '_FSOUND_DSP_GetFFTUnit@0'); + FSOUND_DSP_MixBuffers := GetAddress(FMODHandle, '_FSOUND_DSP_MixBuffers@28'); + FSOUND_DSP_ClearMixBuffer := GetAddress(FMODHandle, '_FSOUND_DSP_ClearMixBuffer@0'); + FSOUND_DSP_GetBufferLength := GetAddress(FMODHandle, '_FSOUND_DSP_GetBufferLength@0'); + FSOUND_DSP_GetBufferLengthTotal := GetAddress(FMODHandle, '_FSOUND_DSP_GetBufferLengthTotal@0'); + FSOUND_DSP_GetSpectrum := GetAddress(FMODHandle, '_FSOUND_DSP_GetSpectrum@0'); + FSOUND_Reverb_SetProperties := GetAddress(FMODHandle, '_FSOUND_Reverb_SetProperties@4'); + FSOUND_Reverb_GetProperties := GetAddress(FMODHandle, '_FSOUND_Reverb_GetProperties@4'); + FSOUND_Reverb_SetChannelProperties := GetAddress(FMODHandle, '_FSOUND_Reverb_SetChannelProperties@8'); + FSOUND_Reverb_GetChannelProperties := GetAddress(FMODHandle, '_FSOUND_Reverb_GetChannelProperties@8'); + FSOUND_Record_SetDriver := GetAddress(FMODHandle, '_FSOUND_Record_SetDriver@4'); + FSOUND_Record_GetNumDrivers := GetAddress(FMODHandle, '_FSOUND_Record_GetNumDrivers@0'); + FSOUND_Record_GetDriverName := GetAddress(FMODHandle, '_FSOUND_Record_GetDriverName@4'); + FSOUND_Record_GetDriver := GetAddress(FMODHandle, '_FSOUND_Record_GetDriver@0'); + FSOUND_Record_StartSample := GetAddress(FMODHandle, '_FSOUND_Record_StartSample@8'); + FSOUND_Record_Stop := GetAddress(FMODHandle, '_FSOUND_Record_Stop@0'); + FSOUND_Record_GetPosition := GetAddress(FMODHandle, '_FSOUND_Record_GetPosition@0'); + FSOUND_File_SetCallbacks := GetAddress(FMODHandle, '_FSOUND_File_SetCallbacks@20'); + FMUSIC_LoadSong := GetAddress(FMODHandle, '_FMUSIC_LoadSong@4'); + FMUSIC_LoadSongEx := GetAddress(FMODHandle, '_FMUSIC_LoadSongEx@24'); + FMUSIC_GetOpenState := GetAddress(FMODHandle, '_FMUSIC_GetOpenState@4'); + FMUSIC_FreeSong := GetAddress(FMODHandle, '_FMUSIC_FreeSong@4'); + FMUSIC_PlaySong := GetAddress(FMODHandle, '_FMUSIC_PlaySong@4'); + FMUSIC_StopSong := GetAddress(FMODHandle, '_FMUSIC_StopSong@4'); + FMUSIC_StopAllSongs := GetAddress(FMODHandle, '_FMUSIC_StopAllSongs@0'); + FMUSIC_SetZxxCallback := GetAddress(FMODHandle, '_FMUSIC_SetZxxCallback@8'); + FMUSIC_SetRowCallback := GetAddress(FMODHandle, '_FMUSIC_SetRowCallback@12'); + FMUSIC_SetOrderCallback := GetAddress(FMODHandle, '_FMUSIC_SetOrderCallback@12'); + FMUSIC_SetInstCallback := GetAddress(FMODHandle, '_FMUSIC_SetInstCallback@12'); + FMUSIC_SetSample := GetAddress(FMODHandle, '_FMUSIC_SetSample@12'); + FMUSIC_SetUserData := GetAddress(FMODHandle, '_FMUSIC_SetUserData@8'); + FMUSIC_OptimizeChannels := GetAddress(FMODHandle, '_FMUSIC_OptimizeChannels@12'); + FMUSIC_SetReverb := GetAddress(FMODHandle, '_FMUSIC_SetReverb@4'); + FMUSIC_SetLooping := GetAddress(FMODHandle, '_FMUSIC_SetLooping@8'); + FMUSIC_SetOrder := GetAddress(FMODHandle, '_FMUSIC_SetOrder@8'); + FMUSIC_SetPaused := GetAddress(FMODHandle, '_FMUSIC_SetPaused@8'); + FMUSIC_SetMasterVolume := GetAddress(FMODHandle, '_FMUSIC_SetMasterVolume@8'); + FMUSIC_SetMasterSpeed := GetAddress(FMODHandle, '_FMUSIC_SetMasterSpeed@8'); + FMUSIC_SetPanSeperation := GetAddress(FMODHandle, '_FMUSIC_SetPanSeperation@8'); + FMUSIC_GetName := GetAddress(FMODHandle, '_FMUSIC_GetName@4'); + FMUSIC_GetType := GetAddress(FMODHandle, '_FMUSIC_GetType@4'); + FMUSIC_GetNumOrders := GetAddress(FMODHandle, '_FMUSIC_GetNumOrders@4'); + FMUSIC_GetNumPatterns := GetAddress(FMODHandle, '_FMUSIC_GetNumPatterns@4'); + FMUSIC_GetNumInstruments := GetAddress(FMODHandle, '_FMUSIC_GetNumInstruments@4'); + FMUSIC_GetNumSamples := GetAddress(FMODHandle, '_FMUSIC_GetNumSamples@4'); + FMUSIC_GetNumChannels := GetAddress(FMODHandle, '_FMUSIC_GetNumChannels@4'); + FMUSIC_GetSample := GetAddress(FMODHandle, '_FMUSIC_GetSample@8'); + FMUSIC_GetPatternLength := GetAddress(FMODHandle, '_FMUSIC_GetPatternLength@8'); + FMUSIC_IsFinished := GetAddress(FMODHandle, '_FMUSIC_IsFinished@4'); + FMUSIC_IsPlaying := GetAddress(FMODHandle, '_FMUSIC_IsPlaying@4'); + FMUSIC_GetMasterVolume := GetAddress(FMODHandle, '_FMUSIC_GetMasterVolume@4'); + FMUSIC_GetGlobalVolume := GetAddress(FMODHandle, '_FMUSIC_GetGlobalVolume@4'); + FMUSIC_GetOrder := GetAddress(FMODHandle, '_FMUSIC_GetOrder@4'); + FMUSIC_GetPattern := GetAddress(FMODHandle, '_FMUSIC_GetPattern@4'); + FMUSIC_GetSpeed := GetAddress(FMODHandle, '_FMUSIC_GetSpeed@4'); + FMUSIC_GetBPM := GetAddress(FMODHandle, '_FMUSIC_GetBPM@4'); + FMUSIC_GetRow := GetAddress(FMODHandle, '_FMUSIC_GetRow@4'); + FMUSIC_GetPaused := GetAddress(FMODHandle, '_FMUSIC_GetPaused@4'); + FMUSIC_GetTime := GetAddress(FMODHandle, '_FMUSIC_GetTime@4'); + FMUSIC_GetRealChannel := GetAddress(FMODHandle, '_FMUSIC_GetRealChannel@8'); + FMUSIC_GetUserData := GetAddress(FMODHandle, '_FMUSIC_GetUserData@4'); + + Result := True; +end; + +procedure FMOD_Unload; +begin + { Only free the library if it was already loaded } + if FMODHandle <> INVALID_MODULEHANDLE_VALUE then +{$IFDEF MSWINDOWS} + FreeLibrary(FMODHandle); +{$ELSE} + dlclose(FMODHandle); +{$ENDIF} + FMODHandle := INVALID_MODULEHANDLE_VALUE; +end; + +var + Saved8087CW: Word; + +{$ifdef FPC} //FPC do not have this function in its RTL +const + Default8087CW = $1332; //according to the FPC site it's the value used in the + //startup code. +procedure Set8087CW( value :word ); Assembler; +asm + FLDCW value +end; +{$endif} + +initialization + FMODHandle := INVALID_MODULEHANDLE_VALUE; + + { Save the current FPU state and then disable FPU exceptions } + Saved8087CW := Default8087CW; + Set8087CW($133f); { Disable all fpu exceptions } + +finalization + { Make sure the library is unloaded } + FMOD_Unload; + + { Reset the FPU to the previous state } + Set8087CW(Saved8087CW); +end. \ No newline at end of file diff --git a/fmodapi375win/api/delphi/fmoderrors.dcu b/fmodapi375win/api/delphi/fmoderrors.dcu new file mode 100644 index 0000000..3ac25d6 Binary files /dev/null and b/fmodapi375win/api/delphi/fmoderrors.dcu differ diff --git a/fmodapi375win/api/delphi/fmoderrors.pas b/fmodapi375win/api/delphi/fmoderrors.pas new file mode 100644 index 0000000..91f7352 --- /dev/null +++ b/fmodapi375win/api/delphi/fmoderrors.pas @@ -0,0 +1,67 @@ +{ =============================================================================================== } +{ FMOD Main header file. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004. } +{ =============================================================================================== } +{ + NOTE: For the demos to run you must have either fmod.dll (in Windows) + or libfmod-3.75.so (in Linux) installed. + + In Windows, copy the fmod.dll file found in the api directory to either of + the following locations (in order of preference) + - your application directory + - Windows\System (95/98) or WinNT\System32 (NT/2000/XP) + + In Linux, make sure you are signed in as root and copy the libfmod-3.75.so + file from the api directory to your /usr/lib/ directory. + Then via a command line, navigate to the /usr/lib/ directory and create + a symbolic link between libfmod-3.75.so and libfmod.so. This is done with + the following command (assuming you are in /usr/lib/)... + ln -s libfmod-3.75.so libfmod.so. +} +{ =============================================================================================== } + +unit fmoderrors; + +interface + +uses + fmodtypes; + +{ + Disable warning for unsafe types in Delphi 7 +} +{$IFDEF VER150} +{$WARN UNSAFE_TYPE OFF} +{$ENDIF} + +function FMOD_ErrorString(ErrorCode: TFModErrors): PChar; + +implementation + +function FMOD_ErrorString(ErrorCode: TFModErrors): PChar; +begin + case ErrorCode of + FMOD_ERR_NONE: Result := 'No errors'; + FMOD_ERR_BUSY: Result := 'Cannot call this command after FSOUND_Init. Call FSOUND_Close first'; + FMOD_ERR_UNINITIALIZED: Result := 'This command failed because FSOUND_Init was not called'; + FMOD_ERR_PLAY: Result := 'Playing the sound failed'; + FMOD_ERR_INIT: Result := 'Error initializing output device'; + FMOD_ERR_ALLOCATED: Result := 'The output device is already in use and cannot be reused'; + FMOD_ERR_OUTPUT_FORMAT: Result := 'Soundcard does not support the features needed for this soundsystem (16bit stereo output)'; + FMOD_ERR_COOPERATIVELEVEL: Result := 'Error setting cooperative level for hardware'; + FMOD_ERR_CREATEBUFFER: Result := 'Error creating hardware sound buffer'; + FMOD_ERR_FILE_NOTFOUND: Result := 'File not found'; + FMOD_ERR_FILE_FORMAT: Result := 'Unknown file format'; + FMOD_ERR_FILE_BAD: Result := 'Error loading file'; + FMOD_ERR_MEMORY: Result := 'Not enough memory or resources'; + FMOD_ERR_VERSION: Result := 'The version number of this file format is not supported'; + FMOD_ERR_INVALID_PARAM: Result := 'An invalid parameter was passed to this function'; + FMOD_ERR_NO_EAX: Result := 'Tried to use an EAX command on a non EAX enabled channel or output'; + FMOD_ERR_CHANNEL_ALLOC: Result := 'Failed to allocate a new channel'; + FMOD_ERR_RECORD: Result := 'Recording is not supported on this machine'; + FMOD_ERR_MEDIAPLAYER: Result := 'Required Mediaplayer codec is not installed'; + else + Result := 'Unknown error'; + end; +end; + +end. diff --git a/fmodapi375win/api/delphi/fmodpresets.pas b/fmodapi375win/api/delphi/fmodpresets.pas new file mode 100644 index 0000000..0120458 --- /dev/null +++ b/fmodapi375win/api/delphi/fmodpresets.pas @@ -0,0 +1,95 @@ +{ =============================================================================================== } +{ FMOD presets header file. Copyright (c), FireLight Technologies Pty, Ltd. 1999-2004. } +{ =============================================================================================== } +{ + NOTE: For the demos to run you must have either fmod.dll (in Windows) + or libfmod-3.75.so (in Linux) installed. + + In Windows, copy the fmod.dll file found in the api directory to either of + the following locations (in order of preference) + - your application directory + - Windows\System (95/98) or WinNT\System32 (NT/2000/XP) + + In Linux, make sure you are signed in as root and copy the libfmod-3.75.so + file from the api directory to your /usr/lib/ directory. + Then via a command line, navigate to the /usr/lib/ directory and create + a symbolic link between libfmod-3.5.so and libfmod.so. This is done with + the following command (assuming you are in /usr/lib/)... + ln -s libfmod-3.75.so libfmod.so. +} + +unit fmodpresets; + +interface + +uses + fmodtypes; + +{$IFDEF VER140} +{$DEFINE COMPILER6_UP} +{$ELSE} + {$IFDEF VER150} + {$DEFINE COMPILER6_UP} + {$ENDIF} +{$ENDIF} + +(* +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS, created by Creative Labs + These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically. + ie + FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC; + + [SEE_ALSO] + FSOUND_Reverb_SetProperties +] +*) + +{$IFDEF COMPILER6_UP}{$J+}{$ENDIF} +const + FSOUND_PRESET_OFF: TFSoundReverbProperties = (Environment: 0; EnvSize: 7.5; EnvDiffusion: 1.00; Room: -10000; RoomHF: -10000; RoomLF: 0; DecayTime: 1.00; DecayHFRatio: 1.00; DecayLFRatio: 1.0; Reflections: -2602; ReflectionsDelay: 0.007; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 200; ReverbDelay: 0.011; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 0.0; Density: 0.0; Flags: $33f); + FSOUND_PRESET_GENERIC: TFSoundReverbProperties = (Environment: 0; EnvSize: 7.5; EnvDiffusion: 1.00; Room: -1000; RoomHF: -100; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.83; DecayLFRatio: 1.0; Reflections: -2602; ReflectionsDelay: 0.007; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 200; ReverbDelay: 0.011; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_PADDEDCELL: TFSoundReverbProperties = (Environment: 1; EnvSize: 1.4; EnvDiffusion: 1.00; Room: -1000; RoomHF: -6000; RoomLF: 0; DecayTime: 0.17; DecayHFRatio: 0.10; DecayLFRatio: 1.0; Reflections: -1204; ReflectionsDelay: 0.001; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 207; ReverbDelay: 0.002; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_ROOM: TFSoundReverbProperties = (Environment: 2; EnvSize: 1.9; EnvDiffusion: 1.00; Room: -1000; RoomHF: -454; RoomLF: 0; DecayTime: 0.40; DecayHFRatio: 0.83; DecayLFRatio: 1.0; Reflections: -1646; ReflectionsDelay: 0.002; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 53; ReverbDelay: 0.003; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_BATHROOM: TFSoundReverbProperties = (Environment: 3; EnvSize: 1.4; EnvDiffusion: 1.00; Room: -1000; RoomHF: -1200; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.54; DecayLFRatio: 1.0; Reflections: -370; ReflectionsDelay: 0.007; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 1030; ReverbDelay: 0.011; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 60.0; Flags: $3f); + FSOUND_PRESET_LIVINGROOM: TFSoundReverbProperties = (Environment: 4; EnvSize: 2.5; EnvDiffusion: 1.00; Room: -1000; RoomHF: -6000; RoomLF: 0; DecayTime: 0.50; DecayHFRatio: 0.10; DecayLFRatio: 1.0; Reflections: -1376; ReflectionsDelay: 0.003; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-1104; ReverbDelay: 0.004; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_STONEROOM: TFSoundReverbProperties = (Environment: 5; EnvSize: 11.6; EnvDiffusion: 1.00; Room: -1000; RoomHF: -300; RoomLF: 0; DecayTime: 2.31; DecayHFRatio: 0.64; DecayLFRatio: 1.0; Reflections: -711; ReflectionsDelay: 0.012; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 83; ReverbDelay: 0.017; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_AUDITORIUM: TFSoundReverbProperties = (Environment: 6; EnvSize: 21.6; EnvDiffusion: 1.00; Room: -1000; RoomHF: -476; RoomLF: 0; DecayTime: 4.32; DecayHFRatio: 0.59; DecayLFRatio: 1.0; Reflections: -789; ReflectionsDelay: 0.020; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-289; ReverbDelay: 0.030; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_CONCERTHALL: TFSoundReverbProperties = (Environment: 7; EnvSize: 19.6; EnvDiffusion: 1.00; Room: -1000; RoomHF: -500; RoomLF: 0; DecayTime: 3.92; DecayHFRatio: 0.70; DecayLFRatio: 1.0; Reflections: -1230; ReflectionsDelay: 0.020; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-2; ReverbDelay: 0.029; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_CAVE: TFSoundReverbProperties = (Environment: 8; EnvSize: 14.6; EnvDiffusion: 1.00; Room: -1000; RoomHF: 0; RoomLF: 0; DecayTime: 2.91; DecayHFRatio: 1.30; DecayLFRatio: 1.0; Reflections: -602; ReflectionsDelay: 0.015; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-302; ReverbDelay: 0.022; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $1f); + FSOUND_PRESET_ARENA: TFSoundReverbProperties = (Environment: 9; EnvSize: 36.2; EnvDiffusion: 1.00; Room: -1000; RoomHF: -698; RoomLF: 0; DecayTime: 7.24; DecayHFRatio: 0.33; DecayLFRatio: 1.0; Reflections: -1166; ReflectionsDelay: 0.020; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 16; ReverbDelay: 0.030; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_HANGAR: TFSoundReverbProperties = (Environment: 10; EnvSize: 50.3; EnvDiffusion: 1.00; Room: -1000; RoomHF: -1000; RoomLF: 0; DecayTime: 10.05; DecayHFRatio: 0.23; DecayLFRatio: 1.0; Reflections: -602; ReflectionsDelay: 0.020; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 198; ReverbDelay: 0.030; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_CARPETTEDHALLWAY: TFSoundReverbProperties = (Environment: 11; EnvSize: 1.9; EnvDiffusion: 1.00; Room: -1000; RoomHF: -4000; RoomLF: 0; DecayTime: 0.30; DecayHFRatio: 0.10; DecayLFRatio: 1.0; Reflections: -1831; ReflectionsDelay: 0.002; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-1630; ReverbDelay: 0.030; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_HALLWAY: TFSoundReverbProperties = (Environment: 12; EnvSize: 1.8; EnvDiffusion: 1.00; Room: -1000; RoomHF: -300; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.59; DecayLFRatio: 1.0; Reflections: -1219; ReflectionsDelay: 0.007; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 441; ReverbDelay: 0.011; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_STONECORRIDOR: TFSoundReverbProperties = (Environment: 13; EnvSize: 13.5; EnvDiffusion: 1.00; Room: -1000; RoomHF: -237; RoomLF: 0; DecayTime: 2.70; DecayHFRatio: 0.79; DecayLFRatio: 1.0; Reflections: -1214; ReflectionsDelay: 0.013; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 395; ReverbDelay: 0.020; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_ALLEY: TFSoundReverbProperties = (Environment: 14; EnvSize: 7.5; EnvDiffusion: 0.30; Room: -1000; RoomHF: -270; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.86; DecayLFRatio: 1.0; Reflections: -1204; ReflectionsDelay: 0.007; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-4; ReverbDelay: 0.011; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.125; EchoDepth: 0.95; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_FOREST: TFSoundReverbProperties = (Environment: 15; EnvSize: 38.0; EnvDiffusion: 0.30; Room: -1000; RoomHF: -3300; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.54; DecayLFRatio: 1.0; Reflections: -2560; ReflectionsDelay: 0.162; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-229; ReverbDelay: 0.088; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.125; EchoDepth: 1.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 79.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_CITY: TFSoundReverbProperties = (Environment: 16; EnvSize: 7.5; EnvDiffusion: 0.50; Room: -1000; RoomHF: -800; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.67; DecayLFRatio: 1.0; Reflections: -2273; ReflectionsDelay: 0.007; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-1691; ReverbDelay: 0.011; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 50.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_MOUNTAINS: TFSoundReverbProperties = (Environment: 17; EnvSize: 100.0; EnvDiffusion: 0.27; Room: -1000; RoomHF: -2500; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.21; DecayLFRatio: 1.0; Reflections: -2780; ReflectionsDelay: 0.300; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-1434; ReverbDelay: 0.100; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 1.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 27.0; Density: 100.0; Flags: $1f); + FSOUND_PRESET_QUARRY: TFSoundReverbProperties = (Environment: 18; EnvSize: 17.5; EnvDiffusion: 1.00; Room: -1000; RoomHF: -1000; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.83; DecayLFRatio: 1.0; Reflections: -10000;ReflectionsDelay: 0.061; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 500; ReverbDelay: 0.025; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.125; EchoDepth: 0.70; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_PLAIN: TFSoundReverbProperties = (Environment: 19; EnvSize: 42.5; EnvDiffusion: 0.21; Room: -1000; RoomHF: -2000; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.50; DecayLFRatio: 1.0; Reflections: -2466; ReflectionsDelay: 0.179; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-1926; ReverbDelay: 0.100; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 1.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 21.0; Density: 100.0; Flags: $3f); + FSOUND_PRESET_PARKINGLOT: TFSoundReverbProperties = (Environment: 20; EnvSize: 8.3; EnvDiffusion: 1.00; Room: -1000; RoomHF: 0; RoomLF: 0; DecayTime: 1.65; DecayHFRatio: 1.50; DecayLFRatio: 1.0; Reflections: -1363; ReflectionsDelay: 0.008; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-1153; ReverbDelay: 0.012; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $1f); + FSOUND_PRESET_SEWERPIPE: TFSoundReverbProperties = (Environment: 21; EnvSize: 1.7; EnvDiffusion: 0.80; Room: -1000; RoomHF: -1000; RoomLF: 0; DecayTime: 2.81; DecayHFRatio: 0.14; DecayLFRatio: 1.0; Reflections: 429; ReflectionsDelay: 0.014; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 1023; ReverbDelay: 0.021; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 0.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 80.0; Density: 60.0; Flags: $3f); + FSOUND_PRESET_UNDERWATER: TFSoundReverbProperties = (Environment: 22; EnvSize: 1.8; EnvDiffusion: 1.00; Room: -1000; RoomHF: -4000; RoomLF: 0; DecayTime: 1.49; DecayHFRatio: 0.10; DecayLFRatio: 1.0; Reflections: -449; ReflectionsDelay: 0.007; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 1700; ReverbDelay: 0.011; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 1.18; ModulationDepth: 0.348; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $3f); + +(* Non I3DL2 presets *) + + FSOUND_PRESET_DRUGGED: TFSoundReverbProperties = (Environment: 23; EnvSize: 1.9; EnvDiffusion: 0.50; Room: -1000; RoomHF: 0; RoomLF: 0; DecayTime: 8.39; DecayHFRatio: 1.39; DecayLFRatio: 1.0; Reflections: -115; ReflectionsDelay: 0.002; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 985; ReverbDelay: 0.030; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 0.25; ModulationDepth: 1.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $1f); + FSOUND_PRESET_DIZZY: TFSoundReverbProperties = (Environment: 24; EnvSize: 1.8; EnvDiffusion: 0.60; Room: -1000; RoomHF: -400; RoomLF: 0; DecayTime: 17.23; DecayHFRatio: 0.56; DecayLFRatio: 1.0; Reflections: -1713; ReflectionsDelay: 0.020; ReflectionsPan: (0.0, 0.0, 0.0); Reverb:-613; ReverbDelay: 0.030; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 1.00; ModulationTime: 0.81; ModulationDepth: 0.310; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $1f); + FSOUND_PRESET_PSYCHOTIC: TFSoundReverbProperties = (Environment: 25; EnvSize: 1.0; EnvDiffusion: 0.50; Room: -1000; RoomHF: -151; RoomLF: 0; DecayTime: 7.56; DecayHFRatio: 0.91; DecayLFRatio: 1.0; Reflections: -626; ReflectionsDelay: 0.020; ReflectionsPan: (0.0, 0.0, 0.0); Reverb: 774; ReverbDelay: 0.030; ReverbPan: (0.0, 0.0, 0.0); EchoTime: 0.250; EchoDepth: 0.00; ModulationTime: 4.00; ModulationDepth: 1.000; AirAbsorptionHF: -5.0; HFReference: 5000.0; LFReference: 250.0; RoomRolloffFactor: 0.0; Diffusion: 100.0; Density: 100.0; Flags: $1f); + +(* PlayStation 2 Only presets *) +(* Delphi/Kylix cannot create PlayStation 2 executables, so there is no need to + convert the PlayStation 2 presets. *) +{$IFDEF COMPILER6_UP}{$J-}{$ENDIF} + +(* [DEFINE_END] *) + +implementation + +end. diff --git a/fmodapi375win/api/delphi/fmodtypes.dcu b/fmodapi375win/api/delphi/fmodtypes.dcu new file mode 100644 index 0000000..3af0e6a Binary files /dev/null and b/fmodapi375win/api/delphi/fmodtypes.dcu differ diff --git a/fmodapi375win/api/delphi/fmodtypes.pas b/fmodapi375win/api/delphi/fmodtypes.pas new file mode 100644 index 0000000..9a9c015 --- /dev/null +++ b/fmodapi375win/api/delphi/fmodtypes.pas @@ -0,0 +1,821 @@ +{================================================================================================ } +{ FMOD Types header file. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004. } +{ =============================================================================================== } +{ + NOTE: For the demos to run you must have either fmod.dll (in Windows) + or libfmod-3.75.so (in Linux) installed. + + In Windows, copy the fmod.dll file found in the api directory to either of + the following locations (in order of preference) + - your application directory + - Windows\System (95/98) or WinNT\System32 (NT/2000/XP) + + In Linux, make sure you are signed in as root and copy the libfmod-3.75.so + file from the api directory to your /usr/lib/ directory. + Then via a command line, navigate to the /usr/lib/ directory and create + a symbolic link between libfmod-3.75.so and libfmod.so. This is done with + the following command (assuming you are in /usr/lib/)... + ln -s libfmod-3.75.so libfmod.so. +} +{ =============================================================================================== } + +unit fmodtypes; + +{$IFDEF FPC} + {$MODE DELPHI} + {$IFDEF WIN32} + {$DEFINE MSWINDOWS} + {$ENDIF} + {$PACKRECORDS C} +{$ENDIF} + +{$IFDEF VER110} + {$DEFINE DELPHI_5_OR_LOWER} +{$ELSE} + {$IFDEF VER120} + {$DEFINE DELPHI_5_OR_LOWER} + {$ELSE} + {$IFDEF VER130} + {$DEFINE DELPHI_5_OR_LOWER} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +interface + +{$IFDEF MSWINDOWS} +uses + Windows; +{$ENDIF} + +{ =============================================================================================== } +{ DEFINITIONS } +{ =============================================================================================== } + +{ + Force four-byte enums +} +{$Z4} + +{ + Disable warning for unsafe types in Delphi 7 +} +{$IFDEF VER150} +{$WARN UNSAFE_TYPE OFF} +{$ENDIF} + +{$IFDEF DELPHI_5_OR_LOWER} +type + PSingle = ^Single; + THandle = Cardinal; +{$ENDIF} + +const + FMOD_VERSION: Single = 3.75; + +{ + FMOD defined types +} + +type + PFSoundSample = Pointer; + PFSoundStream = Pointer; + PFSoundDSPUnit = Pointer; + PFMusicModule = Pointer; + PFSyncPoint = Pointer; + + PFSoundVector = ^TFSoundVector; + TFSoundVector = record + x: Single; + y: Single; + z: Single; + end; + + { + Callback types + } + + TFSoundStreamCallback = function (Stream: PFSoundStream; Buff: Pointer; Length, Param: Integer): ByteBool; stdcall; + TFSoundDSPCallback = function (OriginalBuffer: Pointer; NewBuffer: Pointer; Length, Param: Integer): Pointer; stdcall; + TFMusicCallback = procedure (Module: PFMusicModule; Param: Byte); stdcall; + + TFSoundOpenCallback = function (Name: PChar): Cardinal; stdcall; + TFSoundCloseCallback = procedure (Handle: Cardinal); stdcall; + TFSoundReadCallback = function (Buffer: Pointer; Size: Cardinal; Handle: Cardinal): Cardinal; stdcall; + TFSoundSeekCallback = procedure (Handle: Cardinal; Pos: Cardinal; Mode: Byte); stdcall; + TFSoundTellCallback = function (Handle: Cardinal): Cardinal; stdcall; + + TFSoundAllocCallback = function(Size: Cardinal): Pointer; stdcall; + TFSoundReallocCallback = function(Ptr: Pointer; Size: Cardinal): Pointer; stdcall; + TFSoundFreeCallback = procedure(Ptr: Pointer); stdcall; + + TFMetaDataCallback = function(Name: PChar; Value: PChar; userdata: Integer): ByteBool; stdcall; + +{ +[ENUM] +[ + [DESCRIPTION] + On failure of commands in FMOD, use FSOUND_GetError to attain what happened. + + [SEE_ALSO] + FSOUND_GetError +] +} + +type + TFModErrors = ( + FMOD_ERR_NONE, // No errors + FMOD_ERR_BUSY, // Cannot call this command after FSOUND_Init. Call FSOUND_Close first. + FMOD_ERR_UNINITIALIZED, // This command failed because FSOUND_Init was not called + FMOD_ERR_INIT, // Error initializing output device. + FMOD_ERR_ALLOCATED, // Error initializing output device, but more specifically, the output device is already in use and cannot be reused. + FMOD_ERR_PLAY, // Playing the sound failed. + FMOD_ERR_OUTPUT_FORMAT, // Soundcard does not support the features needed for this soundsystem (16bit stereo output) + FMOD_ERR_COOPERATIVELEVEL, // Error setting cooperative level for hardware. + FMOD_ERR_CREATEBUFFER, // Error creating hardware sound buffer. + FMOD_ERR_FILE_NOTFOUND, // File not found + FMOD_ERR_FILE_FORMAT, // Unknown file format + FMOD_ERR_FILE_BAD, // Error loading file + FMOD_ERR_MEMORY, // Not enough memory or resources + FMOD_ERR_VERSION, // The version number of this file format is not supported + FMOD_ERR_INVALID_PARAM, // An invalid parameter was passed to this function + FMOD_ERR_NO_EAX, // Tried to use an EAX command on a non EAX enabled channel or output. + FMOD_ERR_CHANNEL_ALLOC, // Failed to allocate a new channel + FMOD_ERR_RECORD, // Recording is not supported on this machine + FMOD_ERR_MEDIAPLAYER, // Windows Media Player not installed so cannot play wma or use internet streaming. */ + FMOD_ERR_CDDEVICE // An error occured trying to open the specified CD device + ); + +{ +[ENUM] +[ + [DESCRIPTION] + These output types are used with FSOUND_SetOutput, to choose which output driver to use. + + FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver + does not support DirectX 6 Voice Manager Extensions. + + FSOUND_OUTPUT_WINMM is recommended for NT and CE. + + [SEE_ALSO] + FSOUND_SetOutput + FSOUND_GetOutput +] +} + +type + TFSoundOutputTypes = ( + FSOUND_OUTPUT_NOSOUND, // NoSound driver, all calls to this succeed but do nothing. + FSOUND_OUTPUT_WINMM, // Windows Multimedia driver. + FSOUND_OUTPUT_DSOUND, // DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. + FSOUND_OUTPUT_A3D, // A3D driver. + + FSOUND_OUTPUT_OSS, // Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. + FSOUND_OUTPUT_ESD, // Linux/Unix ESD (Enlightment Sound Daemon) driver. + FSOUND_OUTPUT_ALSA, // Linux Alsa driver. + + FSOUND_OUTPUT_ASIO, // Low latency ASIO driver. + FSOUND_OUTPUT_XBOX, // Xbox driver. + FSOUND_OUTPUT_PS2, // PlayStation 2 driver. + FSOUND_OUTPUT_MAC, // Mac SoundMager driver. + FSOUND_OUTPUT_GC, // Gamecube driver. + FSOUND_OUTPUT_PSP, // PlayStation Portable driver. + + FSOUND_OUTPUT_NOSOUND_NONREALTIME // This is the same as nosound, but the sound generation is driven by FSOUND_Update + ); + + +{ +[ENUM] +[ + [DESCRIPTION] + These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act + upon for other reasons using FSOUND_GetMixer. + It is not necessary to set the mixer. FMOD will autodetect the best mixer for you. + + [SEE_ALSO] + FSOUND_SetMixer + FSOUND_GetMixer +] +} +type + TFSoundMixerTypes = ( + FSOUND_MIXER_AUTODETECT, // CE/PS2/GC Only - Non interpolating/low quality mixer. + FSOUND_MIXER_BLENDMODE, // Removed / obsolete + FSOUND_MIXER_MMXP5, // Removed / obsolete + FSOUND_MIXER_MMXP6, // Removed / obsolete + + FSOUND_MIXER_QUALITY_AUTODETECT,// All platforms - Autodetect the fastest quality mixer based on your cpu. + FSOUND_MIXER_QUALITY_FPU, // Win32/Linux only - Interpolating/volume ramping FPU mixer. + FSOUND_MIXER_QUALITY_MMXP5, // Win32/Linux only - Interpolating/volume ramping P5 MMX mixer. + FSOUND_MIXER_QUALITY_MMXP6, // Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. + + FSOUND_MIXER_MONO, // CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed + FSOUND_MIXER_QUALITY_MONO, // CE/PS2/GC only - MONO Interpolating mixer. For speed + + FSOUND_MIXER_MAX + ); + + +{ +[ENUM] +[ + [DESCRIPTION] + These definitions describe the type of song being played. + + [SEE_ALSO] + FMUSIC_GetType +] +} +type + TFMusicTypes = ( + FMUSIC_TYPE_NONE, + FMUSIC_TYPE_MOD, // Protracker / FastTracker + FMUSIC_TYPE_S3M, // ScreamTracker 3 + FMUSIC_TYPE_XM, // FastTracker 2 + FMUSIC_TYPE_IT, // Impulse Tracker + FMUSIC_TYPE_MIDI, // MIDI file + FMUSIC_TYPE_FSB // FMOD Sample Bank file + ); + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_DSP_PRIORITIES + + [DESCRIPTION] + These default priorities are used by FMOD internal system DSP units. They describe the + position of the DSP chain, and the order of how audio processing is executed. + You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP + unit), disable or even change the priority of a DSP unit. + + [SEE_ALSO] + FSOUND_DSP_Create + FSOUND_DSP_SetPriority + FSOUND_DSP_GetSpectrum +] +} +const + FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT = 0; // DSP CLEAR unit - done first + FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT = 100; // DSP SFX unit - done second + FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT = 200; // DSP MUSIC unit - done third + FSOUND_DSP_DEFAULTPRIORITY_USER = 300; // User priority, use this as reference for your own DSP units + FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT = 900; // This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units + FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT = 1000; // DSP CLIP AND COPY unit - last +// [DEFINE_END] + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_CAPS + + [DESCRIPTION] + Driver description bitfields. Use FSOUND_Driver_GetCaps to determine if a driver enumerated + has the settings you are after. The enumerated driver depends on the output mode, see + FSOUND_OUTPUTTYPES + + [SEE_ALSO] + FSOUND_GetDriverCaps + FSOUND_OUTPUTTYPES +] +} +const + FSOUND_CAPS_HARDWARE = $1; // This driver supports hardware accelerated 3d sound. + FSOUND_CAPS_EAX2 = $2; // This driver supports EAX 2 reverb + FSOUND_CAPS_EAX3 = $10; // This driver supports EAX 3 reverb +// [DEFINE_END] + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_MODES + + [DESCRIPTION] + Sample description bitfields, OR them together for loading and describing samples. + NOTE. If the file format being loaded already has a defined format, such as WAV or MP3, then + trying to override the pre-defined format with a new set of format flags will not work. For + example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS. It will just + ignore the flag and go ahead loading it as 8bits. For these type of formats the only flags + you can specify that will really alter the behaviour of how it is loaded, are the following. + + Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI + Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D + Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO + Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX + PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP + + See flag descriptions for what these do. +] +} +const + FSOUND_LOOP_OFF = $00000001; // For non looping samples. + FSOUND_LOOP_NORMAL = $00000002; // For forward looping samples. + FSOUND_LOOP_BIDI = $00000004; // For bidirectional looping samples. (no effect if in hardware). + FSOUND_8BITS = $00000008; // For 8 bit samples. + FSOUND_16BITS = $00000010; // For 16 bit samples. + FSOUND_MONO = $00000020; // For mono samples. + FSOUND_STEREO = $00000040; // For stereo samples. + FSOUND_UNSIGNED = $00000080; // For user created source data containing unsigned samples. + FSOUND_SIGNED = $00000100; // For user created source data containing signed data. + FSOUND_DELTA = $00000200; // For user created source data stored as delta values. + FSOUND_IT214 = $00000400; // For user created source data stored using IT214 compression. + FSOUND_IT215 = $00000800; // For user created source data stored using IT215 compression. + FSOUND_HW3D = $00001000; // Attempts to make samples use 3d hardware acceleration. (if the card supports it) + FSOUND_2D = $00002000; // Ignores any 3d processing. Overrides FSOUND_HW3D. Located in software. + FSOUND_STREAMABLE = $00004000; // For a streamimg sound where you feed the data to it. */ + FSOUND_LOADMEMORY = $00008000; // "name" will be interpreted as a pointer to data for streaming and samples. + FSOUND_LOADRAW = $00010000; // Will ignore file format and treat as raw pcm. + FSOUND_MPEGACCURATE = $00020000; // For FSOUND_Stream_OpenFile - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_OpenFile for inital opening time performance issues. + FSOUND_FORCEMONO = $00040000; // For forcing stereo streams and samples to be mono - needed if using FSOUND_HW3D and stereo data - incurs a small speed hit for streams + FSOUND_HW2D = $00080000; // 2D hardware sounds. allows hardware specific effects + FSOUND_ENABLEFX = $00100000; // Allows DX8 FX to be played back on a sound. Requires DirectX 8 - Note these sounds cannot be played more than once, be 8 bit, be less than a certain size, or have a changing frequency + FSOUND_MPEGHALFRATE = $00200000; // For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution + FSOUND_XADPCM = $00400000; // For XBOX only - Contents are compressed as XADPCM */ + FSOUND_VAG = $00800000; // For PS2 only - Contents are compressed as Sony VAG format */ + FSOUND_NONBLOCKING = $01000000; // For FSOUND_Stream_OpenFile - Causes stream to open in the background and not block the foreground app - stream plays only when ready. + FSOUND_GCADPCM = $02000000; // For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format + FSOUND_MULTICHANNEL = $04000000; // For PS2 only - Contents are interleaved into a multi-channel (more than stereo) format + FSOUND_USECORE0 = $08000000; // For PS2 only - Sample/Stream is forced to use hardware voices 00-23 + FSOUND_USECORE1 = $10000000; // For PS2 only - Sample/Stream is forced to use hardware voices 24-47 + FSOUND_LOADMEMORYIOP = $20000000; // For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address + +const + FSOUND_NORMAL = (FSOUND_16BITS or FSOUND_SIGNED or FSOUND_MONO); +// [DEFINE_END] + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_CDPLAYMODES + + [DESCRIPTION] + Playback method for a CD Audio track, using FSOUND_CD_SetPlayMode + + [SEE_ALSO] + FSOUND_CD_SetPlayMode + FSOUND_CD_Play +] +} +const + FSOUND_CD_PLAYCONTINUOUS = 0; // Starts from the current track and plays to end of CD. + FSOUND_CD_PLAYONCE = 1; // Plays the specified track then stops. + FSOUND_CD_PLAYLOOPED = 2; // Plays the specified track looped, forever until stopped manually. + FSOUND_CD_PLAYRANDOM = 3; // Plays tracks in random order +// [DEFINE_END] + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_CHANNELSAMPLEMODE + + [DESCRIPTION] + Miscellaneous values for FMOD functions. + + [SEE_ALSO] + FSOUND_PlaySound + FSOUND_PlaySoundEx + FSOUND_Sample_Alloc + FSOUND_Sample_Load + FSOUND_SetPan +] +} +const + FSOUND_FREE = -1; // value to play on any free channel, or to allocate a sample in a free sample slot. + FSOUND_UNMANAGED = -2; // value to allocate a sample that is NOT managed by FSOUND or placed in a sample slot. + FSOUND_ALL = -3; // for a channel index , this flag will affect ALL channels available! Not supported by every function. + FSOUND_STEREOPAN = -1; // value for FSOUND_SetPan so that stereo sounds are not played at half volume. See FSOUND_SetPan for more on this. + FSOUND_SYSTEMCHANNEL = -1000; // special 'channel' ID for all channel based functions that want to alter the global FSOUND software mixing output + FSOUND_SYSTEMSAMPLE = -1000; // special 'sample' ID for all sample based functions that want to alter the global FSOUND software mixing output sample +// [DEFINE_END] + + +{ +[STRUCT_START] +[ + [NAME] + FSOUND_REVERB_PROPERTIES + + [DESCRIPTION] + Structure defining a reverb environment. + + [REMARKS] + For more indepth descriptions of the reverb properties under win32, please see the EAX2/EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). + Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then + the reverb should product a similar effect on either platform. + Only WIN32 supports the reverb api. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [SEE_ALSO] + FSOUND_Reverb_SetProperties + FSOUND_Reverb_GetProperties + FSOUND_REVERB_PRESETS + FSOUND_REVERB_FLAGS +] +} +type + TFSoundReverbProperties = record // MIN MAX DEFAULT DESCRIPTION + Environment: Cardinal; // 0 25 0 sets all listener properties (win32 only) + EnvSize: Single; // 1.0 100.0 7.5 environment size in meters (win32 only) + EnvDiffusion: Single; // 0.0 1.0 1.0 environment diffusion (win32/xbox) + Room: Integer; // -10000 0 -1000 room effect level (at mid frequencies) (win32/xbox) + RoomHF: Integer; // -10000 0 -100 relative room effect level at high frequencies (win32/xbox) + RoomLF: Integer; // -10000 0 0 relative room effect level at low frequencies (win32 only) + DecayTime: Single; // 0.1 20.0 1.49 reverberation decay time at mid frequencies (win32/xbox) + DecayHFRatio: Single; // 0.1 2.0 0.83 high-frequency to mid-frequency decay time ratio (win32/xbox) + DecayLFRatio: Single; // 0.1 2.0 1.0 low-frequency to mid-frequency decay time ratio (win32 only) + Reflections: Integer; // -10000 1000 -2602 early reflections level relative to room effect (win32/xbox) + ReflectionsDelay: Single; // 0.0 0.3 0.007 initial reflection delay time (win32/xbox) + ReflectionsPan: array [0..2] of Single; // 0,0,0 early reflections panning vector (win32 only) + Reverb: Integer; // -10000 2000 200 late reverberation level relative to room effect (win32/xbox) + ReverbDelay: Single; // 0.0 0.1 0.011 late reverberation delay time relative to initial reflection (win32/xbox) + ReverbPan: array [0..2] of Single; // 0,0,0 late reverberation panning vector (win32 only) + EchoTime: Single; // .075 0.25 0.25 echo time (win32 only) + EchoDepth: Single; // 0.0 1.0 0.0 echo depth (win32 only) + ModulationTime: Single; // 0.04 4.0 0.25 modulation time (win32 only) + ModulationDepth: Single; // 0.0 1.0 0.0 modulation depth (win32 only) + AirAbsorptionHF: Single; // -100 0.0 -5.0 change in level per meter at high frequencies (win32 only) + HFReference: Single; // 1000.0 20000 5000.0 reference high frequency (hz) (win32/xbox) + LFReference: Single; // 20.0 1000.0 250.0 reference low frequency (hz) (win32 only) + RoomRolloffFactor: Single; // 0.0 10.0 0.0 like FSOUND_3D_SetRolloffFactor but for room effect (win32/xbox) + Diffusion: Single; // 0.0 100.0 100.0 Value that controls the echo density in the late reverberation decay. (xbox only) + Density: Single; // 0.0 100.0 100.0 Value that controls the modal density in the late reverberation decay (xbox only) + Flags: Cardinal; // FSOUND_REVERB_PROPERTYFLAGS - modifies the behavior of above properties (win32 only) + end; +// [STRUCT_END] + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_FLAGS + + [DESCRIPTION] + Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure. + + [SEE_ALSO] + FSOUND_REVERB_PROPERTIES +] +} +const + FSOUND_REVERBFLAGS_DECAYTIMESCALE = $00000001; // EnvironmentSize affects reverberation decay time + FSOUND_REVERBFLAGS_REFLECTIONSSCALE = $00000002; // EnvironmentSize affects reflection level + FSOUND_REVERBFLAGS_REFLECTIONSDELAYSCALE = $00000004; // EnvironmentSize affects initial reflection delay time + FSOUND_REVERBFLAGS_REVERBSCALE = $00000008; // EnvironmentSize affects reflections level + FSOUND_REVERBFLAGS_REVERBDELAYSCALE = $00000010; // EnvironmentSize affects late reverberation delay time + FSOUND_REVERBFLAGS_DECAYHFLIMIT = $00000020; // AirAbsorptionHF affects DecayHFRatio + FSOUND_REVERBFLAGS_ECHOTIMESCALE = $00000040; // EnvironmentSize affects echo time + FSOUND_REVERBFLAGS_MODULATIONTIMESCALE = $00000080; // EnvironmentSize affects modulation time + FSOUND_REVERB_FLAGS_CORE0 = $00000100; // PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) + FSOUND_REVERB_FLAGS_CORE1 = $00000200; // PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) + FSOUND_REVERBFLAGS_DEFAULT = FSOUND_REVERBFLAGS_DECAYTIMESCALE or FSOUND_REVERBFLAGS_REFLECTIONSSCALE or + FSOUND_REVERBFLAGS_REFLECTIONSDELAYSCALE or FSOUND_REVERBFLAGS_REVERBSCALE or + FSOUND_REVERBFLAGS_REVERBDELAYSCALE or FSOUND_REVERBFLAGS_DECAYHFLIMIT or + FSOUND_REVERB_FLAGS_CORE0 or FSOUND_REVERB_FLAGS_CORE1; +// [DEFINE_END] + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS, created by Creative Labs + These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically. + ie + FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC; + + [SEE_ALSO] + FSOUND_Reverb_SetProperties +] +} +{ +const +// Env Size Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel RefPan Revb RevDel ReverbPan EchoTm EchDp ModTm ModDp AirAbs HFRef LFRef RRlOff Diffus Densty FLAGS + FSOUND_PRESET_OFF = 0, 7.5f, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, 0.0f,0.0f,0.0f, 200, 0.011f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 0.0f, 0.0f, 0x3f ; + FSOUND_PRESET_GENERIC = 0, 7.5f, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, 0.0f,0.0f,0.0f, 200, 0.011f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_PADDEDCELL = 1, 1.4f, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, 0.0f,0.0f,0.0f, 207, 0.002f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_ROOM = 2, 1.9f, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, 0.0f,0.0f,0.0f, 53, 0.003f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_BATHROOM = 3, 1.4f, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, 0.0f,0.0f,0.0f, 1030, 0.011f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 60.0f, 0x3f ; + FSOUND_PRESET_LIVINGROOM = 4, 2.5f, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, 0.0f,0.0f,0.0f, -1104, 0.004f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_STONEROOM = 5, 11.6f, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, 0.0f,0.0f,0.0f, 83, 0.017f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_AUDITORIUM = 6, 21.6f, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, 0.0f,0.0f,0.0f, -289, 0.030f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_CONCERTHALL = 7, 19.6f, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, 0.0f,0.0f,0.0f, -2, 0.029f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_CAVE = 8, 14.6f, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, 0.0f,0.0f,0.0f, -302, 0.022f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f ; + FSOUND_PRESET_ARENA = 9, 36.2f, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, 0.0f,0.0f,0.0f, 16, 0.030f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_HANGAR = 10, 50.3f, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, 0.0f,0.0f,0.0f, 198, 0.030f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_CARPETTEDHALLWAY = 11, 1.9f, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, 0.0f,0.0f,0.0f, -1630, 0.030f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_HALLWAY = 12, 1.8f, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, 0.0f,0.0f,0.0f, 441, 0.011f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_STONECORRIDOR = 13, 13.5f, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, 0.0f,0.0f,0.0f, 395, 0.020f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_ALLEY = 14, 7.5f, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, 0.0f,0.0f,0.0f, -4, 0.011f, 0.0f,0.0f,0.0f, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_FOREST = 15, 38.0f, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, 0.0f,0.0f,0.0f, -229, 0.088f, 0.0f,0.0f,0.0f, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 79.0f, 100.0f, 0x3f ; + FSOUND_PRESET_CITY = 16, 7.5f, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, 0.0f,0.0f,0.0f, -1691, 0.011f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 50.0f, 100.0f, 0x3f ; + FSOUND_PRESET_MOUNTAINS = 17, 100.0f, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, 0.0f,0.0f,0.0f, -1434, 0.100f, 0.0f,0.0f,0.0f, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 27.0f, 100.0f, 0x1f ; + FSOUND_PRESET_QUARRY = 18, 17.5f, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, 0.0f,0.0f,0.0f, 500, 0.025f, 0.0f,0.0f,0.0f, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + FSOUND_PRESET_PLAIN = 19, 42.5f, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, 0.0f,0.0f,0.0f, -1926, 0.100f, 0.0f,0.0f,0.0f, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 21.0f, 100.0f, 0x3f ; + FSOUND_PRESET_PARKINGLOT = 20, 8.3f, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, 0.0f,0.0f,0.0f, -1153, 0.012f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f ; + FSOUND_PRESET_SEWERPIPE = 21, 1.7f, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, 0.0f,0.0f,0.0f, 1023, 0.021f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f ; + FSOUND_PRESET_UNDERWATER = 22, 1.8f, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, 0.0f,0.0f,0.0f, 1700, 0.011f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f ; + +// Non I3DL2 presets + + FSOUND_PRESET_DRUGGED = 23, 1.9f, 0.50f, -1000, 0, 0, 8.39f, 1.39f, 1.0f, -115, 0.002f, 0.0f,0.0f,0.0f, 985, 0.030f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f ; + FSOUND_PRESET_DIZZY = 24, 1.8f, 0.60f, -1000, -400, 0, 17.23f, 0.56f, 1.0f, -1713, 0.020f, 0.0f,0.0f,0.0f, -613, 0.030f, 0.0f,0.0f,0.0f, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f ; + FSOUND_PRESET_PSYCHOTIC = 25, 1.0f, 0.50f, -1000, -151, 0, 7.56f, 0.91f, 1.0f, -626, 0.020f, 0.0f,0.0f,0.0f, 774, 0.030f, 0.0f,0.0f,0.0f, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f ; +} +// [DEFINE_END] + + +{ +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining the properties for a reverb source, related to a FSOUND channel. + For more indepth descriptions of the reverb properties under win32, please see the EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + + Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). + Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then + the reverb should product a similar effect on either platform. + Linux and FMODCE do not support the reverb api. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [SEE_ALSO] + FSOUND_Reverb_SetChannelProperties + FSOUND_Reverb_GetChannelProperties + FSOUND_REVERB_CHANNELFLAGS +] +} +type + TFSoundReverbChannelProperties = record // MIN MAX DEFAULT + Direct: Integer; // -10000 1000 0 direct path level (at low and mid frequencies) (win32/xbox) + DirectHF: Integer; // -10000 0 0 relative direct path level at high frequencies (win32/xbox) + Room: Integer; // -10000 1000 0 room effect level (at low and mid frequencies) (win32/xbox) + RoomHF: Integer; // -10000 0 0 relative room effect level at high frequencies (win32/xbox) + Obstruction: Integer; // -10000 0 0 main obstruction control (attenuation at high frequencies) (win32/xbox) + ObstructionLFRatio: Single; // 0.0 1.0 0.0 obstruction low-frequency level re. main control (win32/xbox) + Occlusion: Integer; // -10000 0 0 main occlusion control (attenuation at high frequencies) (win32/xbox) + OcclusionLFRatio: Single; // 0.0 1.0 0.25 occlusion low-frequency level re. main control (win32/xbox) + OcclusionRoomRatio: Single; // 0.0 10.0 1.5 relative occlusion control for room effect (win32) + OcclusionDirectRatio: Single; // 0.0 10.0 1.0 relative occlusion control for direct path (win32) + Exclusion: Integer; // -10000 0 0 main exlusion control (attenuation at high frequencies) (win32) + ExclusionLFRatio: Single; // 0.0 1.0 1.0 exclusion low-frequency level re. main control (win32) + OutsideVolumeHF: Integer; // -10000 0 0 outside sound cone level at high frequencies (win32) + DopplerFactor: Single; // 0.0 10.0 0.0 like DS3D flDopplerFactor but per source (win32) + RolloffFactor: Single; // 0.0 10.0 0.0 like DS3D flRolloffFactor but per source (win32) + RoomRolloffFactor: Single; // 0.0 10.0 0.0 like DS3D flRolloffFactor but for room effect (win32/xbox) + AirAbsorptionFactor: Single; // 0.0 10.0 1.0 multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES (win32) + Flags: Integer; // FSOUND_REVERB_CHANNELFLAGS - modifies the behavior of properties (win32) + end; +// [STRUCT_END] + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_CHANNELFLAGS + + [DESCRIPTION] + Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure. + + [SEE_ALSO] + FSOUND_REVERB_CHANNELPROPERTIES +] +} +const + FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO = $01; // Automatic setting of 'Direct' due to distance from listener + FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO = $02; // Automatic setting of 'Room' due to distance from listener + FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO = $04; // Automatic setting of 'RoomHF' due to distance from listener + FSOUND_REVERB_CHANNELFLAGS_DEFAULT = FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO or + FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO or + FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO; +// [DEFINE_END] + + +{ +[ENUM] +[ + [DESCRIPTION] + These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel. + + [SEE_ALSO] + FSOUND_FX_Enable + FSOUND_FX_Disable + FSOUND_FX_SetChorus + FSOUND_FX_SetCompressor + FSOUND_FX_SetDistortion + FSOUND_FX_SetEcho + FSOUND_FX_SetFlanger + FSOUND_FX_SetGargle + FSOUND_FX_SetI3DL2Reverb + FSOUND_FX_SetParamEQ + FSOUND_FX_SetWavesReverb +] +} + +type + TFSoundFXModes = ( + FSOUND_FX_CHORUS, + FSOUND_FX_COMPRESSOR, + FSOUND_FX_DISTORTION, + FSOUND_FX_ECHO, + FSOUND_FX_FLANGER, + FSOUND_FX_GARGLE, + FSOUND_FX_I3DL2REVERB, + FSOUND_FX_PARAMEQ, + FSOUND_FX_WAVES_REVERB, + FSOUND_FX_MAX + ); +// [DEFINE_END] + + +{ +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the FSOUND_SetSpeakerMode command. + Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only + interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo. + + [SEE_ALSO] + FSOUND_SetSpeakerMode + + [REMARKS] + Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only + interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo. + + Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure. +] +} +type + TFSoundSpeakerModes = + ( + FSOUND_SPEAKERMODE_DOLBYDIGITAL, // The audio is played through a speaker arrangement of surround speakers with a subwoofer. + FSOUND_SPEAKERMODE_HEADPHONES, // The speakers are headphones. + FSOUND_SPEAKERMODE_MONO, // The speakers are monaural. + FSOUND_SPEAKERMODE_QUAD, // The speakers are quadraphonic. + FSOUND_SPEAKERMODE_STEREO, // The speakers are stereo (default value). + FSOUND_SPEAKERMODE_SURROUND, // The speakers are surround sound. + FSOUND_SPEAKERMODE_DTS // The audio is played through a speaker arrangement of surround speakers with a subwoofer. + ); + FSOUND_SPEAKERMODES = TFSoundSpeakerModes; + + +{ +[DEFINE_START] +[ + [NAME] + FSOUND_INIT_FLAGS + + [DESCRIPTION] + Initialization flags. Use them with FSOUND_Init in the flags parameter to change various behaviour. + + FSOUND_INIT_ENABLESYSTEMCHANNELFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects. + Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small. + This can be fixed with FSOUND_SetBufferSize. Increase the BufferSize until it works. + When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters. + + [SEE_ALSO] + FSOUND_Init +] +} +const + FSOUND_INIT_USEDEFAULTMIDISYNTH = $01; // Causes MIDI playback to force software decoding. + FSOUND_INIT_GLOBALFOCUS = $02; // For DirectSound output - sound is not muted when window is out of focus. + FSOUND_INIT_ENABLESYSTEMCHANNELFX = $04; // For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! + FSOUND_INIT_ACCURATEVULEVELS = $08; // This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit. + FSOUND_INIT_PS2_DISABLECORE0REVERB = $10; // PS2 only - Disable reverb on CORE 0 to regain SRAM. + FSOUND_INIT_PS2_DISABLECORE1REVERB = $20; // PS2 only - Disable reverb on CORE 1 to regain SRAM. + FSOUND_INIT_PS2_SWAPDMACORES = $40; // PS2 only - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around. + FSOUND_INIT_DONTLATENCYADJUST = $80; // Callbacks are not latency adjusted, and are called at mix time. Also information functions are immediate. + FSOUND_INIT_GC_INITLIBS = $100; // Gamecube only - Initializes GC audio libraries. + FSOUND_INIT_STREAM_FROM_MAIN_THREAD = $200; // Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user. + FSOUND_INIT_PS2_USEVOLUMERAMPING = $400; // PS2 only - Turns on volume ramping system to remove hardware clicks. + FSOUND_INIT_DSOUND_DEFERRED = $800; // Win32 only - For DirectSound output. 3D commands are batched together and executed at FSOUND_Update. + FSOUND_INIT_DSOUND_HRTF_LIGHT = $1000; // Win32 only - For DirectSound output. FSOUND_HW3D buffers use a slightly higher quality algorithm when 3d hardware acceleration is not present. + FSOUND_INIT_DSOUND_HRTF_FULL = $2000; // Win32 only - For DirectSound output. FSOUND_HW3D buffers use full quality 3d playback when 3d hardware acceleration is not present. + FSOUND_INIT_XBOX_REMOVEHEADROOM = $4000; // XBox only - By default directsound attenuates all sound by 6db to avoid clipping/distortion. CAUTION. If you use this flag you are responsible for the final mix to make sure clipping / distortion doesn't happen. + FSOUND_INIT_PSP_SILENCEONUNDERRUN = $8000; // PSP only - If streams skip / stutter when device is powered on, either increase stream buffersize, or use this flag instead to play silence while the UMD is recovering. + +// [DEFINE_END] + +(* +[ENUM] +[ + [DESCRIPTION] + Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream. + + [SEE_ALSO] + FSOUND_Stream_Net_GetStatus +] +*) +type + TFSoundStreamNetStatus = + ( + FSOUND_STREAM_NET_NOTCONNECTED, (* Stream hasn't connected yet *) + FSOUND_STREAM_NET_CONNECTING, (* Stream is connecting to remote host *) + FSOUND_STREAM_NET_BUFFERING, (* Stream is buffering data *) + FSOUND_STREAM_NET_READY, (* Stream is ready to play *) + FSOUND_STREAM_NET_ERROR (* Stream has suffered a fatal error *) + ); + + +(* +[ENUM] +[ + [DESCRIPTION] + Describes the type of a particular tag field. + + [SEE_ALSO] + FSOUND_Stream_GetNumTagFields + FSOUND_Stream_GetTagField + FSOUND_Stream_FindTagField +] +*) +type + TFSoundTagFieldType = + ( + FSOUND_TAGFIELD_VORBISCOMMENT, (* A vorbis comment *) + FSOUND_TAGFIELD_ID3V1, (* Part of an ID3v1 tag *) + FSOUND_TAGFIELD_ID3V2, (* An ID3v2 frame *) + FSOUND_TAGFIELD_SHOUTCAST, (* A SHOUTcast header line *) + FSOUND_TAGFIELD_ICECAST, (* An Icecast header line *) + FSOUND_TAGFIELD_ASF (* An Advanced Streaming Format header line *) + ); + + +(* +[DEFINE_START] +[ + [NAME] + FSOUND_STATUS_FLAGS + + [DESCRIPTION] + These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream. + + [SEE_ALSO] + FSOUND_Stream_Net_GetStatus +] +*) +const + FSOUND_PROTOCOL_SHOUTCAST = $00000001; + FSOUND_PROTOCOL_ICECAST = $00000002; + FSOUND_PROTOCOL_HTTP = $00000004; + FSOUND_FORMAT_MPEG = $00010000; + FSOUND_FORMAT_OGGVORBIS = $00020000; +(* [DEFINE_END] *) + +{ +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining a CD table of contents. This structure is returned as a tag from FSOUND_Stream_FindTagField when the tag name "CD_TOC" is specified. + Note: All tracks on the CD - including data tracks- will be represented in this structure so it's use for anything other than generating disc id information is not recommended. + See the cdda example program for info on retrieving and using this structure. + + [SEE_ALSO] + FSOUND_Stream_Open + FSOUND_Stream_FindTagField +] +} +type + TFSoundTOCTag = record + Name: array [0..3] of Char; // The string "TOC" (4th character is 0), just in case this structure is accidentally treated as a string. + NumTracks: Integer; // The number of tracks on the CD. + Min: array [0..99] of Integer; // The start offset of each track in minutes. + Sec: array [0..99] of Integer; // The start offset of each track in seconds. + Frame: array [0..99] of Integer; // The start offset of each track in frames. + end; +// [STRUCT_END] + +implementation + +end. diff --git a/fmodapi375win/api/fmod.dll b/fmodapi375win/api/fmod.dll new file mode 100644 index 0000000..6b0e379 Binary files /dev/null and b/fmodapi375win/api/fmod.dll differ diff --git a/fmodapi375win/api/fmod64.dll b/fmodapi375win/api/fmod64.dll new file mode 100644 index 0000000..2a8bab2 Binary files /dev/null and b/fmodapi375win/api/fmod64.dll differ diff --git a/fmodapi375win/api/inc/fmod.h b/fmodapi375win/api/inc/fmod.h new file mode 100644 index 0000000..54d3562 --- /dev/null +++ b/fmodapi375win/api/inc/fmod.h @@ -0,0 +1,1224 @@ +/* ========================================================================================== */ +/* FMOD Main header file. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004. */ +/* ========================================================================================== */ + +#ifndef _FMOD_H_ +#define _FMOD_H_ + +/* ========================================================================================== */ +/* DEFINITIONS */ +/* ========================================================================================== */ + +#if (!defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(_WIN64) && !defined(_WIN32_WCE) && !defined(_XBOX)) || (defined(__GNUC__) && defined(WIN32)) + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __stdcall + #define __stdcall + #endif +#endif + +#if defined(_WIN32_WCE) + #define F_API _cdecl + #define F_CALLBACKAPI _cdecl +#else + #define F_API __stdcall + #define F_CALLBACKAPI __stdcall +#endif + +#ifdef DLL_EXPORTS + #define DLL_API __declspec(dllexport) +#else + #if defined(__LCC__) || defined(__MINGW32__) || defined(__CYGWIN32__) + #define DLL_API F_API + #else + #define DLL_API + #endif /* __LCC__ || __MINGW32__ || __CYGWIN32__ */ +#endif /* DLL_EXPORTS */ + +#define FMOD_VERSION 3.75f + +/* + FMOD defined types +*/ +typedef struct FSOUND_SAMPLE FSOUND_SAMPLE; +typedef struct FSOUND_STREAM FSOUND_STREAM; +typedef struct FSOUND_DSPUNIT FSOUND_DSPUNIT; +typedef struct FSOUND_SYNCPOINT FSOUND_SYNCPOINT; +typedef struct FMUSIC_MODULE FMUSIC_MODULE; + +/* + Callback types +*/ +typedef void * (F_CALLBACKAPI *FSOUND_OPENCALLBACK) (const char *name); +typedef void (F_CALLBACKAPI *FSOUND_CLOSECALLBACK) (void *handle); +typedef int (F_CALLBACKAPI *FSOUND_READCALLBACK) (void *buffer, int size, void *handle); +typedef int (F_CALLBACKAPI *FSOUND_SEEKCALLBACK) (void *handle, int pos, signed char mode); +typedef int (F_CALLBACKAPI *FSOUND_TELLCALLBACK) (void *handle); + +typedef void * (F_CALLBACKAPI *FSOUND_ALLOCCALLBACK) (unsigned int size); +typedef void * (F_CALLBACKAPI *FSOUND_REALLOCCALLBACK) (void *ptr, unsigned int size); +typedef void (F_CALLBACKAPI *FSOUND_FREECALLBACK) (void *ptr); + +typedef void * (F_CALLBACKAPI *FSOUND_DSPCALLBACK) (void *originalbuffer, void *newbuffer, int length, void *userdata); +typedef signed char (F_CALLBACKAPI *FSOUND_STREAMCALLBACK) (FSOUND_STREAM *stream, void *buff, int len, void *userdata); +typedef signed char (F_CALLBACKAPI *FSOUND_METADATACALLBACK)(char *name, char *value, void *userdata); +typedef void (F_CALLBACKAPI *FMUSIC_CALLBACK) (FMUSIC_MODULE *mod, unsigned char param); + + +/* +[ENUM] +[ + [DESCRIPTION] + On failure of commands in FMOD, use FSOUND_GetError to attain what happened. + + [SEE_ALSO] + FSOUND_GetError +] +*/ +enum FMOD_ERRORS +{ + FMOD_ERR_NONE, /* No errors */ + FMOD_ERR_BUSY, /* Cannot call this command after FSOUND_Init. Call FSOUND_Close first. */ + FMOD_ERR_UNINITIALIZED, /* This command failed because FSOUND_Init or FSOUND_SetOutput was not called */ + FMOD_ERR_INIT, /* Error initializing output device. */ + FMOD_ERR_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ + FMOD_ERR_PLAY, /* Playing the sound failed. */ + FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the features needed for this soundsystem (16bit stereo output) */ + FMOD_ERR_COOPERATIVELEVEL, /* Error setting cooperative level for hardware. */ + FMOD_ERR_CREATEBUFFER, /* Error creating hardware sound buffer. */ + FMOD_ERR_FILE_NOTFOUND, /* File not found */ + FMOD_ERR_FILE_FORMAT, /* Unknown file format */ + FMOD_ERR_FILE_BAD, /* Error loading file */ + FMOD_ERR_MEMORY, /* Not enough memory or resources */ + FMOD_ERR_VERSION, /* The version number of this file format is not supported */ + FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function */ + FMOD_ERR_NO_EAX, /* Tried to use an EAX command on a non EAX enabled channel or output. */ + FMOD_ERR_CHANNEL_ALLOC, /* Failed to allocate a new channel */ + FMOD_ERR_RECORD, /* Recording is not supported on this machine */ + FMOD_ERR_MEDIAPLAYER, /* Windows Media Player not installed so cannot play wma or use internet streaming. */ + FMOD_ERR_CDDEVICE /* An error occured trying to open the specified CD device */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These output types are used with FSOUND_SetOutput, to choose which output driver to use. + + FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver + does not support DirectX 6 Voice Manager Extensions. + + FSOUND_OUTPUT_WINMM is recommended for NT and CE. + + [SEE_ALSO] + FSOUND_SetOutput + FSOUND_GetOutput +] +*/ +enum FSOUND_OUTPUTTYPES +{ + FSOUND_OUTPUT_NOSOUND, /* NoSound driver, all calls to this succeed but do nothing. */ + FSOUND_OUTPUT_WINMM, /* Windows Multimedia driver. */ + FSOUND_OUTPUT_DSOUND, /* DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. */ + FSOUND_OUTPUT_A3D, /* A3D driver. */ + + FSOUND_OUTPUT_OSS, /* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */ + FSOUND_OUTPUT_ESD, /* Linux/Unix ESD (Enlightment Sound Daemon) driver. */ + FSOUND_OUTPUT_ALSA, /* Linux Alsa driver. */ + + FSOUND_OUTPUT_ASIO, /* Low latency ASIO driver */ + FSOUND_OUTPUT_XBOX, /* Xbox driver */ + FSOUND_OUTPUT_PS2, /* PlayStation 2 driver */ + FSOUND_OUTPUT_MAC, /* Mac SoundManager driver */ + FSOUND_OUTPUT_GC, /* Gamecube driver */ + FSOUND_OUTPUT_PSP, /* PlayStation Portable driver */ + + FSOUND_OUTPUT_NOSOUND_NONREALTIME /* This is the same as nosound, but the sound generation is driven by FSOUND_Update */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act + upon for other reasons using FSOUND_GetMixer. + It is not nescessary to set the mixer. FMOD will autodetect the best mixer for you. + + [SEE_ALSO] + FSOUND_SetMixer + FSOUND_GetMixer +] +*/ +enum FSOUND_MIXERTYPES +{ + FSOUND_MIXER_AUTODETECT, /* CE/PS2/GC Only - Non interpolating/low quality mixer. */ + FSOUND_MIXER_BLENDMODE, /* Removed / obsolete. */ + FSOUND_MIXER_MMXP5, /* Removed / obsolete. */ + FSOUND_MIXER_MMXP6, /* Removed / obsolete. */ + + FSOUND_MIXER_QUALITY_AUTODETECT,/* All platforms - Autodetect the fastest quality mixer based on your cpu. */ + FSOUND_MIXER_QUALITY_FPU, /* Win32/Linux only - Interpolating/volume ramping FPU mixer. */ + FSOUND_MIXER_QUALITY_MMXP5, /* Win32/Linux only - Interpolating/volume ramping P5 MMX mixer. */ + FSOUND_MIXER_QUALITY_MMXP6, /* Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. */ + + FSOUND_MIXER_MONO, /* CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed*/ + FSOUND_MIXER_QUALITY_MONO, /* CE/PS2/GC only - MONO Interpolating mixer. For speed */ + + FSOUND_MIXER_MAX +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + These definitions describe the type of song being played. + + [SEE_ALSO] + FMUSIC_GetType +] +*/ +enum FMUSIC_TYPES +{ + FMUSIC_TYPE_NONE, + FMUSIC_TYPE_MOD, /* Protracker / Fasttracker */ + FMUSIC_TYPE_S3M, /* ScreamTracker 3 */ + FMUSIC_TYPE_XM, /* FastTracker 2 */ + FMUSIC_TYPE_IT, /* Impulse Tracker. */ + FMUSIC_TYPE_MIDI, /* MIDI file */ + FMUSIC_TYPE_FSB /* FMOD Sample Bank file */ +}; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_DSP_PRIORITIES + + [DESCRIPTION] + These default priorities are used by FMOD internal system DSP units. They describe the + position of the DSP chain, and the order of how audio processing is executed. + You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP + unit), disable or even change the priority of a DSP unit. + + [SEE_ALSO] + FSOUND_DSP_Create + FSOUND_DSP_SetPriority + FSOUND_DSP_GetSpectrum +] +*/ +#define FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT 0 /* DSP CLEAR unit - done first */ +#define FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT 100 /* DSP SFX unit - done second */ +#define FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT 200 /* DSP MUSIC unit - done third */ +#define FSOUND_DSP_DEFAULTPRIORITY_USER 300 /* User priority, use this as reference for your own DSP units */ +#define FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT 900 /* This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units */ +#define FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT 1000 /* DSP CLIP AND COPY unit - last */ +/* [DEFINE_END] */ + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_CAPS + + [DESCRIPTION] + Driver description bitfields. Use FSOUND_Driver_GetCaps to determine if a driver enumerated + has the settings you are after. The enumerated driver depends on the output mode, see + FSOUND_OUTPUTTYPES + + [SEE_ALSO] + FSOUND_GetDriverCaps + FSOUND_OUTPUTTYPES +] +*/ +#define FSOUND_CAPS_HARDWARE 0x1 /* This driver supports hardware accelerated 3d sound. */ +#define FSOUND_CAPS_EAX2 0x2 /* This driver supports EAX 2 reverb */ +#define FSOUND_CAPS_EAX3 0x10 /* This driver supports EAX 3 reverb */ +/* [DEFINE_END] */ + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_MODES + + [DESCRIPTION] + Sample description bitfields, OR them together for loading and describing samples. + NOTE. If the file format being loaded already has a defined format, such as WAV or MP3, then + trying to override the pre-defined format with a new set of format flags will not work. For + example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS. It will just + ignore the flag and go ahead loading it as 8bits. For these type of formats the only flags + you can specify that will really alter the behaviour of how it is loaded, are the following. + --------- + Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI + Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D + Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO + Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX + PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP + --------- + See flag descriptions for what these do. +] +*/ +#define FSOUND_LOOP_OFF 0x00000001 /* For non looping samples. */ +#define FSOUND_LOOP_NORMAL 0x00000002 /* For forward looping samples. */ +#define FSOUND_LOOP_BIDI 0x00000004 /* For bidirectional looping samples. (no effect if in hardware). */ +#define FSOUND_8BITS 0x00000008 /* For 8 bit samples. */ +#define FSOUND_16BITS 0x00000010 /* For 16 bit samples. */ +#define FSOUND_MONO 0x00000020 /* For mono samples. */ +#define FSOUND_STEREO 0x00000040 /* For stereo samples. */ +#define FSOUND_UNSIGNED 0x00000080 /* For user created source data containing unsigned samples. */ +#define FSOUND_SIGNED 0x00000100 /* For user created source data containing signed data. */ +#define FSOUND_DELTA 0x00000200 /* For user created source data stored as delta values. */ +#define FSOUND_IT214 0x00000400 /* For user created source data stored using IT214 compression. */ +#define FSOUND_IT215 0x00000800 /* For user created source data stored using IT215 compression. */ +#define FSOUND_HW3D 0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */ +#define FSOUND_2D 0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */ +#define FSOUND_STREAMABLE 0x00004000 /* For a streamimg sound where you feed the data to it. */ +#define FSOUND_LOADMEMORY 0x00008000 /* "name" will be interpreted as a pointer to data for streaming and samples. */ +#define FSOUND_LOADRAW 0x00010000 /* Will ignore file format and treat as raw pcm. */ +#define FSOUND_MPEGACCURATE 0x00020000 /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */ +#define FSOUND_FORCEMONO 0x00040000 /* For forcing stereo streams and samples to be mono - needed if using FSOUND_HW3D and stereo data - incurs a small speed hit for streams */ +#define FSOUND_HW2D 0x00080000 /* 2D hardware sounds. allows hardware specific effects */ +#define FSOUND_ENABLEFX 0x00100000 /* Allows DX8 FX to be played back on a sound. Requires DirectX 8 - Note these sounds cannot be played more than once, be 8 bit, be less than a certain size, or have a changing frequency */ +#define FSOUND_MPEGHALFRATE 0x00200000 /* For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution */ +#define FSOUND_IMAADPCM 0x00400000 /* Contents are stored compressed as IMA ADPCM */ +#define FSOUND_VAG 0x00800000 /* For PS2 only - Contents are compressed as Sony VAG format */ +#define FSOUND_NONBLOCKING 0x01000000 /* For FSOUND_Stream_Open/FMUSIC_LoadSong - Causes stream or music to open in the background and not block the foreground app. See FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState to determine when it IS ready. */ +#define FSOUND_GCADPCM 0x02000000 /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */ +#define FSOUND_MULTICHANNEL 0x04000000 /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */ +#define FSOUND_USECORE0 0x08000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 00-23 */ +#define FSOUND_USECORE1 0x10000000 /* For PS2 only - Sample/Stream is forced to use hardware voices 24-47 */ +#define FSOUND_LOADMEMORYIOP 0x20000000 /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address */ +#define FSOUND_IGNORETAGS 0x40000000 /* Skips id3v2 etc tag checks when opening a stream, to reduce seek/read overhead when opening files (helps with CD performance) */ +#define FSOUND_STREAM_NET 0x80000000 /* Specifies an internet stream */ + +#define FSOUND_NORMAL (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO) +/* [DEFINE_END] */ + + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_CDPLAYMODES + + [DESCRIPTION] + Playback method for a CD Audio track, with FSOUND_CD_SetPlayMode + + [SEE_ALSO] + FSOUND_CD_SetPlayMode + FSOUND_CD_Play +] +*/ +#define FSOUND_CD_PLAYCONTINUOUS 0 /* Starts from the current track and plays to end of CD. */ +#define FSOUND_CD_PLAYONCE 1 /* Plays the specified track then stops. */ +#define FSOUND_CD_PLAYLOOPED 2 /* Plays the specified track looped, forever until stopped manually. */ +#define FSOUND_CD_PLAYRANDOM 3 /* Plays tracks in random order */ +/* [DEFINE_END] */ + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_MISC_VALUES + + [DESCRIPTION] + Miscellaneous values for FMOD functions. + + [SEE_ALSO] + FSOUND_PlaySound + FSOUND_PlaySoundEx + FSOUND_Sample_Alloc + FSOUND_Sample_Load + FSOUND_SetPan +] +*/ +#define FSOUND_FREE -1 /* value to play on any free channel, or to allocate a sample in a free sample slot. */ +#define FSOUND_UNMANAGED -2 /* value to allocate a sample that is NOT managed by FSOUND or placed in a sample slot. */ +#define FSOUND_ALL -3 /* for a channel index , this flag will affect ALL channels available! Not supported by every function. */ +#define FSOUND_STEREOPAN -1 /* value for FSOUND_SetPan so that stereo sounds are not played at half volume. See FSOUND_SetPan for more on this. */ +#define FSOUND_SYSTEMCHANNEL -1000 /* special 'channel' ID for all channel based functions that want to alter the global FSOUND software mixing output channel */ +#define FSOUND_SYSTEMSAMPLE -1000 /* special 'sample' ID for all sample based functions that want to alter the global FSOUND software mixing output sample */ + +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining a reverb environment. + For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of EAX2. + Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). + Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then the reverb should product a similar effect on either platform. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [SEE_ALSO] + FSOUND_Reverb_SetProperties + FSOUND_Reverb_GetProperties + FSOUND_REVERB_PRESETS + FSOUND_REVERB_FLAGS +] +*/ +typedef struct _FSOUND_REVERB_PROPERTIES /* MIN MAX DEFAULT DESCRIPTION */ +{ + unsigned int Environment; /* 0 , 25 , 0 , sets all listener properties (WIN32/PS2 only) */ + float EnvSize; /* 1.0 , 100.0 , 7.5 , environment size in meters (WIN32 only) */ + float EnvDiffusion; /* 0.0 , 1.0 , 1.0 , environment diffusion (WIN32/XBOX) */ + int Room; /* -10000, 0 , -1000 , room effect level (at mid frequencies) (WIN32/XBOX/PS2) */ + int RoomHF; /* -10000, 0 , -100 , relative room effect level at high frequencies (WIN32/XBOX) */ + int RoomLF; /* -10000, 0 , 0 , relative room effect level at low frequencies (WIN32 only) */ + float DecayTime; /* 0.1 , 20.0 , 1.49 , reverberation decay time at mid frequencies (WIN32/XBOX) */ + float DecayHFRatio; /* 0.1 , 2.0 , 0.83 , high-frequency to mid-frequency decay time ratio (WIN32/XBOX) */ + float DecayLFRatio; /* 0.1 , 2.0 , 1.0 , low-frequency to mid-frequency decay time ratio (WIN32 only) */ + int Reflections; /* -10000, 1000 , -2602 , early reflections level relative to room effect (WIN32/XBOX) */ + float ReflectionsDelay; /* 0.0 , 0.3 , 0.007 , initial reflection delay time (WIN32/XBOX) */ + float ReflectionsPan[3]; /* , , [0,0,0], early reflections panning vector (WIN32 only) */ + int Reverb; /* -10000, 2000 , 200 , late reverberation level relative to room effect (WIN32/XBOX) */ + float ReverbDelay; /* 0.0 , 0.1 , 0.011 , late reverberation delay time relative to initial reflection (WIN32/XBOX) */ + float ReverbPan[3]; /* , , [0,0,0], late reverberation panning vector (WIN32 only) */ + float EchoTime; /* .075 , 0.25 , 0.25 , echo time (WIN32/PS2 only. PS2 = Delay time for ECHO/DELAY modes only) */ + float EchoDepth; /* 0.0 , 1.0 , 0.0 , echo depth (WIN32/PS2 only. PS2 = Feedback level for ECHO mode only) */ + float ModulationTime; /* 0.04 , 4.0 , 0.25 , modulation time (WIN32 only) */ + float ModulationDepth; /* 0.0 , 1.0 , 0.0 , modulation depth (WIN32 only) */ + float AirAbsorptionHF; /* -100 , 0.0 , -5.0 , change in level per meter at high frequencies (WIN32 only) */ + float HFReference; /* 1000.0, 20000 , 5000.0 , reference high frequency (hz) (WIN32/XBOX) */ + float LFReference; /* 20.0 , 1000.0, 250.0 , reference low frequency (hz) (WIN32 only) */ + float RoomRolloffFactor; /* 0.0 , 10.0 , 0.0 , like FSOUND_3D_SetRolloffFactor but for room effect (WIN32/XBOX) */ + float Diffusion; /* 0.0 , 100.0 , 100.0 , Value that controls the echo density in the late reverberation decay. (XBOX only) */ + float Density; /* 0.0 , 100.0 , 100.0 , Value that controls the modal density in the late reverberation decay (XBOX only) */ + unsigned int Flags; /* FSOUND_REVERB_FLAGS - modifies the behavior of above properties (WIN32/PS2 only) */ +} FSOUND_REVERB_PROPERTIES; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_FLAGS + + [DESCRIPTION] + Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure. + + [SEE_ALSO] + FSOUND_REVERB_PROPERTIES +] +*/ +#define FSOUND_REVERB_FLAGS_DECAYTIMESCALE 0x00000001 /* 'EnvSize' affects reverberation decay time */ +#define FSOUND_REVERB_FLAGS_REFLECTIONSSCALE 0x00000002 /* 'EnvSize' affects reflection level */ +#define FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE 0x00000004 /* 'EnvSize' affects initial reflection delay time */ +#define FSOUND_REVERB_FLAGS_REVERBSCALE 0x00000008 /* 'EnvSize' affects reflections level */ +#define FSOUND_REVERB_FLAGS_REVERBDELAYSCALE 0x00000010 /* 'EnvSize' affects late reverberation delay time */ +#define FSOUND_REVERB_FLAGS_DECAYHFLIMIT 0x00000020 /* AirAbsorptionHF affects DecayHFRatio */ +#define FSOUND_REVERB_FLAGS_ECHOTIMESCALE 0x00000040 /* 'EnvSize' affects echo time */ +#define FSOUND_REVERB_FLAGS_MODULATIONTIMESCALE 0x00000080 /* 'EnvSize' affects modulation time */ +#define FSOUND_REVERB_FLAGS_CORE0 0x00000100 /* PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) */ +#define FSOUND_REVERB_FLAGS_CORE1 0x00000200 /* PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) */ +#define FSOUND_REVERB_FLAGS_DEFAULT (FSOUND_REVERB_FLAGS_DECAYTIMESCALE | \ + FSOUND_REVERB_FLAGS_REFLECTIONSSCALE | \ + FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE | \ + FSOUND_REVERB_FLAGS_REVERBSCALE | \ + FSOUND_REVERB_FLAGS_REVERBDELAYSCALE | \ + FSOUND_REVERB_FLAGS_DECAYHFLIMIT | \ + FSOUND_REVERB_FLAGS_CORE0 | \ + FSOUND_REVERB_FLAGS_CORE1 ) +/* [DEFINE_END] */ + + + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS, created by Creative Labs + These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically. + ie + FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC; + + [SEE_ALSO] + FSOUND_Reverb_SetProperties +] +*/ +/* Env Size Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel RefPan Revb RevDel ReverbPan EchoTm EchDp ModTm ModDp AirAbs HFRef LFRef RRlOff Diffus Densty FLAGS */ +#define FSOUND_PRESET_OFF {0, 7.5f, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 0.0f, 0.0f, 0x33f } +#define FSOUND_PRESET_GENERIC {0, 7.5f, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, { 0.0f,0.0f,0.0f }, 200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_PADDEDCELL {1, 1.4f, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, { 0.0f,0.0f,0.0f }, 207, 0.002f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_ROOM {2, 1.9f, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, { 0.0f,0.0f,0.0f }, 53, 0.003f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_BATHROOM {3, 1.4f, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, { 0.0f,0.0f,0.0f }, 1030, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 60.0f, 0x3f } +#define FSOUND_PRESET_LIVINGROOM {4, 2.5f, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, { 0.0f,0.0f,0.0f }, -1104, 0.004f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_STONEROOM {5, 11.6f, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, { 0.0f,0.0f,0.0f }, 83, 0.017f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_AUDITORIUM {6, 21.6f, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, { 0.0f,0.0f,0.0f }, -289, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CONCERTHALL {7, 19.6f, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, { 0.0f,0.0f,0.0f }, -2, 0.029f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CAVE {8, 14.6f, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, { 0.0f,0.0f,0.0f }, -302, 0.022f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_ARENA {9, 36.2f, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, { 0.0f,0.0f,0.0f }, 16, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_HANGAR {10, 50.3f, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, { 0.0f,0.0f,0.0f }, 198, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CARPETTEDHALLWAY {11, 1.9f, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, { 0.0f,0.0f,0.0f }, -1630, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_HALLWAY {12, 1.8f, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, { 0.0f,0.0f,0.0f }, 441, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_STONECORRIDOR {13, 13.5f, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, { 0.0f,0.0f,0.0f }, 395, 0.020f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_ALLEY {14, 7.5f, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, { 0.0f,0.0f,0.0f }, -4, 0.011f, { 0.0f,0.0f,0.0f }, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_FOREST {15, 38.0f, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, { 0.0f,0.0f,0.0f }, -229, 0.088f, { 0.0f,0.0f,0.0f }, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 79.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_CITY {16, 7.5f, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, { 0.0f,0.0f,0.0f }, -1691, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 50.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_MOUNTAINS {17, 100.0f, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, { 0.0f,0.0f,0.0f }, -1434, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 27.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_QUARRY {18, 17.5f, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, { 0.0f,0.0f,0.0f }, 500, 0.025f, { 0.0f,0.0f,0.0f }, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_PLAIN {19, 42.5f, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, { 0.0f,0.0f,0.0f }, -1926, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 21.0f, 100.0f, 0x3f } +#define FSOUND_PRESET_PARKINGLOT {20, 8.3f, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, { 0.0f,0.0f,0.0f }, -1153, 0.012f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_SEWERPIPE {21, 1.7f, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, { 0.0f,0.0f,0.0f }, 1023, 0.021f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 80.0f, 60.0f, 0x3f } +#define FSOUND_PRESET_UNDERWATER {22, 1.8f, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, { 0.0f,0.0f,0.0f }, 1700, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f } + +/* Non I3DL2 presets */ + +#define FSOUND_PRESET_DRUGGED {23, 1.9f, 0.50f, -1000, 0, 0, 8.39f, 1.39f, 1.0f, -115, 0.002f, { 0.0f,0.0f,0.0f }, 985, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_DIZZY {24, 1.8f, 0.60f, -1000, -400, 0, 17.23f, 0.56f, 1.0f, -1713, 0.020f, { 0.0f,0.0f,0.0f }, -613, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } +#define FSOUND_PRESET_PSYCHOTIC {25, 1.0f, 0.50f, -1000, -151, 0, 7.56f, 0.91f, 1.0f, -626, 0.020f, { 0.0f,0.0f,0.0f }, 774, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f } + +/* PlayStation 2 and PlayStation Portable only presets */ + +#define FSOUND_PRESET_PS2_ROOM {1, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_STUDIO_A {2, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_STUDIO_B {3, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_STUDIO_C {4, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_HALL {5, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_SPACE {6, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_ECHO {7, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_DELAY {8, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } +#define FSOUND_PRESET_PS2_PIPE {9, 0, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f, 0.0f, 0000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0x31f } + +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining the properties for a reverb source, related to a FSOUND channel. + For more indepth descriptions of the reverb properties under win32, please see the EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + + Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). + Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then + the reverb should product a similar effect on either platform. + Linux and FMODCE do not support the reverb api. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [SEE_ALSO] + FSOUND_Reverb_SetChannelProperties + FSOUND_Reverb_GetChannelProperties + FSOUND_REVERB_CHANNELFLAGS +] +*/ +typedef struct _FSOUND_REVERB_CHANNELPROPERTIES /* MIN MAX DEFAULT */ +{ + int Direct; /* -10000, 1000, 0, direct path level (at low and mid frequencies) (WIN32/XBOX) */ + int DirectHF; /* -10000, 0, 0, relative direct path level at high frequencies (WIN32/XBOX) */ + int Room; /* -10000, 1000, 0, room effect level (at low and mid frequencies) (WIN32/XBOX/PS2) */ + int RoomHF; /* -10000, 0, 0, relative room effect level at high frequencies (WIN32/XBOX) */ + int Obstruction; /* -10000, 0, 0, main obstruction control (attenuation at high frequencies) (WIN32/XBOX) */ + float ObstructionLFRatio; /* 0.0, 1.0, 0.0, obstruction low-frequency level re. main control (WIN32/XBOX) */ + int Occlusion; /* -10000, 0, 0, main occlusion control (attenuation at high frequencies) (WIN32/XBOX) */ + float OcclusionLFRatio; /* 0.0, 1.0, 0.25, occlusion low-frequency level re. main control (WIN32/XBOX) */ + float OcclusionRoomRatio; /* 0.0, 10.0, 1.5, relative occlusion control for room effect (WIN32) */ + float OcclusionDirectRatio; /* 0.0, 10.0, 1.0, relative occlusion control for direct path (WIN32) */ + int Exclusion; /* -10000, 0, 0, main exlusion control (attenuation at high frequencies) (WIN32) */ + float ExclusionLFRatio; /* 0.0, 1.0, 1.0, exclusion low-frequency level re. main control (WIN32) */ + int OutsideVolumeHF; /* -10000, 0, 0, outside sound cone level at high frequencies (WIN32) */ + float DopplerFactor; /* 0.0, 10.0, 0.0, like DS3D flDopplerFactor but per source (WIN32) */ + float RolloffFactor; /* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but per source (WIN32) */ + float RoomRolloffFactor; /* 0.0, 10.0, 0.0, like DS3D flRolloffFactor but for room effect (WIN32/XBOX) */ + float AirAbsorptionFactor; /* 0.0, 10.0, 1.0, multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES (WIN32) */ + int Flags; /* FSOUND_REVERB_CHANNELFLAGS - modifies the behavior of properties (WIN32) */ +} FSOUND_REVERB_CHANNELPROPERTIES; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_REVERB_CHANNELFLAGS + + [DESCRIPTION] + Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure. + + [SEE_ALSO] + FSOUND_REVERB_CHANNELPROPERTIES +] +*/ +#define FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO 0x00000001 /* Automatic setting of 'Direct' due to distance from listener */ +#define FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO 0x00000002 /* Automatic setting of 'Room' due to distance from listener */ +#define FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO 0x00000004 /* Automatic setting of 'RoomHF' due to distance from listener */ +#define FSOUND_REVERB_CHANNELFLAGS_DEFAULT (FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO | \ + FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO| \ + FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO) +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel. + + [SEE_ALSO] + FSOUND_FX_Enable + FSOUND_FX_Disable + FSOUND_FX_SetChorus + FSOUND_FX_SetCompressor + FSOUND_FX_SetDistortion + FSOUND_FX_SetEcho + FSOUND_FX_SetFlanger + FSOUND_FX_SetGargle + FSOUND_FX_SetI3DL2Reverb + FSOUND_FX_SetParamEQ + FSOUND_FX_SetWavesReverb +] +*/ +enum FSOUND_FX_MODES +{ + FSOUND_FX_CHORUS, + FSOUND_FX_COMPRESSOR, + FSOUND_FX_DISTORTION, + FSOUND_FX_ECHO, + FSOUND_FX_FLANGER, + FSOUND_FX_GARGLE, + FSOUND_FX_I3DL2REVERB, + FSOUND_FX_PARAMEQ, + FSOUND_FX_WAVES_REVERB, + + FSOUND_FX_MAX +}; + +/* +[ENUM] +[ + [DESCRIPTION] + These are speaker types defined for use with the FSOUND_SetSpeakerMode command. + Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only + interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo. + + Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure. + + [SEE_ALSO] + FSOUND_SetSpeakerMode + +] +*/ +enum FSOUND_SPEAKERMODES +{ + FSOUND_SPEAKERMODE_DOLBYDIGITAL, /* Dolby Digital Output (XBOX or PC only). */ + FSOUND_SPEAKERMODE_HEADPHONES, /* The speakers are headphones. */ + FSOUND_SPEAKERMODE_MONO, /* The speakers are monaural. */ + FSOUND_SPEAKERMODE_QUAD, /* The speakers are quadraphonic. */ + FSOUND_SPEAKERMODE_STEREO, /* The speakers are stereo (default value). */ + FSOUND_SPEAKERMODE_SURROUND, /* The speakers are surround sound. */ + FSOUND_SPEAKERMODE_DTS, /* DTS output (XBOX only). */ + FSOUND_SPEAKERMODE_PROLOGIC2, /* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 doesnt support interior panning, but supports 48 voices simultaneously. */ + FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR /* Dolby Prologic 2. Playstation 2 and Gamecube only. PlayStation 2 does support interior panning, but only supports 24 voices simultaneously. */ +}; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_INIT_FLAGS + + [DESCRIPTION] + Initialization flags. Use them with FSOUND_Init in the flags parameter to change various behaviour. + + FSOUND_INIT_ENABLESYSTEMCHANNELFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects. + Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small. + This can be fixed with FSOUND_SetBufferSize. Increase the BufferSize until it works. + When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters. + + [SEE_ALSO] + FSOUND_Init +] +*/ +#define FSOUND_INIT_USEDEFAULTMIDISYNTH 0x0001 /* Win32 only - Causes MIDI playback to force software decoding. */ +#define FSOUND_INIT_GLOBALFOCUS 0x0002 /* Win32 only - For DirectSound output - sound is not muted when window is out of focus. */ +#define FSOUND_INIT_ENABLESYSTEMCHANNELFX 0x0004 /* Win32 only - For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! (use FSOUND_SYSTEMCHANNEL as channel id) */ +#define FSOUND_INIT_ACCURATEVULEVELS 0x0008 /* This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit */ +#define FSOUND_INIT_PS2_DISABLECORE0REVERB 0x0010 /* PS2 only - Disable reverb on CORE 0 (SPU2 voices 00-23) to regain SRAM */ +#define FSOUND_INIT_PS2_DISABLECORE1REVERB 0x0020 /* PS2 only - Disable reverb on CORE 1 (SPU2 voices 24-47) to regain SRAM */ +#define FSOUND_INIT_PS2_SWAPDMACORES 0x0040 /* PS2 only - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around */ +#define FSOUND_INIT_DONTLATENCYADJUST 0x0080 /* Callbacks are not latency adjusted, and are called at mix time. Also information functions are immediate */ +#define FSOUND_INIT_GC_INITLIBS 0x0100 /* GC only - Initializes GC audio libraries */ +#define FSOUND_INIT_STREAM_FROM_MAIN_THREAD 0x0200 /* Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user */ +#define FSOUND_INIT_PS2_USEVOLUMERAMPING 0x0400 /* PS2 only - Turns on volume ramping system to remove hardware clicks. */ +#define FSOUND_INIT_DSOUND_DEFERRED 0x0800 /* Win32 only - For DirectSound output. 3D commands are batched together and executed at FSOUND_Update. */ +#define FSOUND_INIT_DSOUND_HRTF_LIGHT 0x1000 /* Win32 only - For DirectSound output. FSOUND_HW3D buffers use a slightly higher quality algorithm when 3d hardware acceleration is not present. */ +#define FSOUND_INIT_DSOUND_HRTF_FULL 0x2000 /* Win32 only - For DirectSound output. FSOUND_HW3D buffers use full quality 3d playback when 3d hardware acceleration is not present. */ +#define FSOUND_INIT_XBOX_REMOVEHEADROOM 0x4000 /* XBox only - By default directsound attenuates all sound by 6db to avoid clipping/distortion. CAUTION. If you use this flag you are responsible for the final mix to make sure clipping / distortion doesn't happen. */ +#define FSOUND_INIT_PSP_SILENCEONUNDERRUN 0x8000 /* PSP only - If streams skip / stutter when device is powered on, either increase stream buffersize, or use this flag instead to play silence while the UMD is recovering. */ +/* [DEFINE_END] */ + + +/* +[ENUM] +[ + [DESCRIPTION] + Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream. + + [SEE_ALSO] + FSOUND_Stream_Net_GetStatus +] +*/ +enum FSOUND_STREAM_NET_STATUS +{ + FSOUND_STREAM_NET_NOTCONNECTED = 0, /* Stream hasn't connected yet */ + FSOUND_STREAM_NET_CONNECTING, /* Stream is connecting to remote host */ + FSOUND_STREAM_NET_BUFFERING, /* Stream is buffering data */ + FSOUND_STREAM_NET_READY, /* Stream is ready to play */ + FSOUND_STREAM_NET_ERROR /* Stream has suffered a fatal error */ +}; + + +/* +[ENUM] +[ + [DESCRIPTION] + Describes the type of a particular tag field. + + [SEE_ALSO] + FSOUND_Stream_GetNumTagFields + FSOUND_Stream_GetTagField + FSOUND_Stream_FindTagField +] +*/ +enum FSOUND_TAGFIELD_TYPE +{ + FSOUND_TAGFIELD_VORBISCOMMENT = 0, /* A vorbis comment */ + FSOUND_TAGFIELD_ID3V1, /* Part of an ID3v1 tag */ + FSOUND_TAGFIELD_ID3V2, /* An ID3v2 frame */ + FSOUND_TAGFIELD_SHOUTCAST, /* A SHOUTcast header line */ + FSOUND_TAGFIELD_ICECAST, /* An Icecast header line */ + FSOUND_TAGFIELD_ASF /* An Advanced Streaming Format header line */ +}; + + +/* +[DEFINE_START] +[ + [NAME] + FSOUND_STATUS_FLAGS + + [DESCRIPTION] + These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream. + + [SEE_ALSO] + FSOUND_Stream_Net_GetStatus +] +*/ +#define FSOUND_PROTOCOL_SHOUTCAST 0x00000001 +#define FSOUND_PROTOCOL_ICECAST 0x00000002 +#define FSOUND_PROTOCOL_HTTP 0x00000004 +#define FSOUND_FORMAT_MPEG 0x00010000 +#define FSOUND_FORMAT_OGGVORBIS 0x00020000 +/* [DEFINE_END] */ + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure defining a CD table of contents. This structure is returned as a tag from FSOUND_Stream_FindTagField when the tag name "CD_TOC" is specified. + Note: All tracks on the CD - including data tracks- will be represented in this structure so it's use for anything other than generating disc id information is not recommended. + See the cdda example program for info on retrieving and using this structure. + + [SEE_ALSO] + FSOUND_Stream_Open + FSOUND_Stream_FindTagField +] +*/ +typedef struct _FSOUND_TOC_TAG +{ + char name[4]; /* The string "TOC", just in case this structure is accidentally treated as a string */ + int numtracks; /* The number of tracks on the CD */ + int min[100]; /* The start offset of each track in minutes */ + int sec[100]; /* The start offset of each track in seconds */ + int frame[100]; /* The start offset of each track in frames */ + +} FSOUND_TOC_TAG; + + +/* ========================================================================================== */ +/* FUNCTION PROTOTYPES */ +/* ========================================================================================== */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ================================== */ +/* Initialization / Global functions. */ +/* ================================== */ + +/* + PRE - FSOUND_Init functions. These can't be called after FSOUND_Init is + called (they will fail). They set up FMOD system functionality. +*/ + +DLL_API signed char F_API FSOUND_SetOutput(int outputtype); +DLL_API signed char F_API FSOUND_SetDriver(int driver); +DLL_API signed char F_API FSOUND_SetMixer(int mixer); +DLL_API signed char F_API FSOUND_SetBufferSize(int len_ms); +DLL_API signed char F_API FSOUND_SetHWND(void *hwnd); +DLL_API signed char F_API FSOUND_SetMinHardwareChannels(int min); +DLL_API signed char F_API FSOUND_SetMaxHardwareChannels(int max); +DLL_API signed char F_API FSOUND_SetMemorySystem(void *pool, + int poollen, + FSOUND_ALLOCCALLBACK useralloc, + FSOUND_REALLOCCALLBACK userrealloc, + FSOUND_FREECALLBACK userfree); +/* + Main initialization / closedown functions. + Note : Use FSOUND_INIT_USEDEFAULTMIDISYNTH with FSOUND_Init for software override + with MIDI playback. + : Use FSOUND_INIT_GLOBALFOCUS with FSOUND_Init to make sound audible no matter + which window is in focus. (FSOUND_OUTPUT_DSOUND only) +*/ + +DLL_API signed char F_API FSOUND_Init(int mixrate, int maxsoftwarechannels, unsigned int flags); +DLL_API void F_API FSOUND_Close(); + +/* + Runtime system level functions +*/ + +DLL_API void F_API FSOUND_Update(); /* This is called to update 3d sound / non-realtime output */ + +DLL_API void F_API FSOUND_SetSpeakerMode(unsigned int speakermode); +DLL_API void F_API FSOUND_SetSFXMasterVolume(int volume); +DLL_API void F_API FSOUND_SetPanSeperation(float pansep); +DLL_API void F_API FSOUND_File_SetCallbacks(FSOUND_OPENCALLBACK useropen, + FSOUND_CLOSECALLBACK userclose, + FSOUND_READCALLBACK userread, + FSOUND_SEEKCALLBACK userseek, + FSOUND_TELLCALLBACK usertell); + +/* + System information functions. +*/ + +DLL_API int F_API FSOUND_GetError(); +DLL_API float F_API FSOUND_GetVersion(); +DLL_API int F_API FSOUND_GetOutput(); +DLL_API void * F_API FSOUND_GetOutputHandle(); +DLL_API int F_API FSOUND_GetDriver(); +DLL_API int F_API FSOUND_GetMixer(); +DLL_API int F_API FSOUND_GetNumDrivers(); +DLL_API const char * F_API FSOUND_GetDriverName(int id); +DLL_API signed char F_API FSOUND_GetDriverCaps(int id, unsigned int *caps); +DLL_API int F_API FSOUND_GetOutputRate(); +DLL_API int F_API FSOUND_GetMaxChannels(); +DLL_API int F_API FSOUND_GetMaxSamples(); +DLL_API unsigned int F_API FSOUND_GetSpeakerMode(); +DLL_API int F_API FSOUND_GetSFXMasterVolume(); +DLL_API signed char F_API FSOUND_GetNumHWChannels(int *num2d, int *num3d, int *total); +DLL_API int F_API FSOUND_GetChannelsPlaying(); +DLL_API float F_API FSOUND_GetCPUUsage(); +DLL_API void F_API FSOUND_GetMemoryStats(unsigned int *currentalloced, unsigned int *maxalloced); + +/* =================================== */ +/* Sample management / load functions. */ +/* =================================== */ + +/* + Sample creation and management functions + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Sample_Load to load from memory. + Use FSOUND_LOADRAW flag with FSOUND_Sample_Load to treat as as raw pcm data. +*/ + +DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length); +DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Alloc(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri); +DLL_API void F_API FSOUND_Sample_Free(FSOUND_SAMPLE *sptr); +DLL_API signed char F_API FSOUND_Sample_Upload(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode); +DLL_API signed char F_API FSOUND_Sample_Lock(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); +DLL_API signed char F_API FSOUND_Sample_Unlock(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); + +/* + Sample control functions +*/ + +DLL_API signed char F_API FSOUND_Sample_SetMode(FSOUND_SAMPLE *sptr, unsigned int mode); +DLL_API signed char F_API FSOUND_Sample_SetLoopPoints(FSOUND_SAMPLE *sptr, int loopstart, int loopend); +DLL_API signed char F_API FSOUND_Sample_SetDefaults(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri); +DLL_API signed char F_API FSOUND_Sample_SetDefaultsEx(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri, int varfreq, int varvol, int varpan); +DLL_API signed char F_API FSOUND_Sample_SetMinMaxDistance(FSOUND_SAMPLE *sptr, float min, float max); +DLL_API signed char F_API FSOUND_Sample_SetMaxPlaybacks(FSOUND_SAMPLE *sptr, int max); + +/* + Sample information functions +*/ + +DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Get(int sampno); +DLL_API const char * F_API FSOUND_Sample_GetName(FSOUND_SAMPLE *sptr); +DLL_API unsigned int F_API FSOUND_Sample_GetLength(FSOUND_SAMPLE *sptr); +DLL_API signed char F_API FSOUND_Sample_GetLoopPoints(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend); +DLL_API signed char F_API FSOUND_Sample_GetDefaults(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri); +DLL_API signed char F_API FSOUND_Sample_GetDefaultsEx(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri, int *varfreq, int *varvol, int *varpan); +DLL_API unsigned int F_API FSOUND_Sample_GetMode(FSOUND_SAMPLE *sptr); +DLL_API signed char F_API FSOUND_Sample_GetMinMaxDistance(FSOUND_SAMPLE *sptr, float *min, float *max); + +/* ============================ */ +/* Channel control functions. */ +/* ============================ */ + +/* + Playing and stopping sounds. + Note : Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. + Use FSOUND_ALL as the 'channel' variable to control ALL channels with one function call! +*/ + +DLL_API int F_API FSOUND_PlaySound(int channel, FSOUND_SAMPLE *sptr); +DLL_API int F_API FSOUND_PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused); +DLL_API signed char F_API FSOUND_StopSound(int channel); + +/* + Functions to control playback of a channel. + Note : FSOUND_ALL can be used on most of these functions as a channel value. +*/ + +DLL_API signed char F_API FSOUND_SetFrequency(int channel, int freq); +DLL_API signed char F_API FSOUND_SetVolume(int channel, int vol); +DLL_API signed char F_API FSOUND_SetVolumeAbsolute(int channel, int vol); +DLL_API signed char F_API FSOUND_SetPan(int channel, int pan); +DLL_API signed char F_API FSOUND_SetSurround(int channel, signed char surround); +DLL_API signed char F_API FSOUND_SetMute(int channel, signed char mute); +DLL_API signed char F_API FSOUND_SetPriority(int channel, int priority); +DLL_API signed char F_API FSOUND_SetReserved(int channel, signed char reserved); +DLL_API signed char F_API FSOUND_SetPaused(int channel, signed char paused); +DLL_API signed char F_API FSOUND_SetLoopMode(int channel, unsigned int loopmode); +DLL_API signed char F_API FSOUND_SetCurrentPosition(int channel, unsigned int offset); +DLL_API signed char F_API FSOUND_3D_SetAttributes(int channel, const float *pos, const float *vel); +DLL_API signed char F_API FSOUND_3D_SetMinMaxDistance(int channel, float min, float max); + +/* + Channel information functions. +*/ + +DLL_API signed char F_API FSOUND_IsPlaying(int channel); +DLL_API int F_API FSOUND_GetFrequency(int channel); +DLL_API int F_API FSOUND_GetVolume(int channel); +DLL_API int F_API FSOUND_GetAmplitude(int channel); +DLL_API int F_API FSOUND_GetPan(int channel); +DLL_API signed char F_API FSOUND_GetSurround(int channel); +DLL_API signed char F_API FSOUND_GetMute(int channel); +DLL_API int F_API FSOUND_GetPriority(int channel); +DLL_API signed char F_API FSOUND_GetReserved(int channel); +DLL_API signed char F_API FSOUND_GetPaused(int channel); +DLL_API unsigned int F_API FSOUND_GetLoopMode(int channel); +DLL_API unsigned int F_API FSOUND_GetCurrentPosition(int channel); +DLL_API FSOUND_SAMPLE * F_API FSOUND_GetCurrentSample(int channel); +DLL_API signed char F_API FSOUND_GetCurrentLevels(int channel, float *l, float *r); +DLL_API int F_API FSOUND_GetNumSubChannels(int channel); +DLL_API int F_API FSOUND_GetSubChannel(int channel, int subchannel); +DLL_API signed char F_API FSOUND_3D_GetAttributes(int channel, float *pos, float *vel); +DLL_API signed char F_API FSOUND_3D_GetMinMaxDistance(int channel, float *min, float *max); + +/* ========================== */ +/* Global 3D sound functions. */ +/* ========================== */ + +/* + See also 3d sample and channel based functions above. + Call FSOUND_Update once a frame to process 3d information. +*/ + +DLL_API void F_API FSOUND_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz); +DLL_API void F_API FSOUND_3D_Listener_GetAttributes(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz); +DLL_API void F_API FSOUND_3D_Listener_SetCurrent(int current, int numlisteners); /* use this if you use multiple listeners / splitscreen */ +DLL_API void F_API FSOUND_3D_SetDopplerFactor(float scale); +DLL_API void F_API FSOUND_3D_SetDistanceFactor(float scale); +DLL_API void F_API FSOUND_3D_SetRolloffFactor(float scale); + +/* =================== */ +/* FX functions. */ +/* =================== */ + +/* + Functions to control DX8 only effects processing. + + - FX enabled samples can only be played once at a time, not multiple times at once. + - Sounds have to be created with FSOUND_HW2D or FSOUND_HW3D for this to work. + - FSOUND_INIT_ENABLESYSTEMCHANNELFX can be used to apply hardware effect processing to the + global mixed output of FMOD's software channels. + - FSOUND_FX_Enable returns an FX handle that you can use to alter fx parameters. + - FSOUND_FX_Enable can be called multiple times in a row, even on the same FX type, + it will return a unique handle for each FX. + - FSOUND_FX_Enable cannot be called if the sound is playing or locked. + - FSOUND_FX_Disable must be called to reset/clear the FX from a channel. +*/ + +DLL_API int F_API FSOUND_FX_Enable(int channel, unsigned int fxtype); /* See FSOUND_FX_MODES */ +DLL_API signed char F_API FSOUND_FX_Disable(int channel); /* Disables all effects */ + +DLL_API signed char F_API FSOUND_FX_SetChorus(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); +DLL_API signed char F_API FSOUND_FX_SetCompressor(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay); +DLL_API signed char F_API FSOUND_FX_SetDistortion(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff); +DLL_API signed char F_API FSOUND_FX_SetEcho(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay); +DLL_API signed char F_API FSOUND_FX_SetFlanger(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); +DLL_API signed char F_API FSOUND_FX_SetGargle(int fxid, int RateHz, int WaveShape); +DLL_API signed char F_API FSOUND_FX_SetI3DL2Reverb(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference); +DLL_API signed char F_API FSOUND_FX_SetParamEQ(int fxid, float Center, float Bandwidth, float Gain); +DLL_API signed char F_API FSOUND_FX_SetWavesReverb(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio); + +/* ========================= */ +/* File Streaming functions. */ +/* ========================= */ + +/* + Note : Use FSOUND_LOADMEMORY flag with FSOUND_Stream_Open to stream from memory. + Use FSOUND_LOADRAW flag with FSOUND_Stream_Open to treat stream as raw pcm data. + Use FSOUND_MPEGACCURATE flag with FSOUND_Stream_Open to open mpegs in 'accurate mode' for settime/gettime/getlengthms. + Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. +*/ + +DLL_API signed char F_API FSOUND_Stream_SetBufferSize(int ms); /* call this before opening streams, not after */ + +DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Open(const char *name_or_data, unsigned int mode, int offset, int length); +DLL_API FSOUND_STREAM * F_API FSOUND_Stream_Create(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, void *userdata); +DLL_API signed char F_API FSOUND_Stream_Close(FSOUND_STREAM *stream); + +DLL_API int F_API FSOUND_Stream_Play(int channel, FSOUND_STREAM *stream); +DLL_API int F_API FSOUND_Stream_PlayEx(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused); +DLL_API signed char F_API FSOUND_Stream_Stop(FSOUND_STREAM *stream); + +DLL_API signed char F_API FSOUND_Stream_SetPosition(FSOUND_STREAM *stream, unsigned int position); +DLL_API unsigned int F_API FSOUND_Stream_GetPosition(FSOUND_STREAM *stream); +DLL_API signed char F_API FSOUND_Stream_SetTime(FSOUND_STREAM *stream, int ms); +DLL_API int F_API FSOUND_Stream_GetTime(FSOUND_STREAM *stream); +DLL_API int F_API FSOUND_Stream_GetLength(FSOUND_STREAM *stream); +DLL_API int F_API FSOUND_Stream_GetLengthMs(FSOUND_STREAM *stream); + +DLL_API signed char F_API FSOUND_Stream_SetMode(FSOUND_STREAM *stream, unsigned int mode); +DLL_API unsigned int F_API FSOUND_Stream_GetMode(FSOUND_STREAM *stream); +DLL_API signed char F_API FSOUND_Stream_SetLoopPoints(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm); +DLL_API signed char F_API FSOUND_Stream_SetLoopCount(FSOUND_STREAM *stream, int count); +DLL_API int F_API FSOUND_Stream_GetOpenState(FSOUND_STREAM *stream); /* use with FSOUND_NONBLOCKING opened streams */ +DLL_API FSOUND_SAMPLE * F_API FSOUND_Stream_GetSample(FSOUND_STREAM *stream); +DLL_API FSOUND_DSPUNIT * F_API FSOUND_Stream_CreateDSP(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, void *userdata); + +DLL_API signed char F_API FSOUND_Stream_SetEndCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata); +DLL_API signed char F_API FSOUND_Stream_SetSyncCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata); + +DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_AddSyncPoint(FSOUND_STREAM *stream, unsigned int pcmoffset, const char *name); +DLL_API signed char F_API FSOUND_Stream_DeleteSyncPoint(FSOUND_SYNCPOINT *point); +DLL_API int F_API FSOUND_Stream_GetNumSyncPoints(FSOUND_STREAM *stream); +DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_GetSyncPoint(FSOUND_STREAM *stream, int index); +DLL_API char * F_API FSOUND_Stream_GetSyncPointInfo(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset); + +DLL_API signed char F_API FSOUND_Stream_SetSubStream(FSOUND_STREAM *stream, int index); /* For FMOD .FSB bank files. */ +DLL_API int F_API FSOUND_Stream_GetNumSubStreams(FSOUND_STREAM *stream); /* For FMOD .FSB bank files. */ +DLL_API signed char F_API FSOUND_Stream_SetSubStreamSentence(FSOUND_STREAM *stream, const int *sentencelist, int numitems); + +DLL_API signed char F_API FSOUND_Stream_GetNumTagFields(FSOUND_STREAM *stream, int *num); +DLL_API signed char F_API FSOUND_Stream_GetTagField(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length); +DLL_API signed char F_API FSOUND_Stream_FindTagField(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length); + +/* + Internet streaming functions +*/ + +DLL_API signed char F_API FSOUND_Stream_Net_SetProxy(const char *proxy); +DLL_API signed char F_API FSOUND_Stream_Net_SetTimeout(int timeout); +DLL_API char * F_API FSOUND_Stream_Net_GetLastServerStatus(); +DLL_API signed char F_API FSOUND_Stream_Net_SetBufferProperties(int buffersize, int prebuffer_percent, int rebuffer_percent); +DLL_API signed char F_API FSOUND_Stream_Net_GetBufferProperties(int *buffersize, int *prebuffer_percent, int *rebuffer_percent); +DLL_API signed char F_API FSOUND_Stream_Net_SetMetadataCallback(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, void *userdata); +DLL_API signed char F_API FSOUND_Stream_Net_GetStatus(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags); + +/* =================== */ +/* CD audio functions. */ +/* =================== */ + +/* + Note : 0 = default cdrom. Otherwise specify the drive letter, for example. 'D'. +*/ + +DLL_API signed char F_API FSOUND_CD_Play(char drive, int track); +DLL_API void F_API FSOUND_CD_SetPlayMode(char drive, signed char mode); +DLL_API signed char F_API FSOUND_CD_Stop(char drive); +DLL_API signed char F_API FSOUND_CD_SetPaused(char drive, signed char paused); +DLL_API signed char F_API FSOUND_CD_SetVolume(char drive, int volume); +DLL_API signed char F_API FSOUND_CD_SetTrackTime(char drive, unsigned int ms); +DLL_API signed char F_API FSOUND_CD_OpenTray(char drive, signed char open); + +DLL_API signed char F_API FSOUND_CD_GetPaused(char drive); +DLL_API int F_API FSOUND_CD_GetTrack(char drive); +DLL_API int F_API FSOUND_CD_GetNumTracks(char drive); +DLL_API int F_API FSOUND_CD_GetVolume(char drive); +DLL_API int F_API FSOUND_CD_GetTrackLength(char drive, int track); +DLL_API int F_API FSOUND_CD_GetTrackTime(char drive); + +/* ============== */ +/* DSP functions. */ +/* ============== */ + +/* + DSP Unit control and information functions. + These functions allow you access to the mixed stream that FMOD uses to play back sound on. +*/ + +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_Create(FSOUND_DSPCALLBACK callback, int priority, void *userdata); +DLL_API void F_API FSOUND_DSP_Free(FSOUND_DSPUNIT *unit); +DLL_API void F_API FSOUND_DSP_SetPriority(FSOUND_DSPUNIT *unit, int priority); +DLL_API int F_API FSOUND_DSP_GetPriority(FSOUND_DSPUNIT *unit); +DLL_API void F_API FSOUND_DSP_SetActive(FSOUND_DSPUNIT *unit, signed char active); +DLL_API signed char F_API FSOUND_DSP_GetActive(FSOUND_DSPUNIT *unit); + +/* + Functions to get hold of FSOUND 'system DSP unit' handles. +*/ + +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClearUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetSFXUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetMusicUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetFFTUnit(); +DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClipAndCopyUnit(); + +/* + Miscellaneous DSP functions + Note for the spectrum analysis function to work, you have to enable the FFT DSP unit with + the following code FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); + It is off by default to save cpu usage. +*/ + +DLL_API signed char F_API FSOUND_DSP_MixBuffers(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode); +DLL_API void F_API FSOUND_DSP_ClearMixBuffer(); +DLL_API int F_API FSOUND_DSP_GetBufferLength(); /* Length of each DSP update */ +DLL_API int F_API FSOUND_DSP_GetBufferLengthTotal(); /* Total buffer length due to FSOUND_SetBufferSize */ +DLL_API float * F_API FSOUND_DSP_GetSpectrum(); /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */ + +/* =================================================================================== */ +/* Reverb functions. (eax2/eax3 reverb) (ONLY SUPPORTED ON WIN32 W/ FSOUND_HW3D FLAG) */ +/* =================================================================================== */ + +/* + See top of file for definitions and information on the reverb parameters. +*/ + +DLL_API signed char F_API FSOUND_Reverb_SetProperties(const FSOUND_REVERB_PROPERTIES *prop); +DLL_API signed char F_API FSOUND_Reverb_GetProperties(FSOUND_REVERB_PROPERTIES *prop); +DLL_API signed char F_API FSOUND_Reverb_SetChannelProperties(int channel, const FSOUND_REVERB_CHANNELPROPERTIES *prop); +DLL_API signed char F_API FSOUND_Reverb_GetChannelProperties(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); + +/* ===================================================== */ +/* Recording functions (ONLY SUPPORTED IN WIN32, WINCE) */ +/* ===================================================== */ + +/* + Recording initialization functions +*/ + +DLL_API signed char F_API FSOUND_Record_SetDriver(int outputtype); +DLL_API int F_API FSOUND_Record_GetNumDrivers(); +DLL_API const char * F_API FSOUND_Record_GetDriverName(int id); +DLL_API int F_API FSOUND_Record_GetDriver(); + +/* + Recording functionality. Only one recording session will work at a time. +*/ + +DLL_API signed char F_API FSOUND_Record_StartSample(FSOUND_SAMPLE *sptr, signed char loop); +DLL_API signed char F_API FSOUND_Record_Stop(); +DLL_API int F_API FSOUND_Record_GetPosition(); + +/* ========================================================================================== */ +/* FMUSIC API (MOD,S3M,XM,IT,MIDI PLAYBACK) */ +/* ========================================================================================== */ + +/* + Song management / playback functions. +*/ + +DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSong(const char *name); +DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSongEx(const char *name_or_data, int offset, int length, unsigned int mode, const int *samplelist, int samplelistnum); +DLL_API int F_API FMUSIC_GetOpenState(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_FreeSong(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_PlaySong(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_StopSong(FMUSIC_MODULE *mod); +DLL_API void F_API FMUSIC_StopAllSongs(); + +DLL_API signed char F_API FMUSIC_SetZxxCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback); +DLL_API signed char F_API FMUSIC_SetRowCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep); +DLL_API signed char F_API FMUSIC_SetOrderCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep); +DLL_API signed char F_API FMUSIC_SetInstCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument); + +DLL_API signed char F_API FMUSIC_SetSample(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr); +DLL_API signed char F_API FMUSIC_SetUserData(FMUSIC_MODULE *mod, void *userdata); +DLL_API signed char F_API FMUSIC_OptimizeChannels(FMUSIC_MODULE *mod, int maxchannels, int minvolume); + +/* + Runtime song functions. +*/ + +DLL_API signed char F_API FMUSIC_SetReverb(signed char reverb); /* MIDI only */ +DLL_API signed char F_API FMUSIC_SetLooping(FMUSIC_MODULE *mod, signed char looping); +DLL_API signed char F_API FMUSIC_SetOrder(FMUSIC_MODULE *mod, int order); +DLL_API signed char F_API FMUSIC_SetPaused(FMUSIC_MODULE *mod, signed char pause); +DLL_API signed char F_API FMUSIC_SetMasterVolume(FMUSIC_MODULE *mod, int volume); +DLL_API signed char F_API FMUSIC_SetMasterSpeed(FMUSIC_MODULE *mode, float speed); +DLL_API signed char F_API FMUSIC_SetPanSeperation(FMUSIC_MODULE *mod, float pansep); + +/* + Static song information functions. +*/ + +DLL_API const char * F_API FMUSIC_GetName(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetType(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumOrders(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumPatterns(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumInstruments(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumSamples(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetNumChannels(FMUSIC_MODULE *mod); +DLL_API FSOUND_SAMPLE * F_API FMUSIC_GetSample(FMUSIC_MODULE *mod, int sampno); +DLL_API int F_API FMUSIC_GetPatternLength(FMUSIC_MODULE *mod, int orderno); + +/* + Runtime song information. +*/ + +DLL_API signed char F_API FMUSIC_IsFinished(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_IsPlaying(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetMasterVolume(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetGlobalVolume(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetOrder(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetPattern(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetSpeed(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetBPM(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetRow(FMUSIC_MODULE *mod); +DLL_API signed char F_API FMUSIC_GetPaused(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetTime(FMUSIC_MODULE *mod); +DLL_API int F_API FMUSIC_GetRealChannel(FMUSIC_MODULE *mod, int modchannel); +DLL_API void * F_API FMUSIC_GetUserData(FMUSIC_MODULE *mod); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/fmodapi375win/api/inc/fmod_errors.h b/fmodapi375win/api/inc/fmod_errors.h new file mode 100644 index 0000000..b28b9c4 --- /dev/null +++ b/fmodapi375win/api/inc/fmod_errors.h @@ -0,0 +1,32 @@ +#ifndef _FMOD_ERRORS_H +#define _FMOD_ERRORS_H + +static char *FMOD_ErrorString(int errcode) +{ + switch (errcode) + { + case FMOD_ERR_NONE: return "No errors"; + case FMOD_ERR_BUSY: return "Cannot call this command after FSOUND_Init. Call FSOUND_Close first."; + case FMOD_ERR_UNINITIALIZED: return "This command failed because FSOUND_Init was not called"; + case FMOD_ERR_PLAY: return "Playing the sound failed."; + case FMOD_ERR_INIT: return "Error initializing output device."; + case FMOD_ERR_ALLOCATED: return "The output device is already in use and cannot be reused."; + case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the features needed for this soundsystem (16bit stereo output)"; + case FMOD_ERR_COOPERATIVELEVEL: return "Error setting cooperative level for hardware."; + case FMOD_ERR_CREATEBUFFER: return "Error creating hardware sound buffer."; + case FMOD_ERR_FILE_NOTFOUND: return "File not found"; + case FMOD_ERR_FILE_FORMAT: return "Unknown file format"; + case FMOD_ERR_FILE_BAD: return "Error loading file"; + case FMOD_ERR_MEMORY: return "Not enough memory "; + case FMOD_ERR_VERSION: return "The version number of this file format is not supported"; + case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function"; + case FMOD_ERR_NO_EAX: return "Tried to use an EAX command on a non EAX enabled channel or output."; + case FMOD_ERR_CHANNEL_ALLOC: return "Failed to allocate a new channel"; + case FMOD_ERR_RECORD: return "Recording not supported on this device"; + case FMOD_ERR_MEDIAPLAYER: return "Required Mediaplayer codec is not installed"; + + default : return "Unknown error"; + }; +} + +#endif diff --git a/fmodapi375win/api/inc/fmoddyn.h b/fmodapi375win/api/inc/fmoddyn.h new file mode 100644 index 0000000..4d5e38e --- /dev/null +++ b/fmodapi375win/api/inc/fmoddyn.h @@ -0,0 +1,546 @@ +/* =========================================================================================== */ +/* FMOD Dynamic DLL loading header. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004. */ +/* =========================================================================================== */ + +#ifndef _FMODDYN_H_ +#define _FMODDYN_H_ + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) + #include +#else + #include + #include +#endif +#include + +#include "fmod.h" + +typedef struct +{ + void *module; + + signed char (F_API *FSOUND_SetOutput)(int outputtype); + signed char (F_API *FSOUND_SetDriver)(int driver); + signed char (F_API *FSOUND_SetMixer)(int mixer); + signed char (F_API *FSOUND_SetBufferSize)(int len_ms); + signed char (F_API *FSOUND_SetHWND)(void *hwnd); + signed char (F_API *FSOUND_SetMinHardwareChannels)(int min); + signed char (F_API *FSOUND_SetMaxHardwareChannels)(int max); + signed char (F_API *FSOUND_SetMemorySystem)(void *pool, int poollen, FSOUND_ALLOCCALLBACK useralloc, FSOUND_REALLOCCALLBACK userrealloc, FSOUND_FREECALLBACK userfree); + signed char (F_API *FSOUND_Init)(int mixrate, int maxsoftwarechannels, unsigned int flags); + void (F_API *FSOUND_Close)(); + void (F_API *FSOUND_Update)(); /* you must call this once a frame */ + void (F_API *FSOUND_SetSpeakerMode)(unsigned int speakermode); + void (F_API *FSOUND_SetSFXMasterVolume)(int volume); + void (F_API *FSOUND_SetPanSeperation)(float pansep); + void (F_API *FSOUND_File_SetCallbacks)(FSOUND_OPENCALLBACK useropen, FSOUND_CLOSECALLBACK userclose, FSOUND_READCALLBACK userread, FSOUND_SEEKCALLBACK userseek, FSOUND_TELLCALLBACK usertell); + int (F_API *FSOUND_GetError)(); + float (F_API *FSOUND_GetVersion)(); + int (F_API *FSOUND_GetOutput)(); + void * (F_API *FSOUND_GetOutputHandle)(); + int (F_API *FSOUND_GetDriver)(); + int (F_API *FSOUND_GetMixer)(); + int (F_API *FSOUND_GetNumDrivers)(); + const char * (F_API *FSOUND_GetDriverName)(int id); + signed char (F_API *FSOUND_GetDriverCaps)(int id, unsigned int *caps); + int (F_API *FSOUND_GetOutputRate)(); + int (F_API *FSOUND_GetMaxChannels)(); + int (F_API *FSOUND_GetMaxSamples)(); + unsigned int (F_API *FSOUND_GetSpeakerMode)(); + int (F_API *FSOUND_GetSFXMasterVolume)(); + signed char (F_API *FSOUND_GetNumHWChannels)(int *num2d, int *num3d, int *total); + int (F_API *FSOUND_GetChannelsPlaying)(); + float (F_API *FSOUND_GetCPUUsage)(); + void (F_API *FSOUND_GetMemoryStats)(unsigned int *currentalloced, unsigned int *maxalloced); + FSOUND_SAMPLE * (F_API *FSOUND_Sample_Load)(int index, const char *name_or_data, unsigned int mode, int offset, int length); + FSOUND_SAMPLE * (F_API *FSOUND_Sample_Alloc)(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri); + void (F_API *FSOUND_Sample_Free)(FSOUND_SAMPLE *sptr); + signed char (F_API *FSOUND_Sample_Upload)(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode); + signed char (F_API *FSOUND_Sample_Lock)(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); + signed char (F_API *FSOUND_Sample_Unlock)(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); + signed char (F_API *FSOUND_Sample_SetMode)(FSOUND_SAMPLE *sptr, unsigned int mode); + signed char (F_API *FSOUND_Sample_SetLoopPoints)(FSOUND_SAMPLE *sptr, int loopstart, int loopend); + signed char (F_API *FSOUND_Sample_SetDefaults)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri); + signed char (F_API *FSOUND_Sample_SetDefaultsEx)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri, int varfreq, int varvol, int varpan); + signed char (F_API *FSOUND_Sample_SetMinMaxDistance)(FSOUND_SAMPLE *sptr, float min, float max); + signed char (F_API *FSOUND_Sample_SetMaxPlaybacks)(FSOUND_SAMPLE *sptr, int max); + FSOUND_SAMPLE * (F_API *FSOUND_Sample_Get)(int sampno); + const char * (F_API *FSOUND_Sample_GetName)(FSOUND_SAMPLE *sptr); + unsigned int (F_API *FSOUND_Sample_GetLength)(FSOUND_SAMPLE *sptr); + signed char (F_API *FSOUND_Sample_GetLoopPoints)(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend); + signed char (F_API *FSOUND_Sample_GetDefaults)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri); + signed char (F_API *FSOUND_Sample_GetDefaultsEx)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri, int *varfreq, int *varvol, int *varpan); + unsigned int (F_API *FSOUND_Sample_GetMode)(FSOUND_SAMPLE *sptr); + signed char (F_API *FSOUND_Sample_GetMinMaxDistance)(FSOUND_SAMPLE *sptr, float *min, float *max); + int (F_API *FSOUND_PlaySound)(int channel, FSOUND_SAMPLE *sptr); + int (F_API *FSOUND_PlaySoundEx)(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused); + signed char (F_API *FSOUND_StopSound)(int channel); + signed char (F_API *FSOUND_SetFrequency)(int channel, int freq); + signed char (F_API *FSOUND_SetVolume)(int channel, int vol); + signed char (F_API *FSOUND_SetVolumeAbsolute)(int channel, int vol); + signed char (F_API *FSOUND_SetPan)(int channel, int pan); + signed char (F_API *FSOUND_SetSurround)(int channel, signed char surround); + signed char (F_API *FSOUND_SetMute)(int channel, signed char mute); + signed char (F_API *FSOUND_SetPriority)(int channel, int priority); + signed char (F_API *FSOUND_SetReserved)(int channel, signed char reserved); + signed char (F_API *FSOUND_SetPaused)(int channel, signed char paused); + signed char (F_API *FSOUND_SetLoopMode)(int channel, unsigned int loopmode); + signed char (F_API *FSOUND_SetCurrentPosition)(int channel, unsigned int offset); + signed char (F_API *FSOUND_3D_SetAttributes)(int channel, const float *pos, const float *vel); + signed char (F_API *FSOUND_3D_SetMinMaxDistance)(int channel, float min, float max); + signed char (F_API *FSOUND_IsPlaying)(int channel); + int (F_API *FSOUND_GetFrequency)(int channel); + int (F_API *FSOUND_GetVolume)(int channel); + int (F_API *FSOUND_GetAmplitude)(int channel); + int (F_API *FSOUND_GetPan)(int channel); + signed char (F_API *FSOUND_GetSurround)(int channel); + signed char (F_API *FSOUND_GetMute)(int channel); + int (F_API *FSOUND_GetPriority)(int channel); + signed char (F_API *FSOUND_GetReserved)(int channel); + signed char (F_API *FSOUND_GetPaused)(int channel); + unsigned int (F_API *FSOUND_GetLoopMode)(int channel); + unsigned int (F_API *FSOUND_GetCurrentPosition)(int channel); + FSOUND_SAMPLE * (F_API *FSOUND_GetCurrentSample)(int channel); + signed char (F_API *FSOUND_GetCurrentLevels)(int channel, float *l, float *r); + int (F_API *FSOUND_GetNumSubChannels)(int channel); + int (F_API *FSOUND_GetSubChannel)(int channel, int subchannel); + signed char (F_API *FSOUND_3D_GetAttributes)(int channel, float *pos, float *vel); + signed char (F_API *FSOUND_3D_GetMinMaxDistance)(int channel, float *min, float *max); + void (F_API *FSOUND_3D_SetDopplerFactor)(float scale); + void (F_API *FSOUND_3D_SetDistanceFactor)(float scale); + void (F_API *FSOUND_3D_SetRolloffFactor)(float scale); + void (F_API *FSOUND_3D_Listener_SetCurrent)(int current, int numlisteners); /* use this if you use multiple listeners / splitscreen */ + void (F_API *FSOUND_3D_Listener_SetAttributes)(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz); + void (F_API *FSOUND_3D_Listener_GetAttributes)(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz); + int (F_API *FSOUND_FX_Enable)(int channel, unsigned int fx); /* See FSOUND_FX_MODES */ + signed char (F_API *FSOUND_FX_Disable)(int channel); + signed char (F_API *FSOUND_FX_SetChorus)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); + signed char (F_API *FSOUND_FX_SetCompressor)(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay); + signed char (F_API *FSOUND_FX_SetDistortion)(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff); + signed char (F_API *FSOUND_FX_SetEcho)(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay); + signed char (F_API *FSOUND_FX_SetFlanger)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); + signed char (F_API *FSOUND_FX_SetGargle)(int fxid, int RateHz, int WaveShape); + signed char (F_API *FSOUND_FX_SetI3DL2Reverb)(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference); + signed char (F_API *FSOUND_FX_SetParamEQ)(int fxid, float Center, float Bandwidth, float Gain); + signed char (F_API *FSOUND_FX_SetWavesReverb)(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio); + signed char (F_API *FSOUND_Stream_SetBufferSize)(int ms); /* call this before opening streams, not after */ + FSOUND_STREAM * (F_API *FSOUND_Stream_Open)(const char *name_or_data, unsigned int mode, int offset, int length); + FSOUND_STREAM * (F_API *FSOUND_Stream_Create)(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, void *userdata); + signed char (F_API *FSOUND_Stream_Close)(FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_Play)(int channel, FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_PlayEx)(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused); + signed char (F_API *FSOUND_Stream_Stop)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetPosition)(FSOUND_STREAM *stream, unsigned int position); + unsigned int (F_API *FSOUND_Stream_GetPosition)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetTime)(FSOUND_STREAM *stream, int ms); + int (F_API *FSOUND_Stream_GetTime)(FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_GetLength)(FSOUND_STREAM *stream); + int (F_API *FSOUND_Stream_GetLengthMs)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetMode)(FSOUND_STREAM *stream, unsigned int mode); + unsigned int (F_API *FSOUND_Stream_GetMode)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetLoopPoints)(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm); + signed char (F_API *FSOUND_Stream_SetLoopCount)(FSOUND_STREAM *stream, int count); + int (F_API *FSOUND_Stream_GetOpenState)(FSOUND_STREAM *stream); + FSOUND_SAMPLE * (F_API *FSOUND_Stream_GetSample)(FSOUND_STREAM *stream); /* every stream contains a sample to playback on */ + FSOUND_DSPUNIT * (F_API *FSOUND_Stream_CreateDSP)(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, void *userdata); + signed char (F_API *FSOUND_Stream_SetEndCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata); + signed char (F_API *FSOUND_Stream_SetSyncCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata); + FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_AddSyncPoint)(FSOUND_STREAM *stream, unsigned int pcmoffset, const char *name); + signed char (F_API *FSOUND_Stream_DeleteSyncPoint)(FSOUND_SYNCPOINT *point); + int (F_API *FSOUND_Stream_GetNumSyncPoints)(FSOUND_STREAM *stream); + FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_GetSyncPoint)(FSOUND_STREAM *stream, int index); + char * (F_API *FSOUND_Stream_GetSyncPointInfo)(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset); + signed char (F_API *FSOUND_Stream_SetSubStream)(FSOUND_STREAM *stream, int index); + int (F_API *FSOUND_Stream_GetNumSubStreams)(FSOUND_STREAM *stream); + signed char (F_API *FSOUND_Stream_SetSubStreamSentence)(FSOUND_STREAM *stream, const int *sentencelist, int numitems); + signed char (F_API *FSOUND_Stream_GetNumTagFields)(FSOUND_STREAM *stream, int *num); + signed char (F_API *FSOUND_Stream_GetTagField)(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length); + signed char (F_API *FSOUND_Stream_FindTagField)(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length); + signed char (F_API *FSOUND_Stream_Net_SetProxy)(const char *proxy); + signed char (F_API *FSOUND_Stream_Net_SetTimeout)(int timeout); + char * (F_API *FSOUND_Stream_Net_GetLastServerStatus)(); + signed char (F_API *FSOUND_Stream_Net_SetBufferProperties)(int buffersize, int prebuffer_percent, int rebuffer_percent); + signed char (F_API *FSOUND_Stream_Net_GetBufferProperties)(int *buffersize, int *prebuffer_percent, int *rebuffer_percent); + signed char (F_API *FSOUND_Stream_Net_SetMetadataCallback)(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, void *userdata); + signed char (F_API *FSOUND_Stream_Net_GetStatus)(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags); + signed char (F_API *FSOUND_CD_Play)(char drive, int track); + void (F_API *FSOUND_CD_SetPlayMode)(char drive, signed char mode); + signed char (F_API *FSOUND_CD_Stop)(char drive); + signed char (F_API *FSOUND_CD_SetPaused)(char drive, signed char paused); + signed char (F_API *FSOUND_CD_SetVolume)(char drive, int volume); + signed char (F_API *FSOUND_CD_SetTrackTime)(char drive, unsigned int ms); + signed char (F_API *FSOUND_CD_OpenTray)(char drive, signed char open); + signed char (F_API *FSOUND_CD_GetPaused)(char drive); + int (F_API *FSOUND_CD_GetTrack)(char drive); + int (F_API *FSOUND_CD_GetNumTracks)(char drive); + int (F_API *FSOUND_CD_GetVolume)(char drive); + int (F_API *FSOUND_CD_GetTrackLength)(char drive, int track); + int (F_API *FSOUND_CD_GetTrackTime)(char drive); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_Create)(FSOUND_DSPCALLBACK callback, int priority, void *userdata); + void (F_API *FSOUND_DSP_Free)(FSOUND_DSPUNIT *unit); + void (F_API *FSOUND_DSP_SetPriority)(FSOUND_DSPUNIT *unit, int priority); + int (F_API *FSOUND_DSP_GetPriority)(FSOUND_DSPUNIT *unit); + void (F_API *FSOUND_DSP_SetActive)(FSOUND_DSPUNIT *unit, signed char active); + signed char (F_API *FSOUND_DSP_GetActive)(FSOUND_DSPUNIT *unit); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClearUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetSFXUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetMusicUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetFFTUnit)(); + FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClipAndCopyUnit)(); + signed char (F_API *FSOUND_DSP_MixBuffers)(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode); + void (F_API *FSOUND_DSP_ClearMixBuffer)(); + int (F_API *FSOUND_DSP_GetBufferLength)(); /* Length of each DSP update */ + int (F_API *FSOUND_DSP_GetBufferLengthTotal)(); /* Total buffer length due to FSOUND_SetBufferSize */ + float * (F_API *FSOUND_DSP_GetSpectrum)(); /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */ + signed char (F_API *FSOUND_Reverb_SetProperties)(const FSOUND_REVERB_PROPERTIES *prop); + signed char (F_API *FSOUND_Reverb_GetProperties)(FSOUND_REVERB_PROPERTIES *prop); + signed char (F_API *FSOUND_Reverb_SetChannelProperties)(int channel, const FSOUND_REVERB_CHANNELPROPERTIES *prop); + signed char (F_API *FSOUND_Reverb_GetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); + signed char (F_API *FSOUND_Record_SetDriver)(int outputtype); + int (F_API *FSOUND_Record_GetNumDrivers)(); + const char * (F_API *FSOUND_Record_GetDriverName)(int id); + int (F_API *FSOUND_Record_GetDriver)(); + signed char (F_API *FSOUND_Record_StartSample)(FSOUND_SAMPLE *sptr, signed char loop); + signed char (F_API *FSOUND_Record_Stop)(); + int (F_API *FSOUND_Record_GetPosition)(); + FMUSIC_MODULE * (F_API *FMUSIC_LoadSong)(const char *name); + FMUSIC_MODULE * (F_API *FMUSIC_LoadSongEx)(const char *name_or_data, int offset, int length, unsigned int mode, const int *samplelist, int samplelistnum); + int (F_API *FMUSIC_GetOpenState)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_FreeSong)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_PlaySong)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_StopSong)(FMUSIC_MODULE *mod); + void (F_API *FMUSIC_StopAllSongs)(); + signed char (F_API *FMUSIC_SetZxxCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback); + signed char (F_API *FMUSIC_SetRowCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep); + signed char (F_API *FMUSIC_SetOrderCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep); + signed char (F_API *FMUSIC_SetInstCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument); + signed char (F_API *FMUSIC_SetSample)(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr); + signed char (F_API *FMUSIC_SetUserData)(FMUSIC_MODULE *mod, void *userdata); + signed char (F_API *FMUSIC_OptimizeChannels)(FMUSIC_MODULE *mod, int maxchannels, int minvolume); + signed char (F_API *FMUSIC_SetReverb)(signed char reverb); /* MIDI only */ + signed char (F_API *FMUSIC_SetLooping)(FMUSIC_MODULE *mod, signed char looping); + signed char (F_API *FMUSIC_SetOrder)(FMUSIC_MODULE *mod, int order); + signed char (F_API *FMUSIC_SetPaused)(FMUSIC_MODULE *mod, signed char pause); + signed char (F_API *FMUSIC_SetMasterVolume)(FMUSIC_MODULE *mod, int volume); + signed char (F_API *FMUSIC_SetMasterSpeed)(FMUSIC_MODULE *mode, float speed); + signed char (F_API *FMUSIC_SetPanSeperation)(FMUSIC_MODULE *mod, float pansep); + const char * (F_API *FMUSIC_GetName)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetType)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumOrders)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumPatterns)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumInstruments)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumSamples)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetNumChannels)(FMUSIC_MODULE *mod); + FSOUND_SAMPLE * (F_API *FMUSIC_GetSample)(FMUSIC_MODULE *mod, int sampno); + int (F_API *FMUSIC_GetPatternLength)(FMUSIC_MODULE *mod, int orderno); + signed char (F_API *FMUSIC_IsFinished)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_IsPlaying)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetMasterVolume)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetGlobalVolume)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetOrder)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetPattern)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetSpeed)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetBPM)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetRow)(FMUSIC_MODULE *mod); + signed char (F_API *FMUSIC_GetPaused)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetTime)(FMUSIC_MODULE *mod); + int (F_API *FMUSIC_GetRealChannel)(FMUSIC_MODULE *mod, int modchannel); + unsigned int (F_API *FMUSIC_GetUserData)(FMUSIC_MODULE *mod); +} FMOD_INSTANCE; + + +static FMOD_INSTANCE *FMOD_CreateInstance(char *dllName) +{ + FMOD_INSTANCE *instance; + + instance = (FMOD_INSTANCE *)calloc(sizeof(FMOD_INSTANCE), 1); + if (!instance) + { + return NULL; + } + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) + instance->module = LoadLibrary(dllName); +#else + instance->module = dlopen(dllName, RTLD_LAZY); +#endif + if (!instance->module) + { + free(instance); + return NULL; + } + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) + #define F_GETPROC(_x, _y) \ + { \ + *((unsigned int *)&instance->_x) = (unsigned int)GetProcAddress((HMODULE)instance->module, _y); \ + if (!instance->_x) \ + { \ + FreeLibrary((HMODULE)instance->module); \ + free(instance); \ + return NULL; \ + } \ + } +#else + #define F_GETPROC(_x, _y) \ + { \ + char tmp[] = _y; \ + *(strchr(tmp, '@')) = 0; \ + *((unsigned int *)&instance->_x) = (unsigned int)dlsym(instance->module, &tmp[1]); \ + if (!instance->_x) \ + { \ + dlclose(instance->module); \ + free(instance); \ + return NULL; \ + } \ + } +#endif + + F_GETPROC(FSOUND_SetOutput, "_FSOUND_SetOutput@4"); + F_GETPROC(FSOUND_SetDriver, "_FSOUND_SetDriver@4"); + F_GETPROC(FSOUND_SetMixer, "_FSOUND_SetMixer@4"); + F_GETPROC(FSOUND_SetBufferSize, "_FSOUND_SetBufferSize@4"); + F_GETPROC(FSOUND_SetHWND, "_FSOUND_SetHWND@4"); + F_GETPROC(FSOUND_SetMinHardwareChannels, "_FSOUND_SetMinHardwareChannels@4"); + F_GETPROC(FSOUND_SetMaxHardwareChannels, "_FSOUND_SetMaxHardwareChannels@4"); + F_GETPROC(FSOUND_SetMemorySystem, "_FSOUND_SetMemorySystem@20"); + F_GETPROC(FSOUND_Init, "_FSOUND_Init@12"); + F_GETPROC(FSOUND_Close, "_FSOUND_Close@0"); + F_GETPROC(FSOUND_Update, "_FSOUND_Update@0"); + F_GETPROC(FSOUND_SetSFXMasterVolume, "_FSOUND_SetSFXMasterVolume@4"); + F_GETPROC(FSOUND_SetPanSeperation, "_FSOUND_SetPanSeperation@4"); + F_GETPROC(FSOUND_SetSpeakerMode, "_FSOUND_SetSpeakerMode@4"); + F_GETPROC(FSOUND_GetError, "_FSOUND_GetError@0"); + F_GETPROC(FSOUND_GetVersion, "_FSOUND_GetVersion@0"); + F_GETPROC(FSOUND_GetOutput, "_FSOUND_GetOutput@0"); + F_GETPROC(FSOUND_GetOutputHandle, "_FSOUND_GetOutputHandle@0"); + F_GETPROC(FSOUND_GetDriver, "_FSOUND_GetDriver@0"); + F_GETPROC(FSOUND_GetMixer, "_FSOUND_GetMixer@0"); + F_GETPROC(FSOUND_GetNumDrivers, "_FSOUND_GetNumDrivers@0"); + F_GETPROC(FSOUND_GetDriverName, "_FSOUND_GetDriverName@4"); + F_GETPROC(FSOUND_GetDriverCaps, "_FSOUND_GetDriverCaps@8"); + F_GETPROC(FSOUND_GetOutputRate, "_FSOUND_GetOutputRate@0"); + F_GETPROC(FSOUND_GetMaxChannels, "_FSOUND_GetMaxChannels@0"); + F_GETPROC(FSOUND_GetMaxSamples, "_FSOUND_GetMaxSamples@0"); + F_GETPROC(FSOUND_GetSpeakerMode, "_FSOUND_GetSpeakerMode@0"); + F_GETPROC(FSOUND_GetSFXMasterVolume, "_FSOUND_GetSFXMasterVolume@0"); + F_GETPROC(FSOUND_GetNumHWChannels, "_FSOUND_GetNumHWChannels@12"); + F_GETPROC(FSOUND_GetChannelsPlaying, "_FSOUND_GetChannelsPlaying@0"); + F_GETPROC(FSOUND_GetCPUUsage, "_FSOUND_GetCPUUsage@0"); + F_GETPROC(FSOUND_GetMemoryStats, "_FSOUND_GetMemoryStats@8"); + F_GETPROC(FSOUND_Sample_Load, "_FSOUND_Sample_Load@20"); + F_GETPROC(FSOUND_Sample_Alloc, "_FSOUND_Sample_Alloc@28"); + F_GETPROC(FSOUND_Sample_Free, "_FSOUND_Sample_Free@4"); + F_GETPROC(FSOUND_Sample_Upload, "_FSOUND_Sample_Upload@12"); + F_GETPROC(FSOUND_Sample_Lock, "_FSOUND_Sample_Lock@28"); + F_GETPROC(FSOUND_Sample_Unlock, "_FSOUND_Sample_Unlock@20"); + F_GETPROC(FSOUND_Sample_SetMode, "_FSOUND_Sample_SetMode@8"); + F_GETPROC(FSOUND_Sample_SetLoopPoints, "_FSOUND_Sample_SetLoopPoints@12"); + F_GETPROC(FSOUND_Sample_SetDefaults, "_FSOUND_Sample_SetDefaults@20"); + F_GETPROC(FSOUND_Sample_SetDefaultsEx, "_FSOUND_Sample_SetDefaultsEx@32"); + F_GETPROC(FSOUND_Sample_SetMinMaxDistance, "_FSOUND_Sample_SetMinMaxDistance@12"); + F_GETPROC(FSOUND_Sample_SetMaxPlaybacks, "_FSOUND_Sample_SetMaxPlaybacks@8"); + F_GETPROC(FSOUND_Sample_Get, "_FSOUND_Sample_Get@4"); + F_GETPROC(FSOUND_Sample_GetName, "_FSOUND_Sample_GetName@4"); + F_GETPROC(FSOUND_Sample_GetLength, "_FSOUND_Sample_GetLength@4"); + F_GETPROC(FSOUND_Sample_GetLoopPoints, "_FSOUND_Sample_GetLoopPoints@12"); + F_GETPROC(FSOUND_Sample_GetDefaults, "_FSOUND_Sample_GetDefaults@20"); + F_GETPROC(FSOUND_Sample_GetDefaultsEx, "_FSOUND_Sample_GetDefaultsEx@32"); + F_GETPROC(FSOUND_Sample_GetMode, "_FSOUND_Sample_GetMode@4"); + F_GETPROC(FSOUND_Sample_GetMinMaxDistance, "_FSOUND_Sample_GetMinMaxDistance@12"); + F_GETPROC(FSOUND_PlaySound, "_FSOUND_PlaySound@8"); + F_GETPROC(FSOUND_PlaySoundEx, "_FSOUND_PlaySoundEx@16"); + F_GETPROC(FSOUND_StopSound, "_FSOUND_StopSound@4"); + F_GETPROC(FSOUND_SetFrequency, "_FSOUND_SetFrequency@8"); + F_GETPROC(FSOUND_SetVolume, "_FSOUND_SetVolume@8"); + F_GETPROC(FSOUND_SetVolumeAbsolute, "_FSOUND_SetVolumeAbsolute@8"); + F_GETPROC(FSOUND_SetPan, "_FSOUND_SetPan@8"); + F_GETPROC(FSOUND_SetSurround, "_FSOUND_SetSurround@8"); + F_GETPROC(FSOUND_SetMute, "_FSOUND_SetMute@8"); + F_GETPROC(FSOUND_SetPriority, "_FSOUND_SetPriority@8"); + F_GETPROC(FSOUND_SetReserved, "_FSOUND_SetReserved@8"); + F_GETPROC(FSOUND_SetPaused, "_FSOUND_SetPaused@8"); + F_GETPROC(FSOUND_SetLoopMode, "_FSOUND_SetLoopMode@8"); + F_GETPROC(FSOUND_SetCurrentPosition, "_FSOUND_SetCurrentPosition@8"); + F_GETPROC(FSOUND_3D_SetAttributes, "_FSOUND_3D_SetAttributes@12"); + F_GETPROC(FSOUND_3D_SetMinMaxDistance, "_FSOUND_3D_SetMinMaxDistance@12"); + F_GETPROC(FSOUND_IsPlaying, "_FSOUND_IsPlaying@4"); + F_GETPROC(FSOUND_GetFrequency, "_FSOUND_GetFrequency@4"); + F_GETPROC(FSOUND_GetVolume, "_FSOUND_GetVolume@4"); + F_GETPROC(FSOUND_GetAmplitude, "_FSOUND_GetAmplitude@4"); + F_GETPROC(FSOUND_GetPan, "_FSOUND_GetPan@4"); + F_GETPROC(FSOUND_GetSurround, "_FSOUND_GetSurround@4"); + F_GETPROC(FSOUND_GetMute, "_FSOUND_GetMute@4"); + F_GETPROC(FSOUND_GetPriority, "_FSOUND_GetPriority@4"); + F_GETPROC(FSOUND_GetReserved, "_FSOUND_GetReserved@4"); + F_GETPROC(FSOUND_GetPaused, "_FSOUND_GetPaused@4"); + F_GETPROC(FSOUND_GetLoopMode, "_FSOUND_GetLoopMode@4"); + F_GETPROC(FSOUND_GetCurrentPosition, "_FSOUND_GetCurrentPosition@4"); + F_GETPROC(FSOUND_GetCurrentSample, "_FSOUND_GetCurrentSample@4"); + F_GETPROC(FSOUND_GetCurrentLevels, "_FSOUND_GetCurrentLevels@12"); + F_GETPROC(FSOUND_GetNumSubChannels, "_FSOUND_GetNumSubChannels@4"); + F_GETPROC(FSOUND_GetSubChannel, "_FSOUND_GetSubChannel@8"); + F_GETPROC(FSOUND_3D_GetAttributes, "_FSOUND_3D_GetAttributes@12"); + F_GETPROC(FSOUND_3D_GetMinMaxDistance, "_FSOUND_3D_GetMinMaxDistance@12"); + F_GETPROC(FSOUND_3D_Listener_SetCurrent, "_FSOUND_3D_Listener_SetCurrent@8"); + F_GETPROC(FSOUND_3D_Listener_SetAttributes, "_FSOUND_3D_Listener_SetAttributes@32"); + F_GETPROC(FSOUND_3D_Listener_GetAttributes, "_FSOUND_3D_Listener_GetAttributes@32"); + F_GETPROC(FSOUND_3D_SetDopplerFactor, "_FSOUND_3D_SetDopplerFactor@4"); + F_GETPROC(FSOUND_3D_SetDistanceFactor, "_FSOUND_3D_SetDistanceFactor@4"); + F_GETPROC(FSOUND_3D_SetRolloffFactor, "_FSOUND_3D_SetRolloffFactor@4"); + F_GETPROC(FSOUND_FX_Enable, "_FSOUND_FX_Enable@8"); + F_GETPROC(FSOUND_FX_Disable, "_FSOUND_FX_Disable@4"); + F_GETPROC(FSOUND_FX_SetChorus, "_FSOUND_FX_SetChorus@32"); + F_GETPROC(FSOUND_FX_SetCompressor, "_FSOUND_FX_SetCompressor@28"); + F_GETPROC(FSOUND_FX_SetDistortion, "_FSOUND_FX_SetDistortion@24"); + F_GETPROC(FSOUND_FX_SetEcho, "_FSOUND_FX_SetEcho@24"); + F_GETPROC(FSOUND_FX_SetFlanger, "_FSOUND_FX_SetFlanger@32"); + F_GETPROC(FSOUND_FX_SetGargle, "_FSOUND_FX_SetGargle@12"); + F_GETPROC(FSOUND_FX_SetI3DL2Reverb, "_FSOUND_FX_SetI3DL2Reverb@52"); + F_GETPROC(FSOUND_FX_SetParamEQ, "_FSOUND_FX_SetParamEQ@16"); + F_GETPROC(FSOUND_FX_SetWavesReverb, "_FSOUND_FX_SetWavesReverb@20"); + F_GETPROC(FSOUND_Stream_Open, "_FSOUND_Stream_Open@16"); + F_GETPROC(FSOUND_Stream_Create, "_FSOUND_Stream_Create@20"); + F_GETPROC(FSOUND_Stream_Play, "_FSOUND_Stream_Play@8"); + F_GETPROC(FSOUND_Stream_PlayEx, "_FSOUND_Stream_PlayEx@16"); + F_GETPROC(FSOUND_Stream_Stop, "_FSOUND_Stream_Stop@4"); + F_GETPROC(FSOUND_Stream_Close, "_FSOUND_Stream_Close@4"); + F_GETPROC(FSOUND_Stream_SetEndCallback, "_FSOUND_Stream_SetEndCallback@12"); + F_GETPROC(FSOUND_Stream_SetSyncCallback, "_FSOUND_Stream_SetSyncCallback@12"); + F_GETPROC(FSOUND_Stream_GetSample, "_FSOUND_Stream_GetSample@4"); + F_GETPROC(FSOUND_Stream_CreateDSP, "_FSOUND_Stream_CreateDSP@16"); + F_GETPROC(FSOUND_Stream_SetBufferSize, "_FSOUND_Stream_SetBufferSize@4"); + F_GETPROC(FSOUND_Stream_SetPosition, "_FSOUND_Stream_SetPosition@8"); + F_GETPROC(FSOUND_Stream_GetPosition, "_FSOUND_Stream_GetPosition@4"); + F_GETPROC(FSOUND_Stream_SetTime, "_FSOUND_Stream_SetTime@8"); + F_GETPROC(FSOUND_Stream_GetTime, "_FSOUND_Stream_GetTime@4"); + F_GETPROC(FSOUND_Stream_GetLength, "_FSOUND_Stream_GetLength@4"); + F_GETPROC(FSOUND_Stream_GetLengthMs, "_FSOUND_Stream_GetLengthMs@4"); + F_GETPROC(FSOUND_Stream_SetMode, "_FSOUND_Stream_SetMode@8"); + F_GETPROC(FSOUND_Stream_GetMode, "_FSOUND_Stream_GetMode@4"); + F_GETPROC(FSOUND_Stream_SetSubStream, "_FSOUND_Stream_SetSubStream@8"); + F_GETPROC(FSOUND_Stream_GetNumSubStreams, "_FSOUND_Stream_GetNumSubStreams@4"); + F_GETPROC(FSOUND_Stream_SetSubStreamSentence, "_FSOUND_Stream_SetSubStreamSentence@12"); + F_GETPROC(FSOUND_Stream_SetLoopPoints, "_FSOUND_Stream_SetLoopPoints@12"); + F_GETPROC(FSOUND_Stream_SetLoopCount, "_FSOUND_Stream_SetLoopCount@8"); + F_GETPROC(FSOUND_Stream_AddSyncPoint, "_FSOUND_Stream_AddSyncPoint@12"); + F_GETPROC(FSOUND_Stream_DeleteSyncPoint, "_FSOUND_Stream_DeleteSyncPoint@4"); + F_GETPROC(FSOUND_Stream_GetNumSyncPoints, "_FSOUND_Stream_GetNumSyncPoints@4"); + F_GETPROC(FSOUND_Stream_GetSyncPoint, "_FSOUND_Stream_GetSyncPoint@8"); + F_GETPROC(FSOUND_Stream_GetSyncPointInfo, "_FSOUND_Stream_GetSyncPointInfo@8"); + F_GETPROC(FSOUND_Stream_GetOpenState, "_FSOUND_Stream_GetOpenState@4"); + F_GETPROC(FSOUND_Stream_GetNumTagFields, "_FSOUND_Stream_GetNumTagFields@8"); + F_GETPROC(FSOUND_Stream_GetTagField, "_FSOUND_Stream_GetTagField@24"); + F_GETPROC(FSOUND_Stream_FindTagField, "_FSOUND_Stream_FindTagField@20"); + F_GETPROC(FSOUND_Stream_Net_SetProxy, "_FSOUND_Stream_Net_SetProxy@4"); + F_GETPROC(FSOUND_Stream_Net_GetLastServerStatus, "_FSOUND_Stream_Net_GetLastServerStatus@0"); + F_GETPROC(FSOUND_Stream_Net_SetBufferProperties, "_FSOUND_Stream_Net_SetBufferProperties@12"); + F_GETPROC(FSOUND_Stream_Net_GetBufferProperties, "_FSOUND_Stream_Net_GetBufferProperties@12"); + F_GETPROC(FSOUND_Stream_Net_SetMetadataCallback, "_FSOUND_Stream_Net_SetMetadataCallback@12"); + F_GETPROC(FSOUND_Stream_Net_GetStatus, "_FSOUND_Stream_Net_GetStatus@20"); + F_GETPROC(FSOUND_CD_Play, "_FSOUND_CD_Play@8"); + F_GETPROC(FSOUND_CD_SetPlayMode, "_FSOUND_CD_SetPlayMode@8"); + F_GETPROC(FSOUND_CD_Stop, "_FSOUND_CD_Stop@4"); + F_GETPROC(FSOUND_CD_SetPaused, "_FSOUND_CD_SetPaused@8"); + F_GETPROC(FSOUND_CD_SetVolume, "_FSOUND_CD_SetVolume@8"); + F_GETPROC(FSOUND_CD_SetTrackTime, "_FSOUND_CD_SetTrackTime@8"); + F_GETPROC(FSOUND_CD_OpenTray, "_FSOUND_CD_OpenTray@8"); + F_GETPROC(FSOUND_CD_GetPaused, "_FSOUND_CD_GetPaused@4"); + F_GETPROC(FSOUND_CD_GetTrack, "_FSOUND_CD_GetTrack@4"); + F_GETPROC(FSOUND_CD_GetNumTracks, "_FSOUND_CD_GetNumTracks@4"); + F_GETPROC(FSOUND_CD_GetVolume, "_FSOUND_CD_GetVolume@4"); + F_GETPROC(FSOUND_CD_GetTrackLength, "_FSOUND_CD_GetTrackLength@8"); + F_GETPROC(FSOUND_CD_GetTrackTime, "_FSOUND_CD_GetTrackTime@4"); + F_GETPROC(FSOUND_DSP_Create, "_FSOUND_DSP_Create@12"); + F_GETPROC(FSOUND_DSP_Free, "_FSOUND_DSP_Free@4"); + F_GETPROC(FSOUND_DSP_SetPriority, "_FSOUND_DSP_SetPriority@8"); + F_GETPROC(FSOUND_DSP_GetPriority, "_FSOUND_DSP_GetPriority@4"); + F_GETPROC(FSOUND_DSP_SetActive, "_FSOUND_DSP_SetActive@8"); + F_GETPROC(FSOUND_DSP_GetActive, "_FSOUND_DSP_GetActive@4"); + F_GETPROC(FSOUND_DSP_GetClearUnit, "_FSOUND_DSP_GetClearUnit@0"); + F_GETPROC(FSOUND_DSP_GetSFXUnit, "_FSOUND_DSP_GetSFXUnit@0"); + F_GETPROC(FSOUND_DSP_GetMusicUnit, "_FSOUND_DSP_GetMusicUnit@0"); + F_GETPROC(FSOUND_DSP_GetClipAndCopyUnit, "_FSOUND_DSP_GetClipAndCopyUnit@0"); + F_GETPROC(FSOUND_DSP_GetFFTUnit, "_FSOUND_DSP_GetFFTUnit@0"); + F_GETPROC(FSOUND_DSP_MixBuffers, "_FSOUND_DSP_MixBuffers@28"); + F_GETPROC(FSOUND_DSP_ClearMixBuffer, "_FSOUND_DSP_ClearMixBuffer@0"); + F_GETPROC(FSOUND_DSP_GetBufferLength, "_FSOUND_DSP_GetBufferLength@0"); + F_GETPROC(FSOUND_DSP_GetBufferLengthTotal, "_FSOUND_DSP_GetBufferLengthTotal@0"); + F_GETPROC(FSOUND_DSP_GetSpectrum, "_FSOUND_DSP_GetSpectrum@0"); + F_GETPROC(FSOUND_Reverb_SetProperties, "_FSOUND_Reverb_SetProperties@4"); + F_GETPROC(FSOUND_Reverb_GetProperties, "_FSOUND_Reverb_GetProperties@4"); + F_GETPROC(FSOUND_Reverb_SetChannelProperties, "_FSOUND_Reverb_SetChannelProperties@8"); + F_GETPROC(FSOUND_Reverb_GetChannelProperties, "_FSOUND_Reverb_GetChannelProperties@8"); + F_GETPROC(FSOUND_Record_SetDriver, "_FSOUND_Record_SetDriver@4"); + F_GETPROC(FSOUND_Record_GetNumDrivers, "_FSOUND_Record_GetNumDrivers@0"); + F_GETPROC(FSOUND_Record_GetDriverName, "_FSOUND_Record_GetDriverName@4"); + F_GETPROC(FSOUND_Record_GetDriver, "_FSOUND_Record_GetDriver@0"); + F_GETPROC(FSOUND_Record_StartSample, "_FSOUND_Record_StartSample@8"); + F_GETPROC(FSOUND_Record_Stop, "_FSOUND_Record_Stop@0"); + F_GETPROC(FSOUND_Record_GetPosition, "_FSOUND_Record_GetPosition@0"); + F_GETPROC(FSOUND_File_SetCallbacks, "_FSOUND_File_SetCallbacks@20"); + F_GETPROC(FMUSIC_LoadSong, "_FMUSIC_LoadSong@4"); + F_GETPROC(FMUSIC_LoadSongEx, "_FMUSIC_LoadSongEx@24"); + F_GETPROC(FMUSIC_GetOpenState, "_FMUSIC_GetOpenState@4"); + F_GETPROC(FMUSIC_FreeSong, "_FMUSIC_FreeSong@4"); + F_GETPROC(FMUSIC_PlaySong, "_FMUSIC_PlaySong@4"); + F_GETPROC(FMUSIC_StopSong, "_FMUSIC_StopSong@4"); + F_GETPROC(FMUSIC_StopAllSongs, "_FMUSIC_StopAllSongs@0"); + F_GETPROC(FMUSIC_SetZxxCallback, "_FMUSIC_SetZxxCallback@8"); + F_GETPROC(FMUSIC_SetRowCallback, "_FMUSIC_SetRowCallback@12"); + F_GETPROC(FMUSIC_SetOrderCallback, "_FMUSIC_SetOrderCallback@12"); + F_GETPROC(FMUSIC_SetInstCallback, "_FMUSIC_SetInstCallback@12"); + F_GETPROC(FMUSIC_SetSample, "_FMUSIC_SetSample@12"); + F_GETPROC(FMUSIC_SetUserData, "_FMUSIC_SetUserData@8"); + F_GETPROC(FMUSIC_OptimizeChannels, "_FMUSIC_OptimizeChannels@12"); + F_GETPROC(FMUSIC_SetReverb, "_FMUSIC_SetReverb@4"); + F_GETPROC(FMUSIC_SetLooping, "_FMUSIC_SetLooping@8"); + F_GETPROC(FMUSIC_SetOrder, "_FMUSIC_SetOrder@8"); + F_GETPROC(FMUSIC_SetPaused, "_FMUSIC_SetPaused@8"); + F_GETPROC(FMUSIC_SetMasterVolume, "_FMUSIC_SetMasterVolume@8"); + F_GETPROC(FMUSIC_SetMasterSpeed, "_FMUSIC_SetMasterSpeed@8"); + F_GETPROC(FMUSIC_SetPanSeperation, "_FMUSIC_SetPanSeperation@8"); + F_GETPROC(FMUSIC_GetName, "_FMUSIC_GetName@4"); + F_GETPROC(FMUSIC_GetType, "_FMUSIC_GetType@4"); + F_GETPROC(FMUSIC_GetNumOrders, "_FMUSIC_GetNumOrders@4"); + F_GETPROC(FMUSIC_GetNumPatterns, "_FMUSIC_GetNumPatterns@4"); + F_GETPROC(FMUSIC_GetNumInstruments, "_FMUSIC_GetNumInstruments@4"); + F_GETPROC(FMUSIC_GetNumSamples, "_FMUSIC_GetNumSamples@4"); + F_GETPROC(FMUSIC_GetNumChannels, "_FMUSIC_GetNumChannels@4"); + F_GETPROC(FMUSIC_GetSample, "_FMUSIC_GetSample@8"); + F_GETPROC(FMUSIC_GetPatternLength, "_FMUSIC_GetPatternLength@8"); + F_GETPROC(FMUSIC_IsFinished, "_FMUSIC_IsFinished@4"); + F_GETPROC(FMUSIC_IsPlaying, "_FMUSIC_IsPlaying@4"); + F_GETPROC(FMUSIC_GetMasterVolume, "_FMUSIC_GetMasterVolume@4"); + F_GETPROC(FMUSIC_GetGlobalVolume, "_FMUSIC_GetGlobalVolume@4"); + F_GETPROC(FMUSIC_GetOrder, "_FMUSIC_GetOrder@4"); + F_GETPROC(FMUSIC_GetPattern, "_FMUSIC_GetPattern@4"); + F_GETPROC(FMUSIC_GetSpeed, "_FMUSIC_GetSpeed@4"); + F_GETPROC(FMUSIC_GetBPM, "_FMUSIC_GetBPM@4"); + F_GETPROC(FMUSIC_GetRow, "_FMUSIC_GetRow@4"); + F_GETPROC(FMUSIC_GetPaused, "_FMUSIC_GetPaused@4"); + F_GETPROC(FMUSIC_GetTime, "_FMUSIC_GetTime@4"); + F_GETPROC(FMUSIC_GetRealChannel, "_FMUSIC_GetRealChannel@8"); + F_GETPROC(FMUSIC_GetUserData, "_FMUSIC_GetUserData@4"); + + return instance; +} + +static void FMOD_FreeInstance(FMOD_INSTANCE *instance) +{ + if (instance) + { + if (instance->module) + { +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) + FreeLibrary((HMODULE)instance->module); +#else + dlclose(instance->module); +#endif + } + free(instance); + } +} + +#endif + diff --git a/fmodapi375win/api/inc/wincompat.h b/fmodapi375win/api/inc/wincompat.h new file mode 100644 index 0000000..f660001 --- /dev/null +++ b/fmodapi375win/api/inc/wincompat.h @@ -0,0 +1,81 @@ +#if !defined(WINCOMPAT_INCLUDED) && !defined(PLATFORM_WINDOWS) && !defined(WIN32) && !defined(WINDOWS) && !defined(__WIN32__) +#define WINCOMPAT_INCLUDED + +/** + * + * Author: Magnus Naeslund (mag@fbab.net, mag@bahnhof.se) + * (c) 2000 Magnus Naeslund, all rights reserved + * + */ + +#include +#include +#include +#include +#include +#include + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +#define _kbhit kbhit +#define stricmp strcasecmp +#define strnicmp strncasecmp + +#define Sleep(x) usleep((x)*1000) + +static int inited=0; +static struct termios ori; + +static void tcatexit(){ + tcsetattr(0,0,&ori); +} + +static void init_terminal(){ + struct termios t; + tcgetattr(0,&t); + tcgetattr(0,&ori); + t.c_lflag &= ~(ICANON); + tcsetattr(0,0,&t); + atexit(tcatexit); +} + +static inline int kbhit(){ + fd_set rfds; + struct timeval tv; + + if (!inited){ + inited=1; + init_terminal(); + } + + FD_ZERO(&rfds); + FD_SET(0, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 10*1000; + return select(1, &rfds, NULL, NULL, &tv)>0; +} + +static inline int getch(){ + fd_set rfds; + + if (!inited){ + inited=1; + init_terminal(); + } + + FD_ZERO(&rfds); + FD_SET(0, &rfds); + if (select(1, &rfds, NULL, NULL, NULL)>0) + return getchar(); + else{ + printf("wincompat.h: select() on fd 0 failed\n"); + return 0xDeadBeef; + } +} + +#endif diff --git a/fmodapi375win/api/lib/fmod64vc.lib b/fmodapi375win/api/lib/fmod64vc.lib new file mode 100644 index 0000000..f0369df Binary files /dev/null and b/fmodapi375win/api/lib/fmod64vc.lib differ diff --git a/fmodapi375win/api/lib/fmodbc.lib b/fmodapi375win/api/lib/fmodbc.lib new file mode 100644 index 0000000..0b0399b Binary files /dev/null and b/fmodapi375win/api/lib/fmodbc.lib differ diff --git a/fmodapi375win/api/lib/fmodlcc.lib b/fmodapi375win/api/lib/fmodlcc.lib new file mode 100644 index 0000000..0738c0a Binary files /dev/null and b/fmodapi375win/api/lib/fmodlcc.lib differ diff --git a/fmodapi375win/api/lib/fmodvc.lib b/fmodapi375win/api/lib/fmodvc.lib new file mode 100644 index 0000000..b3c9fd9 Binary files /dev/null and b/fmodapi375win/api/lib/fmodvc.lib differ diff --git a/fmodapi375win/api/lib/fmodwc.lib b/fmodapi375win/api/lib/fmodwc.lib new file mode 100644 index 0000000..12fe755 Binary files /dev/null and b/fmodapi375win/api/lib/fmodwc.lib differ diff --git a/fmodapi375win/api/lib/libfmod.a b/fmodapi375win/api/lib/libfmod.a new file mode 100644 index 0000000..cf2aadf Binary files /dev/null and b/fmodapi375win/api/lib/libfmod.a differ diff --git a/fmodapi375win/api/vb/fmod.bas b/fmodapi375win/api/vb/fmod.bas new file mode 100644 index 0000000..58d16eb --- /dev/null +++ b/fmodapi375win/api/vb/fmod.bas @@ -0,0 +1,914 @@ +Attribute VB_Name = "FMod" +Option Explicit + +' +'FMOD VB6 Module +' + +Public Const FMOD_VERSION = 3.75 + +'************ +'* Enums +'************ + + +' FMOD_ERRORS +' On failure of commands in FMOD, use FSOUND_GetError to attain what happened. +' +Public Enum FMOD_ERRORS + FMOD_ERR_NONE ' No errors + FMOD_ERR_BUSY ' Cannot call this command after FSOUND_Init. Call FSOUND_Close first. + FMOD_ERR_UNINITIALIZED ' This command failed because FSOUND_Init was not called + FMOD_ERR_INIT ' Error initializing output device. + FMOD_ERR_ALLOCATED ' Error initializing output device, but more specifically, the output device is already in use and cannot be reused. + FMOD_ERR_PLAY ' Playing the sound failed. + FMOD_ERR_OUTPUT_FORMAT ' Soundcard does not support the features needed for this soundsystem (16bit stereo output) + FMOD_ERR_COOPERATIVELEVEL ' Error setting cooperative level for hardware. + FMOD_ERR_CREATEBUFFER ' Error creating hardware sound buffer. + FMOD_ERR_FILE_NOTFOUND ' File not found + FMOD_ERR_FILE_FORMAT ' Unknown file format + FMOD_ERR_FILE_BAD ' Error loading file + FMOD_ERR_MEMORY ' Not enough memory + FMOD_ERR_VERSION ' The version number of this file format is not supported + FMOD_ERR_INVALID_PARAM ' An invalid parameter was passed to this function + FMOD_ERR_NO_EAX ' Tried to use an EAX command on a non EAX enabled channel or output. + FMOD_ERR_CHANNEL_ALLOC ' Failed to allocate a new channel + FMOD_ERR_RECORD ' Recording is not supported on this machine + FMOD_ERR_MEDIAPLAYER ' Windows Media Player not installed so cannot play wma or use internet streaming. + FMOD_ERR_CDDEVICE ' An error occured trying to open the specified CD device +End Enum + + +' FSOUND_OUTPUTTYPES +' These output types are used with FSOUND_SetOutput, to choose which output driver to use. +' FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver +' does not support DirectX 6 Voice Manager Extensions. +' FSOUND_OUTPUT_WINMM is recommended for NT and CE. +' +Public Enum FSOUND_OUTPUTTYPES + FSOUND_OUTPUT_NOSOUND ' NoSound driver, all calls to this succeed but do nothing. + FSOUND_OUTPUT_WINMM ' Windows Multimedia driver. + FSOUND_OUTPUT_DSOUND ' DirectSound driver. You need this to get EAX2 or EAX3 support, or FX api support. + FSOUND_OUTPUT_A3D ' A3D driver. + + FSOUND_OUTPUT_OSS ' Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. + FSOUND_OUTPUT_ESD ' Linux/Unix ESD (Enlightment Sound Daemon) driver. + FSOUND_OUTPUT_ALSA ' Linux Alsa driver. + + FSOUND_OUTPUT_ASIO ' Low latency ASIO driver + FSOUND_OUTPUT_XBOX ' Xbox driver + FSOUND_OUTPUT_PS2 ' PlayStation 2 driver + FSOUND_OUTPUT_MAC ' Mac SoundMager driver + FSOUND_OUTPUT_GC ' Gamecube driver + FSOUND_OUTPUT_PSP ' PlayStation Portable driver + + FSOUND_OUTPUT_NOSOUND_NONREALTIME ' This is the same as nosound, but the sound generation is driven by FSOUND_Update +End Enum + + +' FSOUND_MIXERTYPES +' These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act +' upon for other reasons using FSOUND_GetMixer. +' It is not nescessary to set the mixer. FMOD will autodetect the best mixer for you. +' +Public Enum FSOUND_MIXERTYPES + FSOUND_MIXER_AUTODETECT ' CE/PS2 Only - Non interpolating/low quality mixer + FSOUND_MIXER_BLENDMODE ' removed / obsolete. + FSOUND_MIXER_MMXP5 ' removed / obsolete. + FSOUND_MIXER_MMXP6 ' removed / obsolete. + + FSOUND_MIXER_QUALITY_AUTODETECT ' All platforms - Autodetect the fastest quality mixer based on your cpu. + FSOUND_MIXER_QUALITY_FPU ' Win32/Linux only - Interpolating/volume ramping FPU mixer. + FSOUND_MIXER_QUALITY_MMXP5 ' Win32/Linux only - Interpolating/volume ramping FPU mixer. + FSOUND_MIXER_QUALITY_MMXP6 ' Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. + + FSOUND_MIXER_MONO ' CE/PS2 only - MONO non interpolating/low quality mixer. For speed + FSOUND_MIXER_QUALITY_MONO ' CE/PS2 only - MONO Interpolating mixer. For speed +End Enum + + +' FMUSIC_TYPES +' These definitions describe the type of song being played. +' See FMUSIC_GetType +' +Public Enum FMUSIC_TYPES + FMUSIC_TYPE_NONE + FMUSIC_TYPE_MOD 'Protracker / Fasttracker + FMUSIC_TYPE_S3M 'ScreamTracker 3 + FMUSIC_TYPE_XM 'FastTracker 2 + FMUSIC_TYPE_IT 'Impulse Tracker. + FMUSIC_TYPE_MIDI 'MIDI file + FMUSIC_TYPE_FSB 'FMOD Sample Bank file +End Enum + + +' FSOUND_DSP_PRIORITIES +' These default priorities are used by FMOD internal system DSP units. They describe the +' position of the DSP chain, and the order of how audio processing is executed. +' You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP +' unit), disable or even change the priority of a DSP unit. +' +Public Enum FSOUND_DSP_PRIORITIES + FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT = 0 'DSP CLEAR unit - done first + FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT = 100 'DSP SFX unit - done second + FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT = 200 'DSP MUSIC unit - done third + FSOUND_DSP_DEFAULTPRIORITY_USER = 300 'User priority, use this as reference for your own dsp units + FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT = 900 'This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units + FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT = 1000 'DSP CLIP AND COPY unit - last +End Enum + + +' FSOUND_CAPS +' Driver description bitfields. Use FSOUND_Driver_GetCaps to determine if a driver enumerated +' has the settings you are after. The enumerated driver depends on the output mode, see +' FSOUND_OUTPUTTYPES +' +Public Enum FSOUND_CAPS + FSOUND_CAPS_HARDWARE = &H1 ' This driver supports hardware accelerated 3d sound. + FSOUND_CAPS_EAX2 = &H2 ' This driver supports EAX 2 reverb + FSOUND_CAPS_EAX3 = &H10 ' This driver supports EAX 3 reverb +End Enum + + +' FSOUND_MODES +' Sample description bitfields, OR them together for loading and describing samples. +' NOTE. If the file format being loaded already has a defined format, such as WAV or MP3, then +' trying to override the pre-defined format with a new set of format flags will not work. For +' example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS. It will just +' ignore the flag and go ahead loading it as 8bits. For these type of formats the only flags +' you can specify that will really alter the behaviour of how it is loaded, are the following. +' +' Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI +' Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D +' Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO +' Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX +' PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP +' +' See flag descriptions for what these do. +' +Public Enum FSOUND_MODES + FSOUND_LOOP_OFF = &H1 ' For non looping samples. + FSOUND_LOOP_NORMAL = &H2 ' For forward looping samples. + FSOUND_LOOP_BIDI = &H4 ' For bidirectional looping samples. (no effect if in hardware). + FSOUND_8BITS = &H8 ' For 8 bit samples. + FSOUND_16BITS = &H10 ' For 16 bit samples. + FSOUND_MONO = &H20 ' For mono samples. + FSOUND_STEREO = &H40 ' For stereo samples. + FSOUND_UNSIGNED = &H80 ' For source data containing unsigned samples. + FSOUND_SIGNED = &H100 ' For source data containing signed data. + FSOUND_DELTA = &H200 ' For source data stored as delta values. + FSOUND_IT214 = &H400 ' For source data stored using IT214 compression. + FSOUND_IT215 = &H800 ' For source data stored using IT215 compression. + FSOUND_HW3D = &H1000 ' Attempts to make samples use 3d hardware acceleration. (if the card supports it) + FSOUND_2D = &H2000 ' Ignores any 3d processing. overrides FSOUND_HW3D. Located in software. + FSOUND_STREAMABLE = &H4000 ' For realtime streamable samples. If you dont supply this sound may come out corrupted. + FSOUND_LOADMEMORY = &H8000 ' For FSOUND_Sample_Load - name will be interpreted as a pointer to data + FSOUND_LOADRAW = &H10000 ' For FSOUND_Sample_Load/FSOUND_Stream_Open - will ignore file format and treat as raw pcm. + FSOUND_MPEGACCURATE = &H20000 ' For FSOUND_Stream_Open - scans MP2/MP3 (VBR also) for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. + FSOUND_FORCEMONO = &H40000 ' For forcing stereo streams and samples to be mono - needed with FSOUND_HW3D - incurs speed hit + FSOUND_HW2D = &H80000 ' 2d hardware sounds. allows hardware specific effects + FSOUND_ENABLEFX = &H100000 ' Allows DX8 FX to be played back on a sound. Requires DirectX 8 - Note these sounds cant be played more than once, or have a changing frequency + FSOUND_MPEGHALFRATE = &H200000 ' For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution + FSOUND_XADPCM = &H400000 ' For XBOX only - Describes a user sample that its contents are compressed as XADPCM + FSOUND_VAG = &H800000 ' For PS2 only - Describes a user sample that its contents are compressed as Sony VAG format. + FSOUND_NONBLOCKING = &H1000000 ' For FSOUND_Stream_Open - Causes stream to open in the background and not block the foreground app - stream plays only when ready. + FSOUND_GCADPCM = &H2000000 ' For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format + FSOUND_MULTICHANNEL = &H4000000 ' For PS2 only - Contents are interleaved into a multi-channel (more than stereo) format + FSOUND_USECORE0 = &H8000000 ' For PS2 only - Sample/Stream is forced to use hardware voices 00-23 + FSOUND_USECORE1 = &H10000000 ' For PS2 only - Sample/Stream is forced to use hardware voices 24-47 + FSOUND_LOADMEMORYIOP = &H20000000 ' For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address + FSOUND_IGNORETAGS = &H40000000 ' Skips id3v2 etc tag checks when opening a stream, to reduce seek/read overhead when opening files (helps with CD performance) + FSOUND_STREAM_NET = &H80000000 ' Specifies an internet stream + + FSOUND_NORMAL = FSOUND_16BITS Or FSOUND_SIGNED Or FSOUND_MONO +End Enum + + +' FSOUND_CDPLAYMODES +' Playback method for a CD Audio track, with FSOUND_CD_SetPlayMode +' +Public Enum FSOUND_CDPLAYMODES + FSOUND_CD_PLAYCONTINUOUS 'Starts from the current track and plays to end of CD. + FSOUND_CD_PLAYONCE 'Plays the specified track then stops. + FSOUND_CD_PLAYLOOPED 'Plays the specified track looped, forever until stopped manually. + FSOUND_CD_PLAYRANDOM 'Plays tracks in random order +End Enum + + +' FSOUND_CHANNELSAMPLEMODE +' Miscellaneous values for FMOD functions. +' FSOUND_PlaySound, FSOUND_PlaySoundEx, FSOUND_Sample_Alloc, FSOUND_Sample_Load, FSOUND_SetPan +' +Public Enum FSOUND_CHANNELSAMPLEMODE + FSOUND_FREE = -1 ' definition for dynamically allocated channel or sample + FSOUND_UNMANAGED = -2 ' definition for allocating a sample that is NOT managed by fsound + FSOUND_ALL = -3 ' for a channel index or sample index, this flag affects ALL channels or samples available! Not supported by all functions. + FSOUND_STEREOPAN = -1 ' definition for full middle stereo volume on both channels + FSOUND_SYSTEMCHANNEL = -1000 ' special channel ID for channel based functions that want to alter the global FSOUND software mixing output channel + FSOUND_SYSTEMSAMPLE = -1000 ' special sample ID for all sample based functions that want to alter the global FSOUND software mixing output sample +End Enum + + +' FSOUND_REVERB_PROPERTIES +' FSOUND_Reverb_SetProperties, FSOUND_Reverb_GetProperties, FSOUND_REVERB_PROPERTYFLAGS +' +Public Type FSOUND_REVERB_PROPERTIES + ' MIN MAX DEFAULT DESCRIPTION + Environment As Long ' 0 25 0 sets all listener properties + EnvSize As Single ' 1.0 100.0 7.5 environment size in meters + EnvDiffusion As Single ' 0.0 1.0 1.0 environment diffusion + Room As Long ' -10000 0 -1000 room effect level (at mid frequencies) + RoomHF As Long ' -10000 0 -100 relative room effect level at high frequencies + RoomLF As Long ' -10000 0 0 relative room effect level at low frequencies + DecayTime As Single ' 0.1 20.0 1.49 reverberation decay time at mid frequencies + DecayHFRatio As Single ' 0.1 2.0 0.83 high-frequency to mid-frequency decay time ratio + DecayLFRatio As Single ' 0.1 2.0 1.0 low-frequency to mid-frequency decay time ratio + Reflections As Long ' -10000 1000 -2602 early reflections level relative to room effect + ReflectionsDelay As Single ' 0.0 0.3 0.007 initial reflection delay time + ReflectionsPan(3) As Single ' 0,0,0 early reflections panning vector + Reverb As Long ' -1000 2000 200 late reverberation level relative to room effect + ReverbDelay As Single ' 0.0 0.1 0.011 late reverberation delay time relative to initial reflection + ReverbPan(3) As Single ' 0,0,0 late reverberation panning vector + EchoTime As Single ' .075 0.25 0.25 echo time + EchoDepth As Single ' 0.0 1.0 0.0 echo depth + ModulationTime As Single ' 0.04 4.0 0.25 modulation time + ModulationDepth As Single ' 0.0 1.0 0.0 modulation depth + AirAbsorptionHF As Single ' -100 0.0 -5.0 change in level per meter at high frequencies + HFReference As Single ' 1000.0 20000 5000.0 reference high frequency (hz) + LFReference As Single ' 20.0 1000.0 250.0 reference low frequency (hz) + RoomRolloffFactor As Single ' 0.0 10.0 0.0 like FSOUND_3D_SetRolloffFactor but for room effect + Diffusion As Single ' 0.0 100.0 100.0 Value that controls the echo density in the late reverberation decay. (xbox only) + Density As Single ' 0.0 100.0 100.0 Value that controls the modal density in the late reverberation decay (xbox only) + flags As Long ' modifies the behavior of above properties +End Type + + +' FSOUND_REVERB_FLAGS +' Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure. +' +Public Enum FSOUND_REVERB_PROPERTYFLAGS + FSOUND_REVERBFLAGS_DECAYTIMESCALE = &H1 ' EnvironmentSize affects reverberation decay time + FSOUND_REVERBFLAGS_REFLECTIONSSCALE = &H2 ' EnvironmentSize affects reflection level + FSOUND_REVERBFLAGS_REFLECTIONSDELAYSCALE = &H4 ' EnvironmentSize affects initial reflection delay time + FSOUND_REVERBFLAGS_REVERBSCALE = &H8 ' EnvironmentSize affects reflections level + FSOUND_REVERBFLAGS_REVERBDELAYSCALE = &H10 ' EnvironmentSize affects late reverberation delay time + FSOUND_REVERBFLAGS_DECAYHFLIMIT = &H20 ' AirAbsorptionHF affects DecayHFRatio + FSOUND_REVERBFLAGS_ECHOTIMESCALE = &H40 ' EnvironmentSize affects echo time + FSOUND_REVERBFLAGS_MODULATIONTIMESCALE = &H80 ' EnvironmentSize affects modulation time + FSOUND_REVERB_FLAGS_CORE0 = &H100 ' PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) + FSOUND_REVERB_FLAGS_CORE1 = &H200 ' PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) + FSOUND_REVERBFLAGS_DEFAULT = FSOUND_REVERBFLAGS_DECAYTIMESCALE Or FSOUND_REVERBFLAGS_REFLECTIONSSCALE Or FSOUND_REVERBFLAGS_REFLECTIONSDELAYSCALE Or FSOUND_REVERBFLAGS_REVERBSCALE Or FSOUND_REVERBFLAGS_REVERBDELAYSCALE Or FSOUND_REVERBFLAGS_DECAYHFLIMIT Or FSOUND_REVERB_FLAGS_CORE0 Or FSOUND_REVERB_FLAGS_CORE1 +End Enum + + +' FSOUND_REVERB_CHANNELPROPERTIES +' Structure defining the properties for a reverb source, related to a FSOUND channel. +' FSOUND_Reverb_SetEnvironment, FSOUND_Reverb_SetEnvironmentAdvanced +' +Public Type FSOUND_REVERB_CHANNELPROPERTIES + Direct As Long ' direct path level (at low and mid frequencies) + DirectHF As Long ' relative direct path level at high frequencies + Room As Long ' room effect level (at low and mid frequencies) + RoomHF As Long ' relative room effect level at high frequencies + Obstruction As Long ' main obstruction control (attenuation at high frequencies) + ObstructionLFRatio As Single ' obstruction low-frequency level re. main control + Occlusion As Long ' main occlusion control (attenuation at high frequencies) + OcclustionLFRatio As Single ' occlusion low-frequency level re. main control + OcclusionRoomRatio As Single ' relative occlusion control for room effect + OcclusionDirectRatio As Single ' relative occlusion control for direct path + Exclusion As Long ' main exlusion control (attenuation at high frequencies) + ExclusionLFRatio As Single ' exclusion low-frequency level re. main control + OutsideVolumeHF As Long ' outside sound cone level at high frequencies + DopplerFactor As Single ' like DS3D flDopplerFactor but per source + RolloffFactor As Single ' like DS3D flRolloffFactor but per source + RoomRolloffFactor As Single ' like DS3D flRolloffFactor but for room effect + AirAbsorptionFactor As Single ' multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES + flags As Long ' modifies the behavior of properties +End Type + + +' FSOUND_REVERB_CHANNELFLAGS +' Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure. +' +Public Enum FSOUND_REVERB_CHANNELFLAGS + FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO = &H1 ' Automatic setting of Direct due to distance from listener + FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO = &H2 ' Automatic setting of Room due to distance from listener + FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO = &H4 ' Automatic setting of RoomHF due to distance from listener + FSOUND_REVERB_CHANNELFLAGS_DEFAULT = FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO Or FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO Or FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO +End Enum + + +' FSOUND_FX_MODES +' These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel. +' +Public Enum FSOUND_FX_MODES + FSOUND_FX_CHORUS + FSOUND_FX_COMPRESSOR + FSOUND_FX_DISTORTION + FSOUND_FX_ECHO + FSOUND_FX_FLANGER + FSOUND_FX_GARGLE + FSOUND_FX_I3DL2REVERB + FSOUND_FX_PARAMEQ + FSOUND_FX_WAVES_REVERB +End Enum + + +'FSOUND_SPEAKERMODES +'These are speaker types defined for use with the FSOUND_SetSpeakerMode command. +'Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes. Other output modes will only +'interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo. +'Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure. +' +Public Enum FSOUND_SPEAKERMODES + FSOUND_SPEAKERMODE_DOLBYDIGITAL ' The audio is played through a speaker arrangement of surround speakers with a subwoofer. + FSOUND_SPEAKERMODE_HEADPHONE ' The speakers are headphones. + FSOUND_SPEAKERMODE_MONO ' The speakers are monaural. + FSOUND_SPEAKERMODE_QUAD ' The speakers are quadraphonic. + FSOUND_SPEAKERMODE_STEREO ' The speakers are stereo (default value). + FSOUND_SPEAKERMODE_SURROUND ' The speakers are surround sound. + FSOUND_SPEAKERMODE_DTS ' The audio is played through a speaker arrangement of surround speakers with a subwoofer. + FSOUND_SPEAKERMODE_PROLOGIC2 ' Dolby Prologic 2. Playstation 2 and Gamecube only +End Enum + + +' FSOUND_INIT_FLAGS +' Initialization flags. Use them with FSOUND_Init in the flags parameter to change various behaviour. +' FSOUND_INIT_ENABLESYSTEMCHANNELFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects. +' Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small. +' This can be fixed with FSOUND_SetBufferSize. Increase the BufferSize until it works. +' When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters. +' +Public Enum FSOUND_INITMODES + FSOUND_INIT_USEDEFAULTMIDISYNTH = &H1 'Causes MIDI playback to force software decoding. + FSOUND_INIT_GLOBALFOCUS = &H2 'For DirectSound output - sound is not muted when window is out of focus. + FSOUND_INIT_ENABLESYSTEMCHANNELFX = &H4 'For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! + FSOUND_INIT_ACCURATEVULEVELS = &H8 'This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit + FSOUND_INIT_PS2_DISABLECORE0REVERB = &H10 'PS2 only - Disable reverb on CORE 0 to regain SRAM + FSOUND_INIT_PS2_DISABLECORE1REVERB = &H20 'PS2 only - Disable reverb on CORE 1 to regain SRAM + FSOUND_INIT_PS2_SWAPDMACORES = &H40 'PS2 only - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around + FSOUND_INIT_DONTLATENCYADJUST = &H80 'Callbacks are not latency adjusted, and are called at mix time. Also information functions are immediate + FSOUND_INIT_GC_INITLIBS = &H100 'Gamecube only - Initializes GC audio libraries + FSOUND_INIT_STREAM_FROM_MAIN_THREAD = &H200 'Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user + FSOUND_INIT_PS2_USEVOLUMERAMPING = &H400 'PS2 only - Turns on volume ramping system to remove hardware clicks. + FSOUND_INIT_DSOUND_DEFERRED = &H800 'Win32 only - For DirectSound output. 3D commands are batched together and executed at FSOUND_Update. + FSOUND_INIT_DSOUND_HRTF_LIGHT = &H1000 'Win32 only - For DirectSound output. FSOUND_HW3D buffers use a slightly higher quality algorithm when 3d hardware acceleration is not present. + FSOUND_INIT_DSOUND_HRTF_FULL = &H2000 'Win32 only - For DirectSound output. FSOUND_HW3D buffers use full quality 3d playback when 3d hardware acceleration is not present. + FSOUND_INIT_XBOX_REMOVEHEADROOM = &H4000 'XBox only - By default directsound attenuates all sound by 6db to avoid clipping/distortion. CAUTION. If you use this flag you are responsible for the final mix to make sure clipping / distortion doesn't happen. + FSOUND_INIT_PSP_SILENCEONUNDERRUN = &H8000 'PSP only - If streams skip / stutter when device is powered on, either increase stream buffersize, or use this flag instead to play silence while the UMD is recovering. +End Enum + + +' FSOUND_STREAM_NET_STATUS +' Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream. +' +Public Enum FSOUND_STREAM_NET_STATUS + FSOUND_STREAM_NET_NOTCONNECTED ' Stream hasn't connected yet + FSOUND_STREAM_NET_CONNECTING ' Stream is connecting to remote host + FSOUND_STREAM_NET_BUFFERING ' Stream is buffering data + FSOUND_STREAM_NET_READY ' Stream is ready to play + FSOUND_STREAM_NET_ERROR ' Stream has suffered a fatal error +End Enum + + +' FSOUND_TAGFIELD_TYPE +' Describes the type of a particular tag field. +' See FSOUND_Stream_GetNumTagFields, FSOUND_Stream_GetTagField, FSOUND_Stream_FindTagField +' +Public Enum FSOUND_TAGFIELD_TYPE + FSOUND_TAGFIELD_VORBISCOMMENT = 0 ' A vorbis comment + FSOUND_TAGFIELD_ID3V1 ' Part of an ID3v1 tag + FSOUND_TAGFIELD_ID3V2 ' An ID3v2 frame + FSOUND_TAGFIELD_SHOUTCAST ' A SHOUTcast header line + FSOUND_TAGFIELD_ICECAST ' An Icecast header line + FSOUND_TAGFIELD_ASF ' An Advanced Streaming Format header line +End Enum + + +' FSOUND_STATUS_FLAGS +' These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream. +' +Public Enum FSOUND_STATUS_FLAGS + FSOUND_PROTOCOL_SHOUTCAST = &H1 + FSOUND_PROTOCOL_ICECAST = &H2 + FSOUND_PROTOCOL_HTTP = &H4 + FSOUND_FORMAT_MPEG = &H10000 + FSOUND_FORMAT_OGGVORBIS = &H20000 +End Enum + +' FSOUND_TOC_TAG +' FSOUND_Stream_Open, FSOUND_Stream_FindTagField +' +Public Type FSOUND_TOC_TAG + TagName(3) As Byte ' The string "TOC" (4th character is 0), just in case this structure is accidentally treated as a string. + NumTracks As Long ' The number of tracks on the CD. + Min(99) As Long ' The start offset of each track in minutes. + Sec(99) As Long ' The start offset of each track in seconds. + Frame(99) As Long ' The start offset of each track in frames. +End Type + + +'/* ================================== */ +'/* Initialization / Global functions. */ +'/* ================================== */ + + +' PRE - FSOUND_Init functions. These cant be called after FSOUND_Init is +' called (they will fail). They set up FMOD system functionality. + + +Public Declare Function FSOUND_SetOutput Lib "fmod.dll" Alias "_FSOUND_SetOutput@4" (ByVal outputtype As FSOUND_OUTPUTTYPES) As Byte +Public Declare Function FSOUND_SetDriver Lib "fmod.dll" Alias "_FSOUND_SetDriver@4" (ByVal driver As Long) As Byte +Public Declare Function FSOUND_SetMixer Lib "fmod.dll" Alias "_FSOUND_SetMixer@4" (ByVal mixer As FSOUND_MIXERTYPES) As Byte +Public Declare Function FSOUND_SetBufferSize Lib "fmod.dll" Alias "_FSOUND_SetBufferSize@4" (ByVal lenms As Long) As Byte +Public Declare Function FSOUND_SetHWND Lib "fmod.dll" Alias "_FSOUND_SetHWND@4" (ByVal hwnd As Long) As Byte +Public Declare Function FSOUND_SetMinHardwareChannels Lib "fmod.dll" Alias "_FSOUND_SetMinHardwareChannels@4" (ByVal min As Integer) As Byte +Public Declare Function FSOUND_SetMaxHardwareChannels Lib "fmod.dll" Alias "_FSOUND_SetMaxHardwareChannels@4" (ByVal min As Integer) As Byte +Public Declare Function FSOUND_SetMemorySystem Lib "fmod.dll" Alias "_FSOUND_SetMemorySystem@20" (ByVal pool As Long, ByVal poollen As Long, ByVal useralloc As Long, ByVal userrealloc As Long, ByVal userfree As Long) As Byte + +' +' Main initialization / closedown functions. +' Note : Use FSOUND_INIT_USEDEFAULTMIDISYNTH with FSOUND_Init for software override +' with MIDI playback. +' : Use FSOUND_INIT_GLOBALFOCUS with FSOUND_Init to make sound audible no matter +' which window is in focus. (FSOUND_OUTPUT_DSOUND only) +' + +Public Declare Function FSOUND_Init Lib "fmod.dll" Alias "_FSOUND_Init@12" (ByVal mixrate As Long, ByVal maxchannels As Long, ByVal flags As FSOUND_INITMODES) As Byte +Public Declare Function FSOUND_Close Lib "fmod.dll" Alias "_FSOUND_Close@0" () As Long + +' +' Runtime system level functions +' + +Public Declare Function FSOUND_Update Lib "fmod.dll" Alias "_FSOUND_Update@0" () As Long + +Public Declare Function FSOUND_SetSpeakerMode Lib "fmod.dll" Alias "_FSOUND_SetSpeakerMode@4" (ByVal speakermode As FSOUND_SPEAKERMODES) As Long +Public Declare Function FSOUND_SetSFXMasterVolume Lib "fmod.dll" Alias "_FSOUND_SetSFXMasterVolume@4" (ByVal volume As Long) As Long +Public Declare Function FSOUND_SetPanSeperation Lib "fmod.dll" Alias "_FSOUND_SetPanSeperation@4" (ByVal pansep As Single) As Long +Public Declare Function FSOUND_File_SetCallbacks Lib "fmod.dll" Alias "_FSOUND_File_SetCallbacks@20" (ByVal OpenCallback As Long, ByVal CloseCallback As Long, ByVal ReadCallback As Long, ByVal SeekCallback As Long, ByVal TellCallback As Long) As Long + +' +' System information functions. +' + +Public Declare Function FSOUND_GetError Lib "fmod.dll" Alias "_FSOUND_GetError@0" () As FMOD_ERRORS +Public Declare Function FSOUND_GetVersion Lib "fmod.dll" Alias "_FSOUND_GetVersion@0" () As Single +Public Declare Function FSOUND_GetOutput Lib "fmod.dll" Alias "_FSOUND_GetOutput@0" () As FSOUND_OUTPUTTYPES +Public Declare Function FSOUND_GetOutputHandle Lib "fmod.dll" Alias "_FSOUND_GetOutputHandle@0" () As Long +Public Declare Function FSOUND_GetDriver Lib "fmod.dll" Alias "_FSOUND_GetDriver@0" () As Long +Public Declare Function FSOUND_GetMixer Lib "fmod.dll" Alias "_FSOUND_GetMixer@0" () As FSOUND_MIXERTYPES +Public Declare Function FSOUND_GetNumDrivers Lib "fmod.dll" Alias "_FSOUND_GetNumDrivers@0" () As Long +Public Declare Function FSOUND_GetDriverName Lib "fmod.dll" Alias "_FSOUND_GetDriverName@4" (ByVal id As Long) As Long +Public Declare Function FSOUND_GetDriverCaps Lib "fmod.dll" Alias "_FSOUND_GetDriverCaps@8" (ByVal id As Long, ByRef caps As Long) As Byte +Public Declare Function FSOUND_GetOutputRate Lib "fmod.dll" Alias "_FSOUND_GetOutputRate@0" () As Long +Public Declare Function FSOUND_GetMaxChannels Lib "fmod.dll" Alias "_FSOUND_GetMaxChannels@0" () As Long +Public Declare Function FSOUND_GetMaxSamples Lib "fmod.dll" Alias "_FSOUND_GetMaxSamples@0" () As Long +Public Declare Function FSOUND_GetSpeakerMode Lib "fmod.dll" Alias "_FSOUND_GetSpeakerMode@0" () As Long +Public Declare Function FSOUND_GetSFXMasterVolume Lib "fmod.dll" Alias "_FSOUND_GetSFXMasterVolume@0" () As Long +Public Declare Function FSOUND_GetNumHWChannels Lib "fmod.dll" Alias "_FSOUND_GetNumHWChannels@12" (ByRef num2d As Long, ByRef num3d As Long, ByRef total As Long) +Public Declare Function FSOUND_GetChannelsPlaying Lib "fmod.dll" Alias "_FSOUND_GetChannelsPlaying@0" () As Long +Public Declare Function FSOUND_GetCPUUsage Lib "fmod.dll" Alias "_FSOUND_GetCPUUsage@0" () As Single +Public Declare Sub FSOUND_GetMemoryStats Lib "fmod.dll" Alias "_FSOUND_GetMemoryStats@8" (ByRef currentalloced As Long, ByRef maxalloced As Long) + +'/* =================================== */ +'/* Sample management / load functions. */ +'/* =================================== */ + + +' Sample creation and management functions +' Note : Use FSOUND_LOADMEMORY flag with FSOUND_Sample_Load to load from memory. +' Use FSOUND_LOADRAW flag with FSOUND_Sample_Load to treat as as raw pcm data. + + +Public Declare Function FSOUND_Sample_Load Lib "fmod.dll" Alias "_FSOUND_Sample_Load@20" (ByVal index As Long, ByVal name As String, ByVal mode As FSOUND_MODES, ByVal offset As Long, ByVal length As Long) As Long +Public Declare Function FSOUND_Sample_Alloc Lib "fmod.dll" Alias "_FSOUND_Sample_Alloc@28" (ByVal index As Long, ByVal length As Long, ByVal mode As Long, ByVal deffreq As Long, ByVal defvol As Long, ByVal defpan As Long, ByVal defpri As Long) As Long +Public Declare Function FSOUND_Sample_Free Lib "fmod.dll" Alias "_FSOUND_Sample_Free@4" (ByVal sptr As Long) As Long +Public Declare Function FSOUND_Sample_Upload Lib "fmod.dll" Alias "_FSOUND_Sample_Upload@12" (ByVal sptr As Long, ByRef srcdata As Long, ByVal mode As Long) As Byte +Public Declare Function FSOUND_Sample_Lock Lib "fmod.dll" Alias "_FSOUND_Sample_Lock@28" (ByVal sptr As Long, ByVal offset As Long, ByVal length As Long, ByRef ptr1 As Long, ByRef ptr2 As Long, ByRef len1 As Long, ByRef len2 As Long) As Byte +Public Declare Function FSOUND_Sample_Unlock Lib "fmod.dll" Alias "_FSOUND_Sample_Unlock@20" (ByVal sptr As Long, ByVal sptr1 As Long, ByVal sptr2 As Long, ByVal len1 As Long, ByVal len2 As Long) As Byte + + +' Sample control functions + + +Public Declare Function FSOUND_Sample_SetMode Lib "fmod.dll" Alias "_FSOUND_Sample_SetMode@8" (ByVal sptr As Long, ByVal mode As FSOUND_MODES) As Byte +Public Declare Function FSOUND_Sample_SetLoopPoints Lib "fmod.dll" Alias "_FSOUND_Sample_SetLoopPoints@12" (ByVal sptr As Long, ByVal loopstart As Long, ByVal loopend As Long) As Byte +Public Declare Function FSOUND_Sample_SetDefaults Lib "fmod.dll" Alias "_FSOUND_Sample_SetDefaults@20" (ByVal sptr As Long, ByVal deffreq As Long, ByVal defvol As Long, ByVal defpan As Long, ByVal defpri As Long) As Byte +Public Declare Function FSOUND_Sample_SetDefaultsEx Lib "fmod.dll" Alias "_FSOUND_Sample_SetDefaultsEx@32" (ByVal sptr As Long, ByVal deffreq As Long, ByVal defvol As Long, ByVal defpan As Long, ByVal defpri As Long, ByVal varfreq As Long, ByVal varvol As Long, ByVal varpan As Long) As Byte +Public Declare Function FSOUND_Sample_SetMinMaxDistance Lib "fmod.dll" Alias "_FSOUND_Sample_SetMinMaxDistance@12" (ByVal sptr As Long, ByVal min As Single, ByVal max As Single) As Byte +Public Declare Function FSOUND_Sample_SetMaxPlaybacks Lib "fmod.dll" Alias "_FSOUND_Sample_SetMaxPlaybacks@8" (ByVal sptr As Long, ByVal max As Long) As Byte + + +' Sample information functions + + +Public Declare Function FSOUND_Sample_Get Lib "fmod.dll" Alias "_FSOUND_Sample_Get@4" (ByVal sampno As Long) As Long +Public Declare Function FSOUND_Sample_GetName Lib "fmod.dll" Alias "_FSOUND_Sample_GetName@4" (ByVal sptr As Long) As Long +Public Declare Function FSOUND_Sample_GetLength Lib "fmod.dll" Alias "_FSOUND_Sample_GetLength@4" (ByVal sptr As Long) As Long +Public Declare Function FSOUND_Sample_GetLoopPoints Lib "fmod.dll" Alias "_FSOUND_Sample_GetLoopPoints@12" (ByVal sptr As Long, ByRef loopstart As Long, ByRef loopend As Long) As Byte +Public Declare Function FSOUND_Sample_GetDefaults Lib "fmod.dll" Alias "_FSOUND_Sample_GetDefaults@20" (ByVal sptr As Long, ByRef deffreq As Long, ByRef defvol As Long, ByRef defpan As Long, ByRef defpri As Long) As Byte +Public Declare Function FSOUND_Sample_GetDefaultsEx Lib "fmod.dll" Alias "_FSOUND_Sample_GetDefaultsEx@32" (ByVal sptr As Long, ByRef deffreq As Long, ByRef defvol As Long, ByRef defpan As Long, ByRef defpri As Long, ByRef varfreq As Long, ByRef varvol As Long, ByRef varpan As Long) As Byte +Public Declare Function FSOUND_Sample_GetMode Lib "fmod.dll" Alias "_FSOUND_Sample_GetMode@4" (ByVal sptr As Long) As Long +Public Declare Function FSOUND_Sample_GetMinMaxDistance Lib "fmod.dll" Alias "_FSOUND_Sample_GetMinMaxDistance@12" (ByVal sptr As Long, ByRef min As Single, ByRef max As Single) As Byte + +'/* ============================ */ +'/* Channel control functions. */ +'/* ============================ */ + + +' Playing and stopping sounds. +' Note : Use FSOUND_FREE as the channel variable, to let FMOD pick a free channel for you. +' Use FSOUND_ALL as the channel variable to control ALL channels with one function call! + + +Public Declare Function FSOUND_PlaySound Lib "fmod.dll" Alias "_FSOUND_PlaySound@8" (ByVal channel As Long, ByVal sptr As Long) As Long +Public Declare Function FSOUND_PlaySoundEx Lib "fmod.dll" Alias "_FSOUND_PlaySoundEx@16" (ByVal channel As Long, ByVal sptr As Long, ByVal dsp As Long, ByVal startpaused As Byte) As Long +Public Declare Function FSOUND_StopSound Lib "fmod.dll" Alias "_FSOUND_StopSound@4" (ByVal channel As Long) As Byte + + +' Functions to control playback of a channel. +' Note : FSOUND_ALL can be used on most of these functions as a channel value. + + +Public Declare Function FSOUND_SetFrequency Lib "fmod.dll" Alias "_FSOUND_SetFrequency@8" (ByVal channel As Long, ByVal freq As Long) As Byte +Public Declare Function FSOUND_SetVolume Lib "fmod.dll" Alias "_FSOUND_SetVolume@8" (ByVal channel As Long, ByVal Vol As Long) As Byte +Public Declare Function FSOUND_SetVolumeAbsolute Lib "fmod.dll" Alias "_FSOUND_SetVolumeAbsolute@8" (ByVal channel As Long, ByVal Vol As Long) As Byte +Public Declare Function FSOUND_SetPan Lib "fmod.dll" Alias "_FSOUND_SetPan@8" (ByVal channel As Long, ByVal pan As Long) As Byte +Public Declare Function FSOUND_SetSurround Lib "fmod.dll" Alias "_FSOUND_SetSurround@8" (ByVal channel As Long, ByVal surround As Long) As Byte +Public Declare Function FSOUND_SetMute Lib "fmod.dll" Alias "_FSOUND_SetMute@8" (ByVal channel As Long, ByVal mute As Byte) As Byte +Public Declare Function FSOUND_SetPriority Lib "fmod.dll" Alias "_FSOUND_SetPriority@8" (ByVal channel As Long, ByVal Priority As Long) As Byte +Public Declare Function FSOUND_SetReserved Lib "fmod.dll" Alias "_FSOUND_SetReserved@8" (ByVal channel As Long, ByVal reserved As Long) As Byte +Public Declare Function FSOUND_SetPaused Lib "fmod.dll" Alias "_FSOUND_SetPaused@8" (ByVal channel As Long, ByVal Paused As Byte) As Byte +Public Declare Function FSOUND_SetLoopMode Lib "fmod.dll" Alias "_FSOUND_SetLoopMode@8" (ByVal channel As Long, ByVal loopmode As Long) As Byte +Public Declare Function FSOUND_SetCurrentPosition Lib "fmod.dll" Alias "_FSOUND_SetCurrentPosition@8" (ByVal channel As Long, ByVal offset As Long) As Byte +Public Declare Function FSOUND_3D_SetAttributes Lib "fmod.dll" Alias "_FSOUND_3D_SetAttributes@12" (ByVal channel As Long, ByRef Pos As Single, ByRef vel As Single) As Byte +Public Declare Function FSOUND_3D_SetMinMaxDistance Lib "fmod.dll" Alias "_FSOUND_3D_SetMinMaxDistance@12" (ByVal channel As Long, ByVal min As Single, ByVal max As Single) As Byte + +' +' Channel information functions. +' + +Public Declare Function FSOUND_IsPlaying Lib "fmod.dll" Alias "_FSOUND_IsPlaying@4" (ByVal channel As Long) As Byte +Public Declare Function FSOUND_GetFrequency Lib "fmod.dll" Alias "_FSOUND_GetFrequency@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetVolume Lib "fmod.dll" Alias "_FSOUND_GetVolume@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetAmplitude Lib "fmod.dll" Alias "_FSOUND_GetAmplitude@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetPan Lib "fmod.dll" Alias "_FSOUND_GetPan@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetSurround Lib "fmod.dll" Alias "_FSOUND_GetSurround@4" (ByVal channel As Long) As Byte +Public Declare Function FSOUND_GetMute Lib "fmod.dll" Alias "_FSOUND_GetMute@4" (ByVal channel As Long) As Byte +Public Declare Function FSOUND_GetPriority Lib "fmod.dll" Alias "_FSOUND_GetPriority@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetReserved Lib "fmod.dll" Alias "_FSOUND_GetReserved@4" (ByVal channel As Long) As Byte +Public Declare Function FSOUND_GetPaused Lib "fmod.dll" Alias "_FSOUND_GetPaused@4" (ByVal channel As Long) As Byte +Public Declare Function FSOUND_GetLoopMode Lib "fmod.dll" Alias "_FSOUND_GetLoopMode@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetCurrentPosition Lib "fmod.dll" Alias "_FSOUND_GetCurrentPosition@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetCurrentSample Lib "fmod.dll" Alias "_FSOUND_GetCurrentSample@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetCurrentLevels Lib "fmod.dll" Alias "_FSOUND_GetCurrentLevels@12" (ByVal channel As Long, ByRef l As Single, ByRef r As Single) As Byte +Public Declare Function FSOUND_GetNumSubChannels Lib "fmod.dll" Alias "_FSOUND_GetNumSubChannels@4" (ByVal channel As Long) As Long +Public Declare Function FSOUND_GetSubChannel Lib "fmod.dll" Alias "_FSOUND_GetSubChannel@8" (ByVal channel As Long, ByVal subchannel As Long) As Long +Public Declare Function FSOUND_3D_GetAttributes Lib "fmod.dll" Alias "_FSOUND_3D_GetAttributes@12" (ByVal channel As Long, ByRef Pos As Single, ByRef vel As Single) As Byte +Public Declare Function FSOUND_3D_GetMinMaxDistance Lib "fmod.dll" Alias "_FSOUND_3D_GetMinMaxDistance@12" (ByVal channel As Long, ByRef min As Single, ByRef max As Single) As Byte + +'/* ========================== */ +'/* Global 3D sound functions. */ +'/* ========================== */ + +' +' See also 3d sample and channel based functions above. +' Call FSOUND_Update once a frame to process 3d information. +' + +Public Declare Function FSOUND_3D_Listener_SetCurrent Lib "fmod.dll" Alias "_FSOUND_3D_Listener_SetCurrent@8" (ByVal current As Long) As Long +Public Declare Function FSOUND_3D_Listener_SetAttributes Lib "fmod.dll" Alias "_FSOUND_3D_Listener_SetAttributes@32" (ByVal Pos As Single, ByVal vel As Single, ByVal fx As Single, ByVal fy As Single, ByVal fz As Single, ByVal tx As Single, ByVal ty As Single, ByVal tz As Single) As Long +Public Declare Function FSOUND_3D_Listener_GetAttributes Lib "fmod.dll" Alias "_FSOUND_3D_Listener_GetAttributes@32" (ByRef Pos As Single, ByRef vel As Single, ByRef fx As Single, ByRef fy As Single, ByRef fz As Single, ByRef tx As Single, ByRef ty As Single, ByRef tz As Single) As Long +Public Declare Function FSOUND_3D_SetDopplerFactor Lib "fmod.dll" Alias "_FSOUND_3D_SetDopplerFactor@4" (ByVal fscale As Single) As Long +Public Declare Function FSOUND_3D_SetDistanceFactor Lib "fmod.dll" Alias "_FSOUND_3D_SetDistanceFactor@4" (ByVal fscale As Single) As Long +Public Declare Function FSOUND_3D_SetRolloffFactor Lib "fmod.dll" Alias "_FSOUND_3D_SetRolloffFactor@4" (ByVal fscale As Single) As Long + +'/* =================== */ +'/* FX functions. */ +'/* =================== */ + + +' Functions to control DX8 only effects processing. +' +' - FX enabled samples can only be played once at a time, not multiple times at once. +' - Sounds have to be created with FSOUND_HW2D or FSOUND_HW3D for this to work. +' - FSOUND_INIT_ENABLESYSTEMCHANNELFX can be used to apply hardware effect processing to the +' global mixed output of FMOD's software channels. +' - FSOUND_FX_Enable returns an FX handle that you can use to alter fx parameters. +' - FSOUND_FX_Enable can be called multiple times in a row, even on the same FX type, +' it will return a unique handle for each FX. +' - FSOUND_FX_Enable cannot be called if the sound is playing or locked. +' - FSOUND_FX_Disable must be called to reset/clear the FX from a channel. + + +Public Declare Function FSOUND_FX_Enable Lib "fmod.dll" Alias "_FSOUND_FX_Enable@8" (ByVal channel As Long, ByVal fx As FSOUND_FX_MODES) As Long +Public Declare Function FSOUND_FX_Disable Lib "fmod.dll" Alias "_FSOUND_FX_Disable@4" (ByVal channel As Long) As Byte + +Public Declare Function FSOUND_FX_SetChorus Lib "fmod.dll" Alias "_FSOUND_FX_SetChorus@32" (ByVal fxid As Long, ByVal WetDryMix As Single, ByVal Depth As Single, ByVal Feedback As Single, ByVal Frequency As Single, ByVal Waveform As Long, ByVal Delay As Single, ByVal Phase As Long) As Byte +Public Declare Function FSOUND_FX_SetCompressor Lib "fmod.dll" Alias "_FSOUND_FX_SetCompressor@28" (ByVal fxid As Long, ByVal Gain As Single, ByVal Attack As Single, ByVal Release As Single, ByVal Threshold As Single, ByVal Ratio As Single, ByVal Predelay As Single) As Byte +Public Declare Function FSOUND_FX_SetDistortion Lib "fmod.dll" Alias "_FSOUND_FX_SetDistortion@24" (ByVal fxid As Long, ByVal Gain As Single, ByVal Edge As Single, ByVal PostEQCenterFrequency As Single, ByVal PostEQBandwidth As Single, ByVal PreLowpassCutoff As Single) As Byte +Public Declare Function FSOUND_FX_SetEcho Lib "fmod.dll" Alias "_FSOUND_FX_SetEcho@24" (ByVal fxid As Long, ByVal WetDryMix As Single, ByVal Feedback As Single, ByVal LeftDelay As Single, ByVal RightDelay As Single, ByVal PanDelay As Long) As Byte +Public Declare Function FSOUND_FX_SetFlanger Lib "fmod.dll" Alias "_FSOUND_FX_SetFlanger@32" (ByVal fxid As Long, ByVal WetDryMix As Single, ByVal Depth As Single, ByVal Feedback As Single, ByVal Frequency As Single, ByVal Waveform As Long, ByVal Delay As Single, ByVal Phase As Long) As Byte +Public Declare Function FSOUND_FX_SetGargle Lib "fmod.dll" Alias "_FSOUND_FX_SetGargle@12" (ByVal fxid As Long, ByVal RateHz As Long, ByVal WaveShape As Long) As Byte +Public Declare Function FSOUND_FX_SetI3DL2Reverb Lib "fmod.dll" Alias "_FSOUND_FX_SetI3DL2Reverb@52" (ByVal fxid As Long, ByVal Room As Long, ByVal RoomHF As Long, ByVal RoomRolloffFactor As Single, ByVal DecayTime As Single, ByVal DecayHFRatio As Single, ByVal Reflections As Long, ByVal ReflectionsDelay As Single, ByVal Reverb As Long, ByVal ReverbDelay As Single, ByVal Diffusion As Single, ByVal Density As Single, ByVal HFReference As Single) As Byte +Public Declare Function FSOUND_FX_SetParamEQ Lib "fmod.dll" Alias "_FSOUND_FX_SetParamEQ@16" (ByVal fxid As Long, ByVal Center As Single, ByVal Bandwidth As Single, ByVal Gain As Single) As Byte +Public Declare Function FSOUND_FX_SetWavesReverb Lib "fmod.dll" Alias "_FSOUND_FX_SetWavesReverb@20" (ByVal fxid As Long, ByVal InGain As Single, ByVal ReverbMix As Single, ByVal ReverbTime As Single, ByVal HighFreqRTRatio As Single) As Byte + +' ========================= */ +' File Streaming functions. */ +' ========================= */ + +' +' Note : Use FSOUND_LOADMEMORY flag with FSOUND_Stream_Open to stream from memory. +' Use FSOUND_LOADRAW flag with FSOUND_Stream_Open to treat stream as raw pcm data. +' Use FSOUND_MPEGACCURATE flag with FSOUND_Stream_Open to open mpegs in 'accurate mode' for settime/gettime/getlengthms. +' Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you. +' + +Public Declare Function FSOUND_Stream_SetBufferSize Lib "fmod.dll" Alias "_FSOUND_Stream_SetBufferSize@4" (ByVal ms As Long) As Byte + +Public Declare Function FSOUND_Stream_Open Lib "fmod.dll" Alias "_FSOUND_Stream_Open@16" (ByVal filename As String, ByVal mode As FSOUND_MODES, ByVal offset As Long, ByVal length As Long) As Long +Public Declare Function FSOUND_Stream_Open2 Lib "fmod.dll" Alias "_FSOUND_Stream_Open@16" (ByRef data As Byte, ByVal mode As FSOUND_MODES, ByVal offset As Long, ByVal length As Long) As Long +Public Declare Function FSOUND_Stream_Create Lib "fmod.dll" Alias "_FSOUND_Stream_Create@20" (ByVal callback As Long, ByVal length As Long, ByVal mode As Long, ByVal samplerate As Long, ByVal userdata As Long) As Long +Public Declare Function FSOUND_Stream_Close Lib "fmod.dll" Alias "_FSOUND_Stream_Close@4" (ByVal stream As Long) As Byte + +Public Declare Function FSOUND_Stream_Play Lib "fmod.dll" Alias "_FSOUND_Stream_Play@8" (ByVal channel As Long, ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_PlayEx Lib "fmod.dll" Alias "_FSOUND_Stream_PlayEx@16" (ByVal channel As Long, ByVal stream As Long, ByVal dsp As Long, ByVal startpaused As Byte) As Long +Public Declare Function FSOUND_Stream_Stop Lib "fmod.dll" Alias "_FSOUND_Stream_Stop@4" (ByVal stream As Long) As Byte + +Public Declare Function FSOUND_Stream_SetPosition Lib "fmod.dll" Alias "_FSOUND_Stream_SetPosition@8" (ByVal stream As Long, ByVal positition As Long) As Byte +Public Declare Function FSOUND_Stream_GetPosition Lib "fmod.dll" Alias "_FSOUND_Stream_GetPosition@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_SetTime Lib "fmod.dll" Alias "_FSOUND_Stream_SetTime@8" (ByVal stream As Long, ByVal ms As Long) As Byte +Public Declare Function FSOUND_Stream_GetTime Lib "fmod.dll" Alias "_FSOUND_Stream_GetTime@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_GetLength Lib "fmod.dll" Alias "_FSOUND_Stream_GetLength@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_GetLengthMs Lib "fmod.dll" Alias "_FSOUND_Stream_GetLengthMs@4" (ByVal stream As Long) As Long + +Public Declare Function FSOUND_Stream_SetMode Lib "fmod.dll" Alias "_FSOUND_Stream_SetMode@8" (ByVal stream As Long, ByVal mode As Long) As Byte +Public Declare Function FSOUND_Stream_GetMode Lib "fmod.dll" Alias "_FSOUND_Stream_GetMode@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_SetLoopPoints Lib "fmod.dll" Alias "_FSOUND_Stream_SetLoopPoints@12" (ByVal stream As Long, ByVal loopstartpcm As Long, ByVal loopendpcm As Long) As Byte +Public Declare Function FSOUND_Stream_SetLoopCount Lib "fmod.dll" Alias "_FSOUND_Stream_SetLoopCount@8" (ByVal stream As Long, ByVal count As Long) As Byte +Public Declare Function FSOUND_Stream_GetOpenState Lib "fmod.dll" Alias "_FSOUND_Stream_GetOpenState@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_GetSample Lib "fmod.dll" Alias "_FSOUND_Stream_GetSample@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_CreateDSP Lib "fmod.dll" Alias "_FSOUND_Stream_CreateDSP@16" (ByVal stream As Long, ByVal callback As Long, ByVal Priority As Long, ByVal userdata As Long) As Long + +Public Declare Function FSOUND_Stream_SetEndCallback Lib "fmod.dll" Alias "_FSOUND_Stream_SetEndCallback@12" (ByVal stream As Long, ByVal callback As Long, ByVal userdata As Long) As Byte +Public Declare Function FSOUND_Stream_SetSyncCallback Lib "fmod.dll" Alias "_FSOUND_Stream_SetSyncCallback@12" (ByVal stream As Long, ByVal callback As Long, ByVal userdata As Long) As Byte + +Public Declare Function FSOUND_Stream_AddSyncPoint Lib "fmod.dll" Alias "_FSOUND_Stream_AddSyncPoint@12" (ByVal stream As Long, ByVal pcmoffset As Long, ByVal name As String) As Long +Public Declare Function FSOUND_Stream_DeleteSyncPoint Lib "fmod.dll" Alias "_FSOUND_Stream_DeleteSyncPoint@4" (ByVal point As Long) As Byte +Public Declare Function FSOUND_Stream_GetNumSyncPoints Lib "fmod.dll" Alias "_FSOUND_Stream_GetNumSyncPoints@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_GetSyncPoint Lib "fmod.dll" Alias "_FSOUND_Stream_GetSyncPoint@8" (ByVal stream As Long, ByVal index As Long) As Long +Public Declare Function FSOUND_Stream_GetSyncPointInfo Lib "fmod.dll" Alias "_FSOUND_Stream_GetSyncPointInfo@8" (ByVal point As Long, ByRef pcmoffset As Long) As Long + +Public Declare Function FSOUND_Stream_SetSubStream Lib "fmod.dll" Alias "_FSOUND_Stream_SetSubStream@8" (ByVal stream As Long, ByVal index As Long) As Byte +Public Declare Function FSOUND_Stream_GetNumSubStreams Lib "fmod.dll" Alias "_FSOUND_Stream_GetNumSubStreams@4" (ByVal stream As Long) As Long +Public Declare Function FSOUND_Stream_SetSubStreamSentence Lib "fmod.dll" Alias "_FSOUND_Stream_SetSubStreamSentence@12" (ByVal stream As Long, ByRef sentencelist As Long, ByVal numitems As Long) As Byte + +Public Declare Function FSOUND_Stream_GetNumTagFields Lib "fmod.dll" Alias "_FSOUND_Stream_GetNumTagFields@8" (ByVal stream As Long, ByRef num As Long) As Byte +Public Declare Function FSOUND_Stream_GetTagField Lib "fmod.dll" Alias "_FSOUND_Stream_GetTagField@24" (ByVal stream As Long, ByVal num As Long, ByRef tagtype As Long, ByRef name As Long, ByRef value As Long, ByRef length As Long) As Byte +Public Declare Function FSOUND_Stream_FindTagField Lib "fmod.dll" Alias "_FSOUND_Stream_FindTagField@20" (ByVal stream As Long, ByVal tagtype As Long, ByVal name As String, ByRef value As Long, ByRef length As Long) As Byte + +' +' Internet streaming functions +' + +Public Declare Function FSOUND_Stream_Net_SetProxy Lib "fmod.dll" Alias "_FSOUND_Stream_Net_SetProxy@4" (ByVal proxy As String) As Byte +Public Declare Function FSOUND_Stream_Net_GetLastServerStatus Lib "fmod.dll" Alias "_FSOUND_Stream_Net_GetLastServerStatus@0" () As Long +Public Declare Function FSOUND_Stream_Net_SetBufferProperties Lib "fmod.dll" Alias "_FSOUND_Stream_Net_SetBufferProperties@12" (ByVal buffersize As Long, ByVal prebuffer_percent As Long, ByVal rebuffer_percent As Long) As Byte +Public Declare Function FSOUND_Stream_Net_GetBufferProperties Lib "fmod.dll" Alias "_FSOUND_Stream_Net_GetBufferProperties@12" (ByRef buffersize As Long, ByRef prebuffer_percent As Long, ByRef rebuffer_percent As Long) As Byte +Public Declare Function FSOUND_Stream_Net_SetMetadataCallback Lib "fmod.dll" Alias "_FSOUND_Stream_Net_SetMetadataCallback@12" (ByVal stream As Long, ByVal callback As Long, ByVal userdata As Long) As Byte +Public Declare Function FSOUND_Stream_Net_GetStatus Lib "fmod.dll" Alias "_FSOUND_Stream_Net_GetStatus@20" (ByVal stream As Long, ByRef status As Long, ByRef bufferpercentused As Long, ByRef bitrate As Long, ByRef flags As Long) As Byte + +'/* =================== */ +'/* CD audio functions. */ +'/* =================== */ + + +' Note : 0 = default cdrom. Otherwise specify the drive letter, for example. 'D'. + + +Public Declare Function FSOUND_CD_Play Lib "fmod.dll" Alias "_FSOUND_CD_Play@8" (ByVal drive As Byte, ByVal Track As Long) As Byte +Public Declare Function FSOUND_CD_SetPlayMode Lib "fmod.dll" Alias "_FSOUND_CD_SetPlayMode@8" (ByVal drive As Byte, ByVal mode As FSOUND_CDPLAYMODES) As Long +Public Declare Function FSOUND_CD_Stop Lib "fmod.dll" Alias "_FSOUND_CD_Stop@4" (ByVal drive As Byte) As Byte +Public Declare Function FSOUND_CD_SetPaused Lib "fmod.dll" Alias "_FSOUND_CD_SetPaused@8" (ByVal drive As Byte, ByVal Paused As Byte) As Byte +Public Declare Function FSOUND_CD_SetVolume Lib "fmod.dll" Alias "_FSOUND_CD_SetVolume@8" (ByVal drive As Byte, ByVal volume As Long) As Byte +Public Declare Function FSOUND_CD_SetTrackTime Lib "fmod.dll" Alias "_FSOUND_CD_SetTrackTime@8" (ByVal drive As Byte, ByVal ms As Long) As Byte +Public Declare Function FSOUND_CD_OpenTray Lib "fmod.dll" Alias "_FSOUND_CD_OpenTray@8" (ByVal drive As Byte, ByVal openState As Byte) As Byte + +Public Declare Function FSOUND_CD_GetPaused Lib "fmod.dll" Alias "_FSOUND_CD_GetPaused@4" (ByVal drive As Byte) As Byte +Public Declare Function FSOUND_CD_GetTrack Lib "fmod.dll" Alias "_FSOUND_CD_GetTrack@4" (ByVal drive As Byte) As Long +Public Declare Function FSOUND_CD_GetNumTracks Lib "fmod.dll" Alias "_FSOUND_CD_GetNumTracks@4" (ByVal drive As Byte) As Long +Public Declare Function FSOUND_CD_GetVolume Lib "fmod.dll" Alias "_FSOUND_CD_GetVolume@4" (ByVal drive As Byte) As Long +Public Declare Function FSOUND_CD_GetTrackLength Lib "fmod.dll" Alias "_FSOUND_CD_GetTrackLength@8" (ByVal drive As Byte, ByVal Track As Long) As Long +Public Declare Function FSOUND_CD_GetTrackTime Lib "fmod.dll" Alias "_FSOUND_CD_GetTrackTime@4" (ByVal drive As Byte) As Long + +'/* ============== */ +'/* DSP functions. */ +'/* ============== */ + + +' DSP Unit control and information functions. +' These functions allow you access to the mixed stream that FMOD uses to play back sound on. + + +Public Declare Function FSOUND_DSP_Create Lib "fmod.dll" Alias "_FSOUND_DSP_Create@12" (ByVal callback As Long, ByVal Priority As Long, ByVal param As Long) As Long +Public Declare Function FSOUND_DSP_Free Lib "fmod.dll" Alias "_FSOUND_DSP_Free@4" (ByVal unit As Long) As Long +Public Declare Function FSOUND_DSP_SetPriority Lib "fmod.dll" Alias "_FSOUND_DSP_SetPriority@8" (ByVal unit As Long, ByVal Priority As Long) As Long +Public Declare Function FSOUND_DSP_GetPriority Lib "fmod.dll" Alias "_FSOUND_DSP_GetPriority@4" (ByVal unit As Long) As Long +Public Declare Function FSOUND_DSP_SetActive Lib "fmod.dll" Alias "_FSOUND_DSP_SetActive@8" (ByVal unit As Long, ByVal active As Integer) As Long +Public Declare Function FSOUND_DSP_GetActive Lib "fmod.dll" Alias "_FSOUND_DSP_GetActive@4" (ByVal unit As Long) As Byte + + +' Functions to get hold of FSOUND 'system DSP unit' handles + + +Public Declare Function FSOUND_DSP_GetClearUnit Lib "fmod.dll" Alias "_FSOUND_DSP_GetClearUnit@0" () As Long +Public Declare Function FSOUND_DSP_GetSFXUnit Lib "fmod.dll" Alias "_FSOUND_DSP_GetSFXUnit@0" () As Long +Public Declare Function FSOUND_DSP_GetMusicUnit Lib "fmod.dll" Alias "_FSOUND_DSP_GetMusicUnit@0" () As Long +Public Declare Function FSOUND_DSP_GetFFTUnit Lib "fmod.dll" Alias "_FSOUND_DSP_GetFFTUnit@0" () As Long +Public Declare Function FSOUND_DSP_GetClipAndCopyUnit Lib "fmod.dll" Alias "_FSOUND_DSP_GetClipAndCopyUnit@0" () As Long + + +' Miscellaneous DSP functions +' Note for the spectrum analysis function to work, you have to enable the FFT DSP unit with +' the following code FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); +' It is off by default to save cpu usage. + + +Public Declare Function FSOUND_DSP_MixBuffers Lib "fmod.dll" Alias "_FSOUND_DSP_MixBuffers@28" (ByVal destbuffer As Long, ByVal srcbuffer As Long, ByVal length As Long, ByVal freq As Long, ByVal Vol As Long, ByVal pan As Long, ByVal mode As Long) As Byte +Public Declare Function FSOUND_DSP_ClearMixBuffer Lib "fmod.dll" Alias "_FSOUND_DSP_ClearMixBuffer@0" () As Long +Public Declare Function FSOUND_DSP_GetBufferLength Lib "fmod.dll" Alias "_FSOUND_DSP_GetBufferLength@0" () As Long +Public Declare Function FSOUND_DSP_GetBufferLengthTotal Lib "fmod.dll" Alias "_FSOUND_DSP_GetBufferLengthTotal@0" () As Long +Public Declare Function FSOUND_DSP_GetSpectrum Lib "fmod.dll" Alias "_FSOUND_DSP_GetSpectrum@0" () As Long + +'/* =================================================================================== */ +'/* Reverb functions. (eax2/eax3 reverb) (ONLY SUPPORTED ON WIN32 W/ FSOUND_HW3D FLAG) */ +'/* =================================================================================== */ + + +' See top of file for definitions and information on the reverb parameters. + +'The FSOUND_REVERB_PRESETS have not been included in VB yet so they cannot yet be used here... +Public Declare Function FSOUND_Reverb_SetProperties Lib "fmod.dll" Alias "_FSOUND_Reverb_SetProperties@4" (ByRef prop As FSOUND_REVERB_PROPERTIES) As Byte +Public Declare Function FSOUND_Reverb_GetProperties Lib "fmod.dll" Alias "_FSOUND_Reverb_GetProperties@4" (ByRef prop As FSOUND_REVERB_PROPERTIES) As Byte +Public Declare Function FSOUND_Reverb_SetChannelProperties Lib "fmod.dll" Alias "_FSOUND_Reverb_SetChannelProperties@8" (ByVal channel As Long, ByRef prop As FSOUND_REVERB_CHANNELPROPERTIES) As Byte +Public Declare Function FSOUND_Reverb_GetChannelProperties Lib "fmod.dll" Alias "_FSOUND_Reverb_GetChannelProperties@8" (ByVal channel As Long, ByRef prop As FSOUND_REVERB_CHANNELPROPERTIES) As Byte + +'/* ===================================================== */ +'/* Recording functions (ONLY SUPPORTED IN WIN32, WINCE) */ +'/* ===================================================== */ + + +' Recording initialization functions + + +Public Declare Function FSOUND_Record_SetDriver Lib "fmod.dll" Alias "_FSOUND_Record_SetDriver@4" (ByVal outputtype As Long) As Byte +Public Declare Function FSOUND_Record_GetNumDrivers Lib "fmod.dll" Alias "_FSOUND_Record_GetNumDrivers@0" () As Long +Public Declare Function FSOUND_Record_GetDriverName Lib "fmod.dll" Alias "_FSOUND_Record_GetDriverName@4" (ByVal id As Long) As Long +Public Declare Function FSOUND_Record_GetDriver Lib "fmod.dll" Alias "_FSOUND_Record_GetDriver@0" () As Long + + +' Recording functionality. Only one recording session will work at a time. + + +Public Declare Function FSOUND_Record_StartSample Lib "fmod.dll" Alias "_FSOUND_Record_StartSample@8" (ByVal sample As Long, ByVal loopit As Boolean) As Byte +Public Declare Function FSOUND_Record_Stop Lib "fmod.dll" Alias "_FSOUND_Record_Stop@0" () As Byte +Public Declare Function FSOUND_Record_GetPosition Lib "fmod.dll" Alias "_FSOUND_Record_GetPosition@0" () As Long + +'/* ========================================================================================== */ +'/* FMUSIC API (MOD,S3M,XM,IT,MIDI PLAYBACK) */ +'/* ========================================================================================== */ + + +' Song management / playback functions. + + +Public Declare Function FMUSIC_LoadSong Lib "fmod.dll" Alias "_FMUSIC_LoadSong@4" (ByVal name As String) As Long +Public Declare Function FMUSIC_LoadSongEx Lib "fmod.dll" Alias "_FMUSIC_LoadSongEx@24" (ByVal name As String, ByVal offset As Long, ByVal length As Long, ByVal mode As FSOUND_MODES, ByRef sentencelist As Long, ByVal numitems As Long) As Long +Public Declare Function FMUSIC_LoadSongEx2 Lib "fmod.dll" Alias "_FMUSIC_LoadSongEx@24" (ByRef data As Byte, ByVal offset As Long, ByVal length As Long, ByVal mode As FSOUND_MODES, ByRef sentencelist As Long, ByVal numitems As Long) As Long +Public Declare Function FMUSIC_GetOpenState Lib "fmod.dll" Alias "_FMUSIC_GetOpenState@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_FreeSong Lib "fmod.dll" Alias "_FMUSIC_FreeSong@4" (ByVal module As Long) As Byte +Public Declare Function FMUSIC_PlaySong Lib "fmod.dll" Alias "_FMUSIC_PlaySong@4" (ByVal module As Long) As Byte +Public Declare Function FMUSIC_StopSong Lib "fmod.dll" Alias "_FMUSIC_StopSong@4" (ByVal module As Long) As Byte +Public Declare Function FMUSIC_StopAllSongs Lib "fmod.dll" Alias "_FMUSIC_StopAllSongs@0" () As Long + +Public Declare Function FMUSIC_SetZxxCallback Lib "fmod.dll" Alias "_FMUSIC_SetZxxCallback@8" (ByVal module As Long, ByVal callback As Long) As Byte +Public Declare Function FMUSIC_SetRowCallback Lib "fmod.dll" Alias "_FMUSIC_SetRowCallback@12" (ByVal module As Long, ByVal callback As Long, ByVal rowstep As Long) As Byte +Public Declare Function FMUSIC_SetOrderCallback Lib "fmod.dll" Alias "_FMUSIC_SetOrderCallback@12" (ByVal module As Long, ByVal callback As Long, ByVal rowstep As Long) As Byte +Public Declare Function FMUSIC_SetInstCallback Lib "fmod.dll" Alias "_FMUSIC_SetInstCallback@12" (ByVal module As Long, ByVal callback As Long, ByVal instrument As Long) As Byte + +Public Declare Function FMUSIC_SetSample Lib "fmod.dll" Alias "_FMUSIC_SetSample@12" (ByVal module As Long, ByVal sampno As Long, ByVal sptr As Long) As Byte +Public Declare Function FMUSIC_SetUserData Lib "fmod.dll" Alias "_FMUSIC_SetUserData@8" (ByVal module As Long, ByVal userdata As Long) As Byte +Public Declare Function FMUSIC_OptimizeChannels Lib "fmod.dll" Alias "_FMUSIC_OptimizeChannels@12" (ByVal module As Long, ByVal maxchannels As Long, ByVal minvolume As Long) As Byte + + +' Runtime song functions + + +Public Declare Function FMUSIC_SetReverb Lib "fmod.dll" Alias "_FMUSIC_SetReverb@4" (ByVal Reverb As Byte) As Byte +Public Declare Function FMUSIC_SetLooping Lib "fmod.dll" Alias "_FMUSIC_SetLooping@8" (ByVal module As Long, ByVal looping As Byte) As Byte +Public Declare Function FMUSIC_SetOrder Lib "fmod.dll" Alias "_FMUSIC_SetOrder@8" (ByVal module As Long, ByVal order As Long) As Byte +Public Declare Function FMUSIC_SetPaused Lib "fmod.dll" Alias "_FMUSIC_SetPaused@8" (ByVal module As Long, ByVal Pause As Byte) As Byte +Public Declare Function FMUSIC_SetMasterVolume Lib "fmod.dll" Alias "_FMUSIC_SetMasterVolume@8" (ByVal module As Long, ByVal volume As Long) As Byte +Public Declare Function FMUSIC_SetMasterSpeed Lib "fmod.dll" Alias "_FMUSIC_SetMasterSpeed@8" (ByVal module As Long, ByVal speed As Single) As Byte +Public Declare Function FMUSIC_SetPanSeperation Lib "fmod.dll" Alias "_FMUSIC_SetPanSeperation@8" (ByVal module As Long, ByVal pansep As Single) As Byte + + +' Static song information functions + + +Public Declare Function FMUSIC_GetName Lib "fmod.dll" Alias "_FMUSIC_GetName@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetType Lib "fmod.dll" Alias "_FMUSIC_GetType@4" (ByVal module As Long) As FMUSIC_TYPES +Public Declare Function FMUSIC_GetNumOrders Lib "fmod.dll" Alias "_FMUSIC_GetNumOrders@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetNumPatterns Lib "fmod.dll" Alias "_FMUSIC_GetNumPatterns@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetNumInstruments Lib "fmod.dll" Alias "_FMUSIC_GetNumInstruments@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetNumSamples Lib "fmod.dll" Alias "_FMUSIC_GetNumSamples@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetNumChannels Lib "fmod.dll" Alias "_FMUSIC_GetNumChannels@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetSample Lib "fmod.dll" Alias "_FMUSIC_GetSample@8" (ByVal module As Long, ByVal sampno As Long) As Long +Public Declare Function FMUSIC_GetPatternLength Lib "fmod.dll" Alias "_FMUSIC_GetPatternLength@8" (ByVal module As Long, ByVal orderno As Long) As Long + + +' Runtime song information + + +Public Declare Function FMUSIC_IsFinished Lib "fmod.dll" Alias "_FMUSIC_IsFinished@4" (ByVal module As Long) As Byte +Public Declare Function FMUSIC_IsPlaying Lib "fmod.dll" Alias "_FMUSIC_IsPlaying@4" (ByVal module As Long) As Byte +Public Declare Function FMUSIC_GetMasterVolume Lib "fmod.dll" Alias "_FMUSIC_GetMasterVolume@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetGlobalVolume Lib "fmod.dll" Alias "_FMUSIC_GetGlobalVolume@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetOrder Lib "fmod.dll" Alias "_FMUSIC_GetOrder@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetPattern Lib "fmod.dll" Alias "_FMUSIC_GetPattern@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetSpeed Lib "fmod.dll" Alias "_FMUSIC_GetSpeed@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetBPM Lib "fmod.dll" Alias "_FMUSIC_GetBPM@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetRow Lib "fmod.dll" Alias "_FMUSIC_GetRow@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetPaused Lib "fmod.dll" Alias "_FMUSIC_GetPaused@4" (ByVal module As Long) As Byte +Public Declare Function FMUSIC_GetTime Lib "fmod.dll" Alias "_FMUSIC_GetTime@4" (ByVal module As Long) As Long +Public Declare Function FMUSIC_GetRealChannel Lib "fmod.dll" Alias "_FMUSIC_GetRealChannel@8" (ByVal module As Long, ByVal modchannel As Long) As Long +Public Declare Function FMUSIC_GetUserData Lib "fmod.dll" Alias "_FMUSIC_GetUserData@4" (ByVal module As Long) As Long + +'************ +'* Windows Declarations (Added by Adion) +'************ +'Required for GetStringFromPointer +Private Declare Function ConvCStringToVBString Lib "kernel32" Alias "lstrcpyA" (ByVal lpsz As String, ByVal pt As Long) As Long ' Notice the As Long return value replacing the As String given by the API Viewer. +'Required for the FFT/Spectral functions +Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal length As Long) + +'************ +'* FUNCTIONS (Added by Adion) +'************ +'Usage: myerrorstring = FSOUND_GetErrorString(FSOUND_GetError) +Public Function FSOUND_GetErrorString(ByVal errorcode As Long) As String + Select Case errorcode + Case FMOD_ERR_NONE: FSOUND_GetErrorString = "No errors" + Case FMOD_ERR_BUSY: FSOUND_GetErrorString = "Cannot call this command after FSOUND_Init. Call FSOUND_Close first." + Case FMOD_ERR_UNINITIALIZED: FSOUND_GetErrorString = "This command failed because FSOUND_Init was not called" + Case FMOD_ERR_PLAY: FSOUND_GetErrorString = "Playing the sound failed." + Case FMOD_ERR_INIT: FSOUND_GetErrorString = "Error initializing output device." + Case FMOD_ERR_ALLOCATED: FSOUND_GetErrorString = "The output device is already in use and cannot be reused." + Case FMOD_ERR_OUTPUT_FORMAT: FSOUND_GetErrorString = "Soundcard does not support the features needed for this soundsystem (16bit stereo output)" + Case FMOD_ERR_COOPERATIVELEVEL: FSOUND_GetErrorString = "Error setting cooperative level for hardware." + Case FMOD_ERR_CREATEBUFFER: FSOUND_GetErrorString = "Error creating hardware sound buffer." + Case FMOD_ERR_FILE_NOTFOUND: FSOUND_GetErrorString = "File not found" + Case FMOD_ERR_FILE_FORMAT: FSOUND_GetErrorString = "Unknown file format" + Case FMOD_ERR_FILE_BAD: FSOUND_GetErrorString = "Error loading file" + Case FMOD_ERR_MEMORY: FSOUND_GetErrorString = "Not enough memory " + Case FMOD_ERR_VERSION: FSOUND_GetErrorString = "The version number of this file format is not supported" + Case FMOD_ERR_INVALID_PARAM: FSOUND_GetErrorString = "An invalid parameter was passed to this function" + Case FMOD_ERR_NO_EAX: FSOUND_GetErrorString = "Tried to use an EAX command on a non EAX enabled channel or output." + Case FMOD_ERR_CHANNEL_ALLOC: FSOUND_GetErrorString = "Failed to allocate a new channel" + Case FMOD_ERR_RECORD: FSOUND_GetErrorString = "Recording is not supported on this machine" + Case FMOD_ERR_MEDIAPLAYER: FSOUND_GetErrorString = "Required Mediaplayer codec is not installed" + Case FMOD_ERR_CDDEVICE: FSOUND_GetErrorString = "An error occured trying to open the specified CD device" + Case Else: FSOUND_GetErrorString = "Unknown error" + End Select +End Function + +'Thanks to KarLKoX for the following function +'Example: MyDriverName = GetStringFromPointer(FSOUND_GetDriverName(count)) +Public Function GetStringFromPointer(ByVal lpString As Long) As String +Dim NullCharPos As Long +Dim szBuffer As String + + szBuffer = String(255, 0) + ConvCStringToVBString szBuffer, lpString + ' Look for the null char ending the C string + NullCharPos = InStr(szBuffer, vbNullChar) + GetStringFromPointer = Left(szBuffer, NullCharPos - 1) +End Function + +'These functions are added by Adion +Public Function GetSingleFromPointer(ByVal lpSingle As Long) As Single +'A Single is 4 bytes, so we copy 4 bytes +CopyMemory GetSingleFromPointer, ByVal lpSingle, 4 +End Function +'Warning: You should set the fft dsp to active before retreiving the spectrum +'Also make sure the array you pass is dimensioned and ready to use +'FSOUND_DSP_SetActive FSOUND_DSP_GetFFTUnit, 1 +Public Function GetSpectrum(ByRef Spectrum() As Single) +Dim nrOfVals As Long, lpSpectrum As Long +Dim a As Long +If UBound(Spectrum) > 511 Then nrOfVals = 512 Else nrOfVals = UBound(Spectrum) + 1 +lpSpectrum = FSOUND_DSP_GetSpectrum +CopyMemory Spectrum(0), ByVal lpSpectrum, nrOfVals * 4 +End Function diff --git a/fmodapi375win/documentation/FMOD.chm b/fmodapi375win/documentation/FMOD.chm new file mode 100644 index 0000000..989cc5e Binary files /dev/null and b/fmodapi375win/documentation/FMOD.chm differ diff --git a/fmodapi375win/documentation/Revision.txt b/fmodapi375win/documentation/Revision.txt new file mode 100644 index 0000000..142f5ad --- /dev/null +++ b/fmodapi375win/documentation/Revision.txt @@ -0,0 +1,1436 @@ + +====================================================================================== +REVISION HISTORY : FireMOD : Copyright (c) Firelight Technologies, Pty, Ltd, 1994-2005 + http://www.fmod.org +====================================================================================== + + Added feature or noticable improvement + - Bug fix or something removed + * Changed or Information +====================================================================================== + +15/12/05 3.75 +------------ + ++ PSP - Added PSP support! Contact sales@fmod.org for evaluation versions! ++ XBOX - Added FSOUND_INIT_XBOX_REMOVEHEADROOM for 2D sounds to disable the xbox + directsound 6db attenuation on all voices (to avoid clipping). + +- ALL - Fixed rare timing crash, mainly on HyperThreaded or Multi-Processor + machines, when calling FSOUND_Stream_SetPosition or FSOUND_Stream_Play. +- ALL - Sounds not starting paused properly issue fixed. +- ALL - Stability increase calling stream related commands from a sync callback. +- ALL - IMA ADPCM compressed multichannel FSB files with channel count = 2 + played as static fixed. +- ALL - Removed any references to ctype.h so linux has an easier time linking + on old glibc versions. +- ALL - .IT format - Pitch envelope under 'amiga frequencies' issue fixed. +- ALL - .IT format - Pan envelope not panning left issue fixed. +- ALL - .IT format - some songs with extremely high pitch notes were being + clamped by fmod's internal setfrequency function, so that has been + fixed. +- ALL - Fixed stream not opening with FSOUND_NONBLOCKING if + FSOUND_OUTPUT_NOSOUND_NONREALTIME was the output mode. +- ALL - Fixed rare stream crash if FSOUND_NONBLOCKING was used and ran out + of memory. +- ALL - Fixed ogg vorbis seeking causing odd audible playback for a few ms. +- ALL - Removed stall on FSOUND_Stream_SetSubStream or + FSOUND_Stream_SetSubStreamSentence if other streams were playing + simultaneously. +- ALL - Fixed FSOUND_SetMute not taking FSOUND_SetVolumeAbsolute into account + when unmuting. +- ALL - Fixed recording returning an error if fmod was closed then reinitialized +- ALL - Fixed rare failures in FSOUND_Sample_Load if a stream was openened + beforehand. +- LINUX - More OSS and ALSA compatibility fixes, should handle most cards without + a problem now. +- LINUX - Fixed lock on cd device after FSOUND_Close was called so tray wouldnt + eject. +- LINUX - ALSA output now cooperates with other applications better. +- WIN32/ + WIN64/ + WINCE - Fixed thread leak if recording was started and stopped. +- WINCE - Fixed last few milliseconds of mp3 files not playing. +- WINCE - Fixed new streams not being able to be started if memory card or + removable media was removed during playback. +- WINCE - Fixed memory leak. +- PS2 - Mute wasn't muting hardware voices properly. +- PS2 - Free up streams in FSOUND_Close to avoid hang. +- PS2 - Fixed memory leak when using FSOUND_NONBLOCKING and sample list feature + in FMUSIC_LoadSongEx. +- PS2 - Removed rare chance of buzzing noise if FSOUND_SetSpeakerMode was set + and FSOUND_Init had 0 software channels specified. +- PS2 - Fixed FSOUND_STEREOPAN coming out in right speaker with mono sounds. +- PS2 - Unblocked FSOUND_Stream_SetEndCallback from possibly causing a stall. +- MAC - Fixed critical section issues on OS9. +- XBOX - Fixed loop point clicking on PCM based hardware sounds. +- FSBANK - Fixed command line version not returning correct error code to dos. + Also stopped messagebox popping up when -h was specified. + +* WIN32 - CDDA streams now return -3 from FSOUND_Stream_GetOpenState when cd is + ejected. +* PS2 - FSOUND_IsDiskBusy now accepts a parameter to determine if a stream is + in the middle of a close (because stream close can cause blocking in + other functions if they are called while a stream is closing) + +11/11/04 3.741 (Mac only) +------------------------- + +- MAC - Fixed problems with playing Ogg Vorbis files. +- MAC - Fixed threading issues which was causing problems in mac classic. +- MAC - Added "Classic" target to all examples. + +18/10/04 3.74 +------------- + ++ GC - Added FSOUND_GC_PrepareForReset (see fmodgc.h) to prepare for software reset. + This kills streams so FSOUND_Close can be called safely even with the tray + door open. ++ GC - Added FSOUND_GetFreeHWRam to find out how much ARAM is free. ++ GC - Memory footprint lowered. ++ XBOX - FSOUND_Stream_OpenFromHandle added to allow dashboard tracks to be played + after using XOpenSoundtrackSong. + +- ALL - FSOUND_Stream_Play is now faster. +- ALL - Fixed FSOUND_SIGNED / FSOUND_UNSIGNED being ignored when FSOUND_LOADRAW in + FSOUND_Sample_Load/Ex. +- ALL - Stream fix when a stream opened with FSOUND_NONBLOCKING runs out of memory. +- ALL - Memory leak fixed in certain error situations trying to open a stream. +- ALL - Remove rare stream crash. +- ALL - Corruption when using compressed streams and stream loop points in rare cases + fixed. +- ALL - FSOUND_SetVolumeAbsolute not working on software mixed 3D voices or PS2/GC + hardware 3D voices. +- ALL - Fixed S3M arpeggio. +- ALL - Fixed an issue where on some platforms (xbox/gc/dsound) hardware voices would + enter an inconsistent state if channel that had played and ended was paused. +- WIN32 - ASIO Crash fix. +- LINUX - Fixed hang on OSS output if another device was using the same device. +- LINUX - Fixed crash when using ALSA by upgrading to the latest ALSA library. + (It was an ALSA crash not fmod!) +- MAC - Fixed crash on OS9 support. +- XBOX - FSOUND_IsPlaying / FSOUND_GetNumChannelsPlaying fixed when FSOUND_SetPaused + was used. +- XBOX - Sounds going quiet if FSOUND_Reverb_SetChannelProperties was called on 2d + channels fix. Now reverb channel properties are ignored if it is a 2d voice, + as the properties related to a 3d environment anyway. +- PS2 - Fixed crash on streams with loop points in VAG format. +- PS2 - Fixed stream priorities being 0 instead of 256 due to a sifcmd optimization + which lead to the undesirable effect of streams being stealable by the + channel priority system. +- GC - 3D sound rolloff algorithm updated to be consistant with other platforms. +- GC - Fixed unpaused sounds playing through all of ARAM in some cases. +- GC - Fixed audible glitch upon startup in certain cases. +- FSBANK - Fixed program stealing window focus when in hidden mode. + +* ALL - FMUSIC_SetSample now allows hardware samples specified for music files. This + means you can do things like use hardware VAG samples on PS2 in mod files. +* ALL - Renamed stream2 to userstream. +* PS2 - Exposed FSOUND_SetDiskBusy on IOP interface for IOP programmers. +* GC - Reduced memory fragmentation. + +01/06/04 3.73 +------------- + ++ ALL - FSOUND_CD_TrayOpen added. Now close or open is specified manually. ++ WIN32 - Added CD TOC retrieval as an FMOD tag. CDDB diskid generation added + to CDDA example. ++ WIN32 - Extended ASF/WMA tag support added. + +- ALL - FSOUND_Stream_GetTime and stream syncpoint fixes. +- WIN32 - CDDA pausing between tracks fix. +- FSBANK - Command line calls and list file parsing fix. +- GC - Memory alignment crash fix +- PS2 - FSOUND_Init/Close restart fix if FSOUND_INIT_PS2_USEVOLUMERAMPING was specified. +- ALL - FSOUND_CD_Eject removed in favour of FSOUND_CD_TrayOpen. + +* FSBANK - If FSOUND_HW3D is specified on a stereo sample an error is displayed. + + +23/04/04 3.72 +------------- + ++ WIN64 - AMD64 version of fmod available! fmod64.dll. + Runs in Windows XP 64 / Windows Server 2003. ++ ALL - FSOUND_Sample_SetDefaultsEx / FSOUND_Sample_GetDefaultsEx added. + Now includes random variation settings for frequency, volume and pan! ++ ALL - FSOUND_3D_SetMinMaxDistance / FSOUND_3D_GetMinMaxDistance added for per channel + min/max distance control. ++ ALL - 'fsb' example added. Shows loading of an FSB file as a non blocking sample bank, + then plays back the contents using the new random variation ++ WIN32 - Faster DirectSound support, due to many driver calls eliminated. This was + probably the cause of worse performance in FSOUND_HW3D mode than using the + FMOD software mixer. The software mixing mode probably still wins, but it + is better than it used to be. ++ WIN32 - WMA, ASF and WMV now run through FMOD DSP engine / streamer! You can now load + WMA files as samples, do DSP effects and spectrum analysis on these files. ++ WIN32 - ASIO output channels made enumerable and selectable through FSOUND_SetDriver. ++ PS2 - Optimizations on EE<->IOP communication with more EE side caching ++ PS2 - Added FSOUND_IOP_Alloc/Free. ++ PS2 - Added FSOUND_SPU2_Alloc/Free. ++ PS2 - Added FSOUND_SetADSR and FSOUND_SetADSRKeyoff ++ PS2 - Added FSOUND_SetSifCommandInfo, and a similar IOP mechanism for users wanting + to make FMOD cooperate with their own EE<->IOP sif command handlers. ++ PS2 - Stream2 example now shows VAG/ADPCM Hardware playback as well as PCM playback + and has an improved interface. ++ PS2 - 'streamwithdata' example added. This shows using FSOUND_SetDiskBusy, and also + loads game data at the same time without affecting the framerate. ++ PS2 - ShellMpeg example added! This example makes the Sony Shell mpeg movie player + example use FMOD via PCM or ADPCM using a custom FMOD stream. ++ PS2 - Added FMUSIC_SetRowCallback, FMUSIC_SetOrderCallback, FMUSIC_SetZxxCallback and + FMUSIC_SetInstCallback support. ++ PS2 - Added fmodps2iop.h to expose FMOD file and memory routines to IOP programmers. ++ XBOX - Reverb on 2d voices is now possible by calling FSOUND_Reverb_SetChannelProperties. ++ XBOX - FSOUND_Output_XBox_GetEffectImageDesc added in fmodxbox.h ++ CE - FSOUND_File_HasFatalErrorOccurred and FSOUND_HasPowerOnOccurred added in fmodce.h. + ++ FSBANK - Now available as a programmers library! Make your own FSB files without + fsbank.exe! See fsbank.lib, fsbank.h and fsbank.chm. ++ FSBANK - FSBank now allows list files to specify sample defaults and randomization parameters per sound. + +- ALL - FSOUND_Sample_SetMaxPlaybacks fixed when using hardware samples. +- ALL - Voice stealing fix with FSOUND_FREE. +- ALL - FSOUND_IsPlaying / endcallbacks on streams not reacting in time when + FSOUND_INIT_STREAM_FROM_MAIN_THREAD bugfix. +- ALL - mod/s3m/xm fix with pattern loop. +- ALL - mod/s3m/xm/it. Non looping songs now play the very last row instead of cutting it off. +- ALL - .it files now respect the FMUSIC_SetLooping command! +- ALL - FMUSIC_SetOrder now cleans up/resets old channels so skipping to a new part of the song + doesn't cause weird playback issues. +- ALL - FMUSIC_GetRealChannel fix for non playing music channels. +- ALL - Loop points on natively compressed sounds (xadpcm,gcadpcm,vag) working again. +- ALL - ADPCM compressed FSB support fixed. +- WIN32 - Analogue and Digital CDROM support fixes. +- WIN32 - FSOUND_HW3D support now drops back to directsound software buffers instead of fmod + software mixed buffers to remove the issue of latency and possible skipping on + some soundcards due to bad drivers. It avoids the need to have to play with the + mixer buffersize (FSOUND_SetBufferSize). 32 'hardware' voices are now reported + if the card actually has no voices. +- GC - Bugfixes. Stereo sound fixes, crash fixes, pause/unpause fixes and more. +- PS2 - IRX files symbol stripped, now around 130k smaller for each file. +- PS2 - FSOUND_GetPaused fixed with streams that are started paused. +- PS2 - FSOUND_SetDiskBusy now does not block other FMOD commands if executed from another + thread asynchronously. (ie if the game has a threaded filesystem). +- PS2 - Memory saving. 200k on the EE. +- LINUX - Ensoniq 1371 latency fix. +- LINUX - FSOUND_Init stalls/timeouts removed from various dodgy soundcards. +- LINUX - OSS Recording bugs fixed. +- CE - Streams now stop gracefully instead of hanging the thread if a poweron occurs and the file handle + to the stream on a CF card or external medium is lost. +- FSBANK - Many bugfixes. + +* ALL - FSOUND_GetNumHardwareChannels renamed to FSOUND_GetNumHWChannels to give more + information including 2d and 3d channels seperately. +* ALL - FSB files now allow mixture of mono and stereo sounds in the one bank. + FSOUND_Stream_SetSubStreamSentence will fail if it encounters a sentence with mixed + formats but functions like FSOUND_Stream_SetSubStream will work. +* ALL - FSOUND_INIT_ENABLEOUTPUTFX renamed to FSOUND_INIT_ENABLESYSTEMCHANNELFX. + +14/11/03 3.71 +------------- ++ WIN32 - CDDA support. Now you can perform cd ripping, spectrum analysis or DSP effects + on CD audio. See FSOUND_Stream_Open and FSOUND_Stream_SetSubStream. ++ PS2 - New FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR speakermode added as an alternative + to FSOUND_SPEAKERMODE_PROLOGIC2. This method cuts number of sound playbacks to + 24 at once instead of 48, but supports interior panning. Probably not needed in + most games. + +- ALL - FSOUND_Close and stream thread safety fixes for extra stability especially when + using end callbacks. +- ALL - Buffered file system fix to avoid strangely playing streams. +- ALL - Using FSOUND_Stream_SetTime in conjunction with FSOUND_FORCEMONO fix. +- ALL - (except CE and PS2) - Chirping noise fix when not using FSOUND_MPEGACCURATE when + seeking in an mp3. +- ALL - Possible OXM format memory leaks removed. +- WIN32 - WMA tag support fix. +- WIN32 - MP3 static fixed, when playing 2 mp3s at once or loading an mp3 sample while + streaming an mp3 simultaneously, on hyperthreaded cpus. +- LINUX - FSOUND_Close hang fixed. +- PS2 - Sync callback support added +- PS2 - IOP memory leak in the kernel if FSOUND_Init and FSOUND_Close was called +- PS2 - Corruption noise removed in streams if the stream buffersize wasnt big enough and + a stream tried to restart after buffer underrun. +- PS2 - Prologic 2 support fixes in the original PL2 mode. +- CE - Small glitch noise removed when stopping and starting an mp3 stream. +- MAC - linker issues resolved with mach-o build on certain versions of OSX. +- MAC/GC - endian issue fixed with noisy samples in .IT files. + +* ALL - specifying FSOUND_8BITS in loading a sample will now force the sample depth + down to 8bits to save memory. OXM files now also downgrade decoded oggs back + to 8bit when loading if the original XM had them stored as 8bit. + +4/9/03 3.70 +------------- + ++ ALL - Shoutcast / Icecast / HTTP streaming support added! (mp3/ogg vorbis only). ++ ALL - Tag support, I3DV1, I3DV2, Ogg Tags, ASF/WMA tags now readable through api. ++ PS2 - Prologic 2 support now allows use of all 48 hardware channels, instead of 24. ++ PS2 - Delay and Feedback parameters on spu2 hardware reverb now supported through + EchoTime and EchoDepth parameters respectively. ++ WIN32 - FMOD Media Player updated with some new features. Lowpass cpu usage bug fixed. ++ ALL - NetStream example added to make it simpler to understand buffering logic etc. ++ ALL - Saving the recorded result to a wav file added. Shows how to Lock/Unlock a + sample. ++ ALL - FSOUND_Stream_*Sync* API changed around a bit / renamed. Now user points are + stored as a pointer instead of an index, and the 256 limit is removed. ++ WINCE - FSOUND_DSP_GetSpectrum now works! Integer FFT implemented for non FPU devices. + +- ALL - WAV/AIFF only. If a file had loop points embedded, then the mode (ie FSOUND_2D) + was being ignored, fixed. +- ALL - Memory leak fixed if any FSOUND_Stream_*Sync* functions were called with + FSOUND_NONBLOCKING and the stream wasnt ready yet. They now fail if not ready. +- WIN32 - WMA and FSOUND_NONBLOCKING now works. +- XBOX - 360kb or so of memory saved! Also DSSTDFX.BIN is no longer needed. +- PS2 - Ejected or corrupted CDs now recover smoothly on stream playback without making a noise. +- PS2 - FSOUND_Reverb_SetChannelProperties fix which was causing sound to dissapear. +- PS2 - Return values for most channel commands fixed, they were returning the wrong value. +- PS2 - Streams being truncated wth different stream length/buffersize combinations fixed. +- PS2 - FSOUND_GetPaused fixed. +- PS2 - Many other bugfixes. +- MAC - Recording bugfix dependent on OSX version. +- WINCE - fixed mp3 loading as sample bug, for files with corruption in them. + +* ALL - FMUSIC_LoadSongEx now takes an offset parameter for pak/wad/data file loading. +* ALL - FSOUND_Stream_OpenFile is now called FSOUND_Stream_Open and also takes an + offset parameter for pak/wad/data file loading. + +9/6/03 3.63 +------------- ++ ALL - FSBank updated. Now all platforms support compressed FSB formats. + Command line supported added. Source files can now be specified via a text + file, allowing ordering of sounds within fsb files. ++ ALL - FSB format now supports sample banks to hold any sound format that fmod can + load with FSOUND_Sample_Load, so for example you could have 1 fsb with + multiple mp3, ogg and wav files stored within it. ++ ALL - FSOUND_Stream_OpenFile with FSOUND_MPEGACCURATE is now 25% faster! ++ ALL - FSOUND_Stream_SetLoopCount added. ++ ALL - FSOUND_NONBLOCKING support added to FMUSIC_LoadSongEx! Now sample banks can + be loaded in the background. Use new FMUSIC_GetOpenState to poll status. ++ PS2 - Dolby Prologic 2 support added! Use FSOUND_SetSpeakerMode and + FSOUND_SPEAKERMODE_PROLOGIC2. Note that this mode uses 2 hardware voices + for every fmod channel, so the number of channels is effectively halved + from 48 to 24 when using this speaker mode. ++ PS2 - FSOUND_Update now 30-40% faster! ++ PS2 - File routines now split into fmodfile.irx so users can quickly compile or + hook into their own IOP file routines. ++ ALL - FSOUND_INIT_STREAM_FROM_MAIN_THREAD added. This causes FSOUND_Update to + drive the streamer thread. This is mainly because OS8/Macintosh doesnt + like streaming inside an MPTask, which is being worked on. This will work + around it. + +- WIN32 - DirectX 8/9 bug fixed which could cause a crash with FX or recording. +- ALL - FSOUND_Stream_SetTime is now sample accurate with mp3. (it previously + seeked and rounded the position to the nearest mpeg block). +- ALL - MP3 'chirp' noises when seeking (using FSOUND_Stream_SetTime or + FSOUND_Stream_SetPosition) reduced or removed completely. +- PS2 - FSOUND_IsPlaying bug fixes, Prologic 2 support! Hardware click removal! +- PS2 - Greater volume accuracy which removes 'wobbly' sound when using small + mindistances in 3D sound. +- MAC - conflict with cocoa libraries and the symbol _realloc removed. +- ALL - Strange doppler effect when sounds went outside maxdistance fixed. +- ALL - FSOUND_Stream_SynchPoint fixes. +- PS2 - FSB 16byte memleak fixed. +- ALL - AIFF loop point support fixed. +- WINCE - Loading MP3 as sample crash fix. +- WINCE - FSOUND_GetLengthMs fixed with MP3 files. +- FSBANK - Mixing 8 & 16bit sounds dissalowed. A stream is created in a particular + format (based on the first sample in an FSB), and if the first sound was + 8 bit but the rest were 16bit, the result would be noisy 16bit sounds. + +* ALL - win32/mac mainly. FSOUND_Update now yields, causes operating task switch + for smoother multitasking. You should call this function once a frame. +* MAC - fmod_cfm.shlb now only exports the relevant fmod symbols and not the MSL stuff. + +28/02/03 3.62 +------------- ++ GC - GameCube support added! ++ ALL - Added DirectX 9 support. You can now change frequency with + FSOUND_ENABLEFX enabled sounds. ++ ALL - Cross platform IMA ADPCM wav file support! Now you can use ADPCM + compression without windows codecs, and on any platform. ++ ALL - Recording support added to Mac and Linux ports! ++ ALL - FSOUND_Stream_SetMode and FSOUND_Stream_GetMode added to allow control + during playback, such as looping. ++ ALL - FSOUND_Stream_SetSubStreamSentence added! This allows for seamless + stitching/sentencing of streams. VERY useful for things like commentary + where you want parametized audio. FSB format only. ++ ALL - FSOUND_CD_SetTrackTime added. ++ PS2 - Now TRC compliant for sony submissions. ++ PS2 - Added multi-channel interleaved stream support! (FSB format only). If + stereo is 2 interleave channels (L/R), this format allows up to 16 + interleaved channels at once that play simultaneously. This eliminates + seeking and improves CD bandwidth, and also allows interactive music with + tracks that stay in perfect sync. ++ PS2 - FSOUND_Reverb_SetChannelAttributes supported, using Room parameter to make + channel wet/dry. ++ PS2 - Stereo and even 'multichannel' (see above) sample support in hardware. + (FSB format only). ++ WIN32 - New example 'multiple' shows how to load fmod dynamically, and also play + sounds out of 2 soundcards at the same time! ++ WINCE - New complete set of examples! 3d, simple, simplest etc are all included. ++ LINUX - Better compatibility for old cards. ALSA mode now allows device + enumeration. Electic Fence tested. ++ WIN32 - 24 and 32 bit PCM wav files supported! + +- ALL - FSOUND_SetSubStream fixed when in FSOUND_NONBLOCKING mode and mulitiple + calls are issued at once. +- ALL - FSOUND_Stream_SetEndCallback more accurate. +- PS2 - 'Corrupted' stream fix when usage of hardware channels were maxed out. +- PS2 - FSOUND_Stream_PlayEx was accidently blocking, fixed. +- PS2 - Multiple Listeners fix. +- PS2 - FSOUND_SetSFXMasterVolume fix for FSB banks. +- ALL - Stream timing, mod timing, and stream endcallbacks are now more accurate. +- MAC - OS8/9 support working again. + +* ALL - .FSB support is now cross platform. PS2, GameCube and XBox allow compressed + FSB data. +* WIN32 - Made fmod.h and examples more cygwin friendly. +* ALL - FMUSIC_LoadSongMemory is now changed to FMUSIC_LoadSongEx. This function + handles loading from memory and more. +* ALL - Frequency/Volume/Pan/3d position cached to reduce WIN32 driver call overhead? +* LINUX - fmoddyn.h updated and useable for linux. + +18/12/02 3.61 +------------- ++ ALL - Added FMUSIC_SetUserData and FMUSIC_GetUserData ++ ALL - Added FSOUND_3D_Listener_SetCurrent for multiple listener support! ++ ALL - Optimized Ogg Vorbis. Ogg decoding is now 2x faster! + Decoding is nearly 2x quicker than mp3! ++ WIN32 - A3D support re-added as an output mode only, for compatibility. ++ PS2 - Added FSOUND_Stream_SetSubStream/FSOUND_Stream_GetNumSubStreams, for FMOD + .FSB bank files are supported on PS2 Only. Cross platform support is coming. ++ WINCE - Added Ogg Vorbis support via fixed point Tremor API. ++ ALL - Added support for Neil Graham's .XM to .OXM converter. This tool converts + XM samples into ogg files, making them dramatically smaller. ++ WIN32 - Added dynamic loading header fmoddyn.h. This allows you to create multiple + instances of fmod = multiple soundcard output. ++ ALL - Added FSOUND_Stream_SetLoopPoints. ++ ALL - Added FSOUND_Stream_GetOpenState for determining the state of a non blocking stream open. ++ ALL - Added FSOUND_Stream_AddSynchPoint, FSOUND_Stream_DeleteSynchPoint, + FSOUND_Stream_GetNumSynchPoints for sync point manipulation. + Previously they were only available in .WAV or .AIFF files. ++ ALL - Added FSOUND_OUTPUT_NOSOUND_NONREALTIME. Calling FSOUND_Update drives the + software engine as fast as you like. + +- LINUX - Latency fixes. +- LINUX - OSS output now allows /dev/dsp* enumeration. +- PS2 - Numerous fixed and speedups. +- XBOX - Fixed WMA looping. +- WINCE - Added more power off/on support for some iPAQ models that didn't work before. +- WIN32 - Improved ASIO support! More drivers work now that didn't work before. +- WIN32 - CD playback bugfixes. +- WIN32 - MIDI 'caching' bug fixed. +- WIN32 - FSOUND_ALL support now works with WMA channels. +- WIN32 - Pan clicks removed from FSOUND_MIXER_QUALITY_FPU +- WINCE - FSOUND_Stream_GetTime / SetTime / GetLengthMs more accurate for mp3. +- ALL - Lots of memory optimizations. FMOD now uses less memory than ever. + +* FSOUND_3D_Listener_SetDopplerFactor renamed to FSOUND_3D_SetDopplerFactor. +* FSOUND_3D_Listener_SetDistanceFactor renamed to FSOUND_3D_SetDistanceFactor. +* FSOUND_3D_Listener_SetRolloffFactor renamed to FSOUND_3D_SetRolloffFactor. +* FSOUND_3D_Update renamed to FSOUND_Update + +16/08/02 3.6 (WIN32/CE/Linux/Mac/PS2/Xbox Release) +------------- + ++ PS2 - PlayStation 2 support added! ++ XBOX - XBox support added! ++ MAC - Macintosh support added! ++ LINUX - Major rewrite + support for ALSA 0.9! Vortex2 support now working 100%. ++ ALL - Added FSOUND_Sample_SetMaxPlaybacks. ++ ALL - 'Constant power pan' added to software engine for better sounding pans. ++ ALL - FSOUND_NONBLOCKING flag added for opening streams. (streams will open in background) ++ ALL - AIFF Support added with full loop point and sync marker support. ++ ALL - Ogg Vorbis support upgraded to 1.0 final codebase! ++ ALL - FMUSIC_SetLooping added. Music loops by default, so call to stop it looping. ++ ALL - FSOUND_GetCurrentLevels added which returns a seperate left and right VU level. ++ WIN32 - FSOUND_FX_Disable added, so that FSOUND_FX_Enable doesnt have to be called each time. ++ WIN32 - MP2 support optimized, significantly faster. ++ WIN32 & + WINCE - Wave-In recording support added. Now recording works in NT and PocketPC! ++ WINCE - BIDI Looping and negative frequencies now supported. ++ WINCE - Smartphone, CE 2.11 and BE-300 support added. + +- ALL - Better MP3 format detection. +- ALL - WAV sync markers now sorted if they are stored in the wav file out of order. +- ALL - 3d sound and setvolume bug fixed. +- ALL - XM apreggio was upside down on linear frequency tunes bug fixed. +- ALL - FSOUND_SetFrequency. negative followed by positive frequency now works properly. +- ALL - FSOUND_GetCurrentVU removed in favour of FSOUND_GetCurrentLevels. +- WIN32 - Midi fixes. FMUSIC_IsFinished fixed, FMUSIC_StopSong fixed, FMUSIC_LoadSongMemory fixed. +- WIN32 - A3D/Geometry support removed. Geometry may re-appear via FMOD instead of A3D support. +- WIN32 - Fixed DX8 FX (FSOUND_FX_xxx) support. +- WIN32 - Fixed CD Playback functions. +- WINCE - Better support for Casio E115G device. Use 200ms buffer for these devices. +- WINCE - Seeking through SetTime/SetPosition bugfix especially with FSOUND_MPEGACCURATE. +- LINUX - Removed CD access at FSOUND_Init. + +* ALL - maxdistance behaviour unified on all platforms. +* ALL - FSOUND_SPEAKERMODE_5POINT1 is now separated to FSOUND_SPEAKERMODE_DOLBYDIGITAL and + FSOUND_SPEAKERMODE_DTS. +* ALL - Changed FSOUND_INIT_ACCURATEGETCURRENTVU to FSOUND_INIT_ACCURATEVULEVELS. +* WIN32 - Stopping or playing a sound now does not reset the FX list. You have to manually + do this with FSOUND_FX_Disable. This reduces cpu usage if wanting to start and stop + the sound repeatedly. + +11/03/02 3.51 (CE Only release) +------------- ++ WINCE - FSOUND_GetCurrentVU support added ++ WINCE - Optimizations - All remaining emulated floats removed - now pure fixed point! + +- ALL - Memory usage reduced on MOD/S3M/XM/IT playback by up to 200-300kb per instance. +- ALL - Other small fixes. +- WINCE - FSOUND_Init failing on some PocketPC devices fixed. + +* ALL - FSOUND_FORCEMONO enabled by default when a stream or sample is attempted to be + opened with FSOUND_HW3D, so the user doesnt have to specify it manually. + +14/02/02 3.5 +------------- ++ FMOD CE Only. Mono mixers added! (FSOUND_MIXER_MONO and FSOUND_MIXER_QUALITY_MONO). + 30% faster than stereo! ++ EAX3 support added! Advanced reverb api now also supporting occlusion and obstruction. ++ FMOD CE Only. Automatic power off/on recovery! FMOD audio will resume as soon as the power + is turned back on the Pocket PC device with no programmer intervention! ++ Ogg Vorbis version update to 1.0 RC3. ++ New tutorials in the documentation! The basics, DSP tutorial, DX8 FX tutorial and spectrum + analysis. Documentation index revamped and updated. ++ FSOUND_SetMemorySystem added. Allows the user to fexibly control memory allocated by FMOD. ++ Multiple CDROM support added. Pass 0 for default, or 'D','E' etc to select the cd drive. ++ FSOUND_Stream_SetBufferSize added. Useful for streaming from CD when the default size isnt + big enough, and causes audio skips because the cd is being held up. ++ FSOUND_SetFrequency supports negative frequencies. Play sounds backwards! ++ FMOD media player allows seeking in mods and streams by clicking on progress bar ++ Linux version brought up to date. Thanks to SUSE distro guys for helping out. ++ FSOUND_GetCurrentVU latency adjusted (via FSOUND_Init flag), and now emulates a software + mixer giving perfect VU feedback. + +- Sound skips with streams removed by bigger default stream buffersize. (also on CE) +- Divide by 0 in linux version removed. +- Bug fixed where an item appeared on the windows taskbar for FMOD's cdrom handling code. +- Time accuracy bug fixed which affected gettime functions and sync callbacks. +- Fixed distortion on mp3 playback under FMOD CE. +- FSOUND_SetMute using FSOUND_ALL bugfix. +- DirectShow assert removed when an error occured loading wma. +- EAX1 support removed (superceeded by EAX2/EAX3). + +* FSOUND_FX api now allows multiple instances of the same effect per channel. +* Ability to 3d position stereo soures removed in software mode. Streams and samples now default + to FSOUND_STEREOPAN so they are louder. Use FSOUND_FORCEMONO on streams/samples to make them + 3d. +* Intel performance primitives for ARM were tested but removed due to insignificant speed increase. + +13/09/01 3.4 +------------ ++ DX8 fx support ++ Windows CE / PocketPC support added for handhelds! (such as compaq ipaq/casio/jornada etc). + CE support is considered in beta. See the forum at http://www.fmod.org for beta feedback. ++ Ogg Vorbis decoder upgraded to Version 1.0. 1.0 is a large quality improvement! ++ FSOUND_SetCurrentPosition added. ++ FSOUND_GetOutputHandle added to return dsound / waveout / a3d pointer. ++ FSOUND_SetSpeakerMode added. Get true dolby digital/DTS surround output through supported hardware! ++ FSOUND_DSP_GetFFTUnit and FSOUND_DSP_GetSpectrum added. It is now possible to get a spectrum + analysis of FMOD's mixer output in realtime. Great for graphics, beat detection and note detection. ++ FSOUND_PlaySoundEx added. Has 'paused' flag that allows the user to optinally start the sound + paused, set any attribute, and then unpause it later to start it playing. Also can takes + a DSP unit handle, which means channels can now attached or grouped to specific DSP units. ++ FSOUND_DSP_GetBufferLengthTotal for help with DSP buffersize calculations. ++ FSOUND_FORCEMONO flag added for samples/streams. Force stereo sounds to play as mono. ++ FSOUND_ENABLEFX flag added for samples/streams. Enables a sample/stream to use DX8 FX. ++ FSOUND_2DHW flag added for samples/streams. Allows 2d hardware acceleration. ++ "file://" support added for streams. ++ new sample in /samples/dsp added. This shows how to use the new DSP feature of + FSOUND_PlaySoundEx to have wet/dry effects, and also the FSOUND_FX_xxx API on hardware voices. + +- FSOUND_PlaySound3DAttrib removed due to FSOUND_PlaySoundEx. +- FSOUND_Stream_Play3DAttrib removed due to FSOUND_Stream_PlayEx. +- FSOUND_Stream_SetPaused & FSOUND_Stream_GetPaused removed. Use FSOUND_SetPaused, FSOUND_GetPaused instead. +- FSOUND_Stream_SetSynchCallback fix for long files. +- FSOUND_UNMANAGED flag fixed when calling FSOUND_Close. +- Removed small audible glitches or 'chirps' when seeking in an mp3 stream. +- Delay when opening a stream removed. +- Streams now reset's its buffers when FSOUND_Stream_SetTime or FSOUND_Stream_SetPosition is + called. This makes it more cpu intensive to seek, but results in no delays when seeking. +- Small accuracy bugfix in IT replay for looping envelopes. +- fix in delay note + volume envelope for XM. +- A3D Support fixed and working ok again. +- WMA/ASF/etc Support improved. + +* FMUSIC_SetInstCallback behaviour changed to support more than one instrument at a time. + +28/04/01 3.33 +------------- ++ Linux Version update. ++ FSOUND_ALL support added to FSOUND_Reverb_SetMix. + +- EAX2 bugfix with FSOUND_Reverb_GetEnvironmentAdvanced +- Click noise removed from WAV streams if FSOUND_Stream_SetTime was used before Play. +- S3M bugfix for samples with middlec of 0. +- Low quality mixers have been removed. The symbols are there for backwards compatibility + but choosing one will autodetect a quality mixer instead. +- Small bugfix in FPU quality mixer to do with volume ramping. + +* Licensees now get an extensive compile time configuration header to include or exclude as many + fmod features as they like! a stripped FMOD.DLL can be as small as 20k now. + +27/03/01 3.32 +------------- ++ FSOUND_SetVolume, FSOUND_SetPan & FSOUND_IsPlaying support for WMA/ASF/Internet + streams/etc added. Multiple wma's open at once bug fixed. ++ Excellent quality resonant lowpass code added to fmod.exe example. Source available. ++ FSOUND_INIT_GLOBALFOCUS added for directsound output, to allow sound to be heard + even though the window is out of focus. ++ OGG VORBIS - Official beta 4 release included. Previous ver was pre-release beta 4. + +- Recording interface re-enabled. +- MP2 fix - sound coming out one channel for stereo sounds now work properly. +- 3D sound glitch with FSOUND_PlaySound3DAttrib fixed. +- FSOUND_Stream_GetLengthMs returning incorrect results loading multiple mp3's fix. +- exception when loading many wav files fixed. +- MIDI updates - FMUSIC_GetTime works again and support for FMUSIC_IsFinished added +- Possible DX8 related problems removed. +- Better handling of machines with NO soundcard. + +* improved multitasking / buffering = lower cpu usage, more stability for sound output, + especially on weird configs and low spec machines. +* FMOD will now play the audio track out of AVI files - ie DIVX etc :) + +18/02/01 3.31 +------------- ++ WAV Loop point support added! FMOD will now interpret loop points set in soundforge etc. ++ OGG VORBIS - Beta 4 used with FMOD. Fixes problems and has speed benefits. ++ FMUSIC_SetInstCallback added. Get callbacks on mod type instrument numbers. ++ FSOUND_Stream_SetSynchCallback added. Visually drop markers in your wav editing package and + FMOD will callback in time to the points as the sound plays! Great for lipsynching/gfx + demos etc. WAV/RIFF mp3 only. ++ DX8 support added. ++ NT detection added. This will mean WINMM is automatically enabled if FSOUND_Output isnt + called for better performance. All other WIN32 OS'es will use DSOUND. ++ Static library project added for commercial licensees. + +- Extra MP3 error checking, avoids crash on bad mp3 files. (why are there so many?) +- Crash fix on certain combinations of machines with sblive cards. +- WMA / Internet stream support error code fix. +- WAV loader now handles files with 2 data chunks :) +- FSOUND_DSP_ClearMixBuffer now works properly. +- Fixed wobbling row/order/time when you pause a mod. +- small crack noise at the end of looping 8bit wav files fixed. +- FSOUND_Stream_GetTime improved especially with looping streams. +- Zxx sync bug with mod files fixed where more than 1 Zxx was placed on a row. +- XM multiretrig + volume column volume bug fix. + +- LINUX - Oss now opens the socket in nonblocking mode. That should take care of the + lockups some ppl got when another app was using the sound. +- LINUX - Esd now checks (via a select()) if it can send data, blocks if it can't. The + newest Elightment Sound Daemon choked on that one, and it's the Right Thing(tm) to do. + + +* A bug has been found in the win2k sblive drivers to do with volume levels on 3d sounds.. + We suggest you get the newest version. + +17/12/00 3.3 +------------ ++ Linux support added! Big thanks to Magnus Naeslund on this for such a big effort! ++ .MIDI/.RMI support added. (use FMUSIC_LoadSong) ++ .OGG (Ogg Vorbis) support added. (FSOUND_Stream_OpenFile/FSOUND_Sample_Load). ++ .MP2 (mpeg layer 2) support added. (FSOUND_Stream_OpenFile/FSOUND_Sample_Load). ++ .WMA Support added. (FSOUND_Stream_OpenFile). ++ .ASF audio Support added. (FSOUND_Stream_OpenFile). ++ Internet streaming support added! Pass a URL to FSOUND_Stream_OpenFile!!! ++ Volume Ramping ('click removal') added to MMX mixers. All quality mixers now ramp by default. ++ MP3 playback optimized. ++ Delphi and visual basic interface updated. ++ Documentation update. + ++ API changes and new features!!! - ++ FSOUND_Stream_GetLengthMs added. Returns length of stream in milliseconds. ++ FSOUND_Stream_SetTime added. Allows setting the position of a stream in ms. (even VBR mp3s!) ++ FSOUND_Stream_OpenFile added. This combines all the old 'FSOUND_Stream_Open*' commands into 1. ++ FSOUND_Stream_SetEndCallback added. Get a callback when the stream has finished! ++ FSOUND_Stream_GetSample added. Get the internal FSOUND_SAMPLE definition for a stream. ++ FSOUND_Stream_CreateDSP added. Add a DSP effect chain per stream if you want! ++ FSOUND_Stream_Play3DAttrib added. ++ FSOUND_CD_SetVolume and FSOUND_CD_GetVolume added. ++ FSOUND_CD_GetTrackTime added. Returns current track time. ++ FSOUND_CD_GetTrackLength added. Returns track length in milliseconds. ++ FSOUND_Sample_Load replaces all previous FSOUND_Sample_Load* functions. ++ FSOUND_Sample_GetName added. ++ FSOUND_PlaySound3DAttrib added. Replaces FSOUND_3D_PlaySound and FSOUND_PlaySoundAttrib. ++ FSOUND_SetLoopMode added for those who want per channel loop control not per sample. ++ FMUSIC_SetReverb added (for MIDI only currently) + ++ FSOUND_LOADMEMORY flag added which allows sample loading, and STREAMING from a memory pointer. ++ FSOUND_MPEGACCURATE flag added for FSOUND_Stream_SetTime and MP2/MP3. You can use this to get accurate time length, + and set the exact specified time in an MP3 even if it has a Variable BitRate!! (VBR) ++ FSOUND_ALL added to channel and sample flags. This allows 1 function call (to FSOUND_SetVolume + for example) and it will affect ALL channels! The possibilities are cool, such pitchbending all + sounds playing with FSOUND_SetFrequency(FSOUND_ALL, freqval); etc. + + +- Some mod based fixes including better support for corrupted files :} +- Click bug removed on single-shot (non looping) samples for software engine. +- Bug in mmx 8bit sample mixers fixed. +- Streaming files stutter bug upon start removed / lessened. +- MP3 frame filter added to remove corruption/glitches in bad mp3's. +- ADPCM wav file corruption introduced in 3.22 removed. +- FSOUND_Sample_SetLoopPoints bad parameter handling fixed. +- FSOUND_StopAllChannels removed in favour of FSOUND_ALL flag. fmod.dll is still backwards compatible. +- FSOUND_Sample_LoadWav removed in favour of FSOUND_Sample_Load. fmod.dll is still backwards compatible. +- FSOUND_Sample_LoadMpeg removed in favour of FSOUND_Sample_Load. fmod.dll is still backwards compatible. +- FSOUND_Sample_LoadRaw removed in favour of FSOUND_Sample_Load. fmod.dll is still backwards compatible. +- FSOUND_Sample_LoadWavMemory removed in favour of FSOUND_Sample_Load. fmod.dll is still backwards compatible. +- FSOUND_Sample_LoadMpegMemory removed in favour of FSOUND_Sample_Load. fmod.dll is still backwards compatible. +- FSOUND_Stream_Open removed in favour of FSOUND_Stream_OpenFile. fmod.dll is still backwards compatible. +- FSOUND_Stream_OpenWav removed in favour of FSOUND_Stream_OpenFile. fmod.dll is still backwards compatible. +- FSOUND_Stream_OpenMpeg removed in favour of FSOUND_Stream_OpenFile. fmod.dll is still backwards compatible. +- FSOUND_3D_PlaySound removed in favour of FSOUND_PlaySound3DAttrib. fmod.dll is still backwards compatible. +- FSOUND_PlaySoundAttrib removed in favour of FSOUND_PlaySound3DAttrib. fmod.dll is still backwards compatible. +- FSOUND_MIXER_QUALITY_FPU_VOLUMERAMP removed, all quality mixers are volume ramping now. +- FMOD_ERR_INVALID_MIXER error removed in favour of already existing FMOD_ERR_INVALID_PARAM flag. +- FSOUND_GetCurrentVU improved, and bugfixed for stereo samples. +- Other minor bugfixes. + +* Streamer callbacks created with FSOUND_Stream_Create must now return TRUE, or FALSE to terminate the stream. +* FSOUND_MixBuffers renamed to FSOUND_DSP_MixBuffers +* _cdecl calling convention specified for callbacks in case default calling convention is changed (thanks Aristarkh Zagorodnikov) +* changed LCC-WIN32 compiler definition in fmod.h to __LCC__ (not LCCWIN32) so it works better now :) + +05/11/00 3.21 +------------- +* Intermediate update before FMOD 3.3 is released. + ++ New, easier to navigate documentation layout. Recording interface added to documentation :) + +- End of non looping MP3 on rare combination of filelength crash fixed. +- More efficient streaming engine, mp3 and other format playback is even faster than before. +- Master Volume and FSOUND_SetVolumeAbsolute bug fixed. + +04/05/00 3.2 DX3 Patch +----------------------- ++ Improved playback stability with harddisk interruptions occuring in the background. +- DirectX versions *less than* DX7 compatibility problem fixed (most noticable under NT). This was thanks to bug in dsound API (thanks microsoft!) + + +01/05/00 3.2 +------------ +* FSOUND_NORMAL re-defined to (FSOUND_LOOP_OFF | FSOUND_8BITS | FSOUND_MONO), as in some + cases it was being mistaken for a bitfield and or'ed in with other flags when it infact wasnt. (it was 0!) +* FSOUND_EAX interface renamed to FSOUND_Reverb interface. (to fit a3d reverb, software reverb etc not just EAX) + ++ DX7 support added. This adds more hardware voices than previously possible before. ++ EAX 2.0 support added. This means advanced reverb functionality and manual occlusion control. ++ A3D 3.0 support added (FMOD comes with a3dapi.dll now). This adds A3D reverb and advanced reverb support. ++ RECORDING support added. See FSOUND_Record_StartSample, FSOUND_Record_StartWAV etc. ++ FSOUND_MIXER_QUALITY_FPU_VOLUMERAMP mixer added. This removes clicks on sudden volume changes for added quality. ++ MMX quality mixer speed increased AGAIN to crazy speeds! Check out the new comparison charts. ++ 'userdata' parameter added to FSOUND_Stream_Create. ++ FMOD Standalone player/example (fmod.exe). Added 48khz support, MP3,WAV & A3D 3 support! + Reverb added (NR button removed) and lowpass filter declicked. See FMOD.C for the code for all this! ++ New music callbacks! FMUSIC_SetRowCallback, FMUSIC_SetOrderCallback. LATENCY ADJUSTED, so when it calls back on a particular row, it is the row you HEAR. ++ FSOUND_Stream_GetTime smoother and LATENCY ADJUSTED, so when the time displays a value, that is the time into the stream that you HEAR. ++ FMUSIC_GetPatternLength added. (for time calculation purposes) ++ FSOUND_SetMinHardwareChannels and FSOUND_SetMaxHardwareChannels added. Great for controlling 3d Hardware resources. ++ FSOUND_REVERB_IGNOREPARAM added, so you can change specific elements of environmental reverb and ignore others. ++ Delphi interface added! ++ Added fmod_errors.h which contains FMOD_ErrorString. Use this in conjunction with FMOD_GetError to get a string description of the error. + +- PCM .WAV files accidentally did an ACM codec check even if it was PCM. Some machines didn't + have this PCM ACM codec, and so loadwav or openwav failed - ACM check now skipped for PCM files. +- FSOUND_GetCurrentVU fixed! +- 3D - Software engine bugfixed rolloff and distancefactor to make it sound more like DS3D. +- WAV/MP3 - streamer fixes and improvements. +- XM/IT - portamento with multi sample instruments fixed. +- API - FSOUND_Sample_Get somehow dissapeared from the DLL.. back again. +- API - MU-Law functions removed. +- Many other miscellaneous fixes. + +08/01/00 3.11 +------------- ++ RIFF based MP3 files and MP3's with ID3 tags at the start now supported. + +- LoadSongMemory fixed and works again +- Pentium Pro selecting wrong mixer upon autodetect now fixed. +- XM and IT bugfixes. + +24/12/99 3.1 +------------- + +* FMUSIC_OptimizeChannels put back into fmod.h. Im not sure why it dissapeared in the first place :) +* 'stream.exe sample' changed from WAV to a MP3 command line streamer because more people wanted that. +* LoadMemory functions now take a length (length of the buffer). You may have to change your code + to support this (it is not backward compatible with 3.0. I didnt want to add more functions to the + API for such a minor change. + ++ Variable bitrate MP3's now supported! ++ FSOUND_SetHWND added for those who want to specify their own HWND for dsound focus purposes. ++ FSOUND_Stream_GetTime added, for smooth, non lagged, accurate synchronization with stream + playback. + Use this for synchronizing MP3's to your graphics! ++ Added stability to sound output of software engine, for when harddisk accesses occur. + +- 8 bit raw wav streaming bug fixed where output was noisy. +- Streamer start/stop logic bug fixed/improved. (it used to hang on exit if you did several start/stops in a row) +- Small XM bugfix on delay note. +- Fixed startup crash bug. This was caused by BAD DRIVERS. Creative ES1370 sound card drivers + have a bug, and they have the cheek to set the certified bit in the caps. It also reports + 256 hardware 3d channels which is obviously a lie. Thanks to Marcus Aarts, Anders Nilsson and + Shane Stevens for helping me find this one. +- Documentation fixes. + + +12/12/99 3.0 +------------- + +* New timing system, no more update rate, no more mixahead! a lot more stable on shit cards + like awe64, and at the same time, very low latency. +* FSOUND_SetPanSeperation only affects sfx now, not music. +* If mixer is not selected, it defaults to a quality mixer now, not a low quality one like before. +* FSOUND_Geometry_AddPolygon now supplies normal as well AND opening factor. (it takes NULL also) +* FSOUND_3D_Listener_GetAttributes now consistant across all output types. (waveout missed out before) +* FSOUND_SetPaused now works on FSOUND_HW3D buffers. +* FSOUND_SetMute now works on FSOUND_HW3D buffers. +* FSOUND_MixChannel renamed to FSOUND_MixBuffers (it has nothing to do with channels really) +* FSOUND_Listener_SetAttributes does not update 3d info now, FSOUND_3D_Update does. + ++ Added FSOUND_File_SetCallbacks. Use this to make FMOD use your own file operations. ++ Compressed WAV support added ++ MP3 Support added ++ EAX Support added ++ A3D Support added (with full geometry and list support) ++ MMX quality mixer sped up 2-3 times on ppro+ machines! (p6/p2/p3) ++ FSOUND_Driver_GetCaps added.. Now query the capabilities of drivers before calling FSOUND_Init. ++ FSOUND_Stream_Create added - an easier way to stream data. ++ FMUSIC_SetPanSeperation added, for per song pan seperation control. ++ FSOUND_3D_Update added. This is now the global 3d update/flush function, NOT FSOUND_Listener_SetAttributes. ++ FSOUND_Geometry_Material functions implemented ++ Documentation added for geometry stuff, also other documentation updated (playsound, 3d stuff) ++ Software 3D Engine updated! Software sounds used to audibly update on + FSOUND_3D_Emitter_SetAttributes only, and not when the listener was updated. + Now they are updated on neither, they are audibly updated now in FSOUND_3D_Update. + This means you can now move the listener without updating the sources and all the sources will + update automatically! This behaves the same as DS3D now. ++ FSOUND_GEOMETRY_OPENING & FSOUND_GEOMETRY_OPENING_REFERENCE implemented! create doorways. ++ Geometry list functions added. A faster way of processing geometry. + FSOUND_Geometry_AddList(FSOUND_GEOMLIST *geomlist); + FSOUND_Geometry_List_Create(signed char boundingvolume); + FSOUND_Geometry_List_Free(FSOUND_GEOMLIST *geomlist); + FSOUND_Geometry_List_Begin(FSOUND_GEOMLIST *geomlist); + FSOUND_Geometry_List_End(FSOUND_GEOMLIST *geomlist); + FSOUND_Geometry_List_Add(FSOUND_GEOMLIST *geomlist); ++ Added FSOUND_SetBufferSize ++ Added FSOUND_DSP_GetBufferLength + +- FSOUND_Sample_Lock / FSOUND_Sample_Unlock documented properly (oops! :) +- Soak test bug caused wave out to crash after 3 hours of operation.. fixed. +- Fixed bug in FSOUND_Sample_Create +- Some module playback improvements from fmod 2.25. +- IT mod format bug fix. (NNA caused sample vibrato to lose integrity) +- Error code is now set to FMOD_ERR_NONE on all function calls, so you dont parse an error + that was set 10 function calls ago for example. +- NoSound output mode improved. +- Removed FSOUND_SetMixAhead +- Removed FSOUND_SetUpdateRate + +18/10/99 2.25 +------------- +* Version number now included in DLL. (right click on DLL for info) ++ IT - mods composed with IT versions older than 2.0 reenabled. I dont have many + of these songs and it seemed to work straight away and the songs i did have. + They sounded ok, but if there are any problems with old IT mods then mention + them to me and I might try to fix them. (theyre not high on my priority list) +- FMUSIC_SetZxxCallback did not have the correct documentation and just took a + void * as the callback. The actual format of the callback is + callback(FMUSIC_MODULE *mod, unsigned char param). FMUSIC_SetZxxCallback now + forces this. +- IT - Impulse tracker 2.15 compressed samples reenabled :) +- IT - FMOD was interpreting IT's stereo flag for samples, which was erroneously + set by older versions of IT, causing some samples to play twice as fast as they + should. Stereo check removed (IT never supported stereo samples) +- MOD S3M XM IT - Sample offset bug fixed. +- XM IT - minor bugs fixed. +- Closedown stability increased. + +31/08/99 2.24 +------------- +* This is the last FMOD 2.* update unless there are some small niggling bugs. I + need to finish 3.0. +* NOSOUND - FSOUND_OUTPUT_NULL now behaves as if everything is active, therefore + you will get all music callbacks and timers, vu meters, dsp functions and everything + else working correctly etc as if it was playing, but you dont hear anything. +* FMOD ported to N64. +* API - this version is now declared stable. It has been run over with memory leak + tools and numerous memory problems have been found and fixed. +* DSP - Note that the 'length' part of the callback now fluctuates more to increase + output stability, and its maximum size can equal up to the updaterate + mixahead + in milliseconds. +* TOOLS - convert.exe removed. use soundforge or some such program if you want to + convert a wav to a a raw signed datastream. + ++ API - New reference count channel index! The index PlaySound returns now has a + reference count in the top 16bits. This so you can call playsound, store the + return value, then if that channel gets stolen by the priority system, and you + blindy try and keep updating it as if it was from your original playsound, the + new sound wont be affected!! ++ API - FSOUND_Stream_OpenWav added. Now you can stream wav files with ease. This + version still only supports PCM wav, but FMOD 3.0 should change this situation. ++ API - FSOUND_SetSFXMasterVolume & FSOUND_GetSFXMasterVolume added. ++ API - FSOUND_SetVolumeAbsolute added. This volume overrides master volume. Great + if you need to lower the volume of your game effects and make one stand out. ++ MUSIC - FMUSIC_OptimizeChannels added! This function kicks arse if you are trying + to lower channel usage. You give it a 'channels mixed' value, and a 'mod volume' + value, and it wont play sounds in a song that have a lower volume than 'mod volume', + if 'channels mixed' is being exceeded as stated in FSOUND_GetChannelsPlaying. + One example is a game that reduced its maxchannels from 24 to 16 because of this + with no audible difference. (the song had a lot of 'echos' that didnt need to be + audible when things got noisy, so FMOD threw them away.) ++ MUSIC - FMUSIC_GetSample and FMUSIC_SetSample added! This allows you to get control + of samples within a mod! Great if you need to compress samples yourself and then + decompress them back into the mod during your game. This was in 2.23 but i forgot + to mention it here :) ++ STREAM - file streaming example added to the sample directory. Command line driven + and takes a .wav file. + +- 3D - Software doppler effect rewritten, now physically accurate :).. + FSOUND_3D_Listener_SetDopplerFactor() now means something different to the previous + versions. Check the documentation for more on this. +- DRIVER - fixed problem with some peoples machines that have more than 16 + 'soundcards' that i thought would be the maximum. (It is actually just a + hardware card enumerating a whole waveout device for each hardware channel.) +- INTERFACE - command line parameters fixed, and some people not seeing the interface + appear should now be happy. +- IT - channel allocation bug fixed. + +17/08/99 2.23 +-------------- ++ API - FSOUND_UNMANAGED flag added for sample loading/management ++ API - Added FSOUND_DSP_ClearMixBuffer. Use this before doing a biiiiiig harddisk access so you + dont get looping noise/stuttering, (because the harddisk/windows basically bus masters and shuts + down all threads, causing the mixer to stop as well, but the soundcard keeps playing the buffer). +- API - FSOUND_Sample_LoadWav & FSOUND_Sample_LoadWavMemory now return proper error code. +- MIXER - clicks removed from bidi looping sample in quality mixer. +- IT - fixed 2.15 compressed samples now work (oops forgot to call the right decompressor) +- IT - Memory footprint drastically reduced for pattern data (now leaves pattern data compressed and + unpacks on the fly) +- XM - Digitracker saved XM's now work correctly (dont crash, and illegal stuff filtered out) +- XM - envelope bug fixed. +- 3D - divide by 0 bug fixed (when listener and emitter are at the same location) +* API - Sample based functions like FSOUND_Sample_LoadWav etc take an index now, so you can specify + an absolute sample manager index, FSOUND_FREE or FSOUND_UNMANAGED + +18/06/99 2.22 rev 1 +------------------ +- IT - really obscure crash bug fixed. + +18/06/99 2.22 +------------------ +- MOD - accidently broke mod support, fixed +- S3M - fixed bug with bpm's smaller than 20h +- Idle optimization back in + +14/06/99 2.21 +------------------ +* Fix included from 2.2rev1 (registry bug in fmod standalone player) +* VC5 compatible import library included. vc6 only slipped into the last release. ++ IT 'envelope carry' support added. ++ MIXER - big increase in sound stability when harddisk is being accessed!! ++ LCC-WIN32 import library added. +- IT - crash bugfix. (envelopes with loop end before loop start) +- IT - volume bug (not hearing some samples at all) fixed in IT 'sample' mode. +- MOD S3M XM IT - fixed pattern delay bug +- DLL - size of DLL reduced by 12k! + +08/05/99 2.2 rev 1 +------------------ +- INTERFACE - fixed stupid registry bug which cause bad drivers to be initialized + at start up. It caused possible crashing, 000 channels mixed to be displayed + and no sound. + +16/05/99 2.2 +------------ +* FMOD is now a non beta release! +* MIXER - Changing driver on the fly with FSOUND_Driver_Close and + FSOUND_Driver_Init does not stop music playback any more. Everything + continues playing as it had been. +* API - Please read the new documentation on FSOUND_SetUpdateRate and + FSOUND_SetMixAhead!!!! This should remove confusion about what they do + and the issues of cpu usage, response time/latency and sound stability! ++ MIXER - FPU 32bit interpolating high quality mixer added! ++ API - FSOUND_Sample_SetLoopMode added ++ MOD - M!K! mod format supported. ++ INTERFACE - FMOD now saves sound settings in registry. +- API - Safety checking put into FSOUND_SetOutput, FSOUND_SetDriver, + FSOUND_SetMixer, FSOUND_SetUpdateRate and FSOUND_SetMixAhead. These + functions will fail and return an error code if FMOD is active and playing + sounds. You need to close FMOD down to call these functions, then + reinitialize it. FSOUND_Driver_Close and FSOUND_Driver_Init will fail also + if FSOUND has not been initialized with FSOUND_Init. +- MIXER - Fixed rare crash bug when background disk access caused timer + fluctuations. +- MIXER - Fixed rare sound output instability caused by closing and opening + fsound's driver code very quickly in succession. +- MIXER - Fixed crash bug on bidi samples playing backwards, at volume 0, + on the standard blendmode mixer only. (FPU Mixer also) +- MIXER - Fixed horrible fuzzy quality bug with MU-Law compressed samples! +- MIXER - Fixed standard blend mode mixer, which wasnt doing vol0 optimization + on -muted- channels. +- IT - fixed crash bug with mod that reference IT instruments beyond the + number of instruments. +- API - All 'interpolation functions' removed, if you want interpolation select + the FPU interpolating mixer and every sound played will use full 32bit + interpolation. (choosing which channels you want interpolated would end + up being a pain. Most people just want everything interpolated or not) +- CD - various CD player bugs fixed (random play, pause logic etc) +- API - FSOUND_GetCurrentVU now reports correct values for MuLaw compressed + samples. + +09/05/99 2.19b +-------------- +* API release, this includes changes/fixes from 2.18 Update 1 (cdrom fixes) +* Documentation updated +* FMOD is now approaching a non beta state! (no bug reports are coming in) + Beta status will most likely be removed in a few weeks (maybe version 2.20) +* API - FSOUND_SetLatency has been renamed to FSOUND_SetUpdateRate, sorry for + the name change but it is really the incorrect name for what this function does. ++ INTERFACE - Settings now saved in registry. New minimal CD Player panel! ++ CPU usage reduced during idle time. FMOD shuts itself down when nothing is happening. ++ API - FSOUND_Sample_Alloc now allows specification of default priority as well. ++ API - FSOUND_Sample_SetDefaults lets you set a sample's default freq,vol,pan & priority. ++ API - FSOUND_GetCurrentVU added, by request. (useful for vu bars/beat detection?) ++ API - FMUSIC_GetTime added, by request. Useful for exact music synchronization EVERY time. ++ API - FSOUND_GetCurrentSample added, allows you to get the currently playing sample for + a particular channel, useful for comparisons.. ie to see if a particular sample is still + playing on a particular channel. +- API - FSOUND_SetAttributes removed. It was added before due to a request but I + feel it is just API bloat and can be achieved through a macro. + +28/04/99 2.18b Update 1 (player only) +------------------------------------ +* FMOD - player only being updated here, not the API. API releases usually + come on the weekend. (they take more time to prepare) ++ CD - Added continuous, looped and random buttons for playback method. +- CD - All bugs fixed in CD player, all created by BUGS in WIN32 API + functions. (mmsystem & mci commands- some work ok on NT, fail on 95). +- Removed startup dialog box. Defaults to primary device and dsound. Hit config + to change. (maybe use registry later) + +25/04/99 2.18b +-------------- +* API - FSOUND_GetNumChannels renamed to FSOUND_GetMaxChannels ++ CD - New CD commands and support. FSOUND's CD system is a NON POLLING non + intrusive system (unlike windows cd player), for smooth background performance. + Tracks can now be looped, stopped and continued. ++ INTERFACE - new filters! Preverb filter(!) and Noise reduction. ++ INTERFACE - CD Player added. + +17/04/99 2.17b +-------------- +* API - FSOUNDVC.LIB now VC5.0 compatible. +- XM - Fixed crash on sample offset. +- API - FMUSIC_SetPaused fixed. +- MIXER - Fixed MULAW mixer. Remember MULAW only works when a song has 16bit + samples (it converts them to mulaw), otherwise it isn't any different. It + only works for the blend mode mixer as well. The MMX mixers are fast enough + not to need mulaw. + +11/04/99 2.16b +-------------- ++ API - DSP Engine implemented and added! New functions: + FSOUND_DSP_Create,FSOUND_DSP_Free,FSOUND_DSP_SetPriority, + FSOUND_DSP_GetPriority,FSOUND_DSP_SetActive, + FSOUND_DSP_GetActive,FSOUND_DSP_GetClearUnit, + FSOUND_DSP_GetSFXUnit,FSOUND_DSP_GetMusicUnit + FSOUND_DSP_GetClipAndCopyUnit. + See FSOUND_DSP_Create for documentation on this new feature. ++ API - Added FSOUND_MixChannel - now you have direct access to + FSOUND's optimized mixers! +- MOD, S3M, XM, IT - Fixed loader bug introduced in 2.15! (to do + with load from memory system.) +- XM - Found and fixed a sample offset bug introduced a few + versions ago, with 16bit samples. +- API - Echo engine and functions removed - DSP engine is now to + be used. +- API - Fixed bug in FMUSIC_SetOrder. +- API - Fixed bug in FSOUND_GetMixer, it was returning + FSOUND_MIXER_AUTODETECT if that was used in FSOUND_SetMixer, + instead of the actual mixer it was using. +- INTERFACE - loader bug fixed. + +28/03/99 2.15b +-------------- ++ API - Watcom now supported. Watcom users link in the + FSOUNDW.LIB import library. ++ API - Added FMUSIC_LoadSongMemory, now load mod/s3m/xm/it + files from memory handles / resources. ++ API - Added FSOUND_LoadWavMemory, now load wav files from + memory handles / resources. +- API - Fixed bug in FSOUND_Sample_Alloc which allocated samples + with length = 0, and hence no sound came out when played. +- SAMPLE - fixed bugs in fmod sample code. + +21/03/99 2.14b +-------------- +* FSOUND / FMUSIC is now a DLL. The reason is to use a dll is + to make it easier to link on different compilers, and it really + is for aesthetic reasons only to have it as a .lib. (ie 1 exe + releases) and im not interested. +* Examples cleaned up, they dont specify unused .libs any more. +- WAVEOUT - bugfixed, works on NT now, and now actually uses + setmixahead settings. You will have to use large mixaheads + (80-100 and higher on my tests) for WaveOut, or the sound will + break up. There is nothing you can do about this. +- DSOUND - works on NT now (DX3). This is the same as waveout + (dsound3 for nt is a waveout wrapper). You will have to use + large mixahead values (80-100ms and higher on my tests), or it + may break up. ++ API - FSOUND_SetAttributes added ++ API - FSOUND_PlaySoundAttrib added + +14/03/99 2.13b +-------------- +* Programmers API finally released! see + http://www.zip.com.au/~fl for more details! ++ MIXER Stereo sample mixers added. Old way of spawning 2 new + channels is gone.. Under MMX a stereo channel is actually + faster than mono! ++ S3M, XM, IT - Zxx callback now supported. Programmers can set + a callback function for whenever the Z effect is issued from a + song, for synchronizing effects etc. .MOD is not supported. ++ STREAMERS - Streamer API Added for playing very large files. + Currently only supports raw, but mulaw, adpcm and mp3 streamers + are coming. ++ MOD, S3M, XM, IT - Master volume added to API. + This is a true scalar instead of just modifying the song's + global volume like before (ie the song might have adjusted the + global volume after you set it) ++ INTERFACE - Master volume slider added. +- MIXER - Fixed extremely rare crash bug. +- MIXER - volumes were ever so slightly out, ie a channel + panned full right still had about 0.4% (not much) of the sound + playing in the left channel instead of 0% as it should have. +- MISC - many small fixes. + +04/02/99 2.12b +-------------- +- Fixed linear freq problem introduced due to linear freq + optimization, I just removed it now for accuracy sake. +* a little bit more stable? + +02/02/99 2.11b +-------------- +- Fixed BPM problem on all formats. Now loop songs should play ok. +- Fixed sample offset on all formats (oops sorry sample offset was + disabled on mod/s3m/xm since 2.06 accidentaly! noone seemed to + notice hahaha) + +31/01/99 2.10b +-------------- +- Minor Direct Sound bugs fixed. + +30/01/99 2.09b +-------------- +- IT bug fixed with instrument numbers and no note. (most + formats dont retrigger the note in this case, but IT does if + the sample has finished playing, and not before.) +- S3M Bug found in loader. (popped up only due to impulse + tracker saved s3ms). +- IT fixed porta wihout any previous note.. porta on on a + channel that has no channel playing will trigger a new note. +- DRIVER direct sound should work more reliably on NT using + directX. +- INTERFACE fixed song list box bug. Delete happily now without + problems. +- INTERFACE config box now remembers what you last set when you + hit config, and wont change any settings if you hit 'cancel' + (it used to select nosound before) +- DRIVER code now detects incompatible cpu's and exits with an + error instead of crashing? +- XM/IT replay sped up. Linear frequencies processed a lot + faster now. + +26/01/99 2.08b +-------------- ++ DRIVERS added capability to switch drivers on the fly. Use + the 'Config' Button on the interface to change output + devices, soundcards, mixing rates or mixing routines. ++ MIXER added Mu-Law support! This is only for NON-MMX mixing, + and improves the speed of 16bit sample mixing dramatically, with + only a small loss in sample quality. (simulates 12bit accuracy) +- MIXER fixed ugly bug (crashes/noise) with 8bit BIDI looping + samples on standard blend mode mixer. + +24/01/99 2.07b +-------------- ++ IT added volume byte portamentos ++ IT added S6x - Pattern delay by ticks ++ IT added volume byte vibrato ++ IT added sample vibrato +- IT fixed effect S73, S74, S75, S76, S77, S78. These commands + are meant to alter the behaviour of an instrument, except i was + permanently modifying the instrument instead of just altering it + for the note currently being played!! oops.. +- IT / XM - turn off envelopes that have less than 2 points. + (apparently sometimes files can have this) +- IT fixed Hxy Kxy Uxy (vibrato/finevibrato).. if Hxy is followed + by U00 then it continues to be a normal vibrato, even if it says + fine vibrato.. same for Uxy followed by H00.. it continues with + a fine vibrato even if it says normal vibrato.. The y part of + the command needs to have something in it to change vibrato + types. (dumb impulse tracker bug) +- IT fixed volume slide bug in Kxy Lxy +- IT foreground / background channel logic is more accuate now with + NNA's and effect commands. +- MOD, S3M, XM, IT - now checks internal signatures for file verification + as some people were trying to load mod's etc that were renamed to s3m! + yeah yeah thanks a lot otto ;) +- IT fixed S00 - any Sxy command gets remembered and replayed if it + is followed with S00.. (crono - not just SDx and SCx like you said) +- DSOUND fixed init/shutdown code to be cleaner. + + +20/01/99 2.06b +-------------- +- XM fixed BPM issue.. seems FT2's timer is a bit faster than it + really should be.. (roughly 2bpm) mega-sample-loop songs sound + ok now. +- IT another pattern loader crash bug fixed (should be the last) +- IT fixed Gxx bug (portamento).. IT forgets it porta target + after it reaches it. (TheHornet again) +- IT fixed Oxy (sample Offset) bug + +18/01/99 2.05b +-------------- +* MIXER Using large latency again just for fmod.exe with dsound, + to improve stability (im working on it) +- IT Fixed signed/unsigned sample detection in loader +- IT Disabled pitch envelopes for IT's using IIR filters so they + wont sound awful. +- XM Fixed crash bug in loader. + +17/01/99 2.04b +-------------- +* Mixer buffer management totally rewritten, might be a *tiny* + bit slower (becuase of caching), but it is a lot more flexible + and stable. Built in preparation of the DSP plugin API. +* Halved size of both MMX mixer routines (to do with surround) +* API ready to use. Now at beta test stage +* Thanks to TheHornet for his doc on it 'nuances' that were too + subtle to find through normal testing. (bugs found with (***)) +* New more consistant mixer thread management. ++ Volume 0 optimizations! Average mods will now use about 30% + less cpu time (depends on the song) ++ Standard blend mode mixer sped up for 8bit samples ++ Windows Multimedia WaveOut support added. At the moment it + works well but the latency is too long for game sfx. It is + more stable than the direct sound driver (less garbling / + breakups) ++ .WAV sample support added. ++ Stereo sample support added. ++ IT added linear frequencies. ++ IT added panbrello ++ IT added support for 'compatible Gxx' in IT's options +- MIXER Fixed volume 0 optimization hang bug. +- IT fixed effected E/F/G to use the same memory. +- IT fixed SDx delay note bug (SD0 == SD1) (***) +- IT fixed SCx note cut bug (SC0 == SC1) (***) +- IT fixed Qxy retrig (now retrigs across multiple notes like + IT.. other formats ignore retrig if it is higher than the + speed of the song) +- IT fixed Gxx / Lxy (portamento). was 2x too slow. +- IT fixed Vibrato for 'old effects'.. with old effects it is + 2x deeper and does not get updated on tick 0. +- MIXER OOPS! i had '#define ROLLED' left uncommented in my P6 + MMX mixer since version 2.0 or so!! it wasnt using unrolled + loops. Now it is roughly 1.6 times faster! (from 5% to 3% cpu + usage on a p2-266 for mixing 32channels at once) + +14/11/98 2.03b +-------------- ++ Added stability to mixer, removed 150ms crap from 2.02 + +07/11/98 2.02b +-------------- +* ALL players use a new dynamic channel allocation system +- consider MOD, S3M & XM under beta again. (MAY have + broken something!) +* MIXER in an attempt for added stability, for this standalone + player, a different approach is used.. it has a huge + latency (150ms) and takes a bit more cpu time, but shouldnt + break up as much .. for the game library the old method + still stands. (150ms is way too long to wait for a sound + effect to trigger.. so fmod uses 50ms latency for games etc) ++ IT Added NNA's ++ IT Added DCT/DCA's. ++ MIXER Added echo post effect.. hardcoded 50ms echo for now. ++ IT Added Pan Envelope ++ IT Added all volume column effects except for porta commands & + vibrato ++ INTERFACE Added drag and drop. Drag tunes from explorer into + the player to load ++ INTERFACE also command line fileloading (ie associate the exe + in explorer with mod,s3m,xm,it then just doubleclick files + to load them) ++ IT Added most other effects +- ALL Fixed some crashing for songs that specify sample id's that + dont exist. +- XM & IT Fixed Envelope bug - loops were playing 1 tick too long :) +- S3M fixed arpeggio bug causing 0 frequencies (divide by 0) +- IT fixed pattern break and pattern jump .. both params are + hex unlike all other formats. +- IT fixed arpeggio depth +- IT enabled end of song marker.. it was crashing on this b4 +- INTERFACE Fixed memory leak.. it would slowly leak memory in + realtime until windows ran out of resources and crashed! :) +- IT fixed porta bugs.. oops i was portamento'ing 2x too fast +- IT fixed instrument bug. it was updating all nna channel's + envelopes etc, using only the most recent nna's instrument + definition, instead of the instrument that should have been + associated with each individual nna channel. +- IT fixed set pan (Xxx) bug +- IT fixed invalid pattern bug with patterns defined that are + larger than the number of patterns specified in the file. +- IT fixed vibrato (Hxy) bug +- IT fixed big NNA bug.. i was performing NNA's based on the + new instrument's nna flags instead of the one it was + cutting off! +- IT fixed the past nna s7x effects.. now the number of channels + mixed on the interface matches exactly that of impulse + trackers! + +20/10/98 2.01b +-------------- ++ IT Added preliminary volume envelope support (no sustain loops) ++ IT Added channel volume slide ++ IT Added noteoff & notecut (not the effect, the note type) + +19/10/98 2.00b +-------------- +* First private release Version, includes MOD, S3M and XM and IT + support. New software mixers, win32 only. Removed 669,FAR & + MTM support, old interface is gone, new win32 interface.. + jeezus has it been 3 years? im getting too old for this shit:) +* IT Support is REALLY basic.. roughly 30% done. +- XM Fixed bug with envelope loopend. + + + +/|\ + | + | + | + | + + + +30/11/95 1.06 +------------- +* Released with FMODDOC 2, including full source code ++ Totally new fast scrolling interface, some keys have changed. ++ 32channel .MOD support added. (ie dope.mod type, etc) ++ 9 octaves supported now (C-0,B-8), including 7 octaves .MOD ++ No more 64kb sample limit (4gig sample on a GUS? :) ++ MTM support added ++ 669 support added - what an awful format! ++ extended 669 support added - just as bad :) ++ 16 bit support added (err for mtm? ahh well xm will come) ++ Clipping samples at loopend points to save GUS memory ++ S3M support added +- Bugfix where all music came out in left channel on SOME cards + (none I have heard:). Thanks to Brad Thomas for the fix. +- 2 GUS bugs fixed (reported wrong dram size & dram corruption) +* now checks if the samples are too big for the card. +- Voices now play almost simultaneously instead of 1 after the + other like before ++ Added Technicality-Index (tm) meter! Truly a cool feature. ++ Knocked 52% of DRAM upload time! YES it is *2* times faster!! + (eg when.s3m even loads *3* seconds faster than cmod does) +* - FIXED at last. FMOD will now NOT crash (fingers crossed :) +- removed clicking from looping samples +- Vibrato fixed properly this time and is 100%. +* Calculated new volume table. Not so noisy. Less distortion. ++ WildCard Support added! ++ S3M Stereo Control effect SAx added ++ Solo Channel feature added and many other muting features +- Fixed S3M retrig bug ++ Vibrato/Tremolo WaveControl finished properly ++ Keyboard LED flashing added! Lights flash to channels 1-3. +- tempo bug fixed, timing system changed so BPM can drop to 24 ++ FAR support added +* Sample loader redone and >64kb bug fixed, also pattern storage + method changed. +* Panning changed, now values from 0 to 255 to suit FT2. +- Pattern Loop bug fixed, I didnt know pattern loop stored + seperate values for each channel. +- pattern jump + pattern break bug fixed now all those weird + backwards tunes work RIGHT. ++ Added S3M's Fast Volume Slide bug, err feature :) +++ NOW PMODE! Load any sized tune you like now and still have + heaps of memory left ++ NEW tracker screen. Watch pattern data like a tracker +- Keyboard LED flashing removed, caused crashes on some + peoples computers.. sigh it was rather cool. ++ NEW technical info screen. Watch a lot of meaningless info + appear on the screen. Good for developers to check against. +- .MOD bug fixed, now those extremely high and low octaves + supported PROPERLY.. (unlike some cMOD players;) +- sample offset bug fixed. ++ Dynamic interface installed, now any screen can be called up + from any other screen, instead of just from the main screen + like before. +* Error handling changed for a lot better stability. ++ File Selector included for all those losers who wanted it :) ++ Added effect Ixy - Tremor - perfect I think unlike other + players.. compared against Scream Tracker 3 +- Fixed >64kb sample loading bug - was causing crashes +- Fixed MTM loader bug after about 6 hours of tearing out hair +* File Selector now accessable while song is still playing, + press escape to return to the main interface. +- sample uploader recoded, fixed. 16 bit samples now load + a lot better (this is actually from 1.07 which isnt released + yet and probably wont be for a while ;) +- a zillion little other bugs fixed. + +13/6/95 1.05 +------------- +- GUS looping clicks removed. +- Mute bug fixed. Wouldnt unmute unused channles. + +10/6/95 1.04 +------------- +- fixed another crash bug ++ Added cool new pan cycling effect! Hit 'c' to try it. + +7/6/95 1.03 +------------- +- Fixed interface bug (was printing ^g's in sample names) ++ Added effect 8xy (Panning) +- Fixed crash bug maybe.. I think I did, people complained of + the interface crashing.. I've never seen it crash but I found + I was mixing 'new' and 'malloc'.. fixed. ++ Added effect 7xy (Tremolo) - woopee ;) ++ Added mute channels ++ Added panning keys '(' and ')' to set default panning. + +30/5/95 1.02 +------------- +* major internal storage changes! ++ More memory in dos shell! around 30kb on average sized tunes. +* A lot faster. +- Pattern break fixed. Tested on backward.mod by FireLight +- Now mixes at 44.1khz like it should instead of 30khz..oops :} ++ Added effect EEx (Pattern Delay). ++ Added effect E6x (Pattern Loop). +- Retrig fixed now 100% protracker. + +5/4/95 1.01 +------------- +- fixed crash bug / increased speed by not calculating unused + channels. (I don't think i released this version though) + +6/3/95 1.00 +------------- +* FIRST PUBLIC RELEASE (In FireStorm 2 Music Disk) +- Vibrato bug fixed, now works I think :). +* Interface Completely changed looks much nicer now ++ speed of interface increased greatly + +============================================================================== + diff --git a/fmodapi375win/media/canyon.mid b/fmodapi375win/media/canyon.mid new file mode 100644 index 0000000..9530d80 Binary files /dev/null and b/fmodapi375win/media/canyon.mid differ diff --git a/fmodapi375win/media/chimes.wav b/fmodapi375win/media/chimes.wav new file mode 100644 index 0000000..265a37f Binary files /dev/null and b/fmodapi375win/media/chimes.wav differ diff --git a/fmodapi375win/media/drumloop.wav b/fmodapi375win/media/drumloop.wav new file mode 100644 index 0000000..b35e216 Binary files /dev/null and b/fmodapi375win/media/drumloop.wav differ diff --git a/fmodapi375win/media/footsteps.fsb b/fmodapi375win/media/footsteps.fsb new file mode 100644 index 0000000..948ef22 Binary files /dev/null and b/fmodapi375win/media/footsteps.fsb differ diff --git a/fmodapi375win/media/invtro94.s3m b/fmodapi375win/media/invtro94.s3m new file mode 100644 index 0000000..1f2ad5d Binary files /dev/null and b/fmodapi375win/media/invtro94.s3m differ diff --git a/fmodapi375win/media/jaguar.wav b/fmodapi375win/media/jaguar.wav new file mode 100644 index 0000000..0347714 Binary files /dev/null and b/fmodapi375win/media/jaguar.wav differ diff --git a/fmodapi375win/media/jbtennis.wav b/fmodapi375win/media/jbtennis.wav new file mode 100644 index 0000000..77e710c Binary files /dev/null and b/fmodapi375win/media/jbtennis.wav differ diff --git a/fmodapi375win/media/jules.mp3 b/fmodapi375win/media/jules.mp3 new file mode 100644 index 0000000..85ce933 Binary files /dev/null and b/fmodapi375win/media/jules.mp3 differ diff --git a/fmodapi375win/samples/3d/3d.dsp b/fmodapi375win/samples/3d/3d.dsp new file mode 100644 index 0000000..5157bb9 --- /dev/null +++ b/fmodapi375win/samples/3d/3d.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="3d" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=3d - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "3d.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "3d.mak" CFG="3d - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "3d - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "3d - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "3d - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"3d.exe" + +!ELSEIF "$(CFG)" == "3d - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"3d.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "3d - Win32 Release" +# Name "3d - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/3d/3d.exe b/fmodapi375win/samples/3d/3d.exe new file mode 100644 index 0000000..32925ce Binary files /dev/null and b/fmodapi375win/samples/3d/3d.exe differ diff --git a/fmodapi375win/samples/3d/Main.cpp b/fmodapi375win/samples/3d/Main.cpp new file mode 100644 index 0000000..3f7abae --- /dev/null +++ b/fmodapi375win/samples/3d/Main.cpp @@ -0,0 +1,450 @@ +//=============================================================================================== +// 3D.EXE +// Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. +// +// This test shows EAX, DS3D and Software all being used together and the simple commands needed +// to set up some 3d audio. +// This application also displays the use of FSOUND_GetDriverCaps to get information on the +// 3D capabilities of the selected driver +//=============================================================================================== + +#include +#include +#include +#if defined(WIN32) || defined(__WATCOMC__) || defined(_WIN64) + #include + #include +#else + #include "../../api/inc/wincompat.h" +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" // optional + +#define INTERFACE_UPDATETIME 50 // 50ms update for interface + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void Close(FSOUND_SAMPLE *samp1, FSOUND_SAMPLE *samp2, FSOUND_SAMPLE *samp3) +{ + // you dont need to free samples if you let fsound's sample manager look after samples, as + // it will free them all for you. + FSOUND_Sample_Free(samp1); + FSOUND_Sample_Free(samp2); + FSOUND_Sample_Free(samp3); + + FSOUND_Close(); +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main() +{ + FSOUND_SAMPLE *samp1 = NULL, *samp2 = NULL, *samp3 = NULL; + char key, listenerflag = 1; + int driver, i = 0, channel1 = -1, channel2 = -1; + float listenerpos[3] = { 0,0,0 }; + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + // ========================================================================================== + // SELECT OUTPUT METHOD + // ========================================================================================== + + printf("---------------------------------------------------------\n"); + printf("Output Type\n"); + printf("---------------------------------------------------------\n"); +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + printf("1 - Direct Sound\n"); + printf("2 - Windows Multimedia Waveout\n"); + printf("3 - ASIO\n"); +#elif defined(__linux__) + printf("1 - OSS - Open Sound System\n"); + printf("2 - ESD - Elightment Sound Daemon\n"); + printf("3 - ALSA 0.9 - Advanced Linux Sound Architecture\n"); +#endif + printf("4 - NoSound\n"); + printf("---------------------------------------------------------\n"); // print driver names + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + } while (key != 27 && key < '1' && key > '4'); + + switch (key) + { + +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_ASIO); + break; +#elif defined(__linux__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_OSS); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_ESD); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_ALSA); + break; +#endif + case '4' : FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); + break; + default : return 1; + } + + + // ========================================================================================== + // SELECT DRIVER + // ========================================================================================== + + // The following list are the drivers for the output method selected above. + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_ASIO: printf("ASIO"); break; +#elif defined(__linux__) + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("Alsa"); break; +#endif + + }; + printf(" Driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_GetDriverName(i)); // print driver names + { + unsigned int caps = 0; + + FSOUND_GetDriverCaps(i, &caps); + + if (caps & FSOUND_CAPS_HARDWARE) + printf(" * Driver supports hardware 3D sound!\n"); + if (caps & FSOUND_CAPS_EAX2) + printf(" * Driver supports EAX 2 reverb!\n"); + if (caps & FSOUND_CAPS_EAX3) + printf(" * Driver supports EAX 3 reverb!\n"); + } + } + printf("---------------------------------------------------------\n"); // print driver names + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) + return 0; + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_GetNumDrivers()); + + FSOUND_SetDriver(driver); // Select sound card (0 = default) + + { + unsigned int caps = 0; + + FSOUND_GetDriverCaps(FSOUND_GetDriver(), &caps); + + printf("---------------------------------------------------------\n"); + printf("Driver capabilities\n"); + printf("---------------------------------------------------------\n"); + if (!caps) + printf("- This driver will support software mode only.\n It does not properly support 3D sound hardware.\n"); + if (caps & FSOUND_CAPS_HARDWARE) + printf("- Driver supports hardware 3D sound!\n"); + if (caps & FSOUND_CAPS_EAX2) + printf("- Driver supports EAX 2 reverb!\n"); + if (caps & FSOUND_CAPS_EAX3) + printf("- Driver supports EAX 3 reverb!\n"); + printf("---------------------------------------------------------\n"); + } + + FSOUND_SetMixer(FSOUND_MIXER_AUTODETECT); + + // ========================================================================================== + // INITIALIZE + // ========================================================================================== + if (!FSOUND_Init(44100, 32, 0)) + { + printf("Init: %s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + + // ========================================================================================== + // LOAD SAMPLES + // ========================================================================================== + + // ========================================================================================== + // 3D MONO + // ========================================================================================== + + samp1 = FSOUND_Sample_Load(FSOUND_FREE, "../../media/drumloop.wav", FSOUND_HW3D, 0, 0); + if (!samp1) + { + printf("samp1: %s\n", FMOD_ErrorString(FSOUND_GetError())); + Close(samp1, samp2, samp3); + return 1; + } + + // increasing mindistnace makes it louder in 3d space + FSOUND_Sample_SetMinMaxDistance(samp1, 4.0f, 10000.0f); + FSOUND_Sample_SetMode(samp1, FSOUND_LOOP_NORMAL); + + // ========================================================================================== + // 3D MONO + // ========================================================================================== + samp2 = FSOUND_Sample_Load(FSOUND_UNMANAGED, "../../media/jaguar.wav", FSOUND_HW3D, 0, 0); + if (!samp2) + { + printf("samp2: %s\n", FMOD_ErrorString(FSOUND_GetError())); + Close(samp1, samp2, samp3); + return 1; + } + // increasing mindistance makes it louder in 3d space + FSOUND_Sample_SetMinMaxDistance(samp2, 4.0f, 10000.0f); + FSOUND_Sample_SetMode(samp2, FSOUND_LOOP_NORMAL); + + // ========================================================================================== + // 2D STEREO + // ========================================================================================== + samp3 = FSOUND_Sample_Load(FSOUND_UNMANAGED, "../../media/chimes.wav", FSOUND_HW2D, 0, 0); + if (!samp3) + { + printf("samp3: %s\n", FMOD_ErrorString(FSOUND_GetError())); + Close(samp1, samp2, samp3); + return 1; + } + + // ========================================================================================== + // DISPLAY HELP + // ========================================================================================== + + printf("FSOUND Output Method : "); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("FSOUND_OUTPUT_NOSOUND\n"); break; + case FSOUND_OUTPUT_WINMM: printf("FSOUND_OUTPUT_WINMM\n"); break; + case FSOUND_OUTPUT_DSOUND: printf("FSOUND_OUTPUT_DSOUND\n"); break; + case FSOUND_OUTPUT_ASIO: printf("FSOUND_OUTPUT_ASIO\n"); break; + case FSOUND_OUTPUT_OSS: printf("FSOUND_OUTPUT_OSS\n"); break; + case FSOUND_OUTPUT_ESD: printf("FSOUND_OUTPUT_ESD\n"); break; + case FSOUND_OUTPUT_ALSA: printf("FSOUND_OUTPUT_ALSA\n"); break; + }; + + printf("FSOUND Mixer : "); + switch (FSOUND_GetMixer()) + { + case FSOUND_MIXER_BLENDMODE: printf("FSOUND_MIXER_BLENDMODE\n"); break; + case FSOUND_MIXER_MMXP5: printf("FSOUND_MIXER_MMXP5\n"); break; + case FSOUND_MIXER_MMXP6: printf("FSOUND_MIXER_MMXP6\n"); break; + case FSOUND_MIXER_QUALITY_FPU: printf("FSOUND_MIXER_QUALITY_FPU\n"); break; + case FSOUND_MIXER_QUALITY_MMXP5: printf("FSOUND_MIXER_QUALITY_MMXP5\n"); break; + case FSOUND_MIXER_QUALITY_MMXP6: printf("FSOUND_MIXER_QUALITY_MMXP6\n"); break; + }; + printf("FSOUND Driver : "); + printf("%s\n", FSOUND_GetDriverName(FSOUND_GetDriver())); + + int num2d, num3d; + + FSOUND_GetNumHWChannels(&num2d, &num3d, NULL); + + printf("Hardware 2D channels : %d\n", num2d); + printf("Hardware 3D channels : %d\n", num3d); + + printf("=========================================================================\n"); + printf("Press 1 Pause/Unpause 16bit 3D sound at any time\n"); + printf(" 2 Pause/Unpause 8bit 3D sound at any time\n"); + printf(" 3 Play 16bit STEREO 2D sound at any time\n"); + printf(" 4 Change to EAX Reverb mode CONCERTHALL (DirectSound/SBLive only)\n"); + printf(" 5 Change to EAX Reverb mode SEWERPIPE (DirectSound/SBLive only)\n"); + printf(" 6 Change to EAX Reverb mode PSYCHOTIC (DirectSound/SBLive only)\n"); + printf(" < Move listener left (in still mode)\n"); + printf(" > Move listener right (in still mode)\n"); + printf(" SPACE Stop/Start listener automatic movement\n"); + printf(" ESC Quit\n"); + printf("=========================================================================\n"); + + // ========================================================================================== + // PLAY 2 LOOPING SOUNDS + // ========================================================================================== + + + { + float pos[3] = { -10.0f, -0.0f, 0.0f }; + float vel[3] = { 0,0,0 }; + + channel1 = FSOUND_PlaySoundEx(FSOUND_FREE, samp1, NULL, TRUE); + FSOUND_3D_SetAttributes(channel1, pos, vel); + if (!FSOUND_SetPaused(channel1, FALSE)) + { + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + } + } + { + float pos[3] = { 15.0f, -0.0f, -0.0f }; + float vel[3] = { 0,0,0 }; + + channel2 = FSOUND_PlaySoundEx(FSOUND_FREE, samp2, NULL, TRUE); + FSOUND_3D_SetAttributes(channel2, pos, vel); + FSOUND_SetVolume(channel2, 128); + if (!FSOUND_SetPaused(channel2, FALSE)) + { + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + } + } + + // ========================================================================================== + // MAIN LOOP + // ========================================================================================== + + do + { + if (kbhit()) + { + key = getch(); + + if (key == '1') + { + FSOUND_SetPaused(channel1, !FSOUND_GetPaused(channel1)); + } + if (key == '2') + { + FSOUND_SetPaused(channel2, !FSOUND_GetPaused(channel2)); + } + if (key == '3') + { + FSOUND_PlaySound(FSOUND_FREE, samp3); + } + if (key == '4') + { + FSOUND_REVERB_PROPERTIES props = FSOUND_PRESET_CONCERTHALL; + FSOUND_Reverb_SetProperties(&props); + } + if (key == '5') + { + FSOUND_REVERB_PROPERTIES props = FSOUND_PRESET_SEWERPIPE; + FSOUND_Reverb_SetProperties(&props); + } + if (key == '6') + { + FSOUND_REVERB_PROPERTIES props = FSOUND_PRESET_PSYCHOTIC; + FSOUND_Reverb_SetProperties(&props); + } + + if (key == ' ') + { + listenerflag = !listenerflag; + } + + if (!listenerflag) + { + if (key == '<') + { + listenerpos[0] -= 1.0f; + if (listenerpos[0] < -35) + { + listenerpos[0] = -35; + } + } + if (key == '>') + { + listenerpos[0] += 1.0f; + if (listenerpos[0] > 30) + { + listenerpos[0] = 30; + } + } + } + } + + + // ========================================================================================== + // UPDATE THE LISTENER + // ========================================================================================== + { + static float t = 0; + static float lastpos[3] = { 0,0,0 }; + float vel[3]; + + if (listenerflag) + { + listenerpos[0] = ((float)sin(t*0.05f) * 33.0f); // left right pingpong + } + + // ********* NOTE ******* READ NEXT COMMENT!!!!! + // vel = how far we moved last FRAME (m/f), then time compensate it to SECONDS (m/s). + vel[0] = (listenerpos[0]-lastpos[0]) * (1000 / INTERFACE_UPDATETIME); + vel[1] = (listenerpos[1]-lastpos[1]) * (1000 / INTERFACE_UPDATETIME); + vel[2] = (listenerpos[2]-lastpos[2]) * (1000 / INTERFACE_UPDATETIME); + + // store pos for next time + lastpos[0] = listenerpos[0]; + lastpos[1] = listenerpos[1]; + lastpos[2] = listenerpos[2]; + + FSOUND_3D_Listener_SetAttributes(&listenerpos[0], &vel[0], 0, 0, 1.0f, 0, 1.0f, 0); + + t += (30 * (1.0f / (float)INTERFACE_UPDATETIME)); // t is just a time value .. it increments in 30m/s steps in this example + + // print out a small visual display + { + char s[80]; + + sprintf(s, "|.......................<1>......................<2>....................|"); + + s[(int)(listenerpos[0])+35] = 'L'; + printf("%s\r", s); + } + } + + FSOUND_Update(); + + Sleep(INTERFACE_UPDATETIME-1); // -1 for time taken for printf etc + + } while (key != 27); + + printf("\n"); + + // ========================================================================================== + // CLEANUP AND SHUTDOWN + // ========================================================================================== + + Close(samp1, samp2, samp3); + + return 0; +} diff --git a/fmodapi375win/samples/3d/watcom.bat b/fmodapi375win/samples/3d/watcom.bat new file mode 100644 index 0000000..18d21a6 --- /dev/null +++ b/fmodapi375win/samples/3d/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name 3d.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/cdda/Main.cpp b/fmodapi375win/samples/cdda/Main.cpp new file mode 100644 index 0000000..d790406 --- /dev/null +++ b/fmodapi375win/samples/cdda/Main.cpp @@ -0,0 +1,258 @@ +//=============================================================================================== +// CDDA.EXE +// Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. +// +// Use FMOD stream API to do digital CD playback. Also demonstrates how to use FMOD to +// generate a CDDB query. +//=============================================================================================== + +#include +#include + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#else + #include "../../api/inc/wincompat.h" + #include +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" // optional + + +int cddb_sum(int n) +{ + int ret = 0; + + while (n > 0) + { + ret += (n % 10); + n /= 10; + } + + return ret; +} + +unsigned long cddb_discid(FSOUND_TOC_TAG *toc) +{ + int i, t, n = 0; + + for (i = 0; i < toc->numtracks; i++) + { + n += cddb_sum((toc->min[i] * 60) + toc->sec[i]); + } + + t = ((toc->min[toc->numtracks] * 60) + toc->sec[toc->numtracks]) - ((toc->min[0] * 60) + toc->sec[0]); + + return ((n % 0xff) << 24 | t << 8 | toc->numtracks); +} + +void dump_cddb_query(FSOUND_TOC_TAG *toc) +{ + int i; + + printf("cddb query %08x %d", cddb_discid(toc), toc->numtracks); + + for (i = 0; i < toc->numtracks; i++) + { + printf(" %d", (toc->min[i] * (60 * 75)) + (toc->sec[i] * 75) + toc->frame[i]); + } + + printf(" %d\n", (toc->min[toc->numtracks] * 60) + toc->sec[toc->numtracks]); +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main(int argc, char *argv[]) +{ + unsigned char key; + FSOUND_STREAM *stream; + int channel = -1; + int track = 0; + char *cd_error; + char drive_letter[6] = "d:*?j"; + + if (argc < 2) + { + printf("Usage: cdda \n"); + printf("Example: cdda d\n"); + return 1; + } + + drive_letter[0] = argv[1][0]; + if (!((drive_letter[0] >= 'a' && drive_letter[0] <= 'z') || (drive_letter[0] >= 'A' && drive_letter[0] <= 'Z'))) + { + printf("ERROR: Invalid drive letter\n"); + return 1; + } + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("ERROR: You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + if (!FSOUND_Init(44100, 32, 0)) + { + printf("ERROR: %s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + FSOUND_Stream_SetBufferSize(2000); + + stream = FSOUND_Stream_Open(drive_letter, FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!stream) + { + printf("ERROR: %s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + FSOUND_Stream_SetSubStream(stream, 0); + + printf("=========================================================================\n"); + printf("Press f Skip forward 2 seconds\n"); + printf(" b Skip back 2 seconds\n"); + printf(" n Next track\n"); + printf(" SPACE Pause/Unpause\n"); + printf(" ESC Quit\n"); + printf("=========================================================================\n"); + + key = 0; + do + { + static int last_openstate = -1; + + if (stream && (channel < 0)) + { + int this_openstate = FSOUND_Stream_GetOpenState(stream); + + if (this_openstate == -3) + { + if (FSOUND_Stream_FindTagField(stream, 0, "CD_ERROR", (void **)&cd_error, 0)) + { + printf("%s\n", cd_error); + } + else + { + printf("ERROR: Couldn't open CDDA stream\n"); + } + FSOUND_Stream_Close(stream); + FSOUND_Close(); + return 1; + } + + if ((last_openstate != 0) && (this_openstate == 0)) + { + static int firsttime = TRUE; + + if (firsttime) + { + char *cd_device_info; + FSOUND_TOC_TAG *toc; + + if (FSOUND_Stream_FindTagField(stream, 0, "CD_TOC", (void **)&toc, 0)) + { + dump_cddb_query(toc); + } + + if (!FSOUND_Stream_GetTagField(stream, 0, 0, 0, (void **)&cd_device_info, 0)) + { + printf("ERROR: Couldn't get CD_DEVICE_INFO tag\n"); + FSOUND_Stream_Close(stream); + FSOUND_Close(); + return 1; + } + + printf(cd_device_info); + printf("\n=========================================================================\n"); + firsttime = FALSE; + + if (FSOUND_Stream_FindTagField(stream, 0, "CD_ERROR", (void **)&cd_error, 0)) + { + printf("%s\n", cd_error); + FSOUND_Stream_Close(stream); + FSOUND_Close(); + return 1; + } + } + + channel = FSOUND_Stream_PlayEx(FSOUND_FREE, stream, 0, TRUE); + FSOUND_SetPaused(channel, FALSE); + } + + last_openstate = this_openstate; + } + + if (kbhit()) + { + key = getch(); + + if (channel != -1) + { + if (key == ' ') + { + FSOUND_SetPaused(channel, !FSOUND_GetPaused(channel)); + } + + if (key == 'f') + { + FSOUND_Stream_SetTime(stream, FSOUND_Stream_GetTime(stream) + 2000); + } + + if (key == 'b') + { + FSOUND_Stream_SetTime(stream, FSOUND_Stream_GetTime(stream) - 2000); + } + + if (key == 'n') + { + track++; + if (track >= FSOUND_Stream_GetNumSubStreams(stream)) + { + track = 0; + } + FSOUND_Stream_SetSubStream(stream, track); + last_openstate = -2; + channel = -1; + } + } + } + + if (FSOUND_Stream_GetOpenState(stream) == 0) + { + printf("Track %d/%d %02d:%02d/%02d:%02d cpu %5.02f%% \r", track + 1, + FSOUND_Stream_GetNumSubStreams(stream), + FSOUND_Stream_GetTime(stream) / 1000 / 60, + FSOUND_Stream_GetTime(stream) / 1000 % 60, + FSOUND_Stream_GetLengthMs(stream) / 1000 / 60, + FSOUND_Stream_GetLengthMs(stream) / 1000 % 60, + FSOUND_GetCPUUsage()); + } + + FSOUND_Update(); + Sleep(10); + + } while (key != 27); + + printf("\n"); + + FSOUND_Stream_Close(stream); + FSOUND_Close(); + + return 0; +} diff --git a/fmodapi375win/samples/cdda/cdda.dsp b/fmodapi375win/samples/cdda/cdda.dsp new file mode 100644 index 0000000..b4e6f95 --- /dev/null +++ b/fmodapi375win/samples/cdda/cdda.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="cdda" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=cdda - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cdda.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cdda.mak" CFG="cdda - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cdda - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "cdda - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cdda - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0xc09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ../../api/lib/fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"cdda.exe" + +!ELSEIF "$(CFG)" == "cdda - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0xc09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ../../api/lib/fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"cdda.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "cdda - Win32 Release" +# Name "cdda - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/cdda/cdda.exe b/fmodapi375win/samples/cdda/cdda.exe new file mode 100644 index 0000000..2b42687 Binary files /dev/null and b/fmodapi375win/samples/cdda/cdda.exe differ diff --git a/fmodapi375win/samples/cdda/watcom.bat b/fmodapi375win/samples/cdda/watcom.bat new file mode 100644 index 0000000..5b64618 --- /dev/null +++ b/fmodapi375win/samples/cdda/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name cdda.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/cddarip/Main.cpp b/fmodapi375win/samples/cddarip/Main.cpp new file mode 100644 index 0000000..9fa337d --- /dev/null +++ b/fmodapi375win/samples/cddarip/Main.cpp @@ -0,0 +1,235 @@ +//=============================================================================================== +// CDDARIP.EXE +// Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. +// +// Use CDDA streaming to rip a CD track to a wav file +//=============================================================================================== + +#include +#include + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include + #define __PACKED /*dummy*/ +#else + #include "../../api/inc/wincompat.h" + #include + #define __PACKED __attribute__((packed)) /* gcc packed */ +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" // optional + + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) || defined(_WIN32) || defined(__WIN32__) +#pragma pack(1) +#endif + +/* + WAV Structures +*/ +typedef struct +{ + signed char id[4]; + int size; +} RiffChunk; + +struct +{ + RiffChunk chunk __PACKED; + unsigned short wFormatTag __PACKED; /* format type */ + unsigned short nChannels __PACKED; /* number of channels (i.e. mono, stereo...) */ + unsigned int nSamplesPerSec __PACKED; /* sample rate */ + unsigned int nAvgBytesPerSec __PACKED; /* for buffer estimation */ + unsigned short nBlockAlign __PACKED; /* block size of data */ + unsigned short wBitsPerSample __PACKED; /* number of bits per sample of mono data */ +} FmtChunk = { {{'f','m','t',' '}, sizeof(FmtChunk) - sizeof(RiffChunk) }, 1, 2, 44100, 44100 * 2 * 16 / 8, 1 * 2 * 16 / 8, 16 } __PACKED; + +struct +{ + RiffChunk chunk; +} DataChunk = { {{'d','a','t','a'}, 0 } }; + +struct +{ + RiffChunk chunk; + signed char rifftype[4]; +} WavHeader = { {{'R','I','F','F'}, 0 }, {'W','A','V','E'} }; + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) || defined(_WIN32) || defined(__WIN32__) +#pragma pack() +#endif + + +const char bar[56] = "=================================================="; +const char nobar[56] = " "; + +FILE *fp; +signed char stream_ended = FALSE; +unsigned int byteswritten = 0; + + +signed char F_CALLBACKAPI endcallback(FSOUND_STREAM *stream, void *buff, int len, void *param) +{ + stream_ended = TRUE; + return TRUE; +} + + +void * F_CALLBACKAPI DSP_RawWriteCallback(void *originalbuffer, void *newbuffer, int length, void *param) +{ + if (fp && !stream_ended) + { + fwrite(newbuffer, 1, length << 2, fp); + byteswritten += (length << 2); + } + + return newbuffer; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main(int argc, char *argv[]) +{ + char s[256]; + unsigned char key; + char drive_letter[5] = "d:*j"; + int track_num, read_percent; + unsigned int start_time, elapsed_time; + FSOUND_STREAM *stream; + FSOUND_DSPUNIT *rawwrite_dsp; + + start_time = timeGetTime(); + + if (argc < 3) + { + printf("Usage: cddarip \n"); + printf("Example: cddarip d 2\n"); + return 1; + } + + drive_letter[0] = argv[1][0]; + if (!((drive_letter[0] >= 'a' && drive_letter[0] <= 'z') || (drive_letter[0] >= 'A' && drive_letter[0] <= 'Z'))) + { + printf("ERROR: Invalid drive letter\n"); + return 1; + } + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND_NONREALTIME); + + if (!FSOUND_Init(44100, 32, 0)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + fp = fopen("dump.wav", "wb"); + if (!fp) + { + printf("ERROR: Couldn't open dump.wav for writing\n"); + FSOUND_Close(); + return 1; + } + + /* + Before we've even written the headers for the wav out, seek to the offset the raw data will start from. + */ + fseek(fp, sizeof(WavHeader) + sizeof(FmtChunk) + sizeof(DataChunk), SEEK_SET); + + /* + Create a DSP callback which will capture the mixed data and write it to disk + */ + rawwrite_dsp = FSOUND_DSP_Create(&DSP_RawWriteCallback, FSOUND_DSP_DEFAULTPRIORITY_USER, 0); + FSOUND_DSP_SetActive(rawwrite_dsp, TRUE); + + FSOUND_Stream_SetBufferSize(2000); + + stream = FSOUND_Stream_Open(drive_letter, FSOUND_NORMAL, 0, 0); + if (!stream) + { + printf("ERROR: Couldn't create CDDA stream\n"); + FSOUND_DSP_SetActive(rawwrite_dsp, FALSE); + FSOUND_DSP_Free(rawwrite_dsp); + FSOUND_Close(); + return 1; + } + + track_num = atoi(argv[2]); + if ((track_num < 1) || ((track_num - 1) >= FSOUND_Stream_GetNumSubStreams(stream))) + { + printf("ERROR: Invalid track number\n"); + FSOUND_Stream_Close(stream); + FSOUND_DSP_SetActive(rawwrite_dsp, FALSE); + FSOUND_DSP_Free(rawwrite_dsp); + FSOUND_Close(); + return 1; + } + + FSOUND_Stream_SetEndCallback(stream, endcallback, 0); + FSOUND_Stream_SetSubStream(stream, track_num - 1); + FSOUND_Stream_Play(FSOUND_FREE, stream); + + printf("Ripping %s track %d (%02d:%02d)\n", drive_letter, track_num, FSOUND_Stream_GetLengthMs(stream) / 1000 / 60, FSOUND_Stream_GetLengthMs(stream) / 1000 % 60); + + key = 0; + do + { + if (kbhit()) + { + key = getch(); + } + + read_percent = (int)(((float)FSOUND_Stream_GetTime(stream) / (float)FSOUND_Stream_GetLengthMs(stream)) * 100.0f); + s[0] = 0; + strncat(s, bar, (read_percent >> 1) + (read_percent & 1)); + strncat(s, nobar, (100 - read_percent) >> 1); + printf("|%s| %d%% \r", s, read_percent); + + FSOUND_Update(); + + } while ((key != 27) && !stream_ended); + + FSOUND_Stream_Close(stream); + FSOUND_DSP_SetActive(rawwrite_dsp, FALSE); + FSOUND_DSP_Free(rawwrite_dsp); + + /* + Now finalize the wav file by seeking to the start and putting in the headers. + */ + WavHeader.chunk.size = sizeof(FmtChunk) + sizeof(RiffChunk) + byteswritten; + DataChunk.chunk.size = byteswritten; + + fseek(fp, 0, SEEK_SET); + fwrite(&WavHeader, sizeof(WavHeader), 1, fp); + fwrite(&FmtChunk, sizeof(FmtChunk), 1, fp); + fwrite(&DataChunk, sizeof(DataChunk), 1, fp); + fclose(fp); + + FSOUND_Close(); + + elapsed_time = timeGetTime() - start_time; + printf("\nElapsed time: %02d:%02d\n", elapsed_time / 1000 / 60, elapsed_time / 1000 % 60); + + return 0; +} diff --git a/fmodapi375win/samples/cddarip/cddarip.dsp b/fmodapi375win/samples/cddarip/cddarip.dsp new file mode 100644 index 0000000..6d9325d --- /dev/null +++ b/fmodapi375win/samples/cddarip/cddarip.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="cddarip" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=cddarip - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cddarip.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cddarip.mak" CFG="cddarip - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cddarip - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "cddarip - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cddarip - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0xc09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ../../api/lib/fmodvc.lib winmm.lib /nologo /subsystem:console /machine:I386 /out:"cddarip.exe" + +!ELSEIF "$(CFG)" == "cddarip - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0xc09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ../../api/lib/fmodvc.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /out:"cddarip.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "cddarip - Win32 Release" +# Name "cddarip - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/cddarip/cddarip.exe b/fmodapi375win/samples/cddarip/cddarip.exe new file mode 100644 index 0000000..54c9065 Binary files /dev/null and b/fmodapi375win/samples/cddarip/cddarip.exe differ diff --git a/fmodapi375win/samples/cddarip/watcom.bat b/fmodapi375win/samples/cddarip/watcom.bat new file mode 100644 index 0000000..2993608 --- /dev/null +++ b/fmodapi375win/samples/cddarip/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name cddarip.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/dsp/Main.cpp b/fmodapi375win/samples/dsp/Main.cpp new file mode 100644 index 0000000..6aa59a4 --- /dev/null +++ b/fmodapi375win/samples/dsp/Main.cpp @@ -0,0 +1,532 @@ +/*=========================================================================================== + DSP.EXE + Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. + + This example demonstrates advanced DSP usage. + You can now attach sounds to dsp units. The dsp units to be attached to must have a NULL + callback. It is simply a holder for sounds to attach to, and have a specific position in + the DSP chain.. see the diagram below for a visual representation of the DSP chain. + It also demonstrates the use of hardware DirectX 8 FX. +===========================================================================================*/ + + +/* + Priority : 0 100 320-332 400 1000 + Name : [CLEAR]-->[samp1-WET]-->[REVERB]-->[samp1-DRY]-->[CLIPCOPY]-->[SOUNDCARD] + + Note the above priority values correspond to the values in FMOD.H + + FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT 0 + FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT 100 + FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT 200 + FSOUND_DSP_DEFAULTPRIORITY_USER 300 + FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT 900 + FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT 1000 + + Notice how 'SFX' unit is wet (has reverb). This is because it is the default destination + For sound effects if NULL is passed to PlaySoundEx or PlaySound is used. + Also the Reverb DSP has itself positioned AFTER the 'SFX' unit so then we will hear reverb. + Now if a sound is attached to the 'Dry' DSP unit located at priority 400, then it will not + be affected by reverb! +*/ + + +/* + INCLUDES +*/ + +#include +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#elif defined(__linux__) + #include "../../api/inc/wincompat.h" +#endif +#include +#include + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" /* optional */ + +/* + GLOBALS AND DEFINIITIONS +*/ + +/* + Here's our simple reverb again +*/ + +#define REVERB_NUMTAPS 7 +typedef struct +{ + FSOUND_DSPUNIT *Unit; + char *historybuff; /* storage space for tap history */ + char *workarea; /* a place to hold 1 buffer worth of data (for preverb) */ + int delayms; /* delay of p/reverb tab in milliseconds */ + int volume; /* volume of p/reverb tab */ + int pan; /* pan of p/reverb tab */ + int historyoffset; /* running offset into history buffer */ + int historylen; /* size of history buffer in SAMPLES */ +} REVERBTAP; + +/* + Reverb stuff +*/ +REVERBTAP DSP_ReverbTap[REVERB_NUMTAPS]; + +/* + Dry sfx unit +*/ +FSOUND_DSPUNIT *DrySFXUnit = NULL; + + +/* +[ + [DESCRIPTION] + Callback to mix in one reverb tap. It copies the buffer into its own history buffer also. + + [PARAMETERS] + 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down + through the dsp chain. They are in newbuffer. + 'newbuffer' Pointer to buffer passed from previous DSP unit. + 'length' Length in SAMPLES of buffer being passed. + 'userdata' User parameter. In this case it is a pointer to DSP_LowPassBuffer. + + [RETURN_VALUE] + a pointer to the buffer that was passed in, with a tap mixed into it. + + [REMARKS] +] +*/ +void * F_CALLBACKAPI DSP_ReverbCallback(void *originalbuffer, void *newbuffer, int length, void *userdata) +{ + int mixertype = FSOUND_GetMixer(); + int count; + int bytesperoutputsample; + REVERBTAP *tap = (REVERBTAP *)userdata; + union sample + { + void *vptr; + signed int *dptr; + signed short *wptr; + float *fptr; + }; + + if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + bytesperoutputsample = 4; // 16bit stereo + } + else + { + bytesperoutputsample = 8; // 32bit stereo + } + + // reverb history buffer is a ringbuffer. If the length makes the copy wrap, then split the copy + // into end part, and start part.. + if (tap->historyoffset + length > tap->historylen) + { + int taillen = tap->historylen - tap->historyoffset; + int startlen = length - taillen; + + // mix a scaled version of history buffer into output + FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), taillen, 44100, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + FSOUND_DSP_MixBuffers((char *)newbuffer+(taillen * bytesperoutputsample), tap->historybuff, startlen, 44100, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + + // now copy input into reverb/history buffer + { + signed short *dest; + union sample src; + + dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); + src.vptr = newbuffer; + + for (count=0; count < taillen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + { + signed short *dest; + union sample src; + + dest = (signed short *)tap->historybuff; // always 16bit + src.vptr = (char *)newbuffer + (taillen * bytesperoutputsample); + + for (count=0; count < startlen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + + } + // no wrapping reverb buffer, just write dest + else + { + // mix a scaled version of history buffer into output + FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), length, 44100, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + + // now copy input into reverb/history buffer + { + signed short *dest; + union sample src = { newbuffer }; + + dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); + + for (count=0; count < length * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + } + + + tap->historyoffset += length; + if (tap->historyoffset >= tap->historylen) + { + tap->historyoffset -= tap->historylen; + } + + // reverb history has been mixed into new buffer, so return it. + return newbuffer; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void SetupReverb() +{ + /* + REVERB SETUP + */ + /* something to fiddle with. */ + int delay[REVERB_NUMTAPS] = { 131, 149, 173, 211, 281, 401, 457}; /* prime numbers make it sound cool! */ + int volume[REVERB_NUMTAPS] = { 120, 100, 95, 90, 80, 60, 50}; + int pan[REVERB_NUMTAPS] = { 100, 128, 128, 152, 128, 100, 152}; + int count; + + for (count=0; count< REVERB_NUMTAPS; count++) + { + DSP_ReverbTap[count].delayms = delay[count]; + DSP_ReverbTap[count].volume = volume[count]; + DSP_ReverbTap[count].pan = pan[count]; + DSP_ReverbTap[count].historyoffset = 0; + DSP_ReverbTap[count].historylen = (DSP_ReverbTap[count].delayms * 44100 / 1000); + if (DSP_ReverbTap[count].historylen < FSOUND_DSP_GetBufferLength()) + { + DSP_ReverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); /* just in case our calc is not the same. */ + } + + DSP_ReverbTap[count].historybuff = (char *)calloc(DSP_ReverbTap[count].historylen, 4); /* * 4 is for 16bit stereo (mmx only) */ + DSP_ReverbTap[count].workarea = NULL; + DSP_ReverbTap[count].Unit = FSOUND_DSP_Create(&DSP_ReverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+20+(count*2), &DSP_ReverbTap[count]); + + FSOUND_DSP_SetActive(DSP_ReverbTap[count].Unit, TRUE); + } +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void CloseReverb() +{ + int count; + + for (count=0; count +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=dsp - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "dsp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "dsp.mak" CFG="dsp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "dsp - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "dsp - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "dsp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0xc09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 ../../api/lib/fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"dsp.exe" + +!ELSEIF "$(CFG)" == "dsp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0xc09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ../../api/lib/fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"dsp.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "dsp - Win32 Release" +# Name "dsp - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/dsp/dsp.exe b/fmodapi375win/samples/dsp/dsp.exe new file mode 100644 index 0000000..bb7a0f2 Binary files /dev/null and b/fmodapi375win/samples/dsp/dsp.exe differ diff --git a/fmodapi375win/samples/dsp/watcom.bat b/fmodapi375win/samples/dsp/watcom.bat new file mode 100644 index 0000000..4d5b70a --- /dev/null +++ b/fmodapi375win/samples/dsp/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name dsp.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/fmod/Main.c b/fmodapi375win/samples/fmod/Main.c new file mode 100644 index 0000000..c35537e --- /dev/null +++ b/fmodapi375win/samples/fmod/Main.c @@ -0,0 +1,4784 @@ +/* + FMOD.EXE + Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. + + This example really demonstrates the FMOD music system at work, and is a standalone + mod/wav/mp3 player! + It displays a lot of information and uses the DSP engine as well to provide DSP effects under + MMX only. +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" /* optional */ + +#include "resource.h" +#include "sdriver.h" +#include "lowpass.h" +#include "reverb.h" + + +/* + DEFINITIONS +*/ +#define NAME "FSOUND TESTBED" +#define TITLE "FMOD" +#define NUMCHANNELS 128 +#define MAXSONGS 512 +#define FSOUND_BUFFERSIZE 200 /* millisecond value for FMOD buffersize. */ +#define MRU_MAX 16 +#define STREAM_PLAYING 255 + +const float WINDOW_WIDTH = 675.0f; +const float WINDOW_HEIGHT = 324.0f; +const int TEXT_CHANNELSPLAYING_X = 636; +const int TEXT_CHANNELSPLAYING_Y = 237; +const int TEXT_CPUUSAGE_X = 622; +const int TEXT_CPUUSAGE_Y = 273; + +enum +{ + GRAPHICWINDOW_MODINFO = 0, + GRAPHICWINDOW_EQUALISER, + GRAPHICWINDOW_WAVE, + GRAPHICWINDOW_MAX +}; + +enum +{ + SONGTYPE_NONE = 0, + SONGTYPE_MOD, + SONGTYPE_STREAM, + SONGTYPE_NETSTREAM, + SONGTYPE_CD, +}; + +typedef struct +{ + FMUSIC_MODULE *mod; + FSOUND_STREAM *stream; + int channel; + char *url; + int last_status; + int last_netstatus; + char *server_status; + char *title; + char *artist; + char *protocol; + char *format; + char *streamname; + int metadata; + char *listname; + int cdtrack; + unsigned int cdtrack_length; +} SONGTYPE; + +typedef struct +{ + int count; + void **name; + void **displayname; +} Playlist; + +/* + GLOBALS +*/ + +HWND mainhwnd; +HWND streaminfo_hwnd; +HWND netstreaminfo_hwnd; +HWND modinfo_hwnd; +HWND cdinfo_hwnd; +HWND songlist_hwnd; + +#ifdef _WIN64 +UINT_PTR timerid=0; +#else +UINT timerid=0; +#endif + +SONGTYPE song[MAXSONGS + 1]; + +int DraggingCDSlider = FALSE; +int DSP_Ready = FALSE; +int outputfreq = 44100; /* default output freq */ +int playlistsong = 0; +char cddevice = 0; /* 0 is the default device, could be 'D' or 'E' etc */ +float scalex = 1.0f, scaley = 1.0f; + +/* + Lowpass stuff +*/ +FSOUND_DSPUNIT *LowPassUnit; +signed char *LowPassBuffer; +float LowPassCutoffFrequency = 5000.0f; +float LowPassResonance = 1.0f; + +/* + Echo stuff +*/ +#define MAXECHOLEN (500 * outputfreq / 1000) + +FSOUND_DSPUNIT *EchoUnit = NULL; +signed char *EchoBuffer = NULL; +int EchoOffset=0, EchoLen=0; + +/* + Graphical window stuff for Spectrum and oscilliscope. +*/ + +#define GRAPHICWINDOW_WIDTH 256 +#define GRAPHICWINDOW_HEIGHT 116 + +int GraphicWindowCurrent = GRAPHICWINDOW_MODINFO; +BITMAPINFO GraphicWindowBitmap; +RGBQUAD GraphicWindowBitmapData[GRAPHICWINDOW_WIDTH * GRAPHICWINDOW_HEIGHT]; +int graphic_window_x; +int graphic_window_y; + + +/* + Oscilliscope stuff +*/ + +FSOUND_DSPUNIT *OscUnit = NULL; +static signed short *OscBuffer = NULL; +static int OscBlock = 0; + + +/* + SETTINGS +*/ + +int setting_xpos = 0; +int setting_ypos = 0; +int setting_output = 0; +int setting_driver = 0; +int setting_mixer = 0; +int setting_outputrate = 44100; +int setting_buffersize = 64000; +int setting_prebuffer_percent = 95; +int setting_rebuffer_percent = 95; +char setting_http_proxy[2048]; +int setting_cdda = 1; +int setting_jitter = 1; +int setting_forceaspi = 0; +char setting_cdletter[4] = "C:"; + +char url_to_load[4096]; +HINSTANCE g_hinst; +char *mru[MRU_MAX]; +signed char play_button_play = TRUE; + +FSOUND_STREAM *cdda_stream = 0; +int cdda_channel = -1; +int cdda_track = 0; +int cdda_stream_state = -2; + +/* + PROTOTYPES +*/ + +void CloseDown(); +BOOL PlaySong(int index); +BOOL AddToMRU(char *url); +BOOL UpdateModInfo(int songid, BOOL forceupdate); +BOOL UpdateStreamInfo(int songid, BOOL forceupdate); +BOOL UpdateNetStreamInfo(int songid, BOOL forceupdate, BOOL forcequiet); +BOOL UpdateCDInfo(int songid, BOOL forceupdate); +void SelectInfoWindow(); +char *GetCommentValue(FSOUND_STREAM *stream, char *tag); +signed char FreePlaylist(Playlist *playlist); +void DeleteSong(int songid); +void DeleteAllCDTracks(); +signed char StopCDTrack(); + +WNDPROC oldprogressproc; +WNDPROC oldcdtimeproc; + +#ifdef _WIN64 +INT_PTR CALLBACK FMOD_LoadURLDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +#else +BOOL CALLBACK FMOD_LoadURLDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char F_CALLBACKAPI MetadataCallback(char *name, char *value, void *userdata) +{ + char *tmp; + int index = (int)userdata; + + if (!strcmp("ARTIST", name)) + { + if (song[index].artist) + { + free(song[index].artist); + } + tmp = strdup(value); + song[index].artist = tmp; + song[index].metadata++; + } + else if (!strcmp("TITLE", name)) + { + if (song[index].title) + { + free(song[index].title); + } + tmp = strdup(value); + song[index].title = tmp; + song[index].metadata++; + } + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +char *stristr(char *string2, char *string1) +{ + char *s1 = strdup(string1); + char *s2 = strdup(string2); + char *ret = 0; + int i, j; + int len1 = (int)strlen(string1); + int len2 = (int)strlen(string2); + + for (i=0;s1[i];i++) s1[i] = tolower(s1[i]); + for (i=0;s2[i];i++) s2[i] = tolower(s2[i]); + + for (j=0;j < (len2 - len1);j++) + { + char *a = s1; + char *b = &s2[j]; + + for (i=0;(i < len1) && *a && *b;a++, b++, i++) + { + if (*a != *b) + { + break; + } + } + + if (i == len1) + { + ret = &string2[j]; + break; + } + } + + free(s1); + free(s2); + return ret; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void SetFirstCDLetter() +{ + int count; + char str[256]; + + for (count=2;count < 26;count++) + { + sprintf(str, "%c:\\", (char)('A' + count)); + if (GetDriveType(str) == DRIVE_CDROM) + { + strncpy(setting_cdletter, str, 2); + cddevice = str[0]; + break; + } + } +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void LoadSettings() +{ + HKEY key; + DWORD result,size=4; + int i; + + result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\FMOD\\Settings", 0, KEY_QUERY_VALUE , &key); + + setting_output = FSOUND_OUTPUT_DSOUND; + setting_driver = 0; + setting_mixer = FSOUND_MIXER_QUALITY_AUTODETECT; + setting_outputrate = 44100; + + SetFirstCDLetter(); + + if (result != ERROR_SUCCESS) + { + return; + } + + RegQueryValueEx(key, "xpos", 0, NULL, (LPBYTE)&setting_xpos, &size); + RegQueryValueEx(key, "ypos", 0, NULL, (LPBYTE)&setting_ypos, &size); + + RegQueryValueEx(key, "output", 0, NULL, (LPBYTE)&setting_output, &size); + RegQueryValueEx(key, "driver", 0, NULL, (LPBYTE)&setting_driver, &size); + RegQueryValueEx(key, "mixer", 0, NULL, (LPBYTE)&setting_mixer, &size); + RegQueryValueEx(key, "outputrate", 0, NULL, (LPBYTE)&setting_outputrate, &size); + + /* + It is not possible to select nosound from dialog box, so it must be an uninitialized + registry key.. anyway, however it was 0, set it to directsound if it is. + */ + if (!setting_output) + { + setting_output = FSOUND_OUTPUT_DSOUND; + } + if (setting_outputrate < 4000) + { + setting_outputrate = 44100; + } + + for (i=0;i < MRU_MAX;i++) + { + char s[16]; + char *tmp; + + size = 0; + + if (mru[i]) + { + free(mru[i]); + mru[i] = 0; + } + + sprintf(s, "MRU%d", i); + + if (RegQueryValueEx(key, s, 0, NULL, (LPBYTE)s, &size) == ERROR_MORE_DATA) + { + tmp = (char *)malloc(size); + if (!tmp) + { + break; + } + + if (RegQueryValueEx(key, s, 0, NULL, tmp, &size) == ERROR_SUCCESS) + { + mru[i] = tmp; + } + } + } + + RegQueryValueEx(key, "buffersize", 0, NULL, (LPBYTE)&setting_buffersize, &size); + RegQueryValueEx(key, "prebuffer_percent", 0, NULL, (LPBYTE)&setting_prebuffer_percent, &size); + RegQueryValueEx(key, "rebuffer_percent", 0, NULL, (LPBYTE)&setting_rebuffer_percent, &size); + FSOUND_Stream_Net_SetBufferProperties(setting_buffersize, setting_prebuffer_percent, setting_rebuffer_percent); + + size = 2048; + setting_http_proxy[0] = 0; + RegQueryValueEx(key, "http_proxy", 0, NULL, setting_http_proxy, &size); + FSOUND_Stream_Net_SetProxy(setting_http_proxy); + + RegQueryValueEx(key, "cdda", 0, NULL, (LPBYTE)&setting_cdda, &size); + RegQueryValueEx(key, "jitter", 0, NULL, (LPBYTE)&setting_jitter, &size); + RegQueryValueEx(key, "forceaspi", 0, NULL, (LPBYTE)&setting_forceaspi, &size); + + size = 3; + setting_cdletter[0] = 0; + RegQueryValueEx(key, "cdletter", 0, NULL, setting_cdletter, &size); + + /* + If it doesn't have a valid cd drive letter in the registry then set the first cd drive letter + */ + if (GetDriveType(setting_cdletter) != DRIVE_CDROM) + { + SetFirstCDLetter(); + } + + RegCloseKey(key); +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void SaveSettings() +{ + HKEY key; + DWORD result; + int i; + + setting_output = FSOUND_GetOutput(); + setting_driver = FSOUND_GetDriver(); + setting_mixer = FSOUND_GetMixer(); + setting_outputrate = FSOUND_GetOutputRate(); + + RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\FMOD\\Settings", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &result); + RegSetValueEx(key, "xpos", 0, REG_DWORD, (LPBYTE)&setting_xpos, 4); + RegSetValueEx(key, "ypos", 0, REG_DWORD, (LPBYTE)&setting_ypos, 4); + + RegSetValueEx(key, "output", 0, REG_DWORD, (LPBYTE)&setting_output, 4); + RegSetValueEx(key, "driver", 0, REG_DWORD, (LPBYTE)&setting_driver, 4); + RegSetValueEx(key, "mixer", 0, REG_DWORD, (LPBYTE)&setting_mixer, 4); + RegSetValueEx(key, "outputrate", 0, REG_DWORD, (LPBYTE)&setting_outputrate, 4); + + for (i=0;i < MRU_MAX;i++) + { + char s[16]; + + sprintf(s, "MRU%d", i); + + if (mru[i]) + { + RegSetValueEx(key, s, 0, REG_SZ, mru[i], (int)strlen(mru[i]) + 1); + } + else + { + RegDeleteValue(key, s); + } + } + + FSOUND_Stream_Net_GetBufferProperties(&setting_buffersize, &setting_prebuffer_percent, &setting_rebuffer_percent); + RegSetValueEx(key, "buffersize", 0, REG_DWORD, (LPBYTE)&setting_buffersize, 4); + RegSetValueEx(key, "prebuffer_percent", 0, REG_DWORD, (LPBYTE)&setting_prebuffer_percent, 4); + RegSetValueEx(key, "rebuffer_percent", 0, REG_DWORD, (LPBYTE)&setting_rebuffer_percent, 4); + + if (setting_http_proxy[0]) + { + RegSetValueEx(key, "http_proxy", 0, REG_SZ, setting_http_proxy, (int)strlen(setting_http_proxy) + 1); + } + else + { + RegDeleteValue(key, "http_proxy"); + } + + RegSetValueEx(key, "cdda", 0, REG_DWORD, (LPBYTE)&setting_cdda, 4); + RegSetValueEx(key, "jitter", 0, REG_DWORD, (LPBYTE)&setting_jitter, 4); + RegSetValueEx(key, "forceaspi", 0, REG_DWORD, (LPBYTE)&setting_forceaspi, 4); + RegSetValueEx(key, "cdletter", 0, REG_SZ, setting_cdletter, (int)strlen(setting_cdletter) + 1); + + RegCloseKey(key); +} + + + + + +/* +[ + [DESCRIPTION] + A slow and quite unscientific 4th order low pass filter, which leaves the source mix + buffer in tact, and returns a pointer to the new 'dirty' buffer. + + [PARAMETERS] + 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down + through the dsp chain. They are in newbuffer. + 'newbuffer' Pointer to buffer passed from previous DSP unit. + 'length' Length in SAMPLES of buffer being passed. + 'param' User parameter. In this case it is a pointer to LowPassBuffer. + + [RETURN_VALUE] + A pointer to the new modified lowpass buffer, leaving the original buffer untouched. + + [REMARKS] + Leaving the original source data untouched means we still have clean source data to + work with using other chained filters. +] +*/ +void * F_CALLBACKAPI LowPassCallback(void *originalbuffer, void *newbuffer, int length, void *userdata) +{ + int count; + int mixertype = FSOUND_GetMixer(); + union sample + { + void *vptr; + signed int *dptr; + signed short *wptr; + float *fptr; + }; + union sample srcleft, srcright, destleft, destright; + + /* + Must be 16bit stereo integer buffer.. sorry blendmode (32bit) and fpu (32bit float) dont support this. + */ + srcleft.vptr = newbuffer; + destleft.vptr = userdata; + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + srcright.fptr = (float *)newbuffer + 1; + destright.fptr = (float *)userdata + 1; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + srcright.wptr = (signed short *)newbuffer + 1; + destright.wptr = (signed short *)userdata + 1; + } + else + { + srcright.dptr = (signed int *)newbuffer + 1; + destright.dptr = (signed int *)userdata + 1; + } + + length <<= 1; /* *2 for stereo (number of 16 bit samples) */ + + for (count=0; count 32767) l = 32767; + if (r < -32768) r = -32768; + else if (r > 32767) r = 32767; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + destleft.fptr[count] = (float)l; + destright.fptr[count] = (float)r; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + destleft.wptr[count] = (signed short)l; + destright.wptr[count] = (signed short)r; + } + else + { + destleft.dptr[count] = l; + destright.dptr[count] = r; + } + } + + /* + Data has been copied into new buffer, old buffer is still in tact (clean) for another filter + */ + return userdata; +} + + +/* +[ + [DESCRIPTION] + Simple echo callback. It copies the data into its own history buffer, then copies the data back in. + + [PARAMETERS] + 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down + through the dsp chain. They are in newbuffer. + 'newbuffer' Pointer to buffer passed from previous DSP unit. + 'length' Length in SAMPLES of buffer being passed. + 'param' User parameter. In this case it is a pointer to EchoBuffer. + + [RETURN_VALUE] + A pointer to the new modified buffer. The buffer passed in has been modified, and + EchoBuffer has just been filled with a copy of the original information to keep + an echo history for later. + + [REMARKS] + All the <<2 stuff is to convert samples to bytes, as all offsets and lengths are based + on samples not bytes. For mmx the output size is 4 bytes per sample. + + [SEE_ALSO] + LowPassCallback +] +*/ +void * F_CALLBACKAPI EchoCallback(void *originalbuffer, void *newbuffer, int length, void *userdata) +{ + int mixertype = FSOUND_GetMixer(); + char *echobuff = userdata; + int bytesperoutputsample; + int count; + union sample + { + void *vptr; + signed int *dptr; + signed short *wptr; + float *fptr; + }; + + + if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + bytesperoutputsample = 4; // 16bit stereo + } + else + { + bytesperoutputsample = 8; // 32bit stereo + } + + /* + Echobuff is a ringbuffer that we copy the mixbuffer to. + If the length of the write exceeds the end of the echo buffer, + then do the mix in 2 parts, the end part, and the start part. + */ + if (EchoOffset + length > EchoLen) + { + int taillen = EchoLen - EchoOffset; + int startlen = length - taillen; + + /* + Feedback history from echo buffer into mixbuffer + */ + FSOUND_DSP_MixBuffers(newbuffer, echobuff+(EchoOffset << 2), taillen, outputfreq, 128, FSOUND_STEREOPAN, FSOUND_STEREO | FSOUND_16BITS); + FSOUND_DSP_MixBuffers((char *)newbuffer + (taillen * bytesperoutputsample), echobuff, startlen, outputfreq, 128, FSOUND_STEREOPAN, FSOUND_STEREO | FSOUND_16BITS); + + /* + Now copy result into echo buffer again for next time + */ + { + signed short *dest; + union sample src; + + dest = (signed short *)(echobuff + (EchoOffset << 2)); + src.vptr = newbuffer; + + for (count=0; count < taillen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + { + signed short *dest; + union sample src; + + dest = (signed short *)echobuff; // always 16bit + src.vptr = (char *)newbuffer + (taillen * bytesperoutputsample); + + for (count=0; count < startlen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + } + /* + No wrapping echo buffer write, just do a straight write + */ + else + { + /* + Feedback history from echo buffer into mixbuffer + */ + FSOUND_DSP_MixBuffers(newbuffer, echobuff + (EchoOffset << 2), length, outputfreq, 128, FSOUND_STEREOPAN, FSOUND_STEREO | FSOUND_16BITS); + + /* + Now copy result into echo buffer again for next time + */ + { + signed short *dest; + union sample src = { newbuffer }; + + dest = (signed short *)(echobuff + (EchoOffset << 2)); + + for (count=0; count < length * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + } + + EchoOffset+=length; + if (EchoOffset >= EchoLen) + { + EchoOffset -= EchoLen; + } + + /* + Echo history has been mixed into new buffer, so return it. + */ + return newbuffer; +} + + + + +/* +[ + [DESCRIPTION] + Buffering code for oscilliscope. + + [PARAMETERS] + 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down + through the dsp chain. They are in newbuffer. + 'newbuffer' Pointer to buffer passed from previous DSP unit. + 'length' Length in SAMPLES of buffer being passed. + 'param' User parameter. In this case it is 0. + + [RETURN_VALUE] + A pointer to the new modified buffer. + + [REMARKS] + All the <<2 stuff is to convert samples to bytes, as all offsets and lengths are based + on samples not bytes. For mmx the output size is 4 bytes per sample. + + [SEE_ALSO] +] +*/ +void * F_CALLBACKAPI OscCallback(void *originalbuffer, void *newbuffer, int length, void *userdata) +{ + int mixertype = FSOUND_GetMixer(); + int count; + int totalblocks; + signed short *dest; + + totalblocks = FSOUND_DSP_GetBufferLengthTotal() / FSOUND_DSP_GetBufferLength(); + + /* + Convert and downmix into a mono short int buffer. + */ + + dest = &OscBuffer[OscBlock * FSOUND_DSP_GetBufferLength()]; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + float *src = (float *)newbuffer; + + for (count=0; count < length; count++) + { + dest[count] = (signed short)((src[count << 1] + src[(count << 1) + 1]) * 0.5f); + } + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + signed short *src = (signed short *)newbuffer; + + for (count=0; count < length; count++) + { + dest[count] = (signed short)(((int)src[count << 1] + (int)src[(count << 1) + 1]) >> 1); + } + } + else + { + signed int *src = (signed int *)newbuffer; + + for (count=0; count < length; count++) + { + dest[count] = (signed short)((src[count << 1] + src[(count << 1) + 1]) >> 1); + } + } + + OscBlock++; + if (OscBlock >= totalblocks) + { + OscBlock = 0; + } + + return newbuffer; +} + + + +/* +[ + [DESCRIPTION] + Plots a graphic spectrum using FSOUND_DSP_GetSpectrum + + [PARAMETERS] + 'hdc' Handle to device context to paint to. + + [RETURN_VALUE] + void + + [REMARKS] + + [SEE_ALSO] + FSOUND_DSP_GetSpectrum + FSOUND_DSP_GetFFTUnit + PlotOscilliscope +] +*/ +void PlotSpectrum(HDC hdc) +{ + int count, count2; + float *spectrum; + + spectrum = FSOUND_DSP_GetSpectrum(); /* returns an array of 512 floats */ + if (!spectrum) + { + return; + } + + memset(GraphicWindowBitmapData, 0, GRAPHICWINDOW_WIDTH * GRAPHICWINDOW_HEIGHT * sizeof(RGBQUAD)); + + /* + Spectrum graphic is 256 entries wide, and the spectrum is 512 entries. + The upper band of frequencies at 44khz is pretty boring (ie 11-22khz), so we are only + going to display the first 256 frequencies, or (0-11khz) + */ + for (count=0; count < GRAPHICWINDOW_WIDTH; count++) + { + RGBQUAD *pixel; + int y; + + #define calcoffset(_x, _y) (GRAPHICWINDOW_WIDTH * _y) + _x + + y = (int)(spectrum[count] * 4.0f * (float)GRAPHICWINDOW_HEIGHT); + if (y >= GRAPHICWINDOW_HEIGHT) + { + y = GRAPHICWINDOW_HEIGHT - 1; + } + + for (count2=0; count2rgbRed = count2 << 1; + pixel->rgbGreen = 0xFF - (count2 << 1); + pixel->rgbBlue = 0x1F; + } + } + + + SetDIBitsToDevice( + hdc, // Target device HDC + graphic_window_x, + graphic_window_y, + GRAPHICWINDOW_WIDTH, // Destination width + GRAPHICWINDOW_HEIGHT, // Destination height + 0, // X source position + 0, // Adjusted Y source position + (UINT)0, // Start scan line + GraphicWindowBitmap.bmiHeader.biHeight, // Scan lines present + GraphicWindowBitmapData, // Image data + &GraphicWindowBitmap, // DIB header + DIB_RGB_COLORS); // Type of palette +} + + +/* +[ + [DESCRIPTION] + Plots an oscilliscope. + + [PARAMETERS] + 'hdc' Handle to device context to paint to. + + [RETURN_VALUE] + void + + [REMARKS] + The oscilliscope data is buffer because the block of data received in a DSP unit is the block + being mixed ahead of time, not the block that is AUDIBLE. + + [SEE_ALSO] + PlotSpectrum +] +*/ +void PlotOscilliscope(HDC hdc) +{ + memset(GraphicWindowBitmapData, 0, GRAPHICWINDOW_WIDTH * GRAPHICWINDOW_HEIGHT * sizeof(RGBQUAD)); + + if (OscBuffer) + { + int count, count2, offset; + float xoff, step; + signed short *src; + /* + The next pcmblock (Oscblock + 1) is the one that is audible. + */ + offset = (OscBlock + 1) * FSOUND_DSP_GetBufferLength(); + if (offset >= FSOUND_DSP_GetBufferLengthTotal()) + { + offset -= FSOUND_DSP_GetBufferLengthTotal(); + } + + src = &OscBuffer[offset]; + + /* + xoff is the x position that is scaled lookup of the dsp block according to the graphical + window size. + */ + xoff = 0; + step = (float)FSOUND_DSP_GetBufferLength() / (float)GRAPHICWINDOW_WIDTH; + + for (count=0; count < GRAPHICWINDOW_WIDTH; count++) + { + RGBQUAD *pixel; + int x, y, y2; + + #define calcoffset(_x, _y) (GRAPHICWINDOW_WIDTH * _y) + _x + + x = (int)xoff; + y = (int)(((float)src[x] + 32768.0f) / 65536.0f * (float)GRAPHICWINDOW_HEIGHT); + y2 = (int)(((float)src[x+(int)step] + 32768.0f) / 65536.0f * (float)GRAPHICWINDOW_HEIGHT); + + if (y > y2) + { + int tmp = y; + y = y2; + y2 = tmp; + } + + for (count2=y; count2<=y2; count2++) + { + pixel = &GraphicWindowBitmapData[calcoffset(count, count2)]; + pixel->rgbRed = 0xff; + pixel->rgbGreen = 0xff; + pixel->rgbBlue = 0xaf; + } + + xoff += step; + } + } + + + SetDIBitsToDevice( + hdc, // Target device HDC + graphic_window_x, + graphic_window_y, + GRAPHICWINDOW_WIDTH, // Destination width + GRAPHICWINDOW_HEIGHT, // Destination height + 0, // X source position + 0, // Adjusted Y source position + (UINT)0, // Start scan line + GraphicWindowBitmap.bmiHeader.biHeight, // Scan lines present + GraphicWindowBitmapData, // Image data + &GraphicWindowBitmap, // DIB header + DIB_RGB_COLORS); // Type of palette +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +Playlist *ParsePlaylist(char *name) +{ + struct _stat buf; + FILE *fp; + char *filebuf, *p; + Playlist *playlist = 0; + int buflen, count, i; + + if (!name || stricmp((const char *)".pls", (const char *)(&name[strlen(name) - 4]))) + { + return 0; + } + + if (_stat(name, &buf)) + { + return 0; + } + + buflen = buf.st_size + 1; + + filebuf = (char *)malloc(buflen); + if (!filebuf) + { + return 0; + } + + fp = fopen(name, "rb"); + if (!fp) + { + free(filebuf); + return 0; + } + + if (fread(filebuf, 1, buf.st_size, fp) != (unsigned int)buf.st_size) + { + fclose(fp); + free(filebuf); + return 0; + } + + fclose(fp); + + filebuf[buflen - 1] = 0; + + p = stristr(filebuf, "NumberOfEntries="); + if (!p) + { + goto ERR; + } + + p += 16; + count = atoi(p); + + if (!count) + { + goto ERR; + } + + playlist = (Playlist *)calloc(sizeof(Playlist), 1); + if (!playlist) + { + goto ERR; + } + + playlist->count = count; + + playlist->name = (char **)calloc(sizeof(char *) * count, 1); + if (!playlist->name) + { + goto ERR; + } + + playlist->displayname = (char **)calloc(sizeof(char *) * count, 1); + if (!playlist->displayname) + { + goto ERR; + } + + for (i=0;i < count;i++) + { + char tmp[32]; + char *filename, *displayname, *t; + + filename = displayname = 0; + + sprintf(tmp, "File%d=", i + 1); + p = strstr(filebuf, tmp); + if (p) + { + p += strlen(tmp); + t = p; + for (;*t && (*t != 0xa) && (*t != 0xd);t++); + if (*t) + { + char tmpc = *t; + *t = 0; + filename = strdup(p); + *t = tmpc; + } + } + + if (strncmp(filename, "http://", 7) && strncmp(filename, "http:\\\\", 7)) + { + char *tmpname = strdup(filename); + p = &tmpname[strlen(tmpname) - 1]; + for (;(p > tmpname) && (*p != '\\') && (*p != '/');p--); + if ((*p == '\\') || (*p == '/')) + { + p++; + } + displayname = strdup(p); + free(tmpname); + } + + playlist->name[i] = filename; + playlist->displayname[i] = displayname; + } + + free(filebuf); + return playlist; + +ERR: + FreePlaylist(playlist); + free(filebuf); + return 0; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char FreePlaylist(Playlist *playlist) +{ + int i; + + if (!playlist) + { + return FALSE; + } + + if (playlist->name) + { + for (i=0;i < playlist->count;i++) + { + if (playlist->name[i]) + { + free(playlist->name[i]); + } + } + + free(playlist->name); + } + + if (playlist->displayname) + { + for (i=0;i < playlist->count;i++) + { + if (playlist->displayname[i]) + { + free(playlist->displayname[i]); + } + } + + free(playlist->displayname); + } + + free(playlist); + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + Returns FALSE if there's no more room in the song list + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char AddFileToSongList(char *name, char *displayname) +{ + FMUSIC_MODULE *mod = NULL; + FSOUND_STREAM *stream = NULL; + int currsong = 0; + char s[256]; + + if (!strncmp(name, "http://", 7) || !strncmp(name, "http:\\\\", 7)) + { + displayname = name; + } + else + { + stream = NULL; + mod = FMUSIC_LoadSong(name); + if (!mod) + { + stream = FSOUND_Stream_Open(name, FSOUND_NORMAL | FSOUND_2D | FSOUND_MPEGACCURATE | FSOUND_NONBLOCKING, 0, 0); + } + + if (!mod && !stream) + { + MessageBox(0, FMOD_ErrorString(FSOUND_GetError()), "Loading a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + return TRUE; + } + + if (mod) + { + if (FMUSIC_GetType(mod) != FMUSIC_TYPE_IT) /* IT has its own master volume setting */ + { + FMUSIC_SetMasterVolume(mod, 192); + } + if (FMUSIC_GetType(mod) == FMUSIC_TYPE_MOD || FMUSIC_GetType(mod) == FMUSIC_TYPE_S3M) + { + FMUSIC_SetPanSeperation(mod, 0.85f); /* 15% crossover */ + } + } + } + + currsong = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + if (currsong >= MAXSONGS) + { + MessageBox(0, "Error. Unable to fit any more songs in.. please restart app", "Loading a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + return FALSE; + } + + if (mod) + { + song[currsong].mod = mod; + song[currsong].stream = NULL; + song[currsong].url = NULL; + } + else if (stream) + { + song[currsong].stream = stream; + song[currsong].mod = NULL; + song[currsong].url = NULL; + } + else + { + song[currsong].stream = NULL; + song[currsong].mod = NULL; + song[currsong].url = strdup(name); + } + + strcpy(s, displayname); + song[currsong].listname = strdup(displayname); + + SendMessage(songlist_hwnd, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR)s); + UpdateWindow(songlist_hwnd); + SendMessage(songlist_hwnd, LB_SETCURSEL, currsong, 0); + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void LoadSong() +{ + OPENFILENAME ofn; /* common dialog box structure */ + char szDirName[MAX_PATH]; /* directory string */ + char szFile[20481]; /* filename string */ + char szFileTitle[4096]; /* filename string */ + + /* + Obtain the system directory name and store it in szDirName. + */ + GetSystemDirectory(szDirName, sizeof(szDirName)); + + /* + Place the terminating null character in the szFile. + */ + szFile[0] = '\0'; + szFileTitle[0] = '\0'; + + /* + Set the members of the OPENFILENAME structure. + */ + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = mainhwnd; + ofn.lpstrTitle = "Open\0"; + ofn.lpstrFilter = "All song Types\0*.MOD;*.S3M;*.XM;*.IT;*.MID;*.RMI;*.SGT;*.WAV;*.MP2;*.MP3;*.OGG;*.WMA;*.ASF;*.AIFF;*.PLS;*.FSB;*.OXM\0Microsoft WAV (*.WAV)\0*.WAV\0MP2/MP3 (*.MP3 *.MP2)\0*.MP2;*.MP3\0Ogg Vorbis (*.OGG)\0*.OGG\0Windows Media Format (*.WMA *.ASF)\0*.WMA;*.ASF\0Audio Interchange File Format (*.AIFF)\0*.AIFF\0MIDI / DirectMusic Files (*.MID,*.RMI,*.SGT)\0*.MID;*.RMI;*.SGT\0Impulse Tracker (*.IT)\0*.IT\0FastTracker2 (*.XM)\0*.XM\0ScreamTracker 3 (*.S3M)\0*.S3M\0Protracker/FastTracker (*.MOD)\0*.MOD\0Playlist (*.PLS)\0*.PLS\0FMOD Sample Bank (*.FSB)\0*.FSB\0Ogg commpress XM (*.OXM)\0*.OXM\0All files (*.*)\0*.*\0\0"; + ofn.lpstrCustomFilter = NULL; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFile; + ofn.nMaxFile = 20480; /* Huge value allows many files to be multi-selected */ + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = 2048; + ofn.lpstrInitialDir = ".\0"; + ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT; + + /* + Display the Open dialog box. + */ + if (GetOpenFileName(&ofn)) + { + char *path = ofn.lpstrFile; + char *fname = ofn.lpstrFile; + char name[256]; + + /* + Single file + */ + if (ofn.nFileOffset) + { + /* + Skip to the first filename + */ + fname +=ofn.nFileOffset; + *(fname-1) = 0; /* clear the backslash before the filename so the loop below handles it */ + } + /* + Multiple files + */ + else + { + while (*fname++); /* search to the first filename */ + } + + do + { + Playlist *p; + int i; + + /* + Put path in name + */ + strcpy(name, path); + strcat(name, "\\"); + strcat(name, fname); + + /* + Open the file. + */ + p = ParsePlaylist(name); + if (p) + { + for (i=0;i < p->count;i++) + { + AddFileToSongList(p->name[i], p->displayname[i]); + } + + FreePlaylist(p); + } + else + { + AddFileToSongList(name, fname); + } + + while (*fname++); + + Sleep(1); + + } while (*fname); + } +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void LoadURL() +{ + if (DialogBox(g_hinst, MAKEINTRESOURCE(IDD_LOADURLDLG), mainhwnd, FMOD_LoadURLDlgProc)) + { + if (strlen(url_to_load)) + { + int songid = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + if (songid >= MAXSONGS) + { + MessageBox(0, "Error. Unable to fit any more songs in.. please restart app", "Loading a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + return; + } + + song[songid].mod = 0; + song[songid].stream = 0; + song[songid].url = strdup(url_to_load); + song[songid].listname = strdup(url_to_load); + + SendMessage(songlist_hwnd, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR)song[songid].url); + UpdateWindow(songlist_hwnd); + SendMessage(songlist_hwnd, LB_SETCURSEL, songid, 0); + + UpdateNetStreamInfo(songid, TRUE, FALSE); + } + } +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void LoadCD() +{ + int numsongs, songid, i; + char tmp[256]; + + /* + Bomb out if there's a cdda_stream already loading + */ + if (cdda_stream) + { + if (FSOUND_Stream_GetOpenState(cdda_stream) == -2) + { + return; + } + } + + DeleteAllCDTracks(); + + if (cdda_stream) + { + FSOUND_Stream_Close(cdda_stream); + cdda_stream = 0; + cdda_channel = -1; + } + + if (setting_cdda) + { + /* + Use the "!" qualifier to specify "quick open" mode so we can populate the playlist and get + the track lengths quickly + */ + sprintf(tmp, "%s*!j", setting_cdletter); + cdda_stream = FSOUND_Stream_Open(tmp, FSOUND_NORMAL, 0, 0); + if (!cdda_stream) + { + MessageBox(mainhwnd, "Couldn't open cdda stream", "Error", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + + numsongs = FSOUND_Stream_GetNumSubStreams(cdda_stream); + for (i=0;i < numsongs;i++) + { + songid = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + if (songid >= MAXSONGS) + { + MessageBox(0, "Error. Unable to fit any more songs in.. please restart app", "Loading a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + break; + } + + memset(&song[songid], 0, sizeof(song[songid])); + + sprintf(tmp, "Track %02d", i + 1); + song[songid].listname = strdup(tmp); + song[songid].channel = -1; + song[songid].cdtrack = i + 1; + + SendMessage(songlist_hwnd, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR)tmp); + UpdateWindow(songlist_hwnd); + } + + SendMessage(songlist_hwnd, LB_SETCURSEL, 0, 0); + + numsongs = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + for (i=0;i < numsongs;i++) + { + if (song[i].cdtrack) + { + FSOUND_Stream_SetSubStream(cdda_stream, song[i].cdtrack - 1); + song[i].cdtrack_length = FSOUND_Stream_GetLengthMs(cdda_stream); + } + } + + FSOUND_Stream_Close(cdda_stream); + + /* + Now do a normal non-blocking open to setup the stream properly for playing + */ + strcpy(tmp, setting_cdletter); + strcat(tmp, "*"); + if (!setting_jitter) + { + strcat(tmp, "j"); + } + if (setting_forceaspi) + { + strcat(tmp, "a"); + } + cdda_stream = FSOUND_Stream_Open(tmp, FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!cdda_stream) + { + MessageBox(mainhwnd, "Couldn't open cdda stream", "Error", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + + cdda_stream_state = -2; + } + else + { + numsongs = FSOUND_CD_GetNumTracks(cddevice); + if (numsongs) + { + for (i=0;i < numsongs;i++) + { + songid = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + if (songid >= MAXSONGS) + { + MessageBox(0, "Error. Unable to fit any more songs in.. please restart app", "Loading a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + break; + } + + memset(&song[songid], 0, sizeof(song[songid])); + + sprintf(tmp, "Track %02d", i + 1); + song[songid].listname = strdup(tmp); + song[songid].channel = -1; + song[songid].cdtrack = i + 1; + song[songid].cdtrack_length = 0; + + SendMessage(songlist_hwnd, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR)tmp); + UpdateWindow(songlist_hwnd); + SendMessage(songlist_hwnd, LB_SETCURSEL, songid, 0); + } + } + } +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void DeleteAllCDTracks() +{ + int numsongs, i; + + StopCDTrack(); + + numsongs = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + for (i=0;i < numsongs;i++) + { + if (song[i].cdtrack) + { + DeleteSong(i); + i = -1; /* Force it to start at the start */ + numsongs--; + } + } +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char StopCDTrack() +{ + int songid; + int numsongs = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + + if (setting_cdda) + { + for (songid=0;songid < numsongs;songid++) + { + if (song[songid].cdtrack && (song[songid].channel != -1)) + { + FSOUND_Stream_Stop(cdda_stream); + song[songid].channel = -1; + return TRUE; + } + } + } + else + { + FSOUND_CD_Stop(cddevice); + } + + return FALSE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char PlayCDTrack(int songid, int looped) +{ + unsigned int mode; + + if (setting_cdda) + { + if (cdda_stream) + { + if ((song[songid].channel != -1) && FSOUND_IsPlaying(song[songid].channel)) + { + int off = FSOUND_Stream_GetTime(cdda_stream); + int len = FSOUND_Stream_GetLengthMs(cdda_stream); + if ((off < len) && (off > 0)) + { + /* + It's already playing + */ + return TRUE; + } + } + + if (FSOUND_Stream_GetOpenState(cdda_stream) == 0) + { + StopCDTrack(); + + FSOUND_Stream_SetSubStream(cdda_stream, song[songid].cdtrack - 1); + /* + It's non-blocking - wait for it to finish seeking + */ + while (FSOUND_Stream_GetOpenState(cdda_stream) != 0) + { + Sleep(100); + } + + mode = FSOUND_Stream_GetMode(cdda_stream); + mode &= ~(FSOUND_LOOP_OFF | FSOUND_LOOP_NORMAL | FSOUND_LOOP_BIDI); + if (looped == FSOUND_CD_PLAYONCE) + { + mode |= FSOUND_LOOP_OFF; + } + else if (looped == FSOUND_CD_PLAYLOOPED) + { + mode |= FSOUND_LOOP_NORMAL; + } + else + { + mode |= FSOUND_LOOP_OFF; + } + FSOUND_Stream_SetMode(cdda_stream, mode); + + song[songid].channel = FSOUND_Stream_Play(FSOUND_FREE, cdda_stream); + if (song[songid].channel < 0) + { + MessageBox(mainhwnd, "Error. Cannot start song", "Playing a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + return FALSE; + } + } + + return TRUE; + } + } + else + { + if (FSOUND_CD_GetPaused(cddevice)) + { + return FSOUND_CD_SetPaused(cddevice, FALSE); + } + else + { + FSOUND_CD_SetPlayMode(cddevice, looped); + return FSOUND_CD_Play(cddevice, song[songid].cdtrack); + } + } + + return FALSE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void DeleteSong(int songid) +{ + int count; + + if (song[songid].mod) + { + FMUSIC_FreeSong(song[songid].mod); + song[songid].mod = NULL; + } + else if (song[songid].stream) + { + FSOUND_Stream_Close(song[songid].stream); + song[songid].stream = NULL; + + if (song[songid].url) + { + free(song[songid].url); + song[songid].url = 0; + } + } + else if (song[songid].cdtrack) + { + if (setting_cdda) + { + if (song[songid].channel && cdda_stream) + { + FSOUND_Stream_Stop(cdda_stream); + } + } + else + { + if (FSOUND_CD_GetTrack(cddevice) == song[songid].cdtrack) + { + FSOUND_CD_Stop(cddevice); + } + } + } + + song[songid].channel = -1; + + if (song[songid].listname) + { + free(song[songid].listname); + song[songid].listname = 0; + } + + if (song[songid].server_status) + { + free(song[songid].server_status); + song[songid].server_status = 0; + } + + if (song[songid].title) + { + free(song[songid].title); + song[songid].title = 0; + } + + if (song[songid].artist) + { + free(song[songid].artist); + song[songid].artist = 0; + } + + song[songid].protocol = NULL; + song[songid].format = NULL; + song[songid].streamname = NULL; + song[songid].last_status = -1; + + SendMessage(songlist_hwnd, LB_DELETESTRING, songid, 0); + + /* + Shuffle down tunes + */ + for (count=songid+1; count= SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0)) + { + songid = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0) - 1; + if (songid < 0) + { + songid = 0; + } + } + + SendMessage(songlist_hwnd, LB_SETCURSEL, songid, 0); + + UpdateStreamInfo(songid, TRUE); + UpdateNetStreamInfo(songid, TRUE, FALSE); + UpdateModInfo(songid, TRUE); + UpdateCDInfo(songid, TRUE); + SelectInfoWindow(); + + playlistsong = 0; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +BOOL PlaySong(int index) +{ + if (song[index].mod) + { + FMUSIC_SetLooping(song[index].mod, Button_GetCheck(GetDlgItem(mainhwnd, IDC_PLAYLOOPED))); + FMUSIC_PlaySong(song[index].mod); + } + else if (song[index].stream && !song[index].url) + { + FSOUND_Stream_SetMode(song[index].stream, Button_GetCheck(GetDlgItem(mainhwnd, IDC_PLAYLOOPED)) ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF); + song[index].channel = FSOUND_Stream_Play(FSOUND_FREE, song[index].stream); + } + else if (!song[index].stream && song[index].url) + { + song[index].stream = FSOUND_Stream_Open(song[index].url, FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!song[index].stream) + { + MessageBox(mainhwnd, "ERROR: Couldn't open stream", "Playing a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + return FALSE; + } + } + else if (song[index].cdtrack) + { + PlayCDTrack(index, Button_GetCheck(GetDlgItem(mainhwnd, IDC_PLAYLOOPED)) ? FSOUND_CD_PLAYLOOPED : FSOUND_CD_PLAYONCE); + } + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char PlayNextSong() +{ + playlistsong++; + + if (playlistsong >= SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0)) + { + playlistsong = 0; + } + + PlaySong(playlistsong); + + SendMessage(songlist_hwnd, LB_SETCURSEL, playlistsong, 0); + SelectInfoWindow(); + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + Create DSP units and reverb buffers etc + + [PARAMETERS] + void + + [RETURN_VALUE] + void + + [REMARKS] + + [SEE_ALSO] + CloseDSP +] +*/ +void InitDSP() +{ + int bytesperoutputsample; + int mixertype = FSOUND_GetMixer(); + + DSP_Ready = FALSE; + + if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + bytesperoutputsample = 4; // 16bit stereo + } + else + { + bytesperoutputsample = 8; // 32bit stereo + } + + /* + Initalize and create lowpass buffer and DSP unit + */ + LowPass_Init(); + LowPassBuffer = calloc(FSOUND_DSP_GetBufferLength()+256, bytesperoutputsample); + LowPass_Update(LowPassResonance, LowPassCutoffFrequency, outputfreq); + LowPassUnit = FSOUND_DSP_Create(&LowPassCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+1, LowPassBuffer); + + /* + Create buffer and dsp unit for echo effect + */ + EchoLen = MAXECHOLEN; /* 500ms */ + EchoBuffer = calloc(EchoLen, 4); /* The echo buff is always 16bit stereo int regardless of the mixer format, so * 4 */ + EchoOffset = 0; + EchoUnit = FSOUND_DSP_Create(&EchoCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+2, EchoBuffer); + + /* + Create buffer and dsp unit for oscilliscope. + */ + OscUnit = FSOUND_DSP_Create(&OscCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+3, 0); + OscBuffer = calloc(FSOUND_DSP_GetBufferLengthTotal() + 16, 2); /* *2 for mono 16bit buffer */ + + /* + Initialize reverb stuff + */ + Reverb_Init(); + + /* + Create a bitmap to draw the Spectrum into + */ + + // make the header + ZeroMemory( &GraphicWindowBitmap, sizeof( BITMAPINFO ) ); + GraphicWindowBitmap.bmiHeader.biSize = sizeof( GraphicWindowBitmap.bmiHeader ); + GraphicWindowBitmap.bmiHeader.biWidth = GRAPHICWINDOW_WIDTH; + GraphicWindowBitmap.bmiHeader.biHeight = GRAPHICWINDOW_HEIGHT; + GraphicWindowBitmap.bmiHeader.biPlanes = 1; + GraphicWindowBitmap.bmiHeader.biBitCount = 32; + GraphicWindowBitmap.bmiHeader.biCompression = BI_RGB; + GraphicWindowBitmap.bmiHeader.biSizeImage = 0; + GraphicWindowBitmap.bmiHeader.biXPelsPerMeter = 0; + GraphicWindowBitmap.bmiHeader.biYPelsPerMeter = 0; + GraphicWindowBitmap.bmiHeader.biClrUsed = 0; + GraphicWindowBitmap.bmiHeader.biClrImportant = 0; + + + DSP_Ready = TRUE; +} + + +/* +[ + [DESCRIPTION] + Remove all DSP units and reverb buffers etc. + + [PARAMETERS] + void + + [RETURN_VALUE] + void + + [REMARKS] + + [SEE_ALSO] + InitDSP +] +*/ +void CloseDSP() +{ + DSP_Ready = FALSE; + + if (LowPassUnit) + { + FSOUND_DSP_Free(LowPassUnit); + } + LowPassUnit = NULL; + + if (EchoUnit) + { + FSOUND_DSP_Free(EchoUnit); + } + EchoUnit = NULL; + + if (OscUnit) + { + FSOUND_DSP_Free(OscUnit); + } + OscUnit = NULL; + + /* + Free buffers + */ + if (LowPassBuffer) + { + free(LowPassBuffer); + } + LowPassBuffer = NULL; + + if (EchoBuffer) + { + free(EchoBuffer); + } + EchoBuffer = NULL; + + if (OscBuffer) + { + free(OscBuffer); + } + OscBuffer = NULL; + + Reverb_Close(); + LowPass_Close(); +} + + +/* + ** TextWindowProc + * + * PARAMETERS: + * + * DESCRIPTION: Sends back messages to the parent window if this window got focus + * + * RETURNS: + * + */ +long FAR PASCAL ProgressWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_LBUTTONDOWN: + case WM_MOUSEMOVE: + { + int songid = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + + if (message == WM_MOUSEMOVE && wParam != MK_LBUTTON) + { + break; + } + + if (songid != LB_ERR) + { + FMUSIC_MODULE *mod = song[songid].mod; + FSOUND_STREAM *stream = song[songid].stream; + char *url = song[songid].url; + RECT r; + int width; + int xPos = LOWORD(lParam); // horizontal position of cursor + + GetWindowRect(hwnd, &r); + + width = r.right - r.left; + + if (mod) + { + int count; + + for (count=0; count < FMUSIC_GetNumChannels(mod); count++) + { + FSOUND_StopSound(FMUSIC_GetRealChannel(mod, count)); + } + FMUSIC_SetOrder(mod, (int)((float)FMUSIC_GetNumOrders(mod) / (float)width * (float)xPos)); + } + else if (stream && !url) + { + FSOUND_Stream_SetTime(stream, (int)((float)FSOUND_Stream_GetLengthMs(stream) / (float)width * (float)xPos)); + } + else if (song[songid].cdtrack) + { + if (setting_cdda) + { + if ((song[songid].channel != -1) && cdda_stream) + { + FSOUND_Stream_SetTime(cdda_stream, (int)((float)FSOUND_Stream_GetLengthMs(cdda_stream) / (float)width * (float)xPos)); + } + } + else + { + if (song[songid].cdtrack == FSOUND_CD_GetTrack(cddevice)) + { + FSOUND_CD_SetTrackTime(cddevice, (int)((float)FSOUND_CD_GetTrackLength(cddevice, FSOUND_CD_GetTrack(cddevice)) / (float)width * (float)xPos)); + } + } + } + } + break; + } + }; + + return (long)CallWindowProc(oldprogressproc, hwnd, message, wParam, lParam); +} + + +/* + ** TextWindowProc + * + * PARAMETERS: + * + * DESCRIPTION: Sends back messages to the parent window if this window got focus + * + * RETURNS: + * + */ +long FAR PASCAL CDTimeWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_LBUTTONDOWN: + { + DraggingCDSlider = TRUE; + break; + } + case WM_LBUTTONUP: + { + int pos = (int)SendMessage(hwnd, TBM_GETPOS, 0, 0); + + if (setting_cdda) + { + if (cdda_stream) + { + FSOUND_Stream_SetTime(cdda_stream, (int)((float)pos * (float)FSOUND_Stream_GetLengthMs(cdda_stream) / 1000.0f)); + } + } + else + { + FSOUND_CD_SetTrackTime(cddevice, (int)((float)pos * (float)FSOUND_CD_GetTrackLength(cddevice, FSOUND_CD_GetTrack(cddevice)) / 1000.0f)); + } + DraggingCDSlider = FALSE; + break; + } + }; + + return (long)CallWindowProc(oldcdtimeproc, hwnd, message, wParam, lParam); +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +#ifdef _WIN64 +INT_PTR CALLBACK FMOD_DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#else +BOOL CALLBACK FMOD_DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#endif +{ + switch (msg) + { + case WM_INITDIALOG: + { + int count; + RECT r; + + SetFocus(hwnd); + + /* + CALL DRIVER DIALOG BOX + */ + #if 0 + if (!SoundDriver_Init(&outputfreq)) + { + SendMessage(hwnd, WM_CLOSE, 0, 0); + return TRUE; + } + #endif + + /* + CONFIGURE STABILITY OF SOUND OUTPUT UNDER WINDOWS + */ + + FSOUND_SetBufferSize(FSOUND_BUFFERSIZE); + + /* + INITIALIZE FSOUND + */ + FSOUND_SetOutput(setting_output); + FSOUND_SetDriver(setting_driver); + FSOUND_SetMixer(setting_mixer); + FSOUND_SetHWND(hwnd); + + outputfreq = setting_outputrate; + if (!FSOUND_Init(outputfreq, NUMCHANNELS, FSOUND_INIT_GLOBALFOCUS)) + { + MessageBox(hwnd, FMOD_ErrorString(FSOUND_GetError()), "FSOUND", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + SendMessage(hwnd, WM_CLOSE, 0, 0); + return TRUE; + } + + FSOUND_Stream_Net_SetProxy(setting_http_proxy); + FSOUND_Stream_SetBufferSize(1000); + + /* + SET UP A PAINT TIMER FOR INTERFACE + */ + timerid = SetTimer(hwnd, 0, 5, (TIMERPROC)0); + if (!timerid) + { + MessageBox( NULL, "Too many timers in use", "Error", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + return FALSE; + } + + /* + INITIALIZE SONG LIST TO NULL + */ + for (count=0; count= len)) + { + FSOUND_Stream_Close(song[songid].stream); + song[songid].stream = FSOUND_Stream_Open(song[songid].url, FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!song[songid].stream) + { + MessageBox(hwnd, "ERROR: Couldn't open stream", "Playing a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + } + break; + } + } + } + else + { + song[songid].stream = FSOUND_Stream_Open(song[songid].url, FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!song[songid].stream) + { + MessageBox(hwnd, "ERROR: Couldn't open stream", "Playing a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + } + } + else if (song[songid].stream) + { + /* + It's non-blocking - wait for it to finish opening first + */ + if (FSOUND_Stream_GetOpenState(song[songid].stream) != 0) + { + HWND pwhwnd = CreateDialog(g_hinst, MAKEINTRESOURCE(IDD_DIALOGWAIT), mainhwnd, 0); + while (FSOUND_Stream_GetOpenState(song[songid].stream) == -2) + { + Sleep(100); + } + EndDialog(pwhwnd, 0); + } + + FSOUND_Stream_SetMode(song[songid].stream, Button_GetCheck(GetDlgItem(hwnd,IDC_PLAYLOOPED)) ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF); + song[songid].channel = FSOUND_Stream_Play(FSOUND_FREE, song[songid].stream); + if (song[songid].channel < 0) + { + MessageBox(hwnd, "Error. Cannot start song", "Playing a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + } + else if (song[songid].cdtrack) + { + if (!PlayCDTrack(songid, Button_GetCheck(GetDlgItem(hwnd,IDC_PLAYLOOPED)) ? FSOUND_CD_PLAYLOOPED : FSOUND_CD_PLAYONCE)) + { + MessageBox(hwnd, "Error. Cannot start song", "Playing a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + } + } + else + { + MessageBox(hwnd, "Error. Please select a song to play first", "Playing a song", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + } + else + { + int songid = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + if (songid != LB_ERR) + { + if (song[songid].mod) + { + FMUSIC_StopSong(song[songid].mod); + } + else if (song[songid].stream) + { + if (song[songid].url) + { + FSOUND_Stream_Close(song[songid].stream); + song[songid].stream = NULL; + } + else + { + FSOUND_Stream_Stop(song[songid].stream); + } + } + else if (song[songid].cdtrack) + { + if (setting_cdda) + { + if ((song[songid].channel != -1) && cdda_stream) + { + StopCDTrack(); + } + } + else + { + if (song[songid].cdtrack == FSOUND_CD_GetTrack(cddevice)) + { + StopCDTrack(); + } + } + } + + if (song[songid].title) + { + free(song[songid].title); + song[songid].title = 0; + } + + if (song[songid].artist) + { + free(song[songid].artist); + song[songid].artist = 0; + } + + song[songid].channel = -1; + song[songid].protocol = NULL; + song[songid].format = NULL; + song[songid].streamname = NULL; + } + else + { + MessageBox(hwnd, "Error. Please select a song to play first", "Playing a mod", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + } + + break; + } + + case IDC_SPECTRUM: /* GRAPHIC SPECTRUM / INFO BUTTON */ + { + int x, y; + RECT rect; + + if (GraphicWindowCurrent == GRAPHICWINDOW_MODINFO) + { + ShowWindow(modinfo_hwnd, SW_HIDE); + ShowWindow(streaminfo_hwnd, SW_HIDE); + ShowWindow(netstreaminfo_hwnd, SW_HIDE); + ShowWindow(cdinfo_hwnd, SW_HIDE); + } + else if (GraphicWindowCurrent == GRAPHICWINDOW_EQUALISER) + { + FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), FALSE); + } + else if (GraphicWindowCurrent == GRAPHICWINDOW_WAVE) + { + FSOUND_DSP_SetActive(OscUnit, FALSE); + } + + GraphicWindowCurrent++; + if (GraphicWindowCurrent >= GRAPHICWINDOW_MAX) + { + GraphicWindowCurrent = GRAPHICWINDOW_MODINFO; + } + + if (GraphicWindowCurrent == GRAPHICWINDOW_MODINFO) + { + SelectInfoWindow(); + SendMessage(GetDlgItem(hwnd, IDC_SPECTRUM), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Spectrum"); + } + else if (GraphicWindowCurrent == GRAPHICWINDOW_EQUALISER) + { + FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); + SendMessage(GetDlgItem(hwnd, IDC_STATIC_INFO), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Spectrum"); + SendMessage(GetDlgItem(hwnd, IDC_SPECTRUM), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Wave"); + } + else if (GraphicWindowCurrent == GRAPHICWINDOW_WAVE) + { + FSOUND_DSP_SetActive(OscUnit, TRUE); + SendMessage(GetDlgItem(hwnd, IDC_STATIC_INFO), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Oscilliscope"); + SendMessage(GetDlgItem(hwnd, IDC_SPECTRUM), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Info"); + } + + x = graphic_window_x; + y = graphic_window_y; + rect.left = x; + rect.top = y; + rect.right = x + GRAPHICWINDOW_WIDTH; + rect.bottom = y + GRAPHICWINDOW_HEIGHT; + InvalidateRect(hwnd, &rect, TRUE); + + break; + } + + case IDC_SONGLIST : + { + if (HIWORD(wParam) == LBN_SELCHANGE) + { + SelectInfoWindow(); + } + break; + } + + case IDC_CONFIG : + { + int i, numsongs, currsong; + + CloseDSP(); + + /* + Close all open internet streams because all network stuff gets shutdown in FSOUND_Close + */ + numsongs = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + currsong = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + for (i=0;i < numsongs;i++) + { + if (song[i].url && song[i].stream) + { + FSOUND_Stream_Close(song[i].stream); + song[i].stream = 0; + song[i].channel = -1; + song[i].last_status = -1; + + if (i == currsong) + { + UpdateNetStreamInfo(i, TRUE, FALSE); + } + } + } + + if (cdda_stream) + { + FSOUND_Stream_Close(cdda_stream); + cdda_stream = 0; + cdda_channel = -1; + } + + DeleteAllCDTracks(); + + /* + Remember .. FSOUND_Close cleans up all DSP units, so if you still have pointers to them, + it could cause problems (crashes) because they are pointing to freed data. + This is why there is a call to CloseDSP above. + */ + FSOUND_Close(); + + /* + Call up dialog box to select sound options + */ + SoundDriver_Init(&outputfreq); + + FSOUND_SetBufferSize(FSOUND_BUFFERSIZE); + + /* + Initialize FSOUND + */ + + if (!FSOUND_Init(outputfreq,NUMCHANNELS, FSOUND_INIT_GLOBALFOCUS)) + { + MessageBox(hwnd, FMOD_ErrorString(FSOUND_GetError()), "FSOUND", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + return FALSE; + } + + FSOUND_Stream_Net_SetProxy(setting_http_proxy); + FSOUND_Stream_SetBufferSize(1000); + + InitDSP(); + + if (GraphicWindowCurrent == GRAPHICWINDOW_EQUALISER) + { + FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE); + } + else if (GraphicWindowCurrent == GRAPHICWINDOW_WAVE) + { + FSOUND_DSP_SetActive(OscUnit, TRUE); + } + + break; + } + } + + InvalidateRect(songlist_hwnd, NULL, FALSE); + + break; + } + + case WM_DROPFILES : + { + HDROP hDrop = (HDROP)wParam; + int numfiles, count; + char name[1024]; + Playlist *p; + int i; + struct _stat buf; + + numfiles = DragQueryFile(hDrop, 0xFFFFFFFF, &name[0], 1024); + if (!numfiles) + break; + + for (count=0; countcount;i++) + { + AddFileToSongList(p->name[i], p->displayname[i]); + } + + FreePlaylist(p); + } + else + { + AddFileToSongList(name, name); + } + } + + DragFinish(hDrop); + SelectInfoWindow(); + + break; + } + case WM_COPYDATA : + { + Playlist *p; + char *name; + int i; + COPYDATASTRUCT *data; + + data = (COPYDATASTRUCT *)lParam; + if (data->cbData) + { + char tmp[2048]; + + strcpy(tmp, (char *)data->lpData); + name = tmp; + + if (*name == '"') + { + name++; + } + + if (name[strlen(name) - 1] == '"') + { + name[strlen(name) - 1] = 0; + } + + p = ParsePlaylist(name); + if (p) + { + for (i=0;i < p->count;i++) + { + AddFileToSongList(p->name[i], p->displayname[i]); + } + + FreePlaylist(p); + } + else + { + AddFileToSongList(name, name); + } + } + + SelectInfoWindow(); + break; + } + + case WM_TIMER : + { + char s[256]; + HDC hdc = GetDC(hwnd); + HFONT myfont; + FMUSIC_MODULE *mod; + FSOUND_STREAM *stream; + int songid; + int greyoutfilters; + + greyoutfilters = FALSE; + + myfont = GetStockObject(DEFAULT_GUI_FONT); + SelectObject(hdc, myfont); + + SetBkColor(hdc, GetSysColor(COLOR_3DFACE)); + SetTextColor(hdc, RGB(0, 0, 255)); + + sprintf(s, "%03d", FSOUND_GetChannelsPlaying()); + TextOut(hdc, (int)(TEXT_CHANNELSPLAYING_X * scalex), (int)(TEXT_CHANNELSPLAYING_Y * scaley), s, (int)strlen(s)); + + sprintf(s, "%5.02f%% ", FSOUND_GetCPUUsage()); + TextOut(hdc, (int)(TEXT_CPUUSAGE_X * scalex), (int)(TEXT_CPUUSAGE_Y * scaley), s, (int)strlen(s)); + + /* + DSP BUTTONS + */ + if (DSP_Ready) + { + int count; + + /* + If the unit is inactive and the checkbox is checked, then clear preverb buffer + this stops any old preverb dregs hanging around. + */ + if (!FSOUND_DSP_GetActive(PreverbTap[0].Unit) && (char)Button_GetCheck(GetDlgItem(hwnd,IDC_PREVERB))) + { + for (count=0; count < PREVERB_NUMTAPS; count++) + { + memset(PreverbTap[count].historybuff, 0, PreverbTap[count].historylen<<2); /* preverblen is in samples. */ + } + } + for (count=0; count < PREVERB_NUMTAPS; count++) + { + FSOUND_DSP_SetActive(PreverbTap[count].Unit, (char)Button_GetCheck(GetDlgItem(hwnd,IDC_PREVERB))); + } + + /* + If the unit is inactive and the checkbox is checked, then clear reverb buffer + this stops any old reverb dregs hanging around. + */ + if (!FSOUND_DSP_GetActive(ReverbTap[0].Unit) && (char)Button_GetCheck(GetDlgItem(hwnd,IDC_REVERB))) + { + for (count=0; count < REVERB_NUMTAPS; count++) + { + memset(ReverbTap[count].historybuff, 0, ReverbTap[count].historylen<<2); /* preverblen is in samples. */ + } + } + for (count=0; count < REVERB_NUMTAPS; count++) + { + FSOUND_DSP_SetActive(ReverbTap[count].Unit, (char)Button_GetCheck(GetDlgItem(hwnd,IDC_REVERB))); + } + + + /* + MIDI reverb uses the reverb button as well + */ + FMUSIC_SetReverb((char)Button_GetCheck(GetDlgItem(hwnd,IDC_REVERB))); + + + /* + If the unit is inactive and the checkbox is checked, then clear echo buffer + this stops any old echo dregs hanging around. + */ + if (!FSOUND_DSP_GetActive(EchoUnit) && (char)Button_GetCheck(GetDlgItem(hwnd,IDC_ECHO))) + { + /* + Set status + */ + ShowWindow(GetDlgItem(mainhwnd,IDC_ECHOSLIDER), SW_SHOW); + memset(EchoBuffer, 0, MAXECHOLEN); /* echolen is in samples. */ + + SendMessage(GetDlgItem(mainhwnd,IDC_ECHOSLIDER), TBM_SETPOS, TRUE, EchoLen * 1000 / outputfreq); + } + if (FSOUND_DSP_GetActive(EchoUnit) && !(char)Button_GetCheck(GetDlgItem(hwnd,IDC_ECHO))) + { + ShowWindow(GetDlgItem(mainhwnd,IDC_ECHOSLIDER), SW_HIDE); + } + + FSOUND_DSP_SetActive(EchoUnit, (char)Button_GetCheck(GetDlgItem(hwnd,IDC_ECHO))); + + + + if (!FSOUND_DSP_GetActive(LowPassUnit) && (char)Button_GetCheck(GetDlgItem(hwnd,IDC_LOWPASS))) + { + /* + Set status + */ + ShowWindow(GetDlgItem(mainhwnd,IDC_CUTOFFSLIDER), SW_SHOW); + ShowWindow(GetDlgItem(mainhwnd,IDC_RESOSLIDER), SW_SHOW); + + SendMessage(GetDlgItem(mainhwnd,IDC_CUTOFFSLIDER), TBM_SETPOS, TRUE, 520 - (int)(LowPassCutoffFrequency / 10.0f)); + SendMessage(GetDlgItem(mainhwnd,IDC_RESOSLIDER), TBM_SETPOS, TRUE, 520 - (int)(LowPassResonance * 50.0f)); + } + if (FSOUND_DSP_GetActive(LowPassUnit) && !(char)Button_GetCheck(GetDlgItem(hwnd,IDC_LOWPASS))) + { + ShowWindow(GetDlgItem(mainhwnd,IDC_CUTOFFSLIDER), SW_HIDE); + ShowWindow(GetDlgItem(mainhwnd,IDC_RESOSLIDER), SW_HIDE); + } + + FSOUND_DSP_SetActive(LowPassUnit, (char)Button_GetCheck(GetDlgItem(hwnd,IDC_LOWPASS))); + } + + /* + Check PLAYLIST checkbox + */ + if (Button_GetCheck(GetDlgItem(hwnd,IDC_PLAYLIST))) + { + mod = song[playlistsong].mod; + if (mod) + { + if (FMUSIC_IsFinished(mod)) + { + FMUSIC_StopSong(mod); + PlayNextSong(); + } + } + else + { + stream = song[playlistsong].stream; + if (stream) + { + int off = FSOUND_Stream_GetTime(stream); + int len = FSOUND_Stream_GetLengthMs(stream); + + if ((!song[playlistsong].url) || (song[playlistsong].url && (FSOUND_Stream_GetOpenState(song[playlistsong].stream) == 0))) + { + if (off >= len) + { + if (song[playlistsong].url) + { + FSOUND_Stream_Close(stream); + song[playlistsong].stream = 0; + } + else + { + FSOUND_Stream_Stop(stream); + } + + song[playlistsong].channel = -1; + + PlayNextSong(); + } + } + } + else + { + if (song[playlistsong].cdtrack) + { + if (setting_cdda) + { + if ((song[playlistsong].channel != -1) && cdda_stream && (FSOUND_Stream_GetOpenState(cdda_stream) == 0)) + { + int off = FSOUND_Stream_GetTime(cdda_stream); + int len = FSOUND_Stream_GetLengthMs(cdda_stream); + + if (off >= len) + { + StopCDTrack(); + PlayNextSong(); + } + } + } + else + { + int off = FSOUND_CD_GetTrackTime(cddevice); + int len = FSOUND_CD_GetTrackLength(cddevice, FSOUND_CD_GetTrack(cddevice)); + if (off >= len) + { + StopCDTrack(); + PlayNextSong(); + } + } + } + } + } + } + + songid = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + if (songid >= 0) + { + unsigned int lengthms, currtime; + signed char playing = FALSE; + + if (song[songid].mod) + { + mod = song[songid].mod; + UpdateModInfo(songid, FALSE); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, FMUSIC_GetNumOrders(mod)-1)); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETPOS, FMUSIC_GetOrder(mod), 0); + + /* + Grey out fx buttons for midi + */ + if (FMUSIC_GetType(mod) == FMUSIC_TYPE_MIDI) + { + greyoutfilters = TRUE; + } + + playing = FMUSIC_IsPlaying(mod); + } + else if (song[songid].url) + { + UpdateNetStreamInfo(songid, FALSE, FALSE); + + if (song[songid].stream && (song[songid].channel != -1)) + { + playing = FSOUND_IsPlaying(song[songid].channel); + } + } + else if (song[songid].stream) + { + UpdateStreamInfo(songid, FALSE); + + currtime = FSOUND_Stream_GetTime(song[songid].stream); + lengthms = FSOUND_Stream_GetLengthMs(song[songid].stream); + + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, 1000) ); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETPOS, (WPARAM)((float)currtime / (float)lengthms * 1000.0f), 0); + + if (song[songid].channel != -1) + { + playing = FSOUND_IsPlaying(song[songid].channel); + if (currtime >= lengthms) + { + playing = FALSE; + } + } + } + else if (song[songid].cdtrack) + { + UpdateCDInfo(songid, TRUE); + + if (setting_cdda) + { + if ((song[songid].channel != -1) && cdda_stream) + { + currtime = FSOUND_Stream_GetTime(cdda_stream); + lengthms = FSOUND_Stream_GetLengthMs(cdda_stream); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, 1000) ); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETPOS, (WPARAM)((float)currtime / (float)lengthms * 1000.0f), 0); + + playing = FSOUND_IsPlaying(song[songid].channel); + } + else + { + currtime = 0; + lengthms = 1; + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, 1000) ); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETPOS, (WPARAM)((float)currtime / (float)lengthms * 1000.0f), 0); + } + } + else + { + if (song[songid].cdtrack == FSOUND_CD_GetTrack(cddevice)) + { + currtime = FSOUND_CD_GetTrackTime(cddevice); + lengthms = FSOUND_CD_GetTrackLength(cddevice, FSOUND_CD_GetTrack(cddevice)); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, 1000) ); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETPOS, (WPARAM)((float)currtime / (float)lengthms * 1000.0f), 0); + + if (FSOUND_CD_GetTrack(cddevice)) + { + playing = TRUE; + } + } + else + { + currtime = 0; + lengthms = 1; + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, 1000) ); + SendMessage(GetDlgItem(hwnd,IDC_PROGRESS1), PBM_SETPOS, (WPARAM)((float)currtime / (float)lengthms * 1000.0f), 0); + } + } + } + + if (!playing) + { + if (!play_button_play) + { + SetWindowText(GetDlgItem(hwnd, IDC_PLAY), "Play"); + play_button_play = TRUE; + } + } + else + { + if (play_button_play) + { + SetWindowText(GetDlgItem(hwnd, IDC_PLAY), "Stop"); + play_button_play = FALSE; + } + } + + /* + Set position of the master volume slider + */ + if (song[songid].mod) + { + SendMessage(GetDlgItem(hwnd,IDC_SLIDER1), TBM_SETPOS, TRUE, FMUSIC_GetMasterVolume(mod)); + } + else if (song[songid].cdtrack && !setting_cdda) + { + SendMessage(GetDlgItem(hwnd,IDC_SLIDER1), TBM_SETPOS, TRUE, FSOUND_CD_GetVolume(cddevice)); + } + else + { + SendMessage(GetDlgItem(hwnd,IDC_SLIDER1), TBM_SETPOS, TRUE, FSOUND_GetVolume(song[songid].channel)); + } + } + + /* + Update song listbox entries if the open state has changed + */ + { + int numsongs = (int)SendMessage(songlist_hwnd, LB_GETCOUNT, 0, 0); + int count; + + for (count = 0; count < numsongs; count++) + { + int status = -2; + + if (song[count].url) + { + UpdateNetStreamInfo(count, FALSE, TRUE); + } + + if (song[count].stream) + { + status = FSOUND_Stream_GetOpenState(song[count].stream); + } + else if (song[count].mod) + { + status = FMUSIC_GetOpenState(song[count].mod); + } + + if (status != song[count].last_status) + { + if (song[count].stream && !song[count].url && !status) + { + UpdateStreamInfo(count, TRUE); + } + + SendMessage(songlist_hwnd, LB_SETITEMDATA, count, 0); + InvalidateRect(songlist_hwnd, 0, FALSE); + } + song[count].last_status = status; + } + } + + if (greyoutfilters) + { + EnableWindow(GetDlgItem(hwnd,IDC_LOWPASS), FALSE); + EnableWindow(GetDlgItem(hwnd,IDC_PREVERB), FALSE); + EnableWindow(GetDlgItem(hwnd,IDC_ECHO), FALSE); + } + else + { + EnableWindow(GetDlgItem(hwnd,IDC_LOWPASS), TRUE); + EnableWindow(GetDlgItem(hwnd,IDC_PREVERB), TRUE); + EnableWindow(GetDlgItem(hwnd,IDC_ECHO), TRUE); + } + + if (GraphicWindowCurrent == GRAPHICWINDOW_EQUALISER) + { + PlotSpectrum(hdc); + } + else if (GraphicWindowCurrent == GRAPHICWINDOW_WAVE) + { + PlotOscilliscope(hdc); + } + + if (setting_cdda) + { + if (cdda_stream) + { + if (FSOUND_Stream_GetOpenState(cdda_stream) == -3) + { + FSOUND_Stream_Close(cdda_stream); + cdda_stream = 0; + cdda_channel = -1; + MessageBox(0, "ERROR: Unable to open CDDA stream", "Error", MB_ICONHAND | MB_OK | MB_SYSTEMMODAL); + } + else + { + if ((cdda_stream_state != 0) && (FSOUND_Stream_GetOpenState(cdda_stream) == 0)) + { + char *tag; + + cdda_stream_state = 0; + + if (FSOUND_Stream_FindTagField(cdda_stream, FSOUND_TAGFIELD_ASF + 1, "CD_ERROR", (void **)&tag, 0)) + { + MessageBox(mainhwnd, tag, "Error", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + FSOUND_Stream_Close(cdda_stream); + cdda_stream = 0; + cdda_channel = -1; + } + else + { + FSOUND_Stream_SetSubStream(cdda_stream, 0); + while (FSOUND_Stream_GetOpenState(cdda_stream) != 0) + { + Sleep(100); + } + + InvalidateRect(songlist_hwnd, 0, FALSE); + } + } + if (cdda_stream) + { + if (FSOUND_Stream_GetLengthMs(cdda_stream) && !DraggingCDSlider) + { + SendMessage(GetDlgItem(hwnd,IDC_CDTIME), TBM_SETPOS, TRUE, (int)((float)FSOUND_Stream_GetTime(cdda_stream) * 1000.0f / (float)FSOUND_Stream_GetLengthMs(cdda_stream))); + } + } + } + } + } + else + { + if (FSOUND_CD_GetTrack(cddevice)) + { + if (FSOUND_CD_GetTrackLength(cddevice, FSOUND_CD_GetTrack(cddevice)) && !DraggingCDSlider) + { + SendMessage(GetDlgItem(hwnd,IDC_CDTIME), TBM_SETPOS, TRUE, (int)((float)FSOUND_CD_GetTrackTime(cddevice) * 1000.0f / (float)FSOUND_CD_GetTrackLength(cddevice, FSOUND_CD_GetTrack(cddevice)))); + } + } + } + + DeleteObject(myfont); + ReleaseDC(hwnd, hdc); + break; + } + + case WM_MEASUREITEM: + { + LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam; + TEXTMETRIC m; + HDC hdc; + + hdc = GetDC(hwnd); + + GetTextMetrics(hdc, &m); + + ReleaseDC(hwnd, hdc); + + lpmis->itemHeight = m.tmAscent; + return TRUE; + } + case WM_DRAWITEM: + { + DRAWITEMSTRUCT FAR *pDIS; + DWORD crBack; + DWORD crText; + HBRUSH hbrBack; + char szBuf[MAX_PATH]; + int state; + + #define PHDC (pDIS->hDC) + #define PRC (pDIS->rcItem) + + pDIS = (DRAWITEMSTRUCT FAR *)lParam; + + if (pDIS->itemID < 0) + { + break; + + } + memset(szBuf, 0, MAX_PATH); + + /* Draw the focus rectangle for an empty list box or an + empty combo box to indicate that the control has the + focus + */ + if ((int)(pDIS->itemID) < 0) + { + switch(pDIS->CtlType) + { + case ODT_LISTBOX: + { + if ((pDIS->itemAction) & (ODA_FOCUS)) + { + DrawFocusRect (PHDC, &PRC); + } + break; + } + case ODT_COMBOBOX: + { + if ((pDIS->itemState) & (ODS_FOCUS)) + { + DrawFocusRect (PHDC, &PRC); + } + break; + } + } + return TRUE; + } + + /* Get the string */ + switch(pDIS->CtlType) + { + case ODT_LISTBOX: + { + SendMessage ( pDIS->hwndItem, LB_GETTEXT, pDIS->itemID, (LPARAM)(LPSTR)szBuf); + break; + } + case ODT_COMBOBOX: + { + SendMessage ( pDIS->hwndItem, CB_GETLBTEXT, pDIS->itemID, (LPARAM)(LPSTR)szBuf); + break; + } + } + + + if ((pDIS->itemState) & (ODS_SELECTED)) + { + /* Set background and text colors for selected item */ + crBack = GetSysColor (COLOR_HIGHLIGHT); + } + else + { + /* Set background and text colors for unselected item */ + crBack = GetSysColor (COLOR_WINDOW); + } + + if (song[pDIS->itemID].mod) + { + state = FMUSIC_GetOpenState(song[pDIS->itemID].mod); + } + if (song[pDIS->itemID].stream) + { + state = FSOUND_Stream_GetOpenState(song[pDIS->itemID].stream); + } + if (song[pDIS->itemID].cdtrack) + { + if (setting_cdda && cdda_stream) + { + state = FSOUND_Stream_GetOpenState(cdda_stream); + } + else + { + state = 0; + } + } + + switch (state) + { + case 0: crText = (pDIS->itemState & ODS_SELECTED) ? GetSysColor(COLOR_HIGHLIGHTTEXT) : GetSysColor(COLOR_WINDOWTEXT) ; break; + case -1: crText = (pDIS->itemState & ODS_SELECTED) ? GetSysColor(COLOR_HIGHLIGHTTEXT) : RGB(255, 0, 0) ; break; + case -2: crText = (pDIS->itemState & ODS_SELECTED) ? GetSysColor(COLOR_HIGHLIGHTTEXT) : RGB(192, 192, 192) ; break; + case -3: crText = (pDIS->itemState & ODS_SELECTED) ? GetSysColor(COLOR_HIGHLIGHTTEXT) : RGB(255, 0, 0) ; break; + case -4: crText = (pDIS->itemState & ODS_SELECTED) ? GetSysColor(COLOR_HIGHLIGHTTEXT) : RGB(0, 0, 255) ; break; + case -5: crText = (pDIS->itemState & ODS_SELECTED) ? GetSysColor(COLOR_HIGHLIGHTTEXT) : RGB(0, 0, 255) ; break; + } + + // Fill item rectangle with background color + hbrBack = CreateSolidBrush (crBack); + FillRect (PHDC, &PRC, hbrBack); + DeleteObject (hbrBack); + + // Set current background and text colors + SetBkColor (PHDC, crBack); + SetTextColor (PHDC, crText); + + // TextOut uses current background and text colors + TextOut ( PHDC, PRC.left, PRC.top, szBuf, lstrlen(szBuf)); + + /* If enabled item has the input focus, call DrawFocusRect to set or clear the focus rectangle */ + if ((pDIS->itemState) & (ODS_FOCUS)) + { + DrawFocusRect (PHDC, &PRC); + } + break; + } + default: + { + return FALSE; + } + } + + return FALSE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +#ifdef _WIN64 +INT_PTR CALLBACK FMOD_StreamDetailsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#else +BOOL CALLBACK FMOD_StreamDetailsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#endif +{ + switch (msg) + { + case WM_INITDIALOG : + { + RECT r; + char str[8192]; + char tmp[4096]; + int songid, numinfo, i, bitrate; + signed char twotabs = FALSE; + + songid = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + str[0] = 0; + + FSOUND_Stream_GetNumTagFields(song[songid].stream, &numinfo); + + for (i=0;i < numinfo;i++) + { + char *name, *value; + int type, length; + char *str_streaminfotype[6] = + { + "VORBIS", + "ID3V1", + "ID3V2", + "SHOUTcast", + "Icecast", + "ASF" + }; + + if (FSOUND_Stream_GetTagField(song[songid].stream, i, &type, &name, &value, &length)) + { + if (type == FSOUND_TAGFIELD_SHOUTCAST) + { + twotabs = TRUE; + } + + if (type == FSOUND_TAGFIELD_ID3V2 && ((name[0] == 'T' && value[0] == 0) || !strncmp(name, "COMM", 4))) + { + char tmp2[2048]; + int offset = 0; + + if (name[0] == 'T' && value[0] == 0) + { + offset = 1; + } + else if (!strncmp(name, "COMM", 4) && length > 8) + { + offset = 8; /* a quick hack to skip the COMM tag stuff at the start (language etc), check id3.org for more */ + } + + strncpy(tmp2, value + offset, length - offset); + + tmp2[length - 1] = 0; + + sprintf(tmp, "%s\t%s = %s (%d bytes)\r\n", str_streaminfotype[type], name, tmp2, length); + } + else + { + if (type != FSOUND_TAGFIELD_SHOUTCAST) + { + sprintf(tmp, "%s%s%s = %s (%d bytes)\r\n", str_streaminfotype[type], twotabs ? "\t\t" : "\t", name, value, length); + } + else + { + sprintf(tmp, "%s\t%s = %s (%d bytes)\r\n", str_streaminfotype[type], name, value, length); + } + } + + strcat(str, tmp); + } + } + + if (FSOUND_Stream_Net_GetStatus(song[songid].stream, 0, 0, &bitrate, 0)) + { + sprintf(tmp, "Current bitrate : %d\r\n", bitrate); + strcat(str, tmp); + } + + SetWindowText(GetDlgItem(hwnd, IDC_STREAMDETAILSEDIT), str); + PostMessage(GetDlgItem(hwnd, IDC_STREAMDETAILSEDIT), EM_SETSEL, 0, 0); + GetClientRect(hwnd, &r); + MoveWindow(GetDlgItem(hwnd, IDC_STREAMDETAILSEDIT), 0, 0, r.right, r.bottom, TRUE); + + return TRUE; + } + + case WM_COMMAND : + switch (LOWORD(wParam)) + { + case IDOK : + { + EndDialog(hwnd, 0); + return TRUE; + } + } + break; + + case WM_SIZE : + MoveWindow(GetDlgItem(hwnd, IDC_STREAMDETAILSEDIT), 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); + return 0; + + case WM_CLOSE: + EndDialog(hwnd, 0); + return TRUE; + + default: + return FALSE; + } + + return FALSE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +#ifdef _WIN64 +INT_PTR CALLBACK FMOD_InfoDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#else +BOOL CALLBACK FMOD_InfoDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#endif +{ + switch (msg) + { + case WM_COMMAND : + { + switch (LOWORD(wParam)) + { + case IDC_NETSTREAMINFO_DETAILS : + { + int songid = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + if ((songid >= 0) && song[songid].stream) + { + DialogBox(g_hinst, MAKEINTRESOURCE(IDD_STREAMDETAILSDLG), mainhwnd, FMOD_StreamDetailsDlgProc); + } + break; + } + } + break; + } + + case WM_CLOSE: + { + EndDialog(hwnd, 0); + return TRUE; + } + + default: + return FALSE; + } + + return FALSE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +#ifdef _WIN64 +INT_PTR CALLBACK FMOD_LoadURLDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#else +BOOL CALLBACK FMOD_LoadURLDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#endif +{ + switch (msg) + { + case WM_INITDIALOG : + { + int i; + HWND h = GetDlgItem(hwnd, IDC_URLCOMBO); + + ComboBox_ResetContent(h); + + for (i=0;i < MRU_MAX;i++) + { + if (!mru[i]) + { + break; + } + + ComboBox_AddString(h, mru[i]); + } + + url_to_load[0] = 0; + SetFocus(hwnd); + return TRUE; + } + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK : + { + ComboBox_GetText(GetDlgItem(hwnd, IDC_URLCOMBO), url_to_load, 4095); + if (strlen(url_to_load)) + { + AddToMRU(url_to_load); + } + EndDialog(hwnd, 1); + return TRUE; + } + + case IDCANCEL : + { + EndDialog(hwnd, 0); + return TRUE; + } + } + break; + } + + case WM_CLOSE : + { + EndDialog(hwnd, 0); + return TRUE; + } + + default: + return FALSE; + } + + return FALSE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +BOOL AddToMRU(char *url) +{ + int i, j; + + for (i=0;i < MRU_MAX;i++) + { + if (!mru[i]) + { + break; + } + else + { + if (!strcmp(mru[i], url)) + { + if (i) + { + char *tmp = mru[i]; + for (j=i;j > 0;j--) + { + mru[j] = mru[j - 1]; + } + mru[0] = tmp; + } + + return TRUE; + } + } + } + + for (i=MRU_MAX - 1;i > 0;i--) + { + mru[i] = mru[i - 1]; + } + + mru[0] = strdup(url); + + return FALSE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +BOOL UpdateStreamInfo(int songid, BOOL forceupdate) +{ + char s[256]; + static int last_songid = -1; + static unsigned int last_pos = -1; + static int last_time = -1; + BOOL update = forceupdate; + FSOUND_STREAM *stream; + + if (!song[songid].stream) + { + return FALSE; + } + + stream = song[songid].stream; + + if (songid != last_songid) + { + update = TRUE; + } + + if (update) + { + sprintf(s, "Name\t%s", FSOUND_Sample_GetName(FSOUND_Stream_GetSample(stream))); + SetWindowText(GetDlgItem(streaminfo_hwnd, IDC_STREAMINFO_NAME), s); + } + + if ((last_pos != FSOUND_Stream_GetPosition(stream)) || update) + { + sprintf(s, "Pos\t%d/%d", FSOUND_Stream_GetPosition(stream), FSOUND_Stream_GetLength(stream)); + SetWindowText(GetDlgItem(streaminfo_hwnd, IDC_STREAMINFO_POSITION), s); + } + + if ((last_time != FSOUND_Stream_GetTime(stream)) || update) + { + sprintf(s, "Pos\t%d/%d", FSOUND_Stream_GetPosition(stream), FSOUND_Stream_GetLength(stream)); + SetWindowText(GetDlgItem(streaminfo_hwnd, IDC_STREAMINFO_POSITION), s); + sprintf(s, "Time\t%02d:%02d/%02d:%02d", FSOUND_Stream_GetTime(stream) / 1000 / 60, + FSOUND_Stream_GetTime(stream) / 1000 % 60, + FSOUND_Stream_GetLengthMs(stream) / 1000 / 60, + FSOUND_Stream_GetLengthMs(stream) / 1000 % 60); + SetWindowText(GetDlgItem(streaminfo_hwnd, IDC_STREAMINFO_TIME), s); + } + + last_time = FSOUND_Stream_GetTime(stream); + last_pos = FSOUND_Stream_GetPosition(stream); + last_songid = songid; + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +BOOL UpdateCDInfo(int songid, BOOL forceupdate) +{ + char s[256]; + static int last_songid = -1; + static unsigned int last_time = -1; + BOOL update = forceupdate; + unsigned int pos, length; + + if (!song[songid].cdtrack) + { + return FALSE; + } + + if (setting_cdda && !cdda_stream) + { + return FALSE; + } + + if (songid != last_songid) + { + update = TRUE; + } + + if (update) + { + sprintf(s, "Name\tTrack %02d", song[songid].cdtrack); + SetWindowText(GetDlgItem(cdinfo_hwnd, IDC_CDINFO_NAME), s); + } + + if ((setting_cdda && (song[songid].channel != -1)) || (!setting_cdda && (FSOUND_CD_GetTrack(cddevice) == song[songid].cdtrack))) + { + pos = setting_cdda ? FSOUND_Stream_GetTime(cdda_stream) : FSOUND_CD_GetTrackTime(cddevice); + length = setting_cdda ? FSOUND_Stream_GetLengthMs(cdda_stream) : FSOUND_CD_GetTrackLength(cddevice, FSOUND_CD_GetTrack(cddevice)); + + if ((last_time != pos) || update) + { + sprintf(s, "Time\t%02d:%02d/%02d:%02d", pos / 1000 / 60, + pos / 1000 % 60, + length / 1000 / 60, + length / 1000 % 60); + SetWindowText(GetDlgItem(cdinfo_hwnd, IDC_CDINFO_TIME), s); + } + } + else + { + if (setting_cdda && (song[songid].channel == -1)) + { + sprintf(s, "Time\t%02d:%02d/%02d:%02d", 0 / 1000 / 60, + 0 / 1000 % 60, + song[songid].cdtrack_length / 1000 / 60, + song[songid].cdtrack_length / 1000 % 60); + SetWindowText(GetDlgItem(cdinfo_hwnd, IDC_CDINFO_TIME), s); + } + else + { + sprintf(s, "Time\t%02d:%02d/%02d:%02d", 0 / 1000 / 60, + 0 / 1000 % 60, + 0 / 1000 / 60, + 0 / 1000 % 60); + SetWindowText(GetDlgItem(cdinfo_hwnd, IDC_CDINFO_TIME), s); + } + } + + last_time = pos; + last_songid = songid; + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +BOOL UpdateNetStreamInfo(int songid, BOOL forceupdate, BOOL forceqiuet) +{ + static int last_songid = -1; + static int last_read_percent = -1; + signed char update = forceupdate; + int status, off, len, flags; + char str[4096]; + char *tmp; + + if (!song[songid].url) + { + return FALSE; + } + + if (song[songid].stream) + { + int ret = FSOUND_Stream_GetOpenState(song[songid].stream); + if ((ret == -3) || (ret == -1)) + { + status = FSOUND_STREAM_NET_ERROR; + if (song[songid].last_netstatus != status) + { + char *s; + + if (song[songid].server_status) + { + free(song[songid].server_status); + song[songid].server_status = 0; + } + + s = FSOUND_Stream_Net_GetLastServerStatus(); + if (s) + { + song[songid].server_status = strdup(s); + } + } + } + else + { + FSOUND_Stream_Net_GetStatus(song[songid].stream, &status, 0, 0, 0); + + if ((status == FSOUND_STREAM_NET_READY) && (song[songid].channel == -1)) + { + song[songid].channel = FSOUND_Stream_Play(FSOUND_FREE, song[songid].stream); + if (song[songid].channel != -1) + { + FSOUND_Stream_Net_SetMetadataCallback(song[songid].stream, MetadataCallback, (void *)songid); + update = TRUE; + } + } + + if (FSOUND_Stream_GetOpenState(song[songid].stream) == 0) + { + off = FSOUND_Stream_GetTime(song[songid].stream); + len = FSOUND_Stream_GetLengthMs(song[songid].stream); + + if (off >= len) + { + FSOUND_Stream_Close(song[songid].stream); + song[songid].stream = 0; + song[songid].channel = -1; + song[songid].last_status = -2; + } + } + } + } + else + { + status = FSOUND_STREAM_NET_NOTCONNECTED; + } + + if ((songid != last_songid) || (status != song[songid].last_netstatus)) + { + update = TRUE; + } + + if (song[songid].metadata) + { + song[songid].metadata = 0; + update = TRUE; + } + + last_songid = songid; + song[songid].last_netstatus = status; + + if (!forceqiuet) + { + if (update) + { + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STREAM), "Stream"); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_TRACK), "Track"); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_PROTOCOL), "Proto"); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_FORMAT), "Format"); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), "Status"); + + if (!song[songid].url) + { + return TRUE; + } + + switch (status) + { + case FSOUND_STREAM_NET_NOTCONNECTED : + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), "Status\tNot playing"); + break; + + case FSOUND_STREAM_NET_CONNECTING : + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), "Status\tConnecting..."); + break; + + case FSOUND_STREAM_NET_BUFFERING : + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), "Status\tBuffering..."); + break; + + case FSOUND_STREAM_NET_ERROR : + { + if (song[songid].server_status) + { + char tmp[1024]; + sprintf(tmp, "Status\t%s", song[songid].server_status); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), tmp); + } + else + { + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), "Status\tError"); + } + break; + } + + case FSOUND_STREAM_NET_READY : + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), "Status\tPlaying"); + break; + + default : + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STATUS), "Status\tUnknown"); + break; + } + + if (status != FSOUND_STREAM_NET_NOTCONNECTED) + { + sprintf(str, "Track\t%s%s%s", song[songid].artist ? song[songid].artist : "", song[songid].title ? " - " : "", song[songid].title ? song[songid].title : ""); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_TRACK), str); + + if (song[songid].protocol) + { + sprintf(str, "Proto\t%s", song[songid].protocol); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_PROTOCOL), str); + } + + if (song[songid].format) + { + sprintf(str, "Format\t%s", song[songid].format); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_FORMAT), str); + } + + if (song[songid].streamname) + { + sprintf(str, "Stream\t%s", song[songid].streamname); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STREAM), str); + } + } + } + + { + int read_percent; + + FSOUND_Stream_Net_GetStatus(song[songid].stream, 0, &read_percent, 0, 0); + if (read_percent != last_read_percent) + { + SendMessage(GetDlgItem(mainhwnd, IDC_PROGRESS1), PBM_SETRANGE, 0, MAKELPARAM(0, 100) ); + SendMessage(GetDlgItem(mainhwnd, IDC_PROGRESS1), PBM_SETPOS, (WPARAM)read_percent, 0); + } + } + + if (FSOUND_Stream_Net_GetStatus(song[songid].stream, 0, 0, 0, &flags)) + { + if (!song[songid].protocol) + { + char *str_protocol[3] = + { + "SHOUTcast", + "Icecast", + "HTTP" + }; + + if (flags & FSOUND_PROTOCOL_SHOUTCAST) + { + tmp = str_protocol[0]; + } + else if (flags & FSOUND_PROTOCOL_ICECAST) + { + tmp = str_protocol[1]; + } + else if (flags & FSOUND_PROTOCOL_HTTP) + { + tmp = str_protocol[2]; + } + else + { + tmp = 0; + } + + if (tmp) + { + song[songid].protocol = tmp; + sprintf(str, "Proto\t%s", tmp); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_PROTOCOL), str); + } + } + + if (!song[songid].format) + { + char *str_format[2] = + { + "MPEG Layer 3", + "Ogg Vorbis" + }; + + if (flags & FSOUND_FORMAT_MPEG) + { + tmp = str_format[0]; + } + else if (flags & FSOUND_FORMAT_OGGVORBIS) + { + tmp = str_format[1]; + } + else + { + tmp = 0; + } + + if (tmp) + { + song[songid].format = tmp; + sprintf(str, "Format\t%s", tmp); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_FORMAT), str); + } + } + + if (!song[songid].streamname) + { + if (flags & FSOUND_PROTOCOL_SHOUTCAST) + { + FSOUND_Stream_FindTagField(song[songid].stream, FSOUND_TAGFIELD_SHOUTCAST, "icy-name", &tmp, 0); + } + else if (flags & FSOUND_PROTOCOL_ICECAST) + { + FSOUND_Stream_FindTagField(song[songid].stream, FSOUND_TAGFIELD_ICECAST, "ice-name", &tmp, 0); + } + else if (flags & FSOUND_PROTOCOL_HTTP) + { + tmp = song[songid].url; + } + else + { + tmp = 0; + } + + if (tmp) + { + song[songid].streamname = tmp; + sprintf(str, "Stream\t%s", tmp); + SetWindowText(GetDlgItem(netstreaminfo_hwnd, IDC_NETSTREAMINFO_STREAM), str); + } + } + } + } + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +BOOL UpdateModInfo(int songid, BOOL forceupdate) +{ + char s[256]; + static int last_songid = -1; + static int last_speed = -1; + static int last_bpm = -1; + static int last_order = -1; + static int last_pattern = -1; + static int last_row = -1; + char *type[] = + { + "Unknown ", + "Protracker / FastTracker ", + "ScreamTracker 3 ", + "FastTracker 2 ", + "Impulse Tracker ", + "MIDI ", + "FMOD Sample Bank " + }; + FMUSIC_MODULE *mod = song[songid].mod; + BOOL update = forceupdate; + + if (!song[songid].mod) + { + return FALSE; + } + + if (songid != last_songid) + { + update = TRUE; + } + + if (update) + { + sprintf(s, "Name\t%s", FMUSIC_GetName(mod)); + SetWindowText(GetDlgItem(modinfo_hwnd, IDC_MODINFO_NAME), s); + + sprintf(s, "Type\t%s", type[FMUSIC_GetType(mod)]); + SetWindowText(GetDlgItem(modinfo_hwnd, IDC_MODINFO_TYPE), s); + } + + if ((last_speed != FMUSIC_GetSpeed(mod)) || update) + { + sprintf(s, "Speed\t%02d", FMUSIC_GetSpeed(mod)); + SetWindowText(GetDlgItem(modinfo_hwnd, IDC_MODINFO_SPEED), s); + } + + if ((last_bpm != FMUSIC_GetBPM(mod)) || update) + { + sprintf(s, "BPM\t%03d", FMUSIC_GetBPM(mod)); + SetWindowText(GetDlgItem(modinfo_hwnd, IDC_MODINFO_BPM), s); + } + + if ((last_order != FMUSIC_GetOrder(mod)) || update) + { + sprintf(s, "Order\t%03d / %03d", FMUSIC_GetOrder(mod), FMUSIC_GetNumOrders(mod)); + SetWindowText(GetDlgItem(modinfo_hwnd, IDC_MODINFO_ORDER), s); + } + + if ((last_pattern != FMUSIC_GetPattern(mod)) || update) + { + sprintf(s, "Pattern\t%03d / %03d", FMUSIC_GetPattern(mod), FMUSIC_GetNumPatterns(mod)); + SetWindowText(GetDlgItem(modinfo_hwnd, IDC_MODINFO_PATTERN), s); + } + + if ((last_row != FMUSIC_GetRow(mod)) || (last_order != FMUSIC_GetOrder(mod)) || update) + { + sprintf(s, "Row\t%03d / %03d", FMUSIC_GetRow(mod), FMUSIC_GetPatternLength(mod, FMUSIC_GetOrder(mod))); + SetWindowText(GetDlgItem(modinfo_hwnd, IDC_MODINFO_ROW), s); + } + + last_speed = FMUSIC_GetSpeed(mod); + last_bpm = FMUSIC_GetBPM(mod); + last_order = FMUSIC_GetOrder(mod); + last_pattern = FMUSIC_GetPattern(mod); + last_row = FMUSIC_GetRow(mod); + last_songid = songid; + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void SelectInfoWindow() +{ + int songid; + int songtype = SONGTYPE_NONE; + + ShowWindow(modinfo_hwnd, SW_HIDE); + ShowWindow(streaminfo_hwnd, SW_HIDE); + ShowWindow(netstreaminfo_hwnd, SW_HIDE); + ShowWindow(cdinfo_hwnd, SW_HIDE); + + if (GraphicWindowCurrent == GRAPHICWINDOW_MODINFO) + { + songid = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + if (songid != LB_ERR) + { + songtype = song[songid].mod ? SONGTYPE_MOD : song[songid].url ? SONGTYPE_NETSTREAM : song[songid].stream ? SONGTYPE_STREAM : song[songid].cdtrack ? SONGTYPE_CD : SONGTYPE_NONE; + } + + switch (songtype) + { + case SONGTYPE_MOD : + SendMessage(GetDlgItem(mainhwnd, IDC_STATIC_INFO), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Module Info"); + ShowWindow(modinfo_hwnd, SW_SHOW); + break; + + case SONGTYPE_STREAM : + SendMessage(GetDlgItem(mainhwnd, IDC_STATIC_INFO), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Stream Info"); + ShowWindow(streaminfo_hwnd, SW_SHOW); + break; + + case SONGTYPE_NETSTREAM : + SendMessage(GetDlgItem(mainhwnd, IDC_STATIC_INFO), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"Net Stream Info"); + ShowWindow(netstreaminfo_hwnd, SW_SHOW); + break; + + case SONGTYPE_CD : + SendMessage(GetDlgItem(mainhwnd, IDC_STATIC_INFO), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"CD Track Info"); + ShowWindow(cdinfo_hwnd, SW_SHOW); + break; + + case SONGTYPE_NONE : + SendMessage(GetDlgItem(mainhwnd, IDC_STATIC_INFO), WM_SETTEXT, 0, (LPARAM)(LPCTSTR)"No file loaded"); + break; + } + } +} + + +/* +[API] +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +char SetupInterface(HINSTANCE hinst, LPSTR lpCmdLine) +{ + char name[2048]; + RECT r; + int desktop_height,desktop_width; + int window_height,window_width; + int i; + + for (i=0;i < MRU_MAX;i++) + { + mru[i] = 0; + } + + LoadSettings(); + + GetWindowRect(GetDesktopWindow(), &r); + desktop_width = r.right - r.left; + desktop_height = r.bottom - r.top; + + /* + Fix up screwed up xy positions + */ + if (setting_xpos > desktop_width || setting_xpos < 0) + { + setting_xpos = (desktop_width / 2)-320; + } + if (setting_ypos > desktop_height || setting_ypos < 0) + { + setting_ypos = (desktop_height / 2)-140; + } + + mainhwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_INTERFACE), GetDesktopWindow(), FMOD_DlgProc); + + ShowWindow(mainhwnd, SW_HIDE); + + sprintf(name, "FMOD %.2f", FMOD_VERSION); + SetWindowText(mainhwnd, name); + + + /* + Set the icon + */ +#ifdef _WIN64 + SetClassLong(mainhwnd, GCLP_HICON, (LONG) LoadIcon(hinst, MAKEINTRESOURCE(IDI_ICON1))); +#else + SetClassLong(mainhwnd, GCL_HICON, (LONG) LoadIcon(hinst, MAKEINTRESOURCE(IDI_ICON1))); +#endif + + GetWindowRect(mainhwnd, &r); + MoveWindow(mainhwnd, setting_xpos, setting_ypos, r.right, r.bottom, TRUE); + + window_width = r.right - r.left; + window_height = r.bottom - r.top; + scalex = (float)window_width / WINDOW_WIDTH; + scaley = (float)window_height / WINDOW_HEIGHT; + + ShowWindow(mainhwnd, SW_SHOW); + + InitCommonControls(); + + /* + Set the range of the master volume slider + */ + SendMessage(GetDlgItem(mainhwnd,IDC_SLIDER1), TBM_SETRANGE, TRUE, MAKELPARAM(0, 256)); + + /* + Set position of the master volume slider + */ + SendMessage(GetDlgItem(mainhwnd,IDC_SLIDER1), TBM_SETPOS, TRUE, 256); + + /* + set the range of the echo slider + set position of the echo slider + set status + */ + SendMessage(GetDlgItem(mainhwnd,IDC_ECHOSLIDER), TBM_SETRANGE, TRUE, MAKELPARAM(20, 500)); + SendMessage(GetDlgItem(mainhwnd,IDC_ECHOSLIDER), TBM_SETPOS, TRUE, 500); + ShowWindow(GetDlgItem(mainhwnd,IDC_ECHOSLIDER), SW_HIDE); + + /* + set the range of the cutoff freq slider + set position of the cutoff freq slider + set status + */ + SendMessage(GetDlgItem(mainhwnd,IDC_CUTOFFSLIDER), TBM_SETRANGE, TRUE, MAKELPARAM(20, 500)); + SendMessage(GetDlgItem(mainhwnd,IDC_CUTOFFSLIDER), TBM_SETPOS, TRUE, 20); + ShowWindow(GetDlgItem(mainhwnd,IDC_CUTOFFSLIDER), SW_HIDE); + + /* + set the range of the resonance slider + set position of the resonance slider + set status + */ + SendMessage(GetDlgItem(mainhwnd,IDC_RESOSLIDER), TBM_SETRANGE, TRUE, MAKELPARAM(20, 500)); + SendMessage(GetDlgItem(mainhwnd,IDC_RESOSLIDER), TBM_SETPOS, TRUE, 500); + ShowWindow(GetDlgItem(mainhwnd,IDC_RESOSLIDER), SW_HIDE); + + /* + COMMAND LINE + */ + if (strlen(lpCmdLine)) + { + Playlist *p; + int i; + char *filename = name; + + strcpy(filename, lpCmdLine); + + if (*filename == '"') + { + filename++; + } + + if (filename[strlen(filename) - 1] == '"') + { + filename[strlen(filename) - 1] = 0; + } + + /* + Open the file. + */ + p = ParsePlaylist(filename); + if (p) + { + for (i=0;i < p->count;i++) + { + AddFileToSongList(p->name[i], p->displayname[i]); + } + + FreePlaylist(p); + } + else + { + AddFileToSongList(filename, filename); + } + } + + srand(clock()); + Button_SetCheck(GetDlgItem(mainhwnd,IDC_RADIOCONTINUOUS), TRUE); + + /* + Subclass the position slider so we can get the mouse messages and process them there + */ +#ifdef _WIN64 + oldprogressproc = (WNDPROC)GetWindowLong(GetDlgItem(mainhwnd, IDC_PROGRESS1), GWLP_WNDPROC); + oldcdtimeproc = (WNDPROC)GetWindowLong(GetDlgItem(mainhwnd, IDC_CDTIME), GWLP_WNDPROC); + + SetWindowLong(GetDlgItem(mainhwnd, IDC_PROGRESS1), GWLP_WNDPROC, (LONG)&ProgressWindowProc); + SetWindowLong(GetDlgItem(mainhwnd, IDC_CDTIME), GWLP_WNDPROC, (LONG)&CDTimeWindowProc); +#else + oldprogressproc = (WNDPROC)GetWindowLong(GetDlgItem(mainhwnd, IDC_PROGRESS1), GWL_WNDPROC); + oldcdtimeproc = (WNDPROC)GetWindowLong(GetDlgItem(mainhwnd, IDC_CDTIME), GWL_WNDPROC); + + SetWindowLong(GetDlgItem(mainhwnd, IDC_PROGRESS1), GWL_WNDPROC, (LONG)&ProgressWindowProc); + SetWindowLong(GetDlgItem(mainhwnd, IDC_CDTIME), GWL_WNDPROC, (LONG)&CDTimeWindowProc); +#endif + + SetWindowText(GetDlgItem(mainhwnd, IDC_STATIC_INFO), "No file loaded"); + SetWindowText(GetDlgItem(mainhwnd, IDC_INFOWINDOW), ""); + + streaminfo_hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_STREAMINFODLG), GetDlgItem(mainhwnd, IDC_INFOWINDOW), FMOD_InfoDlgProc); + ShowWindow(streaminfo_hwnd, SW_HIDE); + + netstreaminfo_hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_NETSTREAMINFODLG), GetDlgItem(mainhwnd, IDC_INFOWINDOW), FMOD_InfoDlgProc); + ShowWindow(netstreaminfo_hwnd, SW_HIDE); + + cdinfo_hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_CDINFODLG), GetDlgItem(mainhwnd, IDC_INFOWINDOW), FMOD_InfoDlgProc); + ShowWindow(cdinfo_hwnd, SW_HIDE); + + modinfo_hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_MODINFODLG), GetDlgItem(mainhwnd, IDC_INFOWINDOW), FMOD_InfoDlgProc); + ShowWindow(modinfo_hwnd, SW_HIDE); + + url_to_load[0] = 0; + + if (strlen(lpCmdLine)) + { + int songid = (int)SendMessage(songlist_hwnd, LB_GETCURSEL, 0, 0); + UpdateStreamInfo(songid, TRUE); + UpdateNetStreamInfo(songid, TRUE, FALSE); + UpdateModInfo(songid, TRUE); + UpdateCDInfo(songid, TRUE); + SelectInfoWindow(); + } + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void CloseDown() +{ + int count, i; + RECT r; + int desktop_height, desktop_width; + + GetWindowRect(mainhwnd, &r); + setting_xpos = r.left; + setting_ypos = r.top; + + GetWindowRect(GetDesktopWindow(), &r); + desktop_width = r.right - r.left; + desktop_height = r.bottom - r.top; + if (setting_xpos > desktop_width || setting_xpos < 0) + { + setting_xpos = (desktop_width / 2)-320; + } + if (setting_ypos > desktop_height || setting_ypos < 0) + { + setting_ypos = (desktop_height / 2)-140; + } + + SaveSettings(); + + for (i=0;i < MRU_MAX;i++) + { + if (mru[i]) + { + free(mru[i]); + mru[i] = 0; + } + } + + for (count=0; count +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=fmodsample - Win32 Debug64 +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "fmodsample.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "fmodsample.mak" CFG="fmodsample - Win32 Debug64" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "fmodsample - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "fmodsample - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "fmodsample - Win32 Debug64" (based on "Win32 (x86) Application") +!MESSAGE "fmodsample - Win32 Release64" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "fmodsample - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 comctl32.lib shell32.lib gdi32.lib user32.lib comdlg32.lib winmm.lib advapi32.lib ..\..\api\lib\fmodvc.lib /nologo /subsystem:windows /machine:I386 /out:"fmod.exe" + +!ELSEIF "$(CFG)" == "fmodsample - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 comctl32.lib shell32.lib gdi32.lib user32.lib comdlg32.lib winmm.lib advapi32.lib ..\..\api\lib\fmodvc.lib /nologo /subsystem:windows /debug /machine:I386 /out:"fmod.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "fmodsample - Win32 Debug64" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "fmodsample___Win32_Debug64" +# PROP BASE Intermediate_Dir "fmodsample___Win32_Debug64" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug64" +# PROP Intermediate_Dir "Debug64" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_WIN64" /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 comctl32.lib shell32.lib gdi32.lib user32.lib comdlg32.lib winmm.lib advapi32.lib ..\..\api\lib\fmodvc.lib /nologo /subsystem:windows /debug /machine:I386 /out:"fmod.exe" /pdbtype:sept +# ADD LINK32 comctl32.lib shell32.lib gdi32.lib user32.lib comdlg32.lib winmm.lib advapi32.lib ..\..\api\lib\fmod64vc.lib /nologo /subsystem:windows /incremental:no /debug /machine:IX86 /out:"fmod64.exe" /machine:AMD64 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "fmodsample - Win32 Release64" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "fmodsample___Win32_Release64" +# PROP BASE Intermediate_Dir "fmodsample___Win32_Release64" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release64" +# PROP Intermediate_Dir "Release64" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_WIN64" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 comctl32.lib shell32.lib gdi32.lib user32.lib comdlg32.lib winmm.lib advapi32.lib ..\..\api\lib\fmodvc.lib /nologo /subsystem:windows /machine:I386 /out:"fmod.exe" +# ADD LINK32 comctl32.lib shell32.lib gdi32.lib user32.lib comdlg32.lib winmm.lib advapi32.lib ..\..\api\lib\fmod64vc.lib /nologo /subsystem:windows /machine:IX86 /out:"fmod64.exe" /machine:AMD64 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "fmodsample - Win32 Release" +# Name "fmodsample - Win32 Debug" +# Name "fmodsample - Win32 Debug64" +# Name "fmodsample - Win32 Release64" +# Begin Source File + +SOURCE=.\fmod.ico +# End Source File +# Begin Source File + +SOURCE=.\fmod.rc +# End Source File +# Begin Source File + +SOURCE=.\lowpass.c +# End Source File +# Begin Source File + +SOURCE=.\lowpass.h +# End Source File +# Begin Source File + +SOURCE=.\Main.c +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\reverb.c +# End Source File +# Begin Source File + +SOURCE=.\reverb.h +# End Source File +# Begin Source File + +SOURCE=.\sdriver.c +# End Source File +# Begin Source File + +SOURCE=.\sdriver.h +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/fmod/lowpass.c b/fmodapi375win/samples/fmod/lowpass.c new file mode 100644 index 0000000..6659e16 --- /dev/null +++ b/fmodapi375win/samples/fmod/lowpass.c @@ -0,0 +1,371 @@ +/* +Resonant low pass filter source code. +By baltrax@hotmail.com (Zxform) + +- little changes and optimizations by Brett Paterson for FMOD example. + +*/ + +#include +#include +#include + +#include "lowpass.h" + +/************************************************************************** + +FILTER.C - Source code for filter functions + + iir_filter IIR filter floats sample by sample (real time) + +*************************************************************************/ + +FILTER iir; + +/* + * -------------------------------------------------------------------- + * + * iir_filter - Perform IIR filtering sample by sample on floats + * + * Implements cascaded direct form II second order sections. + * Requires FILTER structure for history and coefficients. + * The length in the filter structure specifies the number of sections. + * The size of the history array is 2*iir.length. + * The size of the coefficient array is 4*iir.length + 1 because + * the first coefficient is the overall scale factor for the filter. + * Returns one output sample for each input sample. Allocates history + * array if not previously allocated. + * + * float iir_filter(float input,FILTER *iir) + * + * float input new float input sample + * FILTER *iir pointer to FILTER structure + * + * Returns float value giving the current output. + * + * Allocation errors cause an error message and a call to exit. + * -------------------------------------------------------------------- + */ +float LowPass_Filter(float input) +{ + unsigned int i; + float *hist1_ptr,*hist2_ptr,*coef_ptr; + float output,new_hist,history1,history2; + static float dc = (float)1E-25; + input += dc; + dc = -dc; + + /* allocate history array if different size than last call */ + + coef_ptr = iir.coef; /* coefficient pointer */ + + hist1_ptr = iir.history; /* first history */ + hist2_ptr = hist1_ptr + 1; /* next history */ + + /* 1st number of coefficients array is overall input scale factor, + * or filter gain */ + output = input * (*coef_ptr++); + + for (i = 0 ; i < iir.length; i++) + { + history1 = *hist1_ptr; /* history values */ + history2 = *hist2_ptr; + + output = output - history1 * coef_ptr[0]; + new_hist = output - history2 * coef_ptr[1]; /* poles */ + + output = new_hist + history1 * coef_ptr[2]; + output = output + history2 * coef_ptr[3]; /* zeros */ + + coef_ptr += 4; + *hist2_ptr++ = *hist1_ptr; + *hist1_ptr++ = new_hist; + hist1_ptr++; + hist2_ptr++; + } + + return(output); +} + + +void LowPass_Update(float resonance, float cutoff, int samplerate) +{ + unsigned nInd; + double a0, a1, a2, b0, b1, b2; + double fs; /* Sampling frequency, cutoff frequency */ + double k; /* overall gain factor */ + float *coef; + + k = 1.0; /* Set overall filter gain */ + coef = iir.coef + 1; /* Skip k, or gain */ + fs = (double)samplerate; /* Sampling frequency (Hz) */ + +/* + * Compute z-domain coefficients for each biquad section + * for new Cutoff Frequency and Resonance + */ + for (nInd = 0; nInd < iir.length; nInd++) + { + a0 = ProtoCoef[nInd].a0; + a1 = ProtoCoef[nInd].a1; + a2 = ProtoCoef[nInd].a2; + + b0 = ProtoCoef[nInd].b0; + b1 = ProtoCoef[nInd].b1 / resonance; /* Divide by resonance or Q */ + b2 = ProtoCoef[nInd].b2; + szxform(&a0, &a1, &a2, &b0, &b1, &b2, cutoff, fs, &k, coef); + coef += 4; /* Point to next filter section */ + } + + /* Update overall filter gain in coef array */ + iir.coef[0] = (float)k; +} + + +/* + * -------------------------------------------------------------------- + * + * initn() + * + * Example main function to show how to update filter coefficients. + * We create a 4th order filter (24 db/oct roloff), consisting + * of two second order sections. + * -------------------------------------------------------------------- + */ +signed char LowPass_Init() +{ + +/* + * Setup filter s-domain coefficients + */ + /* Section 1 */ + ProtoCoef[0].a0 = 1.0; + ProtoCoef[0].a1 = 0; + ProtoCoef[0].a2 = 0; + ProtoCoef[0].b0 = 1.0; + ProtoCoef[0].b1 = 0.765367; + ProtoCoef[0].b2 = 1.0; + + /* Section 2 */ + ProtoCoef[1].a0 = 1.0; + ProtoCoef[1].a1 = 0; + ProtoCoef[1].a2 = 0; + ProtoCoef[1].b0 = 1.0; + ProtoCoef[1].b1 = 1.847759; + ProtoCoef[1].b2 = 1.0; + + iir.length = FILTER_SECTIONS; /* Number of filter sections */ + +/* + * Allocate array of z-domain coefficients for each filter section + * plus filter gain variable + */ + iir.coef = (float *) calloc(4 * iir.length + 1, sizeof(float)); + if (!iir.coef) + { +// printf("Unable to allocate coef array, exiting\n"); + return 0; + } + + LowPass_Update(1.0, 5000.0, 44100); + + /* Display filter coefficients */ +// for (nInd = 0; nInd < (iir.length * 4 + 1); nInd++) +// printf("C[%d] = %15.10f\n", nInd, iir.coef[nInd]); +/* + * To process audio samples, call function iir_filter() + * for each audio sample + */ + return 1; +} + +void LowPass_Close() +{ +} + + +/* + * ---------------------------------------------------------- + * bilinear.c + * + * Perform bilinear transformation on s-domain coefficients + * of 2nd order biquad section. + * First design an analog filter and use s-domain coefficients + * as input to szxform() to convert them to z-domain. + * + * Here's the butterworth polinomials for 2nd, 4th and 6th order sections. + * When we construct a 24 db/oct filter, we take to 2nd order + * sections and compute the coefficients separately for each section. + * + * n Polinomials + * -------------------------------------------------------------------- + * 2 s^2 + 1.4142s +1 + * 4 (s^2 + 0.765367s + 1) (s^2 + 1.847759s + 1) + * 6 (s^2 + 0.5176387s + 1) (s^2 + 1.414214 + 1) (s^2 + 1.931852s + 1) + * + * Where n is a filter order. + * For n=4, or two second order sections, we have following equasions for each + * 2nd order stage: + * + * (1 / (s^2 + (1/Q) * 0.765367s + 1)) * (1 / (s^2 + (1/Q) * 1.847759s + 1)) + * + * Where Q is filter quality factor in the range of + * 1 to 1000. The overall filter Q is a product of all + * 2nd order stages. For example, the 6th order filter + * (3 stages, or biquads) with individual Q of 2 will + * have filter Q = 2 * 2 * 2 = 8. + * + * The nominator part is just 1. + * The denominator coefficients for stage 1 of filter are: + * b2 = 1; b1 = 0.765367; b0 = 1; + * numerator is + * a2 = 0; a1 = 0; a0 = 1; + * + * The denominator coefficients for stage 1 of filter are: + * b2 = 1; b1 = 1.847759; b0 = 1; + * numerator is + * a2 = 0; a1 = 0; a0 = 1; + * + * These coefficients are used directly by the szxform() + * and bilinear() functions. For all stages the numerator + * is the same and the only thing that is different between + * different stages is 1st order coefficient. The rest of + * coefficients are the same for any stage and equal to 1. + * + * Any filter could be constructed using this approach. + * + * References: + * Van Valkenburg, "Analog Filter Design" + * Oxford University Press 1982 + * ISBN 0-19-510734-9 + * + * C Language Algorithms for Digital Signal Processing + * Paul Embree, Bruce Kimble + * Prentice Hall, 1991 + * ISBN 0-13-133406-9 + * + * Digital Filter Designer's Handbook + * With C++ Algorithms + * Britton Rorabaugh + * McGraw Hill, 1997 + * ISBN 0-07-053806-9 + * ---------------------------------------------------------- + */ + +void prewarp(double *a0, double *a1, double *a2, double fc, double fs); +void bilinear( + double a0, double a1, double a2, /* numerator coefficients */ + double b0, double b1, double b2, /* denominator coefficients */ + double *k, /* overall gain factor */ + double fs, /* sampling rate */ + float *coef); /* pointer to 4 iir coefficients */ + + +/* + * ---------------------------------------------------------- + * Pre-warp the coefficients of a numerator or denominator. + * Note that a0 is assumed to be 1, so there is no wrapping + * of it. + * ---------------------------------------------------------- + */ +void prewarp( + double *a0, double *a1, double *a2, + double fc, double fs) +{ + double wp, pi; + + pi = 4.0 * atan(1.0); + wp = 2.0 * fs * tan(pi * fc / fs); + + *a2 = (*a2) / (wp * wp); + *a1 = (*a1) / wp; +} + + +/* + * ---------------------------------------------------------- + * bilinear() + * + * Transform the numerator and denominator coefficients + * of s-domain biquad section into corresponding + * z-domain coefficients. + * + * Store the 4 IIR coefficients in array pointed by coef + * in following order: + * beta1, beta2 (denominator) + * alpha1, alpha2 (numerator) + * + * Arguments: + * a0-a2 - s-domain numerator coefficients + * b0-b2 - s-domain denominator coefficients + * k - filter gain factor. initially set to 1 + * and modified by each biquad section in such + * a way, as to make it the coefficient by + * which to multiply the overall filter gain + * in order to achieve a desired overall filter gain, + * specified in initial value of k. + * fs - sampling rate (Hz) + * coef - array of z-domain coefficients to be filled in. + * + * Return: + * On return, set coef z-domain coefficients + * ---------------------------------------------------------- + */ +void bilinear( + double a0, double a1, double a2, /* numerator coefficients */ + double b0, double b1, double b2, /* denominator coefficients */ + double *k, /* overall gain factor */ + double fs, /* sampling rate */ + float *coef /* pointer to 4 iir coefficients */ +) +{ + double ad, bd; + + /* alpha (Numerator in s-domain) */ + ad = 4. * a2 * fs * fs + 2. * a1 * fs + a0; + /* beta (Denominator in s-domain) */ + bd = 4. * b2 * fs * fs + 2. * b1* fs + b0; + + /* update gain constant for this section */ + *k *= ad/bd; + + /* Denominator */ + *coef++ = (float)((2. * b0 - 8. * b2 * fs * fs) / bd); /* beta1 */ + *coef++ = (float)((4. * b2 * fs * fs - 2. * b1 * fs + b0) / bd); /* beta2 */ + + /* Nominator */ + *coef++ = (float)((2. * a0 - 8. * a2 * fs * fs) / ad); /* alpha1 */ + *coef = (float)((4. * a2 * fs * fs - 2. * a1 * fs + a0) / ad); /* alpha2 */ +} + + +/* + * ---------------------------------------------------------- + * Transform from s to z domain using bilinear transform + * with prewarp. + * + * Arguments: + * For argument description look at bilinear() + * + * coef - pointer to array of floating point coefficients, + * corresponding to output of bilinear transofrm + * (z domain). + * + * Note: frequencies are in Hz. + * ---------------------------------------------------------- + */ +void szxform( + double *a0, double *a1, double *a2, /* numerator coefficients */ + double *b0, double *b1, double *b2, /* denominator coefficients */ + double fc, /* Filter cutoff frequency */ + double fs, /* sampling rate */ + double *k, /* overall gain factor */ + float *coef) /* pointer to 4 iir coefficients */ +{ + /* Calculate a1 and a2 and overwrite the original values */ + prewarp(a0, a1, a2, fc, fs); + prewarp(b0, b1, b2, fc, fs); + bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, fs, coef); +} + + diff --git a/fmodapi375win/samples/fmod/lowpass.h b/fmodapi375win/samples/fmod/lowpass.h new file mode 100644 index 0000000..31a33a4 --- /dev/null +++ b/fmodapi375win/samples/fmod/lowpass.h @@ -0,0 +1,46 @@ +#ifndef _LOWPASS_H +#define _LOWPASS_H + + +/* FILTER INFORMATION STRUCTURE FOR FILTER ROUTINES */ + +#define FILTER_SECTIONS 2 /* 2 filter sections for 24 db/oct filter */ + +typedef struct { + unsigned int length; /* size of filter */ + float history[2 * FILTER_SECTIONS]; /* history in filter */ + float *coef; /* pointer to coefficients of filter */ +} FILTER; + +typedef struct { + double a0, a1, a2; /* numerator coefficients */ + double b0, b1, b2; /* denominator coefficients */ +} BIQUAD; + +BIQUAD ProtoCoef[FILTER_SECTIONS]; /* Filter prototype coefficients, + 1 for each filter section */ + +void szxform( + double *a0, double *a1, double *a2, /* numerator coefficients */ + double *b0, double *b1, double *b2, /* denominator coefficients */ + double fc, /* Filter cutoff frequency */ + double fs, /* sampling rate */ + double *k, /* overall gain factor */ + float *coef); /* pointer to 4 iir coefficients */ + + + +#ifdef __cplusplus + extern "C" { +#endif + + signed char LowPass_Init(); + void LowPass_Close(); + float LowPass_Filter(float input); + void LowPass_Update(float resonance, float cutoff, int samplerate); + +#ifdef __cplusplus + } +#endif + +#endif \ No newline at end of file diff --git a/fmodapi375win/samples/fmod/resource.h b/fmodapi375win/samples/fmod/resource.h new file mode 100644 index 0000000..679c62f --- /dev/null +++ b/fmodapi375win/samples/fmod/resource.h @@ -0,0 +1,168 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by fmod.rc +// +#define IDS_APPNAME 1 +#define IDS_NOVIDEODRIVERFOUND 2 +#define IDD_DIALOG1 102 +#define IDR_MENU1 103 +#define IDD_INTERFACE 104 +#define IDI_ICON1 105 +#define IDD_DSENUMBOX 109 +#define IDD_CDINTERFACE 111 +#define IDR_MODULE1 113 +#define IDD_STREAMINFODLG 117 +#define IDD_LOADURLDLG 118 +#define IDD_STREAMDETAILSDLG 120 +#define IDD_MODINFODLG 121 +#define IDD_NETSTREAMINFODLG 122 +#define IDD_ABOUTDLG 123 +#define IDD_CDINFODLG 123 +#define IDB_BITMAP1 125 +#define IDD_DIALOGWAIT 127 +#define IDC_RADIO1 1000 +#define IDC_DRIVERNAME 1001 +#define IDC_RADIO2 1001 +#define IDC_FULLSCREEN 1002 +#define IDC_RADIO3 1002 +#define IDC_ZBUFFER 1003 +#define IDC_RADIO4 1003 +#define IDC_PERSCORRECT 1004 +#define IDC_VIDEOMODE 1005 +#define IDC_RADIO5 1005 +#define IDC_TRIPLEBUFFER 1006 +#define IDC_SONGLIST 1006 +#define IDC_BILINEARFILTER 1007 +#define IDC_BUTTON1 1007 +#define IDC_LOAD 1007 +#define IDC_CONFIG_CDINFO 1007 +#define IDC_ZBUFFER2 1008 +#define IDC_BUTTON2 1008 +#define IDC_DELETE 1008 +#define IDC_DEVICES 1009 +#define IDC_LOADURL 1009 +#define IDC_DSENUM_COMBO 1010 +#define IDC_PROGRESS1 1010 +#define IDC_DSENUM_COMBO2 1011 +#define IDC_BUTTON3 1011 +#define IDC_PLAY 1011 +#define IDC_BUTTON4 1012 +#define IDC_DSENUM_COMBO3 1012 +#define IDC_STOP 1012 +#define IDC_CHECK1 1013 +#define IDC_PLAYLIST 1013 +#define IDC_CONFIG_CDDA 1013 +#define IDC_CHECK2 1014 +#define IDC_ECHO 1014 +#define IDC_CONFIG_JITTER 1014 +#define IDC_CHECK3 1015 +#define IDC_LOWPASS 1015 +#define IDC_CONFIG_FORCEASPI 1015 +#define IDC_CHECK4 1016 +#define IDC_FLANGE 1016 +#define IDC_CDLOOPCHECK 1016 +#define IDC_EQUALIZER 1016 +#define IDC_SPECTRUM 1016 +#define IDC_CHECK5 1017 +#define IDC_PLAYLOOPED 1017 +#define IDC_CHECK6 1018 +#define IDC_RESONANCE 1018 +#define IDC_LOADCD 1018 +#define IDC_BUTTON5 1019 +#define IDC_DEBUG 1019 +#define IDC_CDPLAY 1019 +#define IDC_BUTTON6 1020 +#define IDC_EXIT 1020 +#define IDC_BUTTON7 1021 +#define IDC_ABOUT 1021 +#define IDC_BUTTON8 1022 +#define IDC_ORDER_DEC 1022 +#define IDC_BUTTON9 1023 +#define IDC_ORDER_INC 1023 +#define IDC_LAG 1023 +#define IDC_BUTTON10 1024 +#define IDC_CDSTOP 1024 +#define IDC_BUTTON11 1025 +#define IDC_CDPAUSE 1025 +#define IDC_CHECK7 1026 +#define IDC_BASSBOOST 1026 +#define IDC_NR 1026 +#define IDC_REVERB 1026 +#define IDC_CHECK8 1027 +#define IDC_PREVERB 1027 +#define IDC_CHECK9 1028 +#define IDC_CDBACK 1028 +#define IDC_CONFIG 1029 +#define IDC_SLIDER1 1030 +#define IDC_CDFORWARD 1032 +#define IDC_CDEJECT 1033 +#define IDC_RADIOCONTINUOUS 1039 +#define IDC_RADIORANDOM 1040 +#define IDC_RADIOLOOPED 1042 +#define IDC_CDMAXIMIZE 1043 +#define IDC_CDMINIMIZE 1044 +#define IDC_SLIDER2 1045 +#define IDC_ECHOSLIDER 1045 +#define IDC_CUTOFFSLIDER 1046 +#define IDC_CDVOLUME 1047 +#define IDC_RESOSLIDER 1048 +#define IDC_STATIC_NAME 1049 +#define IDC_STATIC_TYPE 1050 +#define IDC_STATIC_SPEED 1051 +#define IDC_STATIC_BPM 1052 +#define IDC_STATIC_ORDER 1053 +#define IDC_STATIC_PATTERN 1054 +#define IDC_STATIC_ROW 1055 +#define IDC_STATIC_INFO 1056 +#define IDC_CDTIME 1058 +#define IDC_INFOWINDOW 1062 +#define IDC_URLCOMBO 1063 +#define IDC_STREAMINFO_NAME 1065 +#define IDC_STREAMINFO_POSITION 1066 +#define IDC_STREAMINFO_TIME 1067 +#define IDC_STREAMDETAILSEDIT 1069 +#define IDC_MODINFO_NAME 1070 +#define IDC_MODINFO_TYPE 1071 +#define IDC_MODINFO_SPEED 1072 +#define IDC_MODINFO_BPM 1073 +#define IDC_MODINFO_ORDER 1074 +#define IDC_MODINFO_PATTERN 1075 +#define IDC_NETSTREAMINFO_STREAM 1075 +#define IDC_MODINFO_ROW 1076 +#define IDC_NETSTREAMINFO_TRACK 1076 +#define IDC_NETSTREAMINFO_PROTOCOL 1077 +#define IDC_NETSTREAMINFO_FORMAT 1078 +#define IDC_NETSTREAMINFO_STATUS 1079 +#define IDC_NETSTREAMINFO_DETAILS 1080 +#define IDC_ABOUT_OUTPUT 1081 +#define IDC_ABOUT_MIXER 1082 +#define IDC_ABOUT_DRIVER 1083 +#define IDC_ABOUT_CHANNELS 1084 +#define IDC_CONFIG_BUFFERSIZE 1085 +#define IDC_CONFIG_INITIALPERCENT 1086 +#define IDC_CONFIG_REBUFFERPERCENT 1087 +#define IDC_CONFIG_PROXY 1088 +#define IDC_CONFIG_CD 1089 +#define IDC_CDINFO_NAME 1092 +#define IDC_CDINFO_TIME 1094 +#define IDC_CDINFO_JITTER 1095 +#define MENU_ABOUT 40001 +#define MENU_OPEN 40002 +#define MENU_EXIT 40003 +#define MENU_PLAYSOUND 40004 +#define MENU_STOPSOUND 40005 +#define MENU_ADDCHANNELS 40006 +#define MENU_REMOVECHANNELS 40007 +#define MENU_INFO 40009 +#define MENU_STEPTHROUGH 40011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 128 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1096 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/fmodapi375win/samples/fmod/reverb.c b/fmodapi375win/samples/fmod/reverb.c new file mode 100644 index 0000000..70766b6 --- /dev/null +++ b/fmodapi375win/samples/fmod/reverb.c @@ -0,0 +1,419 @@ +#include "reverb.h" + +#include +#include + +/* + Pre-verb stuff +*/ +REVERBTAP PreverbTap[PREVERB_NUMTAPS]; + +/* + Reverb stuff +*/ +REVERBTAP ReverbTap[REVERB_NUMTAPS]; + +extern int outputfreq; + +/* +[ + [DESCRIPTION] + Callback to mix in one reverb tap. It copies the buffer into its own history buffer also. + + [PARAMETERS] + 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down + through the dsp chain. They are in newbuffer. + 'newbuffer' Pointer to buffer passed from previous DSP unit. + 'length' Length in SAMPLES of buffer being passed. + 'param' User parameter. In this case it is a pointer to LowPassBuffer. + + [RETURN_VALUE] + a pointer to the buffer that was passed in, with a tap mixed into it. + + [REMARKS] +] +*/ +void * F_CALLBACKAPI ReverbCallback(void *originalbuffer, void *newbuffer, int length, void *userdata) +{ + int mixertype = FSOUND_GetMixer(); + int count; + int bytesperoutputsample; + REVERBTAP *tap = (REVERBTAP *)userdata; + union sample + { + void *vptr; + signed int *dptr; + signed short *wptr; + float *fptr; + }; + + if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + bytesperoutputsample = 4; // 16bit stereo + } + else + { + bytesperoutputsample = 8; // 32bit stereo + } + + // reverb history buffer is a ringbuffer. If the length makes the copy wrap, then split the copy + // into end part, and start part.. + if (tap->historyoffset + length > tap->historylen) + { + int taillen = tap->historylen - tap->historyoffset; + int startlen = length - taillen; + + // mix a scaled version of history buffer into output + FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), taillen, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + FSOUND_DSP_MixBuffers((char *)newbuffer+(taillen * bytesperoutputsample), tap->historybuff, startlen, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + + // now copy input into reverb/history buffer + { + signed short *dest; + union sample src; + + dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); + src.vptr = newbuffer; + + for (count=0; count < taillen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + { + signed short *dest; + union sample src; + + dest = (signed short *)tap->historybuff; // always 16bit + src.vptr = (char *)newbuffer + (taillen * bytesperoutputsample); + + for (count=0; count < startlen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + + } + // no wrapping reverb buffer, just write dest + else + { + // mix a scaled version of history buffer into output + FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), length, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + + // now copy input into reverb/history buffer + { + signed short *dest; + union sample src = { newbuffer }; + + dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); + + for (count=0; count < length * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + } + + + tap->historyoffset += length; + if (tap->historyoffset >= tap->historylen) + { + tap->historyoffset -= tap->historylen; + } + + // reverb history has been mixed into new buffer, so return it. + return newbuffer; +} + + +/* +[ + [DESCRIPTION] + Similair to a reverb tap except the history copy and the tap mix are done back to front. + + [PARAMETERS] + 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down + through the dsp chain. They are in newbuffer. + 'newbuffer' Pointer to buffer passed from previous DSP unit. + 'length' Length in SAMPLES of buffer being passed. + 'param' User parameter. In this case it is a pointer to a REVERBTAP structure + + [RETURN_VALUE] + A pointer to the new modified buffer. + + [REMARKS] + + [SEE_ALSO] + LowPassCallback +] +*/ +void * F_CALLBACKAPI PreverbCallback(void *originalbuffer, void *newbuffer, int length, void *userdata) +{ + int mixertype = FSOUND_GetMixer(); + int count; + REVERBTAP *tap = (REVERBTAP *)userdata; + int bytesperoutputsample; + union sample + { + void *vptr; + signed int *dptr; + signed short *wptr; + float *fptr; + }; + + if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + bytesperoutputsample = 4; // 16bit stereo + } + else + { + bytesperoutputsample = 8; // 32bit stereo + } + + // preverbbuff is a ringbuffer. If the length makes the copy wrap, then split the copy + // into end part, and start part + if (tap->historyoffset + length > tap->historylen) + { + int taillen = tap->historylen - tap->historyoffset; + int startlen = length - taillen; // whatever is left + + // get a clean version of the preverb buffer (should be an unscaled history of the mixbuffer) + memcpy(tap->workarea, tap->historybuff + (tap->historyoffset * bytesperoutputsample), taillen * bytesperoutputsample); + memcpy(tap->workarea + (taillen * bytesperoutputsample), tap->historybuff, (length - taillen) * bytesperoutputsample); + + // now copy input into preverb/history buffer + memcpy(tap->historybuff + (tap->historyoffset * bytesperoutputsample), newbuffer, taillen * bytesperoutputsample); + memcpy(tap->historybuff, (signed char *)newbuffer + (taillen * bytesperoutputsample), (length - taillen) * bytesperoutputsample); + } + // no wrapping preverb buffer, just write dest + else + { + // get a clean version of the preverb buffer (should be an unscaled history of the mixbuffer) + memcpy(tap->workarea, tap->historybuff + (tap->historyoffset * bytesperoutputsample), length * bytesperoutputsample); + + // now copy input into preverb/history buffer + memcpy(tap->historybuff + (tap->historyoffset * bytesperoutputsample), newbuffer, length * bytesperoutputsample); + } + + /* + Now we mix a copy of the NEW input into our preverbed buffer + */ + { + union sample src = { newbuffer }; + signed short *dest = (signed short *)tap->workarea2; + + for (count=0; count < length * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + + // now mix a scaled input into this + FSOUND_DSP_MixBuffers(tap->workarea, tap->workarea2, length, outputfreq, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + + tap->historyoffset += length; + if (tap->historyoffset >= tap->historylen) + { + tap->historyoffset -= tap->historylen; + } + + // preverb history has been mixed into new buffer, so return it. + return tap->workarea; +} + + +void Reverb_Init() +{ + int bytesperoutputsample; + int mixertype = FSOUND_GetMixer(); + + if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + bytesperoutputsample = 4; // 16bit stereo + } + else + { + bytesperoutputsample = 8; // 32bit stereo + } + + // ==================================================================================================================== + // PREVERB SETUP + // ==================================================================================================================== + { + int delay[PREVERB_NUMTAPS] = { 57, 97, 163 }; // // prime numbers! dont go lower than 20! it will be smaller than the DSP bufferlen!! (a check is done below for this) + int volume[PREVERB_NUMTAPS] = { 128, 78, 46 }; + int pan[PREVERB_NUMTAPS] = { 128-24, 128+24, 128 }; + int count; + + for (count=0; count< PREVERB_NUMTAPS; count++) + { + PreverbTap[count].delayms = delay[count]; + PreverbTap[count].volume = volume[count]; + PreverbTap[count].pan = pan[count]; + PreverbTap[count].historyoffset = 0; + PreverbTap[count].historylen = (PreverbTap[count].delayms * outputfreq / 1000); + + if (PreverbTap[count].historylen < FSOUND_DSP_GetBufferLength()) + { + PreverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); // just in case our calc is not the same. + } + + PreverbTap[count].historybuff = calloc(PreverbTap[count].historylen + 2048, bytesperoutputsample); + PreverbTap[count].workarea = calloc(FSOUND_DSP_GetBufferLength(), bytesperoutputsample); + PreverbTap[count].workarea2 = calloc(FSOUND_DSP_GetBufferLength(), 4); + PreverbTap[count].Unit = FSOUND_DSP_Create(&PreverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+count, &PreverbTap[count]); + } + } + + // ==================================================================================================================== + // REVERB SETUP + // ==================================================================================================================== + { + // something to fiddle with.. + int delay[REVERB_NUMTAPS] = { 131, 149, 173, 211, 281, 401, 457}; // prime numbers! + int volume[REVERB_NUMTAPS] = { 120, 100, 95, 90, 80, 60, 50}; + int pan[REVERB_NUMTAPS] = { 100, 128, 128, 152, 128, 100, 152}; + int count; + + for (count=0; count< REVERB_NUMTAPS; count++) + { + ReverbTap[count].delayms = delay[count]; + ReverbTap[count].volume = volume[count]; + ReverbTap[count].pan = pan[count]; + ReverbTap[count].historyoffset = 0; + ReverbTap[count].historylen = (ReverbTap[count].delayms * outputfreq / 1000); + if (ReverbTap[count].historylen < FSOUND_DSP_GetBufferLength()) + { + ReverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); // just in case our calc is not the same. + } + + ReverbTap[count].historybuff = calloc(ReverbTap[count].historylen, 4); // * 4 is for 16bit stereo buffer + ReverbTap[count].workarea = NULL; + ReverbTap[count].workarea2 = NULL; + ReverbTap[count].Unit = FSOUND_DSP_Create(&ReverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+20+(count*2), &ReverbTap[count]); + } + } +} + + +void Reverb_Close() +{ + int count; + + for (count=0; count +#include +#include +#include +#include + +#include "../../api/inc/fmod.h" + +#include "sdriver.h" +#include "resource.h" + +#ifdef _WIN64 +INT_PTR CALLBACK SoundDriverDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +#else +BOOL CALLBACK SoundDriverDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + +WNDPROC oldcomboproc; +HWND DeviceComboHwnd; + +extern int setting_buffersize; +extern int setting_prebuffer_percent; +extern int setting_rebuffer_percent; +extern char setting_http_proxy[2048]; +extern char setting_cdletter[4]; +extern signed char setting_cdda; +extern signed char setting_jitter; +extern signed char setting_forceaspi; +extern char cddevice; + + +/* + Function to call to create dialog box +*/ +char SoundDriver_Init(long *freq) +{ + HWND hwnd = GetForegroundWindow(); +#ifdef _WIN64 + HINSTANCE hinst = (HINSTANCE)GetWindowLong(hwnd,GWLP_HINSTANCE); +#else + HINSTANCE hinst = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE); +#endif + + return (char)DialogBoxParam(hinst,MAKEINTRESOURCE(IDD_DSENUMBOX), hwnd, SoundDriverDlgProc, (LPARAM)freq); +} + + +/* + SubClassed windowproc for the 'select output' combobox +*/ +long CALLBACK ComboWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_COMMAND: + { + int count; + + if (ComboBox_GetCurSel(hwnd) == 0) + FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + else if (ComboBox_GetCurSel(hwnd) == 1) + FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + else + FSOUND_SetOutput(FSOUND_OUTPUT_ASIO); + + SendMessage(DeviceComboHwnd, CB_RESETCONTENT, 0, 0); + + for (count=0; count < FSOUND_GetNumDrivers(); count++) + ComboBox_AddString(DeviceComboHwnd, FSOUND_GetDriverName(count)); + + ComboBox_SetCurSel(DeviceComboHwnd,0); + UpdateWindow(DeviceComboHwnd); + + break; + } + + }; + + return (long)oldcomboproc(hwnd, message, wParam, lParam); +} + + +/* + Window proc for dialog box +*/ +#ifdef _WIN64 +INT_PTR CALLBACK SoundDriverDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#else +BOOL CALLBACK SoundDriverDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +#endif +{ + static HWND hCombo, hRadio, hCheckbox; + static long *freq; + static long lastoutput=0, lastdriver=0, lastmixer=0, lastoutputrate=44100; + char str[1024]; + + switch (msg) + { + case WM_INITDIALOG: + { + char str[1024]; + int count, buffersize, prebuffer_percent, rebuffer_percent, thisitem, cur; + + /* + Remember what came in last + */ + lastoutput = FSOUND_GetOutput(); + lastdriver = FSOUND_GetDriver(); + lastmixer = FSOUND_GetMixer(); + lastoutputrate = FSOUND_GetOutputRate(); + +#ifdef _WIN64 + if (lastmixer != FSOUND_MIXER_AUTODETECT && + lastmixer != FSOUND_MIXER_QUALITY_AUTODETECT && + lastmixer != FSOUND_MIXER_MONO && + lastmixer != FSOUND_MIXER_QUALITY_MONO) + { + lastmixer = FSOUND_MIXER_QUALITY_AUTODETECT; + } +#else + if (lastmixer > FSOUND_MIXER_QUALITY_MMXP6) + { + lastmixer = FSOUND_MIXER_QUALITY_MMXP6; + } +#endif + + if (lastoutput < FSOUND_OUTPUT_WINMM || lastoutput > FSOUND_OUTPUT_ASIO) + { + lastoutput = FSOUND_OUTPUT_DSOUND; /* somehow lastoutput got corrupted */ + } + if (lastdriver < 0) + { + lastdriver = 0; /* somehow lastdriver got corrupted */ + } + + FSOUND_SetOutput(lastoutput); + + /* + SET UP OUTPUT COMBO BOX + */ + hCombo = GetDlgItem(hwnd,IDC_DSENUM_COMBO3); + ComboBox_AddString(hCombo,"Direct Sound"); + ComboBox_AddString(hCombo,"Windows Multimedia WaveOut"); + ComboBox_AddString(hCombo,"ASIO Low latency"); + + if (lastoutput == FSOUND_OUTPUT_DSOUND) + { + ComboBox_SetCurSel(hCombo,0); + } + if (lastoutput == FSOUND_OUTPUT_WINMM) + { + ComboBox_SetCurSel(hCombo,1); + } + if (lastoutput == FSOUND_OUTPUT_ASIO) + { + ComboBox_SetCurSel(hCombo,2); + } + + /* + Subclass this combo box + */ +#ifdef _WIN64 + oldcomboproc = (WNDPROC)GetWindowLong(hCombo, GWLP_WNDPROC); + SetWindowLong(hCombo, GWLP_WNDPROC, (LONG)ComboWindowProc); +#else + oldcomboproc = (WNDPROC)GetWindowLong(hCombo, GWL_WNDPROC); + SetWindowLong(hCombo, GWL_WNDPROC, (LONG)ComboWindowProc); +#endif + + /* + SET UP MIXER COMBO BOX + */ + hCombo = GetDlgItem(hwnd,IDC_DSENUM_COMBO2); + ComboBox_AddString(hCombo,"Autodetect"); +#ifndef _WIN64 + ComboBox_AddString(hCombo,"Interpolation/Volume Ramping - FPU "); + ComboBox_AddString(hCombo,"Interpolation/Volume Ramping - Pentium MMX"); + ComboBox_AddString(hCombo,"Interpolation/Volume Ramping - P6/P2/P3+ MMX"); +#endif + + if (lastmixer == FSOUND_MIXER_QUALITY_AUTODETECT) ComboBox_SetCurSel(hCombo,0); +#ifndef _WIN64 + if (lastmixer == FSOUND_MIXER_QUALITY_FPU) ComboBox_SetCurSel(hCombo,1); + if (lastmixer == FSOUND_MIXER_QUALITY_MMXP5) ComboBox_SetCurSel(hCombo,2); + if (lastmixer == FSOUND_MIXER_QUALITY_MMXP6) ComboBox_SetCurSel(hCombo,3); +#endif + + /* + SET UP DRIVER COMBO BOX + */ + hCombo = GetDlgItem(hwnd,IDC_DSENUM_COMBO); + DeviceComboHwnd = hCombo; + for (count=0; count < FSOUND_GetNumDrivers(); count++) + { + ComboBox_AddString(hCombo,FSOUND_GetDriverName(count)); + } + + if (ComboBox_GetCount(hCombo)) + { + ComboBox_SetCurSel(hCombo, lastdriver); + } + + /* + SET UP FREQUENCY RADIO BUTTON + */ + if (lastoutputrate == 48000) hRadio = GetDlgItem(hwnd,IDC_RADIO5); + else if (lastoutputrate == 44100) hRadio = GetDlgItem(hwnd,IDC_RADIO1); + else if (lastoutputrate == 22050) hRadio = GetDlgItem(hwnd,IDC_RADIO2); + else if (lastoutputrate == 11025) hRadio = GetDlgItem(hwnd,IDC_RADIO3); + else if (lastoutputrate == 8000) hRadio = GetDlgItem(hwnd,IDC_RADIO4); + else hRadio = GetDlgItem(hwnd,IDC_RADIO1); + + freq = (long *)lParam; + Button_SetCheck(hRadio, TRUE); + + /* + SET UP INTERNET STREAMING VALUES + */ + FSOUND_Stream_Net_GetBufferProperties(&buffersize, &prebuffer_percent, &rebuffer_percent); + sprintf(str, "%d", buffersize); + SetWindowText(GetDlgItem(hwnd, IDC_CONFIG_BUFFERSIZE), str); + sprintf(str, "%d", prebuffer_percent); + SetWindowText(GetDlgItem(hwnd, IDC_CONFIG_INITIALPERCENT), str); + sprintf(str, "%d", rebuffer_percent); + SetWindowText(GetDlgItem(hwnd, IDC_CONFIG_REBUFFERPERCENT), str); + SetWindowText(GetDlgItem(hwnd, IDC_CONFIG_PROXY), setting_http_proxy); + + /* + SET UP CD SETTINGS + */ + thisitem = 0; + hCombo = GetDlgItem(hwnd, IDC_CONFIG_CD); + for (count=2;count < 26;count++) + { + sprintf(str, "%c:\\", (char)('A' + count)); + if (GetDriveType(str) == DRIVE_CDROM) + { + str[2] = 0; + ComboBox_AddString(hCombo, str); + if (!strcmp(str, setting_cdletter)) + { + cur = thisitem; + } + thisitem++; + } + } + ComboBox_SetCurSel(hCombo, cur); + + hCheckbox = GetDlgItem(hwnd, IDC_CONFIG_CDDA); + Button_SetCheck(hCheckbox, setting_cdda); + + hCheckbox = GetDlgItem(hwnd, IDC_CONFIG_JITTER); + Button_SetCheck(hCheckbox, setting_jitter); + + hCheckbox = GetDlgItem(hwnd, IDC_CONFIG_FORCEASPI); + Button_SetCheck(hCheckbox, setting_forceaspi); + + return TRUE; + } + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDOK : + { + int buffersize, prebuffer_percent, rebuffer_percent; + + hCombo = GetDlgItem(hwnd,IDC_DSENUM_COMBO); + + FSOUND_SetDriver((char)ComboBox_GetCurSel(hCombo)); + + if (Button_GetCheck(GetDlgItem(hwnd,IDC_RADIO5))) *freq = 48000; + else if (Button_GetCheck(GetDlgItem(hwnd,IDC_RADIO1))) *freq = 44100; + else if (Button_GetCheck(GetDlgItem(hwnd,IDC_RADIO2))) *freq = 22050; + else if (Button_GetCheck(GetDlgItem(hwnd,IDC_RADIO3))) *freq = 11025; + else if (Button_GetCheck(GetDlgItem(hwnd,IDC_RADIO4))) *freq = 8000; + + hCombo = GetDlgItem(hwnd,IDC_DSENUM_COMBO2); + switch (ComboBox_GetCurSel(hCombo)) + { + case 0: + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT); + break; + case 1: + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU); + break; + case 2: + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_MMXP5); + break; + case 3: + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_MMXP6); + break; + } + + GetWindowText(GetDlgItem(hwnd, IDC_CONFIG_BUFFERSIZE), str, 1023); + buffersize = atoi(str); + GetWindowText(GetDlgItem(hwnd, IDC_CONFIG_INITIALPERCENT), str, 1023); + prebuffer_percent = atoi(str); + GetWindowText(GetDlgItem(hwnd, IDC_CONFIG_REBUFFERPERCENT), str, 1023); + rebuffer_percent = atoi(str); + + if (buffersize < 8192) + { + MessageBox(hwnd, "Buffer size too small!", "Warning", MB_OK | MB_ICONWARNING); + return TRUE; + } + + if ((prebuffer_percent <= 0) || (prebuffer_percent > 99)) + { + MessageBox(hwnd, "Initial buffer percent must be between 1 - 99", "Warning", MB_OK | MB_ICONWARNING); + return TRUE; + } + + if ((rebuffer_percent <= 0) || (rebuffer_percent > 99)) + { + MessageBox(hwnd, "Rebuffer percent must be between 1 - 99", "Warning", MB_OK | MB_ICONWARNING); + return TRUE; + } + + setting_buffersize = buffersize; + setting_prebuffer_percent = prebuffer_percent; + setting_rebuffer_percent = rebuffer_percent; + FSOUND_Stream_Net_SetBufferProperties(setting_buffersize, setting_prebuffer_percent, setting_rebuffer_percent); + + GetWindowText(GetDlgItem(hwnd, IDC_CONFIG_PROXY), setting_http_proxy, 2047); + FSOUND_Stream_Net_SetProxy(setting_http_proxy); + + hCombo = GetDlgItem(hwnd, IDC_CONFIG_CD); + ComboBox_GetLBText(hCombo, ComboBox_GetCurSel(hCombo), str); + strncpy(setting_cdletter, str, 2); + cddevice = str[0]; + + hCheckbox = GetDlgItem(hwnd, IDC_CONFIG_CDDA); + setting_cdda = Button_GetCheck(hCheckbox); + + hCheckbox = GetDlgItem(hwnd, IDC_CONFIG_JITTER); + setting_jitter = Button_GetCheck(hCheckbox); + + hCheckbox = GetDlgItem(hwnd, IDC_CONFIG_FORCEASPI); + setting_forceaspi = Button_GetCheck(hCheckbox); + + EndDialog(hwnd,TRUE); + return TRUE; + } + + case IDCANCEL: + FSOUND_SetOutput(lastoutput); + FSOUND_SetDriver(lastdriver); + FSOUND_SetMixer(lastmixer); + + EndDialog(hwnd, FALSE); + return TRUE; + + case IDC_CONFIG_CDINFO : + { + FILE *fp; + char cdstring[5]; + char *cd_device_info; + FSOUND_STREAM *stream; + STARTUPINFO startup_info; + PROCESS_INFORMATION process_info; + + if (!FSOUND_Init(44100, 4, 0)) + { + MessageBox(hwnd, "ERROR: CD/DVD device info not available", "Error", MB_ICONERROR | MB_OK); + break; + } + + hCombo = GetDlgItem(hwnd, IDC_CONFIG_CD); + ComboBox_GetLBText(hCombo, ComboBox_GetCurSel(hCombo), str); + sprintf(cdstring, "%s*?", str); + + stream = FSOUND_Stream_Open(cdstring, 0, 0, 0); + if (!stream) + { + MessageBox(hwnd, "ERROR: CD/DVD device info not available", "Error", MB_ICONERROR | MB_OK); + FSOUND_Close(); + break; + } + + if (FSOUND_Stream_FindTagField(stream, FSOUND_TAGFIELD_ASF + 1, "CD_DEVICE_INFO", (void **)&cd_device_info, 0)) + { + fp = fopen("cd_device_info.txt", "wb"); + fwrite(cd_device_info, 1, strlen(cd_device_info), fp); + fclose(fp); + + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.cb = sizeof(STARTUPINFO); + + if (CreateProcess(0, + "notepad cd_device_info.txt", + 0, + 0, + TRUE, + NORMAL_PRIORITY_CLASS, + 0, + 0, + &startup_info, + &process_info)) + { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + } + else + { + MessageBox(hwnd, "ERROR: CD/DVD device info not available", "Error", MB_ICONERROR | MB_OK); + } + } + else + { + if (FSOUND_Stream_FindTagField(stream, FSOUND_TAGFIELD_ASF + 1, "CD_ERROR", (void **)&cd_device_info, 0)) + { + MessageBox(hwnd, cd_device_info, "Error", MB_ICONHAND|MB_OK|MB_SYSTEMMODAL); + } + else + { + MessageBox(hwnd, "ERROR: CD/DVD device info not available", "Error", MB_ICONERROR | MB_OK); + } + } + + FSOUND_Stream_Close(stream); + FSOUND_Close(); + break; + } + + case IDC_ABOUT : + { + char tmp[128]; + sprintf(tmp, "FMOD %.2f Media Player Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004", FMOD_VERSION); + MessageBox(hwnd, tmp, "About", MB_OK); + break; + } + } + break; + } + default: + { + return FALSE; + } + } + + return FALSE; +} + diff --git a/fmodapi375win/samples/fmod/sdriver.h b/fmodapi375win/samples/fmod/sdriver.h new file mode 100644 index 0000000..970c19e --- /dev/null +++ b/fmodapi375win/samples/fmod/sdriver.h @@ -0,0 +1,8 @@ +#ifndef _SDRIVER_H_ +#define _SDRIVER_H_ + +char SoundDriver_Init(long *freq); + +#endif + + diff --git a/fmodapi375win/samples/fsb/Main.cpp b/fmodapi375win/samples/fsb/Main.cpp new file mode 100644 index 0000000..f6700d6 --- /dev/null +++ b/fmodapi375win/samples/fsb/Main.cpp @@ -0,0 +1,189 @@ +//=============================================================================================== +// FSB.EXE +// Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. +// +// This example demonstrates use of the FMOD Sample Bank format and also usage of the +// FSOUND_Sample_SetDefaultsEx function. +//=============================================================================================== + +#include +#include + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#else + #include "../../api/inc/wincompat.h" +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" // optional + + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main(int argc, char *argv[]) +{ + FSOUND_SAMPLE *sample; + FMUSIC_MODULE *mod; + char key; + int sampleindex = 0, variation = 1, lastopenstate = -1; + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); +#elif defined(__linux__) + FSOUND_SetOutput(FSOUND_OUTPUT_OSS); +#endif + + // ========================================================================================== + // SELECT DRIVER + // ========================================================================================== + { + long i,driver=0; + char key; + + // The following list are the drivers for the output method selected above. + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_A3D: printf("A3D"); break; + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightenment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("ALSA"); break; + }; + printf(" Driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_GetDriverName(i)); // print driver names + } + printf("---------------------------------------------------------\n"); // print driver names + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) exit(0); + + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_GetNumDrivers()); + + FSOUND_SetDriver(driver); // Select sound card (0 = default) + } + + // ========================================================================================== + // INITIALIZE + // ========================================================================================== + if (!FSOUND_Init(44100, 32, 0)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + // ========================================================================================== + // OPEN FSB + // ========================================================================================== + mod = FMUSIC_LoadSongEx("../../media/footsteps.fsb", 0, 0, FSOUND_NONBLOCKING, 0, 0); + if (!mod) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + printf("=========================================================================\n"); + printf("Press SPACE to toggle pitch/volume variation\n"); + printf("Press ESC to quit\n"); + printf("=========================================================================\n"); + printf("\n"); + + key = 0; + do + { + printf("Pitch/volume variation: %s \r", variation ? "on" : "off"); + fflush(stdout); + + /* + Set initial defaults for both samples. Do this only once as soon as the FSB has finished loading. + */ + if ((lastopenstate != 0) && (FMUSIC_GetOpenState(mod) == 0)) + { + sample = FMUSIC_GetSample(mod, 0); + FSOUND_Sample_SetDefaultsEx(sample, -1, -1, -1, -1, 2000, 128, -1); + sample = FMUSIC_GetSample(mod, 1); + FSOUND_Sample_SetDefaultsEx(sample, -1, -1, -1, -1, 2000, 128, -1); + lastopenstate = 0; + } + + /* + Play a sample from the FSB. Do this once every frame when the FSB has finished loading. + */ + if (FMUSIC_GetOpenState(mod) == 0) + { + sample = FMUSIC_GetSample(mod, sampleindex++ & 1); + FSOUND_PlaySound(FSOUND_FREE, sample); + } + + if (kbhit()) + { + key = getch(); + if (key == ' ') + { + variation ^= 1; + } + + /* + Change the defaults/variations on both samples. + */ + if (variation) + { + sample = FMUSIC_GetSample(mod, 0); + FSOUND_Sample_SetDefaultsEx(sample, -1, -1, -1, -1, 2000, 128, -1); + sample = FMUSIC_GetSample(mod, 1); + FSOUND_Sample_SetDefaultsEx(sample, -1, -1, -1, -1, 2000, 128, -1); + } + else + { + sample = FMUSIC_GetSample(mod, 0); + FSOUND_Sample_SetDefaultsEx(sample, -1, -1, -1, -1, 0, 0, 0); + sample = FMUSIC_GetSample(mod, 1); + FSOUND_Sample_SetDefaultsEx(sample, -1, -1, -1, -1, 0, 0, 0); + } + } + + Sleep(600 + (variation ? (rand() % 100) : 50)); + + } while (key != 27); + + printf("\n"); + + FMUSIC_FreeSong(mod); + FSOUND_Close(); + + return 0; +} diff --git a/fmodapi375win/samples/fsb/fsb.dsp b/fmodapi375win/samples/fsb/fsb.dsp new file mode 100644 index 0000000..43c8b2f --- /dev/null +++ b/fmodapi375win/samples/fsb/fsb.dsp @@ -0,0 +1,89 @@ +# Microsoft Developer Studio Project File - Name="fsb" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=fsb - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "fsb.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "fsb.mak" CFG="fsb - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "fsb - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "fsb - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "fsb - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0xc09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"fsb.exe" + +!ELSEIF "$(CFG)" == "fsb - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0xc09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"fsb.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "fsb - Win32 Release" +# Name "fsb - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/fsb/fsb.exe b/fmodapi375win/samples/fsb/fsb.exe new file mode 100644 index 0000000..50522ef Binary files /dev/null and b/fmodapi375win/samples/fsb/fsb.exe differ diff --git a/fmodapi375win/samples/fsb/watcom.bat b/fmodapi375win/samples/fsb/watcom.bat new file mode 100644 index 0000000..e39ffba --- /dev/null +++ b/fmodapi375win/samples/fsb/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name fsb.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/multiple/Main.cpp b/fmodapi375win/samples/multiple/Main.cpp new file mode 100644 index 0000000..84e1a3a --- /dev/null +++ b/fmodapi375win/samples/multiple/Main.cpp @@ -0,0 +1,241 @@ +/*=============================================================================================== + MULTIPLE.EXE + Copyright (c), Firelight Technologies Pty, Ltd 1999-2004. + + This example demonstrates how to use dynamic loading of fmod.dll to achieve multiple soundcard + output at the same time. If you do not have 2 soundcards you will have to select the same + device twice. + Besides this, it is a good helper to display how fmod.dll can be loaded dynamically without + having to link an import library. + + IMPORTANT!!! You must copy fmod.dll to fmod2.dll or libfmod-3.63.so to libfmod-3.63_2.so to + avoid operating systems caching the dll! +===============================================================================================*/ + +#include + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#else + #include "../../api/inc/wincompat.h" +#endif + +#include "../../api/inc/fmoddyn.h" +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" /* optional */ + +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + #define FMOD_LIB "fmod.dll" + #define FMOD_LIB2 "fmod2.dll" +#else + #define FMOD_LIB "libfmod-3.70.so" + #define FMOD_LIB2 "libfmod-3.70_2.so" +#endif + +#define FMOD_LIB_PATH "../../api/" ## FMOD_LIB +#define FMOD_LIB_PATH2 "../../api/" ## FMOD_LIB2 + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main() +{ + FMOD_INSTANCE *fmod1, *fmod2; + FSOUND_SAMPLE *samp1, *samp2; + int key; + int driver, i; + +/* system("copy ..\\..\\api\\fmod.dll ..\\..\\api\\fmod2.dll"); */ + + fmod1 = FMOD_CreateInstance(FMOD_LIB_PATH); + fmod2 = FMOD_CreateInstance(FMOD_LIB_PATH2); + + if (!fmod1) + { + printf("Error : Cannot find %s!\n", FMOD_LIB); + return 1; + } + if (!fmod2) + { + printf("Error : Cannot find %s!\n", FMOD_LIB2); + printf("You have to copy %s to %s first to make this work\n", FMOD_LIB, FMOD_LIB2); + return 1; + } + + if (fmod1->FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + if (fmod2->FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + fmod1->FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + fmod2->FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); +#else + fmod1->FSOUND_SetOutput(FSOUND_OUTPUT_OSS); + fmod2->FSOUND_SetOutput(FSOUND_OUTPUT_OSS); +#endif + + /* + SELECT DRIVER 1 + */ + + /* + The following list are the drivers for the output method selected above. + */ + printf("---------------------------------------------------------\n"); + printf("Select soundcard #1\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < fmod1->FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, fmod1->FSOUND_GetDriverName(i)); /* print driver names */ + } + printf("---------------------------------------------------------\n"); + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) + { + return 0; + } + driver = key - '1'; + } while (driver < 0 || driver >= fmod1->FSOUND_GetNumDrivers()); + + fmod1->FSOUND_SetDriver(driver); /* Select sound card (0 = default) */ + + printf("---------------------------------------------------------\n"); + printf("Select soundcard #2\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < fmod2->FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, fmod2->FSOUND_GetDriverName(i)); /* print driver names */ + } + printf("---------------------------------------------------------\n"); + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) + { + return 0; + } + driver = key - '1'; + } while (driver < 0 || driver >= fmod2->FSOUND_GetNumDrivers()); + + fmod2->FSOUND_SetDriver(driver); /* Select sound card (0 = default) */ + + /* + INITIALIZE + */ + if (!fmod1->FSOUND_Init(44100, 32, FSOUND_INIT_USEDEFAULTMIDISYNTH)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(fmod1->FSOUND_GetError())); + return 1; + } + + /* + INITIALIZE + */ + if (!fmod2->FSOUND_Init(44100, 32, FSOUND_INIT_USEDEFAULTMIDISYNTH)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(fmod2->FSOUND_GetError())); + return 1; + } + + /* + LOAD SAMPLE (twice) + */ + + samp1 = fmod1->FSOUND_Sample_Load(FSOUND_UNMANAGED, "../../media/drumloop.wav", FSOUND_NORMAL | FSOUND_2D, 0, 0); + if (!samp1) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(fmod1->FSOUND_GetError())); + return 1; + } + fmod1->FSOUND_Sample_SetMode(samp1, FSOUND_LOOP_OFF); /* this wav has loop points in it which turns looping on.. turn it off! */ + + samp2 = fmod2->FSOUND_Sample_Load(FSOUND_UNMANAGED, "../../media/drumloop.wav", FSOUND_NORMAL | FSOUND_2D, 0, 0); + if (!samp1) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(fmod2->FSOUND_GetError())); + return 1; + } + fmod2->FSOUND_Sample_SetMode(samp2, FSOUND_LOOP_OFF); /* this wav has loop points in it which turns looping on.. turn it off! */ + + /* + DISPLAY HELP + */ + + printf("=========================================================================\n"); + printf("Press 1 Play 16bit sound on soundcard #1\n"); + printf(" 2 Play 16bit sound on soundcard #2\n"); + printf(" ESC Quit\n"); + printf("=========================================================================\n"); + + do + { + key = 0; + + if (kbhit()) + { + key = getch(); + + if (key == '1') + { + fmod1->FSOUND_PlaySound(FSOUND_FREE, samp1); + } + if (key == '2') + { + fmod2->FSOUND_PlaySound(FSOUND_FREE, samp2); + } + } + + Sleep(10); + + } while (key != 27); + + printf("\n"); + + /* + CLEANUP AND SHUTDOWN + */ + + fmod1->FSOUND_Sample_Free(samp1); + fmod2->FSOUND_Sample_Free(samp2); + + fmod1->FSOUND_Close(); + fmod2->FSOUND_Close(); + + FMOD_FreeInstance(fmod1); + FMOD_FreeInstance(fmod2); + + return 0; +} + diff --git a/fmodapi375win/samples/multiple/multiple.dsp b/fmodapi375win/samples/multiple/multiple.dsp new file mode 100644 index 0000000..c4d1dfb --- /dev/null +++ b/fmodapi375win/samples/multiple/multiple.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="multiple" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=multiple - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "multiple.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "multiple.mak" CFG="multiple - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "multiple - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "multiple - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "multiple - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0xc09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 /out:"multiple.exe" + +!ELSEIF "$(CFG)" == "multiple - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0xc09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /out:"multiple.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "multiple - Win32 Release" +# Name "multiple - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/multiple/multiple.exe b/fmodapi375win/samples/multiple/multiple.exe new file mode 100644 index 0000000..83e9a20 Binary files /dev/null and b/fmodapi375win/samples/multiple/multiple.exe differ diff --git a/fmodapi375win/samples/multiple/watcom.bat b/fmodapi375win/samples/multiple/watcom.bat new file mode 100644 index 0000000..535fdec --- /dev/null +++ b/fmodapi375win/samples/multiple/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name multiple.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/netstream/Main.cpp b/fmodapi375win/samples/netstream/Main.cpp new file mode 100644 index 0000000..a1b3ddb --- /dev/null +++ b/fmodapi375win/samples/netstream/Main.cpp @@ -0,0 +1,243 @@ +//=============================================================================================== +// netstream.exe +// Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. +// +// This example shows how to play internet streams (SHOUTcast/Icecast2/HTTP) +//=============================================================================================== + +#include + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#else + #include "../../api/inc/wincompat.h" + #include +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" + + +const char *status_str[] = +{ + "NOTCONNECTED", + "CONNECTING ", + "BUFFERING ", + "READY ", + "ERROR " +}; + +const char bar[56] = "=================================================="; +const char nobar[56] = " "; + +char artist[256] = ""; +char title[256] = ""; +int metanum = 0; + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char F_CALLBACKAPI metacallback(char *name, char *value, void *userdata) +{ + if (!strcmp("ARTIST", name)) + { + strcpy(artist, value); + return TRUE; + } + + if (!strcmp("TITLE", name)) + { + strcpy(title, value); + metanum++; + return TRUE; + } + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main(int argc, char *argv[]) +{ + FSOUND_STREAM *stream; + int read_percent = 0, i, driver = 0, channel = -1, status = 0, openstate, bitrate; + unsigned int flags; + char s[256] = ""; + char key; + + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + if ((argc < 2) || (strnicmp(argv[1], "http:", 5))) + { + printf("-------------------------------------------------------------\n"); + printf("FMOD netstream example.\n"); + printf("Copyright (c) Firelight Technologies Pty, Ltd, 1999-2004.\n"); + printf("-------------------------------------------------------------\n"); + printf("Syntax: netstream \n"); + printf("Example: netstream http://www.fmod.org/stream.mp3\n\n"); + return 1; + } + +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); +#elif defined(__linux__) + FSOUND_SetOutput(FSOUND_OUTPUT_OSS); +#endif + + // ========================================================================================== + // SELECT DRIVER + // ========================================================================================== + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_A3D: printf("A3D"); break; + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightenment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("ALSA"); break; + }; + printf(" Driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_GetDriverName(i)); + } + printf("---------------------------------------------------------\n"); + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) exit(0); + + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_GetNumDrivers()); + + FSOUND_SetDriver(driver); + + // ========================================================================================== + // INITIALIZE + // ========================================================================================== + if (!FSOUND_Init(44100, 32, 0)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + /* + Internet streams can work with a much smaller stream buffer than normal streams because they + use another level of buffering on top of the stream buffer. + */ + FSOUND_Stream_SetBufferSize(100); + + /* + Here's where we set the size of the network buffer and some buffering parameters. + In this case we want a network buffer of 64k, we want it to prebuffer 60% of that when we first + connect, and we want it to rebuffer 80% of that whenever we encounter a buffer underrun. + */ + FSOUND_Stream_Net_SetBufferProperties(64000, 60, 80); + + /* + Open the stream using FSOUND_NONBLOCKING because the connect/buffer process might take a long time + */ + stream = FSOUND_Stream_Open(argv[1], FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!stream) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + printf("\nPress ESC to quit...\n\n"); + + key = 0; + do + { + if (kbhit()) + { + key = getch(); + } + + /* + Play the stream if it's not already playing + */ + if (channel < 0) + { + channel = FSOUND_Stream_PlayEx(FSOUND_FREE, stream, NULL, TRUE); + FSOUND_SetPaused(channel, FALSE); + + if (channel != -1) + { + FSOUND_Stream_Net_SetMetadataCallback(stream, metacallback, 0); + } + } + + openstate = FSOUND_Stream_GetOpenState(stream); + if ((openstate == -1) || (openstate == -3)) + { + printf("\nERROR: failed to open stream!\n"); + printf("SERVER: %s\n", FSOUND_Stream_Net_GetLastServerStatus()); + break; + } + + FSOUND_Stream_Net_GetStatus(stream, &status, &read_percent, &bitrate, &flags); + + /* + Show how much of the net buffer is used and what the status is + */ + if (metanum) + { + printf("%s - %s\n", artist, title); + metanum = 0; + } + s[0] = 0; + strncat(s, bar, (read_percent >> 1) + (read_percent & 1)); + strncat(s, nobar, (100 - read_percent) >> 1); + printf("|%s| %d%% %s\r", s, read_percent, status_str[status]); + + Sleep(16); + + } while (key != 27); + + printf("\n"); + + FSOUND_Stream_Close(stream); + FSOUND_Close(); + + return 0; +} diff --git a/fmodapi375win/samples/netstream/netstream.dsp b/fmodapi375win/samples/netstream/netstream.dsp new file mode 100644 index 0000000..2e557cc --- /dev/null +++ b/fmodapi375win/samples/netstream/netstream.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="netstream" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=netstream - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "netstream.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "netstream.mak" CFG="netstream - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "netstream - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "netstream - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "netstream - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0xc09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"netstream.exe" + +!ELSEIF "$(CFG)" == "netstream - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0xc09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"netstream.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "netstream - Win32 Release" +# Name "netstream - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/netstream/netstream.exe b/fmodapi375win/samples/netstream/netstream.exe new file mode 100644 index 0000000..327e2f9 Binary files /dev/null and b/fmodapi375win/samples/netstream/netstream.exe differ diff --git a/fmodapi375win/samples/netstream/watcom.bat b/fmodapi375win/samples/netstream/watcom.bat new file mode 100644 index 0000000..ae4452c --- /dev/null +++ b/fmodapi375win/samples/netstream/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name netstream.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/record/Main.cpp b/fmodapi375win/samples/record/Main.cpp new file mode 100644 index 0000000..8574c34 --- /dev/null +++ b/fmodapi375win/samples/record/Main.cpp @@ -0,0 +1,783 @@ +/* + RECORD.EXE + Copyright (c), Firelight Technologies Pty, Ltd, 2000-2004. + + This example shows how to record data to a static sample, or record dynamically, and have + a dsp unit processing the result. + The reverb below is taken from /samples/fmod/fmod.c +*/ + +#include +#include + +#if defined(WIN32) || defined(__WATCOMC__) || defined(_WIN32) || defined(__WIN32__) + #include + #include + #define __PACKED /*dummy*/ +#else + #include "../../api/inc/wincompat.h" + #include + #define __PACKED __attribute__((packed)) /* gcc packed */ +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" /* optional */ + +#define ENABLEREVERB TRUE +#define RECORDRATE 44100 +#define RECORDLEN (RECORDRATE * 5) /* 5 seconds at RECORDRATE khz */ +#define OUTPUTRATE 44100 + +#define REVERB_NUMTAPS 7 + +typedef struct +{ + FSOUND_DSPUNIT *Unit; + char *historybuff; /* storage space for tap history */ + char *workarea; /* a place to hold 1 buffer worth of data (for reverb) */ + int delayms; /* delay of reverb tab in milliseconds */ + int volume; /* volume of reverb tab */ + int pan; /* pan of reverb tab */ + int historyoffset; /* running offset into history buffer */ + int historylen; /* size of history buffer in SAMPLES */ +} REVERBTAP; + +/* + Reverb stuff +*/ +REVERBTAP DSP_ReverbTap[REVERB_NUMTAPS]; + +/* +[ + [DESCRIPTION] + Callback to mix in one reverb tap. It copies the buffer into its own history buffer also. + + [PARAMETERS] + 'originalbuffer' Pointer to the original mixbuffer, not any buffers passed down + through the dsp chain. They are in newbuffer. + 'newbuffer' Pointer to buffer passed from previous DSP unit. + 'length' Length in SAMPLES of buffer being passed. + 'param' User parameter. In this case it is a pointer to DSP_LowPassBuffer. + + [RETURN_VALUE] + a pointer to the buffer that was passed in, with a tap mixed into it. + + [REMARKS] +] +*/ +void * F_CALLBACKAPI DSP_ReverbCallback(void *originalbuffer, void *newbuffer, int length, void *param) +{ + int mixertype = FSOUND_GetMixer(); + int count; + int bytesperoutputsample; + REVERBTAP *tap = (REVERBTAP *)param; + union sample + { + void *vptr; + signed int *dptr; + signed short *wptr; + float *fptr; + }; + + if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + bytesperoutputsample = 4; // 16bit stereo + } + else + { + bytesperoutputsample = 8; // 32bit stereo + } + + // reverb history buffer is a ringbuffer. If the length makes the copy wrap, then split the copy + // into end part, and start part.. + if (tap->historyoffset + length > tap->historylen) + { + int taillen = tap->historylen - tap->historyoffset; + int startlen = length - taillen; + + // mix a scaled version of history buffer into output + FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), taillen, OUTPUTRATE, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + FSOUND_DSP_MixBuffers((char *)newbuffer+(taillen * bytesperoutputsample), tap->historybuff, startlen, OUTPUTRATE, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + + // now copy input into reverb/history buffer + { + signed short *dest; + union sample src; + + dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); + src.vptr = newbuffer; + + for (count=0; count < taillen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + { + signed short *dest; + union sample src; + + dest = (signed short *)tap->historybuff; // always 16bit + src.vptr = (char *)newbuffer + (taillen * bytesperoutputsample); + + for (count=0; count < startlen * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + + } + // no wrapping reverb buffer, just write dest + else + { + // mix a scaled version of history buffer into output + FSOUND_DSP_MixBuffers(newbuffer, tap->historybuff + (tap->historyoffset << 2), length, OUTPUTRATE, tap->volume, tap->pan, FSOUND_STEREO | FSOUND_16BITS); + + // now copy input into reverb/history buffer + { + signed short *dest; + union sample src = { newbuffer }; + + dest = (signed short *)(tap->historybuff + (tap->historyoffset << 2)); + + for (count=0; count < length * 2; count++) + { + int val; + + if (mixertype == FSOUND_MIXER_QUALITY_FPU) + { + val = (int)src.fptr[count]; + } + else if (mixertype == FSOUND_MIXER_MMXP5 || mixertype == FSOUND_MIXER_MMXP6 || mixertype == FSOUND_MIXER_QUALITY_MMXP5 || mixertype == FSOUND_MIXER_QUALITY_MMXP6) + { + val = (int)src.wptr[count]; + } + else + { + val = (int)src.dptr[count]; + } + val = (val > 32767 ? 32767 : val < -32768 ? -32768 : val); + dest[count] = val; + } + } + } + + + tap->historyoffset += length; + if (tap->historyoffset >= tap->historylen) + { + tap->historyoffset -= tap->historylen; + } + + // reverb history has been mixed into new buffer, so return it. + return newbuffer; +} + + +/* +[ + [DESCRIPTION] + Initializes reverb, creates DSP units and history buffers for all reverb tabs + + [PARAMETERS] + + [RETURN_VALUE] + void + + [REMARKS] +] +*/ +void SetupReverb() +{ + /* + REVERB SETUP + */ + /* something to fiddle with. */ + int delay[REVERB_NUMTAPS] = { 131, 149, 173, 211, 281, 401, 457}; /* prime numbers make it sound good! */ + int volume[REVERB_NUMTAPS] = { 120, 100, 95, 90, 80, 60, 50}; + int pan[REVERB_NUMTAPS] = { 100, 128, 128, 152, 128, 100, 152}; + int count; + + for (count=0; count< REVERB_NUMTAPS; count++) + { + DSP_ReverbTap[count].delayms = delay[count]; + DSP_ReverbTap[count].volume = volume[count]; + DSP_ReverbTap[count].pan = pan[count]; + DSP_ReverbTap[count].historyoffset = 0; + DSP_ReverbTap[count].historylen = (DSP_ReverbTap[count].delayms * 44100 / 1000); + if (DSP_ReverbTap[count].historylen < FSOUND_DSP_GetBufferLength()) + DSP_ReverbTap[count].historylen = FSOUND_DSP_GetBufferLength(); /* just in case our calc is not the same. */ + + DSP_ReverbTap[count].historybuff = (char *)calloc(DSP_ReverbTap[count].historylen, 4); /* * 4 is for 16bit stereo (mmx only) */ + DSP_ReverbTap[count].workarea = NULL; + DSP_ReverbTap[count].Unit = FSOUND_DSP_Create(&DSP_ReverbCallback, FSOUND_DSP_DEFAULTPRIORITY_USER+20+(count*2), (void *)&DSP_ReverbTap[count]); + + FSOUND_DSP_SetActive(DSP_ReverbTap[count].Unit, TRUE); + } +} + + +/* +[ + [DESCRIPTION] + Shuts down and frees anything to do with the software reverb + + [PARAMETERS] + + [RETURN_VALUE] + void + + [REMARKS] +] +*/ +void CloseReverb() +{ + int count; + + for (count=0; count '4'); + + switch (key) + { +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); + break; +#elif defined(__linux__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_OSS); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_ESD); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_ALSA); + break; +#endif + default : return 0; + } + + /* + SELECT OUTPUT DRIVER + */ + + /* The following list are the drivers for the output method selected above. */ + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("ALSA"); break; + }; + printf(" Driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_GetDriverName(i)); /* print driver names */ + } + printf("---------------------------------------------------------\n"); /* print driver names */ + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) + { + FSOUND_Close(); + return 0; + } + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_GetNumDrivers()); + + FSOUND_SetDriver(driver); /* Select sound card (0 = default) */ + + /* + SELECT MIXER + */ + + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT); + + /* + INITIALIZE + */ + if (!FSOUND_Init(OUTPUTRATE, 64, FSOUND_INIT_ACCURATEVULEVELS)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 0; + } + + + /* + SELECT INPUT DRIVER (can be done before or after init) + */ + + /* The following list are the drivers for the output method selected above. */ + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("ALSA"); break; + }; + printf(" Recording device driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_Record_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_Record_GetDriverName(i)); /* print driver names */ + } + printf("---------------------------------------------------------\n"); /* print driver names */ + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) + return 0; + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_Record_GetNumDrivers()); + + if (!FSOUND_Record_SetDriver(driver)) /* Select input sound card (0 = default) */ + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 0; + } + + /* + DISPLAY HELP + */ + + printf("FSOUND Output Method : "); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("FSOUND_OUTPUT_NOSOUND\n"); break; + case FSOUND_OUTPUT_WINMM: printf("FSOUND_OUTPUT_WINMM\n"); break; + case FSOUND_OUTPUT_DSOUND: printf("FSOUND_OUTPUT_DSOUND\n"); break; + case FSOUND_OUTPUT_OSS: printf("FSOUND_OUTPUT_OSS\n"); break; + case FSOUND_OUTPUT_ESD: printf("FSOUND_OUTPUT_ESD\n"); break; + case FSOUND_OUTPUT_ALSA: printf("FSOUND_OUTPUT_ALSA\n"); break; + }; + + printf("FSOUND Mixer : "); + switch (FSOUND_GetMixer()) + { + case FSOUND_MIXER_BLENDMODE: printf("FSOUND_MIXER_BLENDMODE\n"); break; + case FSOUND_MIXER_MMXP5: printf("FSOUND_MIXER_MMXP5\n"); break; + case FSOUND_MIXER_MMXP6: printf("FSOUND_MIXER_MMXP6\n"); break; + case FSOUND_MIXER_QUALITY_FPU: printf("FSOUND_MIXER_QUALITY_FPU\n"); break; + case FSOUND_MIXER_QUALITY_MMXP5:printf("FSOUND_MIXER_QUALITY_MMXP5\n"); break; + case FSOUND_MIXER_QUALITY_MMXP6:printf("FSOUND_MIXER_QUALITY_MMXP6\n"); break; + }; + printf("FSOUND Driver : %s\n", FSOUND_GetDriverName(FSOUND_GetDriver())); + printf("FSOUND Record Driver : %s\n", FSOUND_Record_GetDriverName(FSOUND_Record_GetDriver())); + + /* + RECORD INTO A STATIC SAMPLE + */ + + /* + Create a sample to record into + */ + if (FSOUND_GetOutput() == FSOUND_OUTPUT_OSS) + { + samp1 = FSOUND_Sample_Alloc(FSOUND_UNMANAGED, RECORDLEN, FSOUND_MONO | FSOUND_8BITS | FSOUND_UNSIGNED, RECORDRATE, 255, 128, 255); + } + else + { + samp1 = FSOUND_Sample_Alloc(FSOUND_UNMANAGED, RECORDLEN, FSOUND_STEREO | FSOUND_16BITS , RECORDRATE, 255, 128, 255); + } + + printf("\n"); + printf("=========================================================================\n"); + printf("Press a key to start recording 5 seconds worth of data\n"); + printf("=========================================================================\n"); + + getch(); + + if (!FSOUND_Record_StartSample(samp1, FALSE)) /* it will record into this sample for 5 seconds then stop */ + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + + FSOUND_Close(); + return 0; + } + + do + { + printf("Recording position = %d\r", FSOUND_Record_GetPosition()); + Sleep(50); + } while (FSOUND_Record_GetPosition() < RECORDLEN && !kbhit()); + + FSOUND_Record_Stop(); /* it already stopped anyway */ + + printf("\n=========================================================================\n"); + printf("Press a key to play back recorded data\n"); + printf("=========================================================================\n"); + + getch(); + + channel = FSOUND_PlaySound(FSOUND_FREE, samp1); + + printf("Playing back sound...\n"); + + do + { + printf("Playback position = %d\r", FSOUND_GetCurrentPosition(channel)); + Sleep(50); + } while (FSOUND_IsPlaying(channel) && !kbhit()); + + if (FSOUND_GetOutput() == FSOUND_OUTPUT_OSS) + { + FSOUND_Sample_Free(samp1); + FSOUND_Close(); + return 0; + } + + + /* + SAVED TO + */ + SaveToWav(samp1); + + printf("\nSaved to record.wav!\n"); + + + /* + REALTIME FULL DUPLEX RECORD / PLAYBACK! + */ + + printf("\n=========================================================================\n"); + printf("Press a key to do some full duplex realtime recording!\n"); + printf("(with reverb for mmx users)\n"); + printf("=========================================================================\n"); + + getch(); + + FSOUND_Sample_SetMode(samp1, FSOUND_LOOP_NORMAL); /* make it a looping sample */ + + if (!FSOUND_Record_StartSample(samp1, TRUE)) /* start recording and make it loop also */ + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + + FSOUND_Close(); + return 0; + } + + /* + Increase this value if the sound sounds corrupted or the time between recording + and hearing the result is longer than it should be.. + */ + #define RECORD_DELAY_MS 25 + #define RECORD_DELAY_SAMPLES (RECORDRATE * RECORD_DELAY_MS / 1000) + + /* + Let the record cursor move forward a little bit first before we try to play it + (the position jumps in blocks, so any non 0 value will mean 1 block has been recorded) + */ + while (!FSOUND_Record_GetPosition()) + { + Sleep(1); + } + +#ifdef ENABLEREVERB + SetupReverb(); +#endif + + channel = FSOUND_PlaySound(FSOUND_FREE, samp1); /* play the sound */ + + originalfreq = FSOUND_GetFrequency(channel); + +/* printf("initial delay = %d\n", FSOUND_GetCurrentPosition(channel) - FSOUND_Record_GetPosition()); */ + + do + { + int playpos, recordpos, diff; + static int oldrecordpos = 0, oldplaypos = 0; + + playpos = FSOUND_GetCurrentPosition(channel); + recordpos = FSOUND_Record_GetPosition(); + + /* + NOTE : As the recording and playback frequencies arent guarranteed to be exactly in + sync, we have to adjust the playback frequency to keep the 2 cursors just enough + apart not to overlap. (and sound corrupted) + This code tries to keep it inside a reasonable size window just behind the record + cursor. ie [........|play window|<-delay->|<-Record cursor.............] + */ + + /* + Dont do this code if either of the cursors just wrapped + */ + if (playpos > oldplaypos && recordpos > oldrecordpos) + { + diff = playpos - recordpos; + + if (diff > -RECORD_DELAY_SAMPLES) + { + FSOUND_SetFrequency(channel, originalfreq - 1000); /* slow it down */ + } + else if (diff < -(RECORD_DELAY_SAMPLES * 2)) + { + FSOUND_SetFrequency(channel, originalfreq + 1000); /* speed it up */ + } + else + { + FSOUND_SetFrequency(channel, originalfreq); + } + } + + oldplaypos = playpos; + oldrecordpos = recordpos; + + /* + Print some info and a VU meter (vu is smoothed) + */ + { + char vu[19]; + float vuval, l, r; + static float smoothedvu = 0; + + FSOUND_GetCurrentLevels(channel, &l, &r); + vuval = (l+r) * 0.5f; + vuval *= 18.0f; + + #define VUSPEED 0.2f + + if (vuval > smoothedvu) + { + smoothedvu = vuval; + } + + smoothedvu -= VUSPEED; + if (smoothedvu < 0) + { + smoothedvu = 0; + } + + memset(vu, 0, 19); + memset(vu, '=', (int)(smoothedvu)); + + printf("Play=%6d Rec=%6d (gap=%6d, freqchange=%6d hz) VU:%-15s\r", playpos, recordpos, diff, FSOUND_GetFrequency(channel) - originalfreq, vu); + } + + Sleep(10); + } while (!kbhit()); + + getch(); + + FSOUND_StopSound(channel); + FSOUND_Record_Stop(); + +#ifdef ENABLEREVERB + CloseReverb(); +#endif + + /* + CLEANUP AND SHUTDOWN + */ + + FSOUND_Sample_Free(samp1); + FSOUND_Close(); + return 0; +} + diff --git a/fmodapi375win/samples/record/record.dsp b/fmodapi375win/samples/record/record.dsp new file mode 100644 index 0000000..dceacc0 --- /dev/null +++ b/fmodapi375win/samples/record/record.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="record" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=record - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "record.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "record.mak" CFG="record - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "record - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "record - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "record - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"record.exe" + +!ELSEIF "$(CFG)" == "record - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"record.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "record - Win32 Release" +# Name "record - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/record/record.exe b/fmodapi375win/samples/record/record.exe new file mode 100644 index 0000000..90e980a Binary files /dev/null and b/fmodapi375win/samples/record/record.exe differ diff --git a/fmodapi375win/samples/record/watcom.bat b/fmodapi375win/samples/record/watcom.bat new file mode 100644 index 0000000..d4df00a --- /dev/null +++ b/fmodapi375win/samples/record/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name record.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/simple/Main.cpp b/fmodapi375win/samples/simple/Main.cpp new file mode 100644 index 0000000..c0adeac --- /dev/null +++ b/fmodapi375win/samples/simple/Main.cpp @@ -0,0 +1,452 @@ +/*=============================================================================================== + SIMPLE.EXE + Copyright (c), Firelight Technologies Pty, Ltd 1999-2004. + + This example demonstrates some fundamental FMOD usage, including device enumeration, output + mode selection, user file I/O callbacks, loading and playing samples and a music file, and + calling some runtime manipulation and information functions. +===============================================================================================*/ + +#include +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#elif defined(__linux__) + #include "../../api/inc/wincompat.h" +#endif +#include + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" /* optional */ + +/* + File callbacks +*/ +void * F_CALLBACKAPI myopen(const char *name) +{ + return fopen(name, "rb"); +} + +void F_CALLBACKAPI myclose(void *handle) +{ + fclose((FILE *)handle); +} + +int F_CALLBACKAPI myread(void *buffer, int size, void *handle) +{ + return (int)fread(buffer, 1, size, (FILE *)handle); +} + +int F_CALLBACKAPI myseek(void *handle, int pos, signed char mode) +{ + return fseek((FILE *)handle, pos, mode); +} + +int F_CALLBACKAPI mytell(void *handle) +{ + return ftell((FILE *)handle); +} + +/* + Memory allocation callbacks +*/ +void * F_CALLBACKAPI myalloc(unsigned int size) +{ + printf("FMOD Malloc'ed %d bytes\n", size); + + return malloc(size); +} + +void * F_CALLBACKAPI myrealloc(void *data, unsigned int size) +{ + printf("FMOD Realloced'ed %d bytes\n", size); + + return realloc(data, size); +} + +void F_CALLBACKAPI myfree(void *ptr) +{ + printf("FMOD freed some memory\n"); + + free(ptr); +} + + + +void F_CALLBACKAPI ordercallback(FMUSIC_MODULE *mod, unsigned char param) +{ + printf("\nOrder Callback : param %d\n", param); +} + +void F_CALLBACKAPI instcallback(FMUSIC_MODULE *mod, unsigned char param) +{ + printf("\nInst Callback : param %d\n", param); +} + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main() +{ + FMUSIC_MODULE *mod = 0; + FSOUND_SAMPLE *samp1 = 0, *samp2 = 0, *samp3 = 0; + int key; + int driver, i; + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + /* + SELECT OUTPUT METHOD + */ + + printf("---------------------------------------------------------\n"); + printf("Output Type\n"); + printf("---------------------------------------------------------\n"); +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + printf("1 - Direct Sound\n"); + printf("2 - Windows Multimedia Waveout\n"); + printf("3 - ASIO\n"); +#elif defined(__linux__) + printf("1 - OSS - Open Sound System\n"); + printf("2 - ESD - Elightment Sound Daemon\n"); + printf("3 - ALSA 0.9 - Advanced Linux Sound Architecture\n"); +#endif + + printf("4 - NoSound\n"); + printf("---------------------------------------------------------\n"); /* print driver names */ + printf("Press a corresponding number or ESC to quit\n"); + + + do + { + key = getch(); + } while (key != 27 && key < '1' && key > '4'); + + switch (key) + { +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_ASIO); + break; +#elif defined(__linux__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_OSS); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_ESD); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_ALSA); + break; +#endif + case '4' : FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); + break; + + default : return 1; + } + + /* + Set custom file callbacks? This doesnt have to be done, its just here as an example. + Not MIDI files do not use file callbacks so midi loading will fail. FMUSIC_LoadSongMemory could be used to load the midi. + */ +#if 0 + FSOUND_File_SetCallbacks(myopen, myclose, myread, myseek, mytell); +#endif + + /* + Set custom memory callbacks? This is optional as well of course. + */ +#if 0 + /* user callbacks */ + if (!FSOUND_SetMemorySystem(NULL, 0, myalloc, myrealloc, myfree)) +#else + /* internal memory management - give it 1 mb and no more mallocs will come from fmod */ + if (!FSOUND_SetMemorySystem(malloc(4*1024*1024), 4*1024*1024, NULL, NULL, NULL)) +#endif + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + + /* + SELECT DRIVER + */ + + /* + The following list are the drivers for the output method selected above. + */ + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_ASIO: printf("ASIO"); break; +#elif defined(__linux__) + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("ALSA"); break; +#endif + + }; + + printf(" Driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_GetDriverName(i)); /* print driver names */ + } + printf("---------------------------------------------------------\n"); + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) + { + return 0; + } + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_GetNumDrivers()); + + FSOUND_SetDriver(driver); /* Select sound card (0 = default) */ + + /* + INITIALIZE + */ + if (!FSOUND_Init(44100, 32, FSOUND_INIT_USEDEFAULTMIDISYNTH)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + + /* + LOAD SONG + */ + + /* + The following list are the drivers for the output method selected above. + */ + printf("---------------------------------------------------------\n"); + printf(" Select Music Type\n"); + printf("---------------------------------------------------------\n"); + printf("1 - MOD\n"); + printf("2 - MIDI (Using Default Software Synth)\n"); + printf("---------------------------------------------------------\n"); + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + } while (key != 27 && key < '1' && key > '2'); + + switch (key) + { + case '1' : mod = FMUSIC_LoadSong("../../media/invtro94.s3m"); + break; + case '2' : mod = FMUSIC_LoadSong("../../media/canyon.mid"); + break; + default : return 1; + } + + if (!mod) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + /* + LOAD SAMPLES + */ + + /* PCM,44,100 Hz, 8 Bit, Mono */ + samp1 = FSOUND_Sample_Load(FSOUND_UNMANAGED, "../../media/drumloop.wav", FSOUND_NORMAL | FSOUND_HW2D, 0, 0); /* hardware? why not, just to show it can be done */ + if (!samp1) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + FSOUND_Sample_SetMode(samp1, FSOUND_LOOP_OFF); /* this wav has loop points in it which turns looping on.. turn it off! */ + + /* PCM,22,050 Hz, 16 Bit, Mono */ + samp2 = FSOUND_Sample_Load(FSOUND_UNMANAGED, "../../media/jaguar.wav", FSOUND_NORMAL, 0, 0); + if (!samp2) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + + /* PCM,22,050 Hz, 8 Bit, Stereo */ + samp3 = FSOUND_Sample_Load(FSOUND_UNMANAGED, "../../media/chimes.wav", FSOUND_NORMAL, 0, 0); + if (!samp3) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + + /* + DISPLAY HELP + */ + + printf("FSOUND Output Method : "); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("FSOUND_OUTPUT_NOSOUND\n"); break; + case FSOUND_OUTPUT_WINMM: printf("FSOUND_OUTPUT_WINMM\n"); break; + case FSOUND_OUTPUT_DSOUND: printf("FSOUND_OUTPUT_DSOUND\n"); break; + case FSOUND_OUTPUT_ASIO: printf("FSOUND_OUTPUT_ASIO\n"); break; + case FSOUND_OUTPUT_OSS: printf("FSOUND_OUTPUT_OSS\n"); break; + case FSOUND_OUTPUT_ESD: printf("FSOUND_OUTPUT_ESD\n"); break; + case FSOUND_OUTPUT_ALSA: printf("FSOUND_OUTPUT_ALSA\n"); break; + }; + + printf("FSOUND Mixer : "); + switch (FSOUND_GetMixer()) + { + case FSOUND_MIXER_BLENDMODE: printf("FSOUND_MIXER_BLENDMODE\n"); break; + case FSOUND_MIXER_MMXP5: printf("FSOUND_MIXER_MMXP5\n"); break; + case FSOUND_MIXER_MMXP6: printf("FSOUND_MIXER_MMXP6\n"); break; + case FSOUND_MIXER_QUALITY_FPU: printf("FSOUND_MIXER_QUALITY_FPU\n"); break; + case FSOUND_MIXER_QUALITY_MMXP5: printf("FSOUND_MIXER_QUALITY_MMXP5\n"); break; + case FSOUND_MIXER_QUALITY_MMXP6: printf("FSOUND_MIXER_QUALITY_MMXP6\n"); break; + }; + printf("FSOUND Driver : %s\n", FSOUND_GetDriverName(FSOUND_GetDriver())); + + printf("=========================================================================\n"); + printf("Press 1 Play 16bit sound at any time\n"); + printf(" 2 Play 8bit sound at any time (limited to 3 at a time using FSOUND_Sample_SetMaxPlaybacks)\n"); + printf(" 3 Play 16bit STEREO sound at any time\n"); + printf(" < Rewind mod back 1 order\n"); + printf(" > FastForward mod forward 1 order\n"); + printf(" SPACE Pause/unpause music at any time\n"); + printf(" ESC Quit\n"); + printf("=========================================================================\n"); + printf("Playing \"%s\"...\n", FMUSIC_GetName(mod)); + + { + int count; + for (count=0; count < FMUSIC_GetNumSamples(mod) && count < 20; count+=2) + { + const char *a,*b; + a = FSOUND_Sample_GetName(FMUSIC_GetSample(mod, count)); + b = FSOUND_Sample_GetName(FMUSIC_GetSample(mod, count+1)); + if (!a) + a = ""; + if (!b) + b = ""; + printf("%02d %-33s ", count, a); + printf("%02d %-33s\n", count+1, b); + } + } + + FSOUND_Sample_SetMaxPlaybacks(samp2, 3); + + /* + START PLAYING MUSIC! + */ + FMUSIC_SetOrderCallback(mod, ordercallback, 1); + FMUSIC_SetInstCallback(mod, instcallback, 5); + FMUSIC_SetMasterVolume(mod, 192); + FMUSIC_SetLooping(mod, FALSE); + FMUSIC_PlaySong(mod); + + do + { + key = 0; + + printf("order = %d/%d, row = %d/%d time = %d.%02d finished %d channels = %d cpu = %.02f%% \r", + FMUSIC_GetOrder(mod), + FMUSIC_GetNumOrders(mod), + FMUSIC_GetRow(mod), + FMUSIC_GetPatternLength(mod, FMUSIC_GetOrder(mod)), + FMUSIC_GetTime(mod) / 1000, + FMUSIC_GetTime(mod) % 1000 / 10, + FMUSIC_IsFinished(mod), + FSOUND_GetChannelsPlaying(), + FSOUND_GetCPUUsage()); + + if (kbhit()) + { + key = getch(); + + if (key == ' ') + { + FMUSIC_SetPaused(mod, !FMUSIC_GetPaused(mod)); + } + if (key == '1') + { + FSOUND_PlaySound(FSOUND_FREE, samp1); + } + if (key == '2') + { + int channel; + + channel = FSOUND_PlaySoundEx(FSOUND_FREE, samp2, NULL, TRUE); + FSOUND_SetCurrentPosition(channel, FSOUND_Sample_GetLength(samp2)-1); + FSOUND_SetFrequency(channel, -22050); /* Play it backwards! */ + FSOUND_SetVolume(channel, 255); + FSOUND_SetPan(channel, 255); /* pan it all the way to the right */ + FSOUND_SetPaused(channel, FALSE); + } + if (key == '3') + { + int channel; + + channel = FSOUND_PlaySoundEx(FSOUND_FREE, samp3, NULL, TRUE); + FSOUND_SetPaused(channel, FALSE); + } + if (key == '>') + { + FMUSIC_SetOrder(mod, FMUSIC_GetOrder(mod)+1); + } + if (key == '<') + { + FMUSIC_SetOrder(mod, FMUSIC_GetOrder(mod)-1); + } + } + + Sleep(10); + + } while (key != 27); + + FMUSIC_StopSong(mod); + + printf("\n"); + + /* + CLEANUP AND SHUTDOWN + */ + FSOUND_Sample_Free(samp1); + FSOUND_Sample_Free(samp2); + FSOUND_Sample_Free(samp3); + FMUSIC_FreeSong(mod); + + FSOUND_Close(); + + + return 0; +} + + diff --git a/fmodapi375win/samples/simple/simple.dsp b/fmodapi375win/samples/simple/simple.dsp new file mode 100644 index 0000000..382d814 --- /dev/null +++ b/fmodapi375win/samples/simple/simple.dsp @@ -0,0 +1,154 @@ +# Microsoft Developer Studio Project File - Name="simple" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=simple - Win32 Debug64 +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "simple.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "simple.mak" CFG="simple - Win32 Debug64" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "simple - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "simple - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "simple - Win32 Debug64" (based on "Win32 (x86) Console Application") +!MESSAGE "simple - Win32 Release64" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "simple - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PLATFORM_WINDOWS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"simple.exe" +# SUBTRACT LINK32 /map + +!ELSEIF "$(CFG)" == "simple - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "_DEBUG" /D "PLATFORM_WINDOWS" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib user32.lib /nologo /subsystem:console /debug /machine:IX86 /out:"simple.exe" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "simple - Win32 Debug64" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "simple___Win32_Debug64" +# PROP BASE Intermediate_Dir "simple___Win32_Debug64" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug64" +# PROP Intermediate_Dir "Debug64" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "_DEBUG" /D "PLATFORM_WINDOWS" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "_DEBUG" /D "PLATFORM_WINDOWS" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 ..\..\api\lib\fmodvc.lib user32.lib /nologo /subsystem:console /debug /machine:I386 /out:"simple.exe" /pdbtype:sept +# SUBTRACT BASE LINK32 /map +# ADD LINK32 ..\..\api\lib\fmod64vc.lib /nologo /subsystem:console /debug /machine:IX86 /out:"simple64.exe" /machine:AMD64 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "simple - Win32 Release64" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "simple___Win32_Release64" +# PROP BASE Intermediate_Dir "simple___Win32_Release64" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release64" +# PROP Intermediate_Dir "Release64" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PLATFORM_WINDOWS" /FD /c +# SUBTRACT BASE CPP /YX +# ADD CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "PLATFORM_WINDOWS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"simple.exe" +# SUBTRACT BASE LINK32 /map +# ADD LINK32 ..\..\api\lib\fmod64vc.lib /nologo /subsystem:console /machine:IX86 /out:"simple64.exe" /machine:AMD64 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "simple - Win32 Release" +# Name "simple - Win32 Debug" +# Name "simple - Win32 Debug64" +# Name "simple - Win32 Release64" +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/simple/simple.exe b/fmodapi375win/samples/simple/simple.exe new file mode 100644 index 0000000..a6641ae Binary files /dev/null and b/fmodapi375win/samples/simple/simple.exe differ diff --git a/fmodapi375win/samples/simple/watcom.bat b/fmodapi375win/samples/simple/watcom.bat new file mode 100644 index 0000000..8bc8910 --- /dev/null +++ b/fmodapi375win/samples/simple/watcom.bat @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name simple.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/simplest/Main.cpp b/fmodapi375win/samples/simplest/Main.cpp new file mode 100644 index 0000000..e0158ee --- /dev/null +++ b/fmodapi375win/samples/simplest/Main.cpp @@ -0,0 +1,76 @@ +/*=============================================================================================== + SIMPLEST.EXE + Copyright (c), Firelight Technologies Pty, Ltd, 1999,2000. + + This is the simplest way to play a song through FMOD. It is basically Init, Load, Play! +===============================================================================================*/ + +#include +#include +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#else + #include "../../api/inc/wincompat.h" +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" /* optional */ + +int main() +{ + FMUSIC_MODULE *mod = NULL; + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + exit(1); + } + + /* + INITIALIZE + */ + if (!FSOUND_Init(32000, 64, 0)) + { + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + exit(1); + } + + + /* + LOAD SONG + */ + mod = FMUSIC_LoadSong("../../media/invtro94.s3m"); + if (!mod) + { + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + exit(1); + } + FMUSIC_PlaySong(mod); + + /* + UPDATE INTERFACE + */ + + printf("Press any key to quit\n"); + printf("=========================================================================\n"); + printf("Playing %s...\n", FMUSIC_GetName(mod)); + do + { + printf("order = %d/%d, row = %d/%d channels playing = %d cpu usage = %.02f%% \r", FMUSIC_GetOrder(mod), FMUSIC_GetNumOrders(mod), FMUSIC_GetRow(mod), FMUSIC_GetPatternLength(mod, FMUSIC_GetOrder(mod)), FSOUND_GetChannelsPlaying(), FSOUND_GetCPUUsage()); + Sleep(10); + } while (!kbhit()); + + getch(); + + printf("\n"); + + /* + FREE SONG AND SHUT DOWN + */ + + FMUSIC_FreeSong(mod); + FSOUND_Close(); + + return 0; +} diff --git a/fmodapi375win/samples/simplest/Simplest.dsp b/fmodapi375win/samples/simplest/Simplest.dsp new file mode 100644 index 0000000..8af6467 --- /dev/null +++ b/fmodapi375win/samples/simplest/Simplest.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="simplest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=simplest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Simplest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Simplest.mak" CFG="simplest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "simplest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "simplest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "simplest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"simplest.exe" + +!ELSEIF "$(CFG)" == "simplest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"simplest.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "simplest - Win32 Release" +# Name "simplest - Win32 Debug" +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/simplest/WATCOM.BAT b/fmodapi375win/samples/simplest/WATCOM.BAT new file mode 100644 index 0000000..5b11971 --- /dev/null +++ b/fmodapi375win/samples/simplest/WATCOM.BAT @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name simplest.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/simplest/simplest.exe b/fmodapi375win/samples/simplest/simplest.exe new file mode 100644 index 0000000..179572b Binary files /dev/null and b/fmodapi375win/samples/simplest/simplest.exe differ diff --git a/fmodapi375win/samples/stream/Main.cpp b/fmodapi375win/samples/stream/Main.cpp new file mode 100644 index 0000000..9789ece --- /dev/null +++ b/fmodapi375win/samples/stream/Main.cpp @@ -0,0 +1,303 @@ +//=============================================================================================== +// STREAM.EXE +// Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. +// +// This example takes a command line parameter, a wav/mp2/mp3/ogg etc file, and uses the streamer +// system to play it back. +//=============================================================================================== + +#include +#include +#include + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#else + #include "../../api/inc/wincompat.h" +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" // optional + +int channel = -1; + +void *F_CALLBACKAPI myopen(const char *name) +{ + return (void *)fopen(name, "rb"); +} + +void F_CALLBACKAPI myclose(void *handle) +{ + fclose((FILE *)handle); +} + +int F_CALLBACKAPI myread(void *buffer, int size, void *handle) +{ + return fread(buffer, 1, size, (FILE *)handle); +} + +int F_CALLBACKAPI myseek(void *handle, int pos, signed char mode) +{ + return fseek((FILE *)handle, pos, mode); +} + +int F_CALLBACKAPI mytell(void *handle) +{ + return ftell((FILE *)handle); +} + + +/* +[ + [DESCRIPTION] + End of stream user callback, initialized with FSOUND_Stream_SetEndCallback or + FSOUND_Stream_SetSynchCallback + + [PARAMETERS] + 'stream' A pointer to the stream that ended. + 'buff' This is NULL for end of stream callbacks, or a string for synch callbacks. + 'len' This is reserved and is always 0 for end and synch callbacks. ignore. + 'param' This is the value passed to FSOUND_Stream_SetEndCallback or + FSOUND_Stream_SetSynchCallback as a user data value. + + [RETURN_VALUE] + TRUE or FALSE, the value is ignored. + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char F_CALLBACKAPI endcallback(FSOUND_STREAM *stream, void *buff, int len, void *param) +{ + // end of stream callback doesnt have a 'buff' value, if it doesnt it could be a synch point. + if (buff) + { + printf("\nSYNCHPOINT : \"%s\"\n", buff); + } + else + { + printf("\nSTREAM ENDED!!\n"); + } + + return TRUE; +} + + +/* +[ + [DESCRIPTION] + main entry point into streamer example. + + [PARAMETERS] + 'argc' Number of command line parameters. + 'argv' Parameter list + + [RETURN_VALUE] + void + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main(int argc, char *argv[]) +{ + FSOUND_STREAM *stream; + FSOUND_SAMPLE *sptr; + char key; + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + if (argc < 2) + { + printf("-------------------------------------------------------------\n"); + printf("FMOD Streamer example.\n"); + printf("Copyright (c) Firelight Technologies Pty, Ltd, 1999-2004.\n"); + printf("-------------------------------------------------------------\n"); + printf("Syntax: stream infile.[mp2 mp3 wav ogg wma asf]\n\n"); + return 1; + } + +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); +#elif defined(__linux__) + FSOUND_SetOutput(FSOUND_OUTPUT_OSS); +#endif + + // Set custom file callbacks? This doesnt have to be done, its just here as an example. + FSOUND_File_SetCallbacks(myopen, myclose, myread, myseek, mytell); + + // ========================================================================================== + // SELECT DRIVER + // ========================================================================================== + { + long i,driver=0; + char key; + + // The following list are the drivers for the output method selected above. + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_A3D: printf("A3D"); break; + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightenment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("ALSA"); break; + }; + printf(" Driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_GetDriverName(i)); // print driver names + } + printf("---------------------------------------------------------\n"); // print driver names + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) exit(0); + + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_GetNumDrivers()); + + FSOUND_SetDriver(driver); // Select sound card (0 = default) + } + + // ========================================================================================== + // INITIALIZE + // ========================================================================================== + if (!FSOUND_Init(44100, 32, 0)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + return 1; + } + + FSOUND_Stream_SetBufferSize(1000); + + // ========================================================================================== + // OPEN STREAM (use #if 1 for streaming from memory) + // ========================================================================================== +#if 0 + { + FILE *fp; + int length; + char *data; + + fp = fopen(argv[1], "rb"); + if (!fp) + { + printf("Error!\n"); + printf("File Not Found\n"); + FSOUND_Close(); + return 1; + } + fseek(fp, 0, SEEK_END); + length = ftell(fp); + fseek(fp, 0, SEEK_SET); + + data = (char *)malloc(length); + fread(data, length, 1, fp); + fclose(fp); + + stream = FSOUND_Stream_Open(data, FSOUND_NORMAL | FSOUND_MPEGACCURATE | FSOUND_LOADMEMORY, 0, length); + + // The memory pointer MUST remain valid while streaming! + } +#else + + if (!strnicmp(argv[1], "http:", 5)) + { + printf("Connecting to %s, please wait (this may take some time)....\n", argv[1]); + } + stream = FSOUND_Stream_Open(argv[1], FSOUND_NORMAL | FSOUND_MPEGACCURATE, 0, 0); + if (!stream) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + + return 1; + } + +#endif + + // ========================================================================================== + // SET AN END OF STREAM CALLBACK AND RIFF SYNCH POINTS CALLBACK + // ========================================================================================== + FSOUND_Stream_SetEndCallback(stream, endcallback, 0); + FSOUND_Stream_SetSyncCallback(stream, endcallback, 0); + + + printf("=========================================================================\n"); + printf("Press SPACE to pause/unpause\n"); + printf("Press 'f' to fast forward 2 seconds\n"); + printf("Press ESC to quit\n"); + printf("=========================================================================\n"); + printf("Playing stream...\n\n"); + + sptr = FSOUND_Stream_GetSample(stream); + if (sptr) + { + int freq; + FSOUND_Sample_GetDefaults(sptr, &freq, NULL, NULL, NULL); + printf("Name : %s\n", FSOUND_Sample_GetName(sptr)); + printf("Frequency : %d\n\n", freq); + } + + key = 0; + do + { + if (channel < 0) + { + // ========================================================================================== + // PLAY STREAM + // ========================================================================================== + channel = FSOUND_Stream_PlayEx(FSOUND_FREE, stream, NULL, TRUE); + FSOUND_SetPaused(channel, FALSE); + } + + if (kbhit()) + { + key = getch(); + if (key == ' ') + { + FSOUND_SetPaused(channel, !FSOUND_GetPaused(channel)); + } + if (key == 'f') + { + FSOUND_Stream_SetTime(stream, FSOUND_Stream_GetTime(stream) + 2000); + } + } + + printf("pos %6d/%6d time %02d:%02d/%02d:%02d cpu %5.02f%% \r", FSOUND_Stream_GetPosition(stream), + FSOUND_Stream_GetLength(stream), + FSOUND_Stream_GetTime(stream) / 1000 / 60, + FSOUND_Stream_GetTime(stream) / 1000 % 60, + FSOUND_Stream_GetLengthMs(stream) / 1000 / 60, + FSOUND_Stream_GetLengthMs(stream) / 1000 % 60, + FSOUND_GetCPUUsage()); + + Sleep(10); + + } while (key != 27); + + printf("\n"); + + FSOUND_Stream_Close(stream); + + FSOUND_Close(); + + return 0; +} diff --git a/fmodapi375win/samples/stream/WATCOM.BAT b/fmodapi375win/samples/stream/WATCOM.BAT new file mode 100644 index 0000000..e84f9d9 --- /dev/null +++ b/fmodapi375win/samples/stream/WATCOM.BAT @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name stream.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/stream/runme.bat b/fmodapi375win/samples/stream/runme.bat new file mode 100644 index 0000000..e31e71e --- /dev/null +++ b/fmodapi375win/samples/stream/runme.bat @@ -0,0 +1,6 @@ +@echo off + +echo ==================================================== +echo Stream demo showing off RIFF synch point callbacks!! +echo ==================================================== +stream.exe ../../media/jbtennis.wav diff --git a/fmodapi375win/samples/stream/stream.dsp b/fmodapi375win/samples/stream/stream.dsp new file mode 100644 index 0000000..a998fcc --- /dev/null +++ b/fmodapi375win/samples/stream/stream.dsp @@ -0,0 +1,91 @@ +# Microsoft Developer Studio Project File - Name="stream" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 60000 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=stream - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "stream.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "stream.mak" CFG="stream - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "stream - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "stream - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "stream - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib user32.lib /nologo /subsystem:console /machine:I386 /out:"stream.exe" +# SUBTRACT LINK32 /debug /nodefaultlib + +!ELSEIF "$(CFG)" == "stream - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"stream.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "stream - Win32 Release" +# Name "stream - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/stream/stream.exe b/fmodapi375win/samples/stream/stream.exe new file mode 100644 index 0000000..218adae Binary files /dev/null and b/fmodapi375win/samples/stream/stream.exe differ diff --git a/fmodapi375win/samples/userstream/Main.cpp b/fmodapi375win/samples/userstream/Main.cpp new file mode 100644 index 0000000..e5ce513 --- /dev/null +++ b/fmodapi375win/samples/userstream/Main.cpp @@ -0,0 +1,312 @@ +//=============================================================================================== +// USERSTREAM.EXE +// Copyright (c), Firelight Technologies Pty, Ltd, 1999-2004. +// +// This sample specifically demonstrates the user callback streaming facility, and generates a +// very strange noise! :) +//=============================================================================================== + +#include +#include + +#if defined(WIN32) || defined(_WIN64) || defined(__WATCOMC__) + #include + #include +#else + #include "../../api/inc/wincompat.h" +#endif + +#include "../../api/inc/fmod.h" +#include "../../api/inc/fmod_errors.h" // optional + + +/* +[ + [DESCRIPTION] + User dsp callback for a stream! + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +void * F_CALLBACKAPI dspcallback(void *originalbuffer, void *newbuffer, int length, void *param) +{ + int count; + signed short *stereo16bitbuffer = (signed short *)newbuffer; + + for (count=0; count>2 = 16bit stereo (4 bytes per sample) + { + *stereo16bitbuffer >>= 1; + *(stereo16bitbuffer+1) >>= 1; + + stereo16bitbuffer+=2; + } + + return newbuffer; +} + + +/* +[ + [DESCRIPTION] + User streamer callback + + [PARAMETERS] + 'stream' pointer to the stream supplying the callback + 'buff' pointer to the streamer buffer to fill. + 'len' length of the data block in BYTES + + [RETURN_VALUE] + + [REMARKS] + What a strange noise!!! + (heh heh) + + [SEE_ALSO] +] +*/ +signed char F_CALLBACKAPI streamcallback(FSOUND_STREAM *stream, void *buff, int len, void *param) +{ + int count; + static float t1 = 0, t2 = 0; // time + static float v1 = 0, v2 = 0; // velocity + signed short *stereo16bitbuffer = (signed short *)buff; + + for (count=0; count>2; count++) // >>2 = 16bit stereo (4 bytes per sample) + { + *stereo16bitbuffer++ = (signed short)(sin(t1) * 32767.0f); // left channel + *stereo16bitbuffer++ = (signed short)(sin(t2) * 32767.0f); // right channel + + t1 += 0.01f + v1; + t2 += 0.0142f + v2; + v1 += (float)(sin(t1) * 0.002f); + v2 += (float)(sin(t2) * 0.002f); + } + +// printf("callback : buff = %p, len = %d, time = %.02f param = %d\n", buff, len, (float)FSOUND_Stream_GetTime(stream) / 1000.0f, param); + + return 1; +} + + + +/* +[ + [DESCRIPTION] + End of stream user callback, initialized with FSOUND_Stream_SetEndCallback or + FSOUND_Stream_SetSynchCallback + + [PARAMETERS] + 'stream' A pointer to the stream that ended. + 'buff' This is NULL for end of stream callbacks, or a string for synch callbacks. + 'len' This is reserved and is always 0 for end and synch callbacks. ignore. + 'param' This is the value passed to FSOUND_Stream_SetEndCallback or + FSOUND_Stream_SetSynchCallback as a user data value. + + [RETURN_VALUE] + TRUE or FALSE, the value is ignored. + + [REMARKS] + + [SEE_ALSO] +] +*/ +signed char F_CALLBACKAPI endcallback(FSOUND_STREAM *stream, void *buff, int len, void *param) +{ + // end of stream callback doesnt have a 'buff' value, if it doesnt it could be a synch point. + if (buff) + { + printf("\nSYNCHPOINT : \"%s\"\n", buff); + } + else + { + printf("\nSTREAM ENDED!!\n"); + } + + return TRUE; +} + + + +/* +[ + [DESCRIPTION] + + [PARAMETERS] + + [RETURN_VALUE] + + [REMARKS] + + [SEE_ALSO] +] +*/ +int main() +{ + FSOUND_STREAM *stream; + FSOUND_DSPUNIT *dsp1,*dsp2; + char key; + + if (FSOUND_GetVersion() < FMOD_VERSION) + { + printf("Error : You are using the wrong DLL version! You should be using FMOD %.02f\n", FMOD_VERSION); + return 1; + } + + printf("-------------------------------------------------------------\n"); + printf("FSOUND Streamer example.\n"); + printf("Copyright (c) Firelight Technologies Pty, Ltd, 2001-2004.\n"); + printf("-------------------------------------------------------------\n"); + + + printf("---------------------------------------------------------\n"); + printf("Output Type\n"); + printf("---------------------------------------------------------\n"); +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + printf("1 - Direct Sound\n"); + printf("2 - Windows Multimedia Waveout\n"); + printf("3 - ASIO\n"); +#elif defined(__linux__) + printf("1 - OSS - Open Sound System\n"); + printf("2 - ESD - Elightment Sound Daemon\n"); + printf("3 - ALSA 0.9 - Advanced Linux Sound Architecture\n"); +#endif + printf("4 - NoSound\n"); + printf("---------------------------------------------------------\n"); // print driver names + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + } while (key != 27 && key < '1' && key > '4'); + + switch (key) + { +#if defined(WIN32) || defined(_WIN64) || defined(__CYGWIN32__) || defined(__WATCOMC__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_ASIO); + break; +#elif defined(__linux__) + case '1' : FSOUND_SetOutput(FSOUND_OUTPUT_OSS); + break; + case '2' : FSOUND_SetOutput(FSOUND_OUTPUT_ESD); + break; + case '3' : FSOUND_SetOutput(FSOUND_OUTPUT_ALSA); + break; +#endif + case '4' : FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); + break; + default : exit(0); + } + + // ========================================================================================== + // SELECT DRIVER + // ========================================================================================== + { + int i,driver=0; + char key; + + // The following list are the drivers for the output method selected above. + printf("---------------------------------------------------------\n"); + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: printf("NoSound"); break; + case FSOUND_OUTPUT_WINMM: printf("Windows Multimedia Waveout"); break; + case FSOUND_OUTPUT_DSOUND: printf("Direct Sound"); break; + case FSOUND_OUTPUT_ASIO: printf("ASIO"); break; + case FSOUND_OUTPUT_OSS: printf("Open Sound System"); break; + case FSOUND_OUTPUT_ESD: printf("Enlightment Sound Daemon"); break; + case FSOUND_OUTPUT_ALSA: printf("Alsa"); break; + + }; + printf(" Driver list\n"); + printf("---------------------------------------------------------\n"); + + for (i=0; i < FSOUND_GetNumDrivers(); i++) + { + printf("%d - %s\n", i+1, FSOUND_GetDriverName(i)); // print driver names + } + printf("---------------------------------------------------------\n"); // print driver names + printf("Press a corresponding number or ESC to quit\n"); + + do + { + key = getch(); + if (key == 27) exit(0); + driver = key - '1'; + } while (driver < 0 || driver >= FSOUND_GetNumDrivers()); + + FSOUND_SetDriver(driver); // Select sound card (0 = default) + } + + // ========================================================================================== + // INITIALIZE + // ========================================================================================== + if (!FSOUND_Init(44100, 16, 0)) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + + // ========================================================================================== + // CREATE USER STREAM + // ========================================================================================== + stream = FSOUND_Stream_Create(streamcallback, 6*2048, FSOUND_NORMAL | FSOUND_16BITS | FSOUND_STEREO, 44100, (void *)12345); + if (!stream) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + } + + FSOUND_Stream_SetEndCallback(stream, endcallback, 0); + + dsp1 = FSOUND_Stream_CreateDSP(stream, dspcallback, 0, 0); // priority 0 = it comes first in dsp chain. + dsp2 = FSOUND_Stream_CreateDSP(stream, dspcallback, 1, 0); // priority 1 = it comes last + + printf("Press any key to quit\n"); + printf("=========================================================================\n"); + printf("Playing stream...\n"); + + // ========================================================================================== + // PLAY STREAM + // ========================================================================================== + if (FSOUND_Stream_Play(FSOUND_FREE, stream) == -1) + { + printf("Error!\n"); + printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); + return 1; + + } + + printf("******* Hit a key to active stream DSP unit #1 to halve the stream volume.\n"); + getch(); + + FSOUND_DSP_SetActive(dsp1, 1); + printf("******* Now hit a key to active stream DSP unit #2 to quarter the stream volume.\n"); + getch(); + FSOUND_DSP_SetActive(dsp2, 1); + printf("******* How hit a key to finish.\n"); + + getch(); + + printf("\n"); + + FSOUND_DSP_Free(dsp1); + FSOUND_DSP_Free(dsp2); + + FSOUND_Stream_Close(stream); + + FSOUND_Close(); + + return 0; +} diff --git a/fmodapi375win/samples/userstream/WATCOM.BAT b/fmodapi375win/samples/userstream/WATCOM.BAT new file mode 100644 index 0000000..9f1b692 --- /dev/null +++ b/fmodapi375win/samples/userstream/WATCOM.BAT @@ -0,0 +1,2 @@ +wpp386 main.cpp +wlink system nt name userstream.exe file main.obj library ..\..\api\lib\fmodwc.lib diff --git a/fmodapi375win/samples/userstream/userstream.dsp b/fmodapi375win/samples/userstream/userstream.dsp new file mode 100644 index 0000000..a77545c --- /dev/null +++ b/fmodapi375win/samples/userstream/userstream.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="userstream" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 60000 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=userstream - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "userstream.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "userstream.mak" CFG="userstream - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "userstream - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "userstream - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "userstream - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"userstream.exe" + +!ELSEIF "$(CFG)" == "userstream - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"userstream.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "userstream - Win32 Release" +# Name "userstream - Win32 Debug" +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/samples/userstream/userstream.exe b/fmodapi375win/samples/userstream/userstream.exe new file mode 100644 index 0000000..747c65f Binary files /dev/null and b/fmodapi375win/samples/userstream/userstream.exe differ diff --git a/fmodapi375win/samplesdelphi/3d1/Ex3d1.dpr b/fmodapi375win/samplesdelphi/3d1/Ex3d1.dpr new file mode 100644 index 0000000..c63b465 --- /dev/null +++ b/fmodapi375win/samplesdelphi/3d1/Ex3d1.dpr @@ -0,0 +1,463 @@ +//=============================================================================================== +// ex3D1.exe +// Copyright (c), Firelight Multimedia, 1999. +// +// This test shows EAX, DS3D, A3D and Software all being used together. For vortex cards +// geometry will obstruct and relfect sounds. +// This refreshes the scene every frame. +// To see how to use geometry lists, see sample Ex3D2 which is a slight variation on this one. +// Converted to Delphi by Bocevski Dragan mailto: d_bocevski@yahoo.com +//=============================================================================================== +// History +// +// 2001/09/09 by Steve 'Sly' Williams +// - Updated to version 3.40 +// +// 2000/12/15 by Steve 'Sly' Williams +// - Updated to version 3.30 +// +// 2000/11/14 by Steve 'Sly' Williams +// - Fixed version check +// - Added FMODErrors to uses clause +// - Added check for Delphi 4 to change wVirtualKeyCode to wVirtualScanCode +// +// 2002/02/13 by Steve 'Sly' Williams +// - Updated for FMOD 3.50 +// +// 2002/12/19 by Steve 'Sly' Williams +// - Updated for FMOD 3.61 +//=============================================================================================== +program ex3d1; + +uses + fmod, fmodtypes, fmoderrors, fmodpresets +{$IFDEF MSWINDOWS} + , Windows +{$ENDIF} + ; + +{$APPTYPE CONSOLE} + +const + UPDATETIME = 50; // 50ms update for interface + NUMPOLYS = 4; + +procedure Close(samp1, samp2, samp3: PFSoundSample); +begin + // you dont need to free samples if you let fsound's sample manager look after samples, as + // it will free them all for you. + FSOUND_Sample_Free(samp1); + FSOUND_Sample_Free(samp2); + FSOUND_Sample_Free(samp3); + + FSOUND_Close(); +end; + +var + stream: PFSoundStream; + key, dw: DWORD; + driver: Integer; + enm: TFSoundOutputTypes; + h, h1: THandle; + buf: input_record; + c: coord; + s: String; + samp1: PFSoundSample = nil; + samp2: PFSoundSample = nil; + samp3: PFSoundSample = nil; + openflag, listenerflag: Boolean; + i, channel1, channel2: Longint; + listenerpos: array[0..2] of Single; + lastpos: array[0..2] of Single = (0, 0, 0); + t: Single; + pos, vel: TFSoundVector; + caps: Cardinal; + Channels2D, Channels3D, ChannelsTotal: Integer; + // COORDINATE SYSTEM : X = right, Y = up, Z = forwards. (Left handed) + poly: array[0..NUMPOLYS - 1, 0..3, 0..2] of Single = + ( + (// left wall + (-35.0, -20.0, -20.0), + (-35.0, 20.0, -20.0), + (-35.0, 20.0, 20.0), + (-35.0, -20.0, 20.0) + ), + (// front wall + (-35.0, 20.0, 20.0), + (10.0, 20.0, 20.0), + (10.0, -20.0, 20.0), + (-35.0, -20.0, 20.0) + ), + (// back wall + (-35.0, -20.0, -20.0), + (10.0, -20.0, -20.0), + (10.0, 20.0, -20.0), + (-35.0, 20.0, -20.0) + ), + (// right wall + (10.0, -20.0, -20.0), + (10.0, -20.0, 20.0), + (10.0, 20.0, 20.0), + (10.0, 20.0, -20.0) + ) + ); + doorpoly: array[0..3, 0..2] of Single = + (// hole in right wall + (10.0, -20.0, -5.0), + (10.0, -20.0, 5.0), + (10.0, 20.0, 5.0), + (10.0, 20.0, -5.0) + ); + normal: array[0..NUMPOLYS - 1, 0..2] of Single = + ( + (1.0, 0.0, 0.0), // left wall + (-1.0, 0.0, 0.0), // right wall + (0.0, 0.0, -1.0), // front wall + (0.0, 0.0, 1.0) // back wall + ); +begin + openflag := False; + listenerflag := True; + listenerpos[0] := 0; + listenerpos[1] := 0; + listenerpos[2] := 0; + t := 0; + SetLength(s, 80); + SetConsoleTitle('Example Ex3D1 (3d enviroment)'); + h := GetStdHandle(STD_INPUT_HANDLE); + h1 := GetStdHandle(STD_OUTPUT_HANDLE); + Buf.EventType := Key_Event; + c.X := 1; + c.Y := 23; + if FMOD_VERSION > FSOUND_GetVersion then + begin + WriteLn('Error: You are using FMOD version ', FSOUND_GetVersion: 3: 2, '. You should be using version ', FMOD_VERSION: 3: 2); + Exit; + end; + +// ========================================================================================== +// SELECT OUTPUT METHOD +// ========================================================================================== + + writeln; + writeln('---------------------------------------------------------'); + writeln('Output Type'); + writeln('---------------------------------------------------------'); +{$IFDEF MSWINDOWS} + writeln('1 - Direct Sound'); + writeln('2 - Windows Multimedia Waveout'); + writeln('3 - A3D'); +{$ENDIF} +{$IFDEF LINUX} + writeln('1 - Open Sound System (OSS) (Linux, Solaris, freebsd)'); + writeln('2 - Enlightment Sound Daemon (ESD, Linux, more ...)'); + writeln('3 - Alsa Sound System (Linux)'); +{$ENDIF} + writeln('4 - NoSound'); + writeln('---------------------------------------------------------'); // print driver names + writeln('Press a corresponding number or ESC to quit'); + + repeat + Sleep(50); + FlushConsoleInputBuffer(h); + repeat + ReadConsoleInput(h, buf, 1, dw); + until buf.Event.KeyEvent.bKeyDown = false; +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + case key of +{$IFDEF MSWINDOWS} + ord('1'): FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + ord('2'): FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + ord('3'): FSOUND_SetOutput(FSOUND_OUTPUT_A3D); +{$ENDIF} +{$IFDEF LINUX} + ord('1'): FSOUND_SetOutput(FSOUND_OUTPUT_OSS); + ord('2'): FSOUND_SetOutput(FSOUND_OUTPUT_ESD); + ord('3'): FSOUND_SetOutput(FSOUND_OUTPUT_ALSA); +{$ENDIF} + ord('4'): FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); + 27: exit; + end; + until ((key >= ord('1')) and (key <= ord('4'))); + +// ========================================================================================== +// SELECT DRIVER +// ========================================================================================== + + +// The following list are the drivers for the output method selected above. + writeln('---------------------------------------------------------'); + enm := FSOUND_GetOutput(); + case enm of +{$IFDEF MSWINDOWS} + FSOUND_OUTPUT_WINMM: write('Windows Multimedia Waveout'); + FSOUND_OUTPUT_DSOUND: write('Direct Sound'); + FSOUND_OUTPUT_A3D: write('A3D'); +{$ENDIF} +{$IFDEF LINUX} + FSOUND_OUTPUT_OSS: write('Open Sound System'); + FSOUND_OUTPUT_ESD: write('Enlightenment Sound Daemon'); + FSOUND_OUTPUT_ALSA: write('Alsa'); +{$ENDIF} + FSOUND_OUTPUT_NOSOUND: write('NoSound'); + end; + writeln(' Driver list'); + writeln('---------------------------------------------------------'); + for i := 0 to FSOUND_GetNumDrivers() - 1 do + begin + writeln(i + 1, ' - ', FSOUND_GetDriverName(i)); // print driver names + + FSOUND_GetDriverCaps(i, caps); + + if caps and FSOUND_CAPS_HARDWARE <> 0 then + writeln(' * Driver supports hardware 3D sound!'); + end; + writeln('---------------------------------------------------------'); // print driver names + writeln('Press a corresponding number or ESC to quit'); + repeat + FlushConsoleInputBuffer(h); + repeat + ReadConsoleInput(h, buf, 1, dw); + until buf.Event.KeyEvent.bKeyDown = false; +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if (ord(key) = 27) then exit; + driver := ord(key) - ord('1'); + until ((driver > 0) or (driver <= FSOUND_GetNumDrivers())); + FSOUND_SetDriver(driver); // Select sound card (0 = default) + + FSOUND_GetDriverCaps(FSOUND_GetDriver(), caps); + + writeln('---------------------------------------------------------'); + writeln('Driver capabilities'); + writeln('---------------------------------------------------------'); + if caps = 0 then + begin + WriteLn('- This driver will support software mode only.'); + WriteLn(' It does not properly support 3D sound hardware.'); + end + else if caps and FSOUND_CAPS_HARDWARE <> 0 then + begin + WriteLn(' * Driver supports hardware 3D sound!'); + end; + +// ========================================================================================== +// INITIALIZE +// ========================================================================================== + if not FSOUND_Init(44100, 32, 0) then + begin + writeln('Error! Initializing'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + Close(samp1, samp2, samp3); + Exit; + end; + +// ========================================================================================== +// LOAD SAMPLES +// ========================================================================================== + +// ========================================================================================== +// 3D MONO +// ========================================================================================== + samp1 := FSOUND_Sample_Load(FSOUND_FREE, '../../media/drumloop.wav', FSOUND_HW3D, 0, 0); + if samp1 = nil then + begin + writeln('Error! Loading sample1'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + Close(samp1, samp2, samp3); + Exit; + end; + // increasing mindistance makes it louder in 3d space + FSOUND_Sample_SetMinMaxDistance(samp1, 4.0, 1000.0); + FSOUND_Sample_SetMode(samp1, FSOUND_LOOP_NORMAL); + +// ========================================================================================== +// 3D MONO +// ========================================================================================== + samp2 := FSOUND_Sample_Load(FSOUND_UNMANAGED, '../../media/jaguar.wav', FSOUND_HW3D, 0, 0); + if samp2 = nil then + begin + writeln('Error! Loading sample2'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + Close(samp1, samp2, samp3); + Exit; + end; + // increasing mindistance makes it louder in 3d space + FSOUND_Sample_SetMinMaxDistance(samp2, 3.0, 1000.0); + FSOUND_Sample_SetMode(samp2, FSOUND_LOOP_NORMAL); + +// ========================================================================================== +// 3D STEREO +// ========================================================================================== + samp3 := FSOUND_Sample_Load(FSOUND_UNMANAGED, '../../media/chimes.wav', FSOUND_2D, 0, 0); + if samp3 = nil then + begin + writeln('Error! Loading 16bit Stereo sample'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + Close(samp1, samp2, samp3); + Exit; + end; + +// ========================================================================================== +// DISPLAY HELP +// ========================================================================================== + + write('FSOUND Output Method : '); + case (FSOUND_GetOutput()) of +{$IFDEF MSWINDOWS} + FSOUND_OUTPUT_WINMM: writeln('FSOUND_OUTPUT_WINMM'); + FSOUND_OUTPUT_DSOUND: writeln('FSOUND_OUTPUT_DSOUND'); + FSOUND_OUTPUT_A3D: writeln('FSOUND_OUTPUT_A3D'); +{$ENDIF} +{$IFDEF LINUX} + FSOUND_OUTPUT_OSS: writeln('FSOUND_OUTPUT_OSS'); + FSOUND_OUTPUT_ESD: writeln('FSOUND_OUTPUT_ESD'); + FSOUND_OUTPUT_ALSA: writeln('FSOUND_OUTPUT_ALSA'); +{$ENDIF} + FSOUND_OUTPUT_NOSOUND: writeln('FSOUND_OUTPUT_NOSOUND'); + end; + + write('FSOUND Mixer : '); + case (FSOUND_GetMixer()) of + FSOUND_MIXER_BLENDMODE: writeln('FSOUND_MIXER_BLENDMODE'); + FSOUND_MIXER_MMXP5: writeln('FSOUND_MIXER_MMXP5'); + FSOUND_MIXER_MMXP6: writeln('FSOUND_MIXER_MMXP6'); + FSOUND_MIXER_QUALITY_FPU: writeln('FSOUND_MIXER_QUALITY_FPU'); + FSOUND_MIXER_QUALITY_MMXP5: writeln('FSOUND_MIXER_QUALITY_MMXP5'); + FSOUND_MIXER_QUALITY_MMXP6: writeln('FSOUND_MIXER_QUALITY_MMXP6'); + end; + write('FSOUND Driver : '); + writeln(FSOUND_GetDriverName(FSOUND_GetDriver())); + FSOUND_GetNumHWChannels(Channels2D, Channels3D, ChannelsTotal); + writeln('Hardware 3D channels : ', Channels3D); + + writeln('========================================================================='); + writeln('Press 1 Pause/Unpause 16bit 3D sound at any time'); + writeln(' 2 Pause/Unpause 8bit 3D sound at any time'); + writeln(' 3 Play 16bit STEREO 2D sound at any time'); + writeln(' 4 Change to reverb mode CONCERTHALL (DirectSound/SBLive only)'); + writeln(' 5 Change to reverb mode SEWERPIPE (DirectSound/SBLive only)'); + writeln(' 6 Change to reverb mode PSYCHOTIC (DirectSound/SBLive only)'); + writeln(' 7 Open/Close door on right wall (affects A3D only)'); + writeln(' <- Move listener left (in still mode)'); + writeln(' -> Move listener right (in still mode)'); + writeln(' SPACE SPACE to stop/start listener automatic movement'); + writeln(' ESC Quit'); + writeln('========================================================================='); + +// ========================================================================================== +// PLAY 2 LOOPING SOUNDS +// ========================================================================================== + + + pos.x := -10; pos.y := -0; pos.z := 0; + vel.x := 0; vel.y := 0; vel.z := 0; + channel1 := FSOUND_PlaySoundEx(FSOUND_FREE, samp1, nil, True); + FSOUND_3D_SetAttributes(channel1, @pos, @vel); + FSOUND_SetPaused(channel1, False); + + pos.x := 15; pos.y := -0; pos.z := -0; + vel.x := 0; vel.y := 0; vel.z := 0; + channel2 := FSOUND_PlaySoundEx(FSOUND_FREE, samp2, nil, True); + FSOUND_3D_SetAttributes(channel2, @pos, @vel); + FSOUND_SetPaused(channel2, False); + +// ========================================================================================== +// MAIN LOOP +// ========================================================================================== + + FSOUND_Reverb_SetProperties(FSOUND_PRESET_CONCERTHALL); +// FSOUND_Reverb_SetEnvironmentAdvanced(FSOUND_ENVIRONMENT_HALLWAY, -10000, 0, 0.0, 1.0, 0.5, -10000, .02, -10000, .04, 100.0, 100.0, 5000.0); + + repeat + FlushConsoleInputBuffer(h); + Sleep(50); + PeekConsoleInput(h, buf, 1, dw); + if dw > 0 then + begin +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if (key = ord('1')) then + FSOUND_SetPaused(channel1, not FSOUND_GetPaused(channel1)); + if (key = ord('2')) then + FSOUND_SetPaused(channel2, not FSOUND_GetPaused(channel2)); + if (key = ord('3')) then + FSOUND_PlaySoundEx(FSOUND_FREE, samp3, nil, False); + if (key = ord('4')) then + FSOUND_Reverb_SetProperties(FSOUND_PRESET_CONCERTHALL); + if (key = ord('5')) then + FSOUND_Reverb_SetProperties(FSOUND_PRESET_SEWERPIPE); + if (key = ord('6')) then + FSOUND_Reverb_SetProperties(FSOUND_PRESET_PSYCHOTIC); + if (key = ord('7')) then + openflag := not openflag; + if (key = ord(' ')) then + listenerflag := not listenerflag; + if key = 27 then exit; + if not listenerflag then + begin + if (key = vk_left) then + begin + listenerpos[0] := listenerpos[0] - 1.0; + if (listenerpos[0] < -35) then + listenerpos[0] := -35; + end; + if (key = vk_right) then + begin + listenerpos[0] := listenerpos[0] + 1.0; + if (listenerpos[0] > 30) then + listenerpos[0] := 30; + end; + end; + end; + +// ========================================================================================== +// UPDATE THE LISTENER +// ========================================================================================== + if (listenerflag) then + listenerpos[0] := (sin(t * 0.05) * 33.0); // left right pingpong + + // vel = how far we moved last FRAME (m/f), then time compensate it to SECONDS (m/s). + vel.x := (listenerpos[0] - lastpos[0]) * (1000 / UPDATETIME); + vel.y := (listenerpos[1] - lastpos[1]) * (1000 / UPDATETIME); + vel.z := (listenerpos[2] - lastpos[2]) * (1000 / UPDATETIME); + // store pos for next time + lastpos[0] := listenerpos[0]; + lastpos[1] := listenerpos[1]; + lastpos[2] := listenerpos[2]; + FSOUND_3D_Listener_SetAttributes(@listenerpos[0], @vel.x, 0, 0, 1.0, 0, 1.0, 0); + t := t + (30 * (1.0 / UPDATETIME)); // 50m/s + + // print out a small visual display + SetConsoleCursorPosition(h1, c); + if openflag then + s := '|.......................<1>..................| <2> Door: Open ' + else + s := '|.......................<1>..................| <2> Door: Closed '; + s[trunc(listenerpos[0] + 35)] := 'L'; + if (openflag) then + s[10 + 35] := ':'; + SetConsoleCursorPosition(h1, c); + WriteConsole(h1, pchar(s), length(s) - 1, dw, nil); + s := ' '; + + FSOUND_Update(); + until false; + + WriteLn; + FSOUND_Stream_Close(stream); + + Close(samp1, samp2, samp3); +end. + diff --git a/fmodapi375win/samplesdelphi/FMod/about.dfm b/fmodapi375win/samplesdelphi/FMod/about.dfm new file mode 100644 index 0000000..3ab38fc --- /dev/null +++ b/fmodapi375win/samplesdelphi/FMod/about.dfm @@ -0,0 +1,1551 @@ +object frmAbout: TfrmAbout + Left = 349 + Top = 285 + BorderStyle = bsDialog + Caption = 'FMOD Music System' + ClientHeight = 245 + ClientWidth = 500 + Color = clWhite + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + Position = poMainFormCenter + OnCreate = FormCreate + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object lblCopyright: TLabel + Left = 8 + Top = 88 + Width = 202 + Height = 13 + Caption = 'Copyright '#169' 1994-2003 Firelight Multimedia' + end + object imgLogo: TImage + Left = 0 + Top = 0 + Width = 500 + Height = 86 + Picture.Data = { + 07544269746D61702EAC0000424D2EAC0000000000003604000028000000F401 + 0000560000000100080000000000F8A70000120B0000120B0000000100000001 + 0000080400000E0E060018040000181000002500000025080000180C08001810 + 1000181800002110000025140000291800001821000021210000252500001C1B + 0B003508000035100000351800002B190C002E260000392100002E2608002F27 + 1200421800003929000039200800392612004C15000052210000422900004823 + 0A0032330300423500003B370800363514004E2D00004A39000048330C004636 + 1500523100005D2B00005A3500005A390000552F08006339000056310E005534 + 15003C420C004C420C005A420000524210003C4A0D004D4A0B00455011004E5B + 1000634200005A4A00005A4208005A4214005A4A0C005A4A18005E4E00005A5D + 0D0069330600693912006F4204006D4412006B4A0000774A00006F4A0800734A + 1100635200006B52000063520800635214006F520400844A00006F520C00734F + 1500635A0000675E0200735A000073630000675E08006F5E08006B5D0D006760 + 15007B5200007B5E0000735715007363140081540200895402007B5A08008458 + 11006C6B02007B6308006C6B12007B6B0800846300008C630000886308007E64 + 13007374070073761500846B0400847B0000886D0800846F14008A7E0100847F + 1100946903008F6B0C008E6815008E731200927D04008C8408008E7B1200908A + 0A009D6D0400986D1600998210009A920E00AA790600AC791300B48C0900CB98 + 0E004E442D005B602F0076592300725F3900717621008474220075752C007475 + 45008C6C24008C80220094792200A27E20008B723500958133008E7A41008D7C + 54008A8F210095942600A1921B009D972900B3871800AF892600B5991D00B19D + 2B0092903C0094925300AC8F4000A9935600B19E3900B4AD3800ABA05600B1B0 + 5500CA921900CB952600CFA21D00CEA02D00D1AE2000CFB12D00E0AE2000E2B1 + 2D00CBAA3C00D2B93700E5AF3900E2BD3500C9B14B00C4B35D00E3B64300DBB8 + 5400E7C42F00E4CA3E00D9C84C00ECC84700F5C33D00F4C34E00F9D33D00F7D7 + 4A00DACB5B00E8CF5D00EFC85D00EFD65A00FBCE5200F7D05E00F9D85B00FCE4 + 5700928F7600AD9E7D00BDB67100BAB89000D4BE7100E0D06F00D1C29300DCD4 + 8E00F1CE6D00EFD67300F7DE6300F8D86D00EED38000F1DE7500EDD48D00EBD6 + 9E00F7E46B00FCED6A00F7E17B00FDED7700ECE58600F4F17F00FCDE8900FFF0 + 8000F5E88E00EAE99900FBE59400F9E49F00FFEF8C00FBF78F00F8F39A00FDFD + 9A00D4CCB700E9E6B800F7EBA500F3E5BE00FFEBA900FBEBB900F9E3C800F9EF + C500F5F9A800FFFCAA00F2FAB600FFFBB500F7F7C100FFEFC600FCFCC000FBFF + C600EEE7DB00F9F2D800FFF7CE00F9F7DC00FBFFCE00FFFBDA00F7FFDE00FFFB + E200F7F8ED00F7F3F700F5F7FB00FFFFF700F1F9FF00F7FFFF00FFF7FF00FFFF + FF00111212151E120B15151215121215181518181F181F241D242829241D1E1D + 1E24242A2C2A2C2C1D2424242428282B2B3A24282C241D28282A2B2D3A423A2A + 2A41282A282B2A2B2B2D383838422D3842444C494C4C4C5259596A737A635363 + 6D615363636B6D75767A7A927B94969696A496A4A3A5A5A5A7A9ABABB4ABB4B1 + B4B3B4B3B3B7B3B7BBBEB7B3B3B3B3B3B7B7B3BBB7B7B7B3B3B3B1B1B3B3B3B3 + B6B3B3B4B1B4B0ABB0B4B0B0B0B4ABB0A7B0A6B0A7A7A6A6B0A7A6A6A6A7A6A6 + B0A7A6A6A6A6A6B0A67F7F7F7F7F7F7F7C7FA07C7F7C7E7C78654D45442D2828 + 241E2424242528282A2A2B2B282B2825282B282C2B2C2B2B2B2A3A433A383841 + 38444444444C444444444449444C4C524C524C584952585258525E595C59595E + 645E59596459645C59645959596459595959616459615961616663616367636D + 636D63636D636D696D6D8585898989908D9093959A939C9C9CA3A8A8A8A8AFAE + AFAEAFBAAFB5BABABABAC8BAC8BDBAC8BDC8CAC8BDC8BBC8B9B9C8BABDB9C8BA + BAC8BABABAB3BABAB2B5BAAEB5AFB5B5AEB5AEAEAEAEAAAEAAAEAAAAAAAAAEAA + AAAAA5AAAAA3AAA1A7A1A1A3A1A1A1A17DA17D7D7D7D7D7D7D5D4D41402E241E + 191A140B0B0B0B0B1309130A130F0A130A0F1309130913090F0A0909090A090A + 090A13090A1305130A1113121312150B1A0B1A0B1516111F2626241E211E1E1E + 1E2421241E282828282B2A2D3A2D43322A2B2A2A2B2B322D4638382D2B2B2B2B + 2B3A38383C38383A3A38413841444646464E38423A464B42434E474E474C4E47 + 4C4E4C5E475E5252525961666A637493957A6353636D6D6F76767A89927A927A + 92929696969DA29DA4A5A9A9ABABABABB1B4B1B3B6B3B7B3B7B3BCBEBFBEBFBC + B7B3B7BBB7B7BCB7BEBFBEB7B7B3B3B7B7B7B7B7B7B7B7BCB6B3B1B0B1B4B1B0 + B4B4B0B4B4A7B0B4B0B0A7B0B0B0A6A7B0B0B0B0B0B0A7B0A6A7B0A6A6A6A67F + 7F7F7FA07F7FA07FA07F7E7C7C706566584638322B3A2B3A3A2E322B3A2B3A38 + 3A32323A323A323A383C383C424A43444646464A46464C524C4C524C4E524C5E + 4C5E5E525E595E525E5E58615E5E6661665E6661665E66666166616666616461 + 6659616461616661646164616A6361636763676367636D69676D696D85696769 + 5B856F8589908D8D93959A979C9CA8A8A8ACA8AEAFAEAFB5AFBABABABABABAC8 + BABDC8BDC8BDC8BBCBC8BDC8BDC8BAC8BDC8BABDC8BABABDBABAB3BAB5BAB3BA + B3B5AEB5AFB5AEB3AEAEB5AAAEAAAEAAAEAAAAAAAAAAAAAAA3AAA3AAA3A3A6A1 + A1A1A1A17DA17D7DA17D7D7D7D5F4D5F412E281F1E1A150B160B0B0B0A0A130A + 130913090F0A0A13090A0A13090A090A13060A0A0A090A13090A1309130A1312 + 0B12131215141216121215313A3A35323C25393132313232393A3E444A384E4E + 4C4E4E4E4C46484C4A464C615E5A52464C4E49444852555E5555494E4C4E4C4E + 5E5E5E615E615E524E5E5E555E555A615E676161616166616C6A6A636A6B6C6E + 6A6B6A7B93927576778976857689899092918B92939797979DA49DA5A5A9A9A9 + B1ABB1B3B4B3B7B7B5B7BEB7BEB7BEBEBEBFCACABFBEBEBFBEBEBFBEBFBFCABF + BFB7B7BEB7BFB7BEB7BFB7BEB7B7B7B7B6B7B1B6B3B6B6B3B6B4B4B0B6B4B0B4 + B4B6B0B0B4B0B4B4B0B6B4B4B0B0B0B4A6A6A6A6A6A6A6A2A6A0A27FA0A07FA0 + 7C7C78725F5E4E463C463C443C4A383A384A464B464A4A463C484E494A4C4C54 + 4C4C524C524C5E52525E5E555E5E5A5E5E5A615F615E616161615E666766615F + 666D6666666766666C6663666C666C666C676C666C676C666366616A616A6161 + 6D616D6763676367635B6D5B6D695B845B695B84858486858989898D98919598 + 9C9C9C9DACA8AEACAEAFAFB2BAAFBABAC8BAC8BABAC8C8B9CBC8CBC8CBC8CBC8 + CBC8BDC8BDC8BDC8BDC8BDC8BDB9BABABBB5BAB5B5BAB3B5B3AEB5AEB3AEAEAE + AEAEAEAEAEAAAEAAAEAAAEAAAAAAA5AAA3AAA3A3A1A1A1A1A17DA17DA17DA17D + 7D794D41414026261E1E161A0B0B130B0A130A0F0A130A1309130A0F0A090F09 + 0A090F090A0A0A0F051309090F0A091309130A1213141214121A0B1A141A1233 + 3A332532352525312B313231323232383844384A464C4C44443E38464A4C4C4E + 5E4C4944444946464C554E5E5549484C4A464E525E4C675961525252554E4C52 + 4C4C52525252615961596461646A616A6A6C6A6A6C757A7A776F636353536967 + 696D6F856F899092919797979D9DA49DA5A5A9A9A9B1ABB1B3B3B4B3B7BCB7BC + B7BBB7BFBEBFCABFCABFBEBFB7BFBFBFBEBFBFD1BFBEBFB7BFBEB7BFBFBEBFBF + BFB7B7B7B7B6B3B6B6B3B6BCB6B6B4B6B4B6B4B0B4B6B4B0B0B4B4B4B4B4B4B0 + B4B4B4B0B4B0A6A6A6A2A2A27FA0A0A07FA0A0A07E7D7C73665F4C4E463C383C + 384A3A4A464A474A464A4A4A384A494A49514C4C4C544C555E5255595E525E5E + 5E5E5E5E5E5E5E675E615F616161665E66615F666166666D6666666666666666 + 66666666666666616666666666636463616A616A61616367615B61555B555B62 + 5657565757573F5757628457848489908D989893939D9D9C9D9DACA9AFAEAFAE + AFBAAFBABABABAC5BAC8BDC8C8BDCBC9CBCBC8CBC8CBC8CBC8CBC8C8CBBDC8BD + BDC8BDBABDBABBB5BAB5B5BAB3B5B3B5AEB3B5AEB3AEAEAEB4AEAEB4AEAAAEAA + AEAAAAAAA3AAA3A3A3A1A1A1A17DA17DA17D7D7D7D794D5F41413A2C1E1F1614 + 120E0B0B0A0B0A130913090F0A0F0A0A09130909090913090A0F090A0F0A090A + 09090A090A0A130B0B120B161214160B1A0B111F1B1E1E1526191E1E1E1E1F1E + 24212C2C282C2A413A412A2A2829242A2C2B2D382D2B2A2A2A293A2D3A414A38 + 322B32322B383841444646444438384438384A46444A424A444644444C444C4C + 4C444E4C4E4C5E5A677261554844484C4E4A56606260626868696F6F6F909091 + 7B939D9DA49DA4A5A5A5A9ABABABB1B1B3B3B3B3B3B7BCBBBFBEBFBECABFBBB7 + BBB7BFBFBFB7BFBFBFBFB7B7B7B7BFB7B7B7B7B7B7B7B7B3B3B1B6B6B1B0B6B3 + B0B4B4B1B4B0B6B4B4B4B4B0A7B0B4B0B0B4B0B4B0B0B0B4A7A7A67FA27FA27F + 7FA07FA07FA07F7E7C7D7870664C443832322B3A2B3A3A2B3A383A383A38322B + 32323239383A384A3844444444444649464C4C4C4C49524C494C524C4C525252 + 5258525852585E595E59665E6659645E64616664666459645E64596659646164 + 59616459636161616153615555554C55544A4A4A3F4A3F3C3F353F3F3F575784 + 8486848490909890989D919D9D9D9DB29DACACAFAFAFBAAFBAB9C8BAC8B9C8CB + C8CBCBC8CBCBCBCBCBCBC8CBCBC8CBCBC8CBCBBDCBBBBDB9BDBDBABABCBAB5B5 + B5BAB3AFB5B3AEB5AEAEB5AEAEAEAEAEAEB4AAAEAAABAAA8AAA3A3AAA1A3A1A1 + A195A17DA17DA17D7D7D4D5F41432E2E261E1A1A16120B0B130A130A0F0A130A + 13090F0A130609090F09090F09090F0909090F09090F0909090A130A130B150B + 150B12160B14051B1215120915120B121512151515181E181E1824241D28241E + 1F1E1F2424242C2A2A241D24241E2428282A3A2A2424242824282B382B383838 + 282B2B2B2B28322B2B322B2B322B3238383844383838383A384A825F4E38322B + 32393E3A393C393E3E3F50503F51626068686F6F90907B93939D9796A4A5A5A9 + A9ABA9AAABB1B3B2B3B2BBB9BBB2BBCABBBBB9B9BBBBBBBBBBBBBBBBBBBBBBB7 + B2B7B2BBB7B2BBB7BBB3B3B3B1B1B1B1B1ABB3B3ABB1B4ABABB4B0B0ABABB4AB + A6ABAEB4A7ABABABAEB0ABA7ABA7A2A2A0A07FA0A07EA07EA07E947E7C7C7065 + 5E45383228282528252825242528252825252825252428282B252B2B322D322D + 383838383838443844443844443844484444494C4C4C4C4C5852585258525852 + 585258585258595959595C595259595959585959595952596364615955525255 + 514C54494A544A3F3C3F3C3F353F35373F3F3F5781628484848490989098989D + 989D9D9FB2B2B2B2B2B2B8BABABABAC8BAC8B9CBC8C9C8CBCBCBCBCBCCCBCBCB + C8CBC8CBC8CBC8C8BDBDC8BDBDC8BABCBABCBAB5BAB5B3B5B3AFB5B3B5B3AEB3 + AEB5AEAEAEAEAEAEAEAAAAAAAAA8AAA1A3A3A1A1A1A17DA1A17DA17D7D794D5F + 41434131281F19161A0B0B0B0B130A0A130913090F0A13060A0A0F0909060A03 + 0A030909060A08090909090A0F0A0A0B0A130B120B1A1412161502801A1A2614 + 1E1919191E1E1E2424241E1E242424283A282B2428282424242C3A2A2C2B2528 + 2828322B3A463A2B25252B25323232384C443A3232323232323238443938384A + 3846384649443844484438394F824E3C443244554951483F573F3F393F3F3F3F + 3F5754626268696990909091919D939D9D9DA9A9A9ACB1B2B2B2B2B8B9C5B9B9 + B9BBC5B9C9C9C5C9B8B9C5CAC9C5BBC5D0CDCAC9BBB8BBBBC5CAC9C9BFBBBAC8 + C8B3B7B7B3B5BCB3B2AFB2B5BAAEB3B1B1AEB3B3AAAAB5AEB3B2B2B5B3AEAEAB + AEABA7A3A3A1A1A3A0A1A0A1A07EA0957D946C6C725F463E253A2C253A252525 + 3235254A392B3E283938393832383E444446444444444C444649454C584C584C + 58525E585E525E4C52585958595C61595C645E64646159645964596464645964 + 64596159646159616461595359595353535255524C4E544A4A4A4A3E37393F35 + 3C35373537353737373F628184848486909890989D9F919D9F9DB29FB29FB2B8 + B8BAC8BAC8C8C8B9C9C8CBC8CBCCCBCBD2CBCCCBCBCBC8CBCBC8CBCBC8CBC8BD + C8BDBDC8BDBABABAB5BAB5B5B3B5B3AFB5AFB3B5AEB3AEB3AEB5AEAEAEAEAEAE + AAAAA8AAA3A3A1A1A1A1A1A1A17DA17D7D7D794D5F41422E261E1E19160B130A + 13090A0F0A0F0A0A1309090A0F090A090A090909060908090903090909090809 + 0A090A0B0D0B13140B121314121308878F998F8E8E998F8F8F998F998E9B8E9B + 9B9B999B9B9A8E9B9A8F9A999B9B9B9B9A8F9A9B999B9A9A9A9B9B9A9B9B9A99 + 9A9E9B9E9E9A9E9A9B9B9B9B9B9E9A9E9A9B9E9B9B9B9E9A9B9EAC9B9A9EAD9B + 9A9B9E9A9E9EAC9C9F9A9E9C99989E9E9E9E9D9E9E9E9F9E9F9F9D9F9F9F9FB8 + 9FB8B8B8C5CAB9CAD0CAD0D0D3D1D7D3D3D7D3D5D3D7D7D7DCDCDDDCDDD7D7DC + DDDDDDDDDCDCD7D7DDD7D7DDD7D7D6D3D3D7DCDAD7D3D1D1D3D1D1D3D7D3D3D3 + D2D1D1D1D1D1D1D1BECAD2D3D1D1D1D3CACAD1CAD0D1BEBCBDB5B5BCB4B5B5BC + B4B5AFB3AEABA9A8AF9A9C9B8E8F988E988E988E988E4A394B3E4A4A444A464A + 4E4A4E4C4E4C4C5E4C5E525E585E5E5E5E5E5E5E5E5E5E615E5E61595E595E64 + 5E6459666164666661666C666A66666C666C66666C666366616C616A616A6164 + 61615961595553555556554E564A4A3F4A4A3C373F353735373637373737813F + 848484848690989099909D9F9D9D9FB2B2B2B8B8B8B8BABAC8BAC8C8C8C9C9C9 + D2CBCCCBCCCBCBCCCBCCCBCBCCCBCBC9CCCBCBC8C8C8C8BDC8BDBDBABABABCBA + B5BAB3B5B3B5B5AFB3B5AEB5B3AEB5AEAEB3AEAEAEAEAAAAA3AAA1AAA1A1A1A1 + A1A1A17D957D795F5D47403A2C261E1B19160B130A0F0A130A090A0F05130613 + 09090F0909090903090909030A0F090908090909080A0F0A130B0B12160B121A + 121603272721303325322731263A313A3A323C413B43434B433B463C433C3B43 + 434B4F4A3A3C383C384E4A4E5A4C4A463C4A463C4E4F5A5A5A4E5A4E4B4E4E4B + 4F4A4E4E4C564E565A555E55614E5546566782554949535B6D6367675B6D696D + 6962625B626262625B846262696969699084909098939D9C9D9DA9B2ACB2B2B2 + B2B8B3B8B7B1BBBFBBBECACACACAD1D0CBD0CBCACABBD0BBD0D3D3D0CABBBBCA + CAD0D0CABFBFBEBBBBBBBBBFB7BEBFBFB2B2BBBBBEB3B6B6B1B1B1B7B4B0B4B6 + B1B1B7B6B1B1B6B0B1B4ABA9A6A4A2A4A4A67FA27FA2A2A27E7F7B748B716A60 + 4A4B3B3C4B3C3D4B3C3C8E4B57324B324A2B4A444A4446494E444C4C454C584C + 524C5E5E615C595E595E645E61595E596159665E6666666666666A666666666A + 66666C66666C666C666C666C6166636C6663616161646153616155556156564E + 56564B544A3F3F4B3C3735373537363736373737813784818484879098989F91 + 9F9D9D9FB29FB2B8B8B8B8C5BAC8C8C5C8C8CCCBCCCBD2CCCBCCCBD2C8D2C8D2 + CBCCCBD2CBCBCCCBCBCBC8CBBDC8BDC8BDBDBABDBABCBAB5BAB3B5B3B5B3B5AF + B5B3B5AEB5AEAEAEAEAEAEAAAAA3A3A3A1A1A1A1A1A1A17D7D7D79795F4D432D + 2C281E191A1612130A0F0B0A0F0A130913091309091309090F09090903090309 + 090309090909030A08090A0B0B0B130B1312141213150A2319191426211E1919 + 21241E2128282828282D3A2D3A2A282A282A2B2B3B2D432B2B2B2B25323A444E + 4A463238322B2D384346434F463238384A3839384438443844464A4A494A3E49 + 4C48385A825B323248525153514C5B554C4E55515151504A515050503F575762 + 3F60686869846269909090919C9D9D9DA9A99DB2B2A9B2B3B3B7B7B7BBBEBDBE + BEBFBFD1CACACABECAD1D1CACACAD0CABFD1BEBFBEBEBFBBBFBFBFBBBBBBBFB1 + B7B7B0B1D0B2B2B7B3B6B6B6B1B1B1B7BCB4B0B6B6B1B1B6B6B6B1B6B0B4B1A6 + A2A2A27F7FA27F7FA0A0A0967F7E7C7878706151323A252C31253A2525253C8E + 2B3A3A32253A3E3839443E4644444C464C4C4C4C4C58494C454C4C4C4C4C5252 + 5852525852525859595C615964595C5964595964596459596459645959596459 + 61645961535959595953595253525555555256544C544A4A3F4A3C3E373C3535 + 36363637363736373781378484848490909898989F9F9F9F9FB29FB8B8B8B8C5 + B8C8B9C8C9C8C9CCCBCCD2CBD6CBD6CBD2CBD2CBCCCBD2CBCCD2CBCBC8CBCCCB + C8CBC8BDBDC8BDBDBABDBABAB5BAB5BCBAB3B5B3B5BAB3B5AFB5B5AEAEAEAEAE + AAA8AAA1A3A3A3A1A1A1A17DA17D7D795F5F47403A2C1E1E191A0B1A130B130F + 0B0F0A13050F13090F0A090909090F09090F0909030A0309090A08090A080A08 + 0B0F0B1612131513150B00050B1A09140B150B1212151215181E1D1E1D1E241F + 1E181E1F181E1D2424281D1E18241F1E1D2824282828241F2424282D2A2D2A2A + 2A24242828282A252B2B2A2A2A2A28282B25283228283A433B1D1E3248495148 + 48494B383C464A383E3E3E3E3E39393539313D3C373F3737373F626269696990 + 9093939D9D9DA9B29DB2B2B2B2B3B3BABBBCBBBDB3BBBCBECABEBFBCBBCABBCA + BEBFBEBEBEBDBBBEBEB7B7BFB7BFB7BBB9BBB8B7B7B7B7A59DA9AEB3B3B3B1B6 + ABB1AEB3B6B0B0B6B1B1B3B6B4B4B6B1B0B4ABA7A4A2A2A27F7F7F7FA1A1A1A1 + 7F947D79795D583E2A2424211E242124211E21218F2B2525242528282A282B2B + 2B2D2B382B383838383842444442444444444C45444C4549444C584C58525858 + 5258525C525C595C59595C595E58595259525952595252595253595259525953 + 5252555355555455494A544A3F3E3C3739373535363534353636373637373781 + 3784848487909099909F989F9F9FB8B8B8B8B8C5C5C5C9C8C9C9CCCBCCD2CCD2 + D2D2CCD2D2CCD6D2D2C9D2D2D2CBD2C9D2CBCBCBCBC8CBC8C8CBBDBDBDBDBABD + BABAB5BAB5BCB3BAB3B5BAB3B5B3AFB5AEAEAEAEAEAAAAA8AAA3A3A3A1A1A1A1 + 7DA17D7D795F5F41402B241E1E191A0B160B130B0F0B0A0F1309130913090A0F + 09090A030909060A030909080909090809090A0A0A0A0B0B120B120B12141316 + 1A1E1926191E261B24262626242B2A2A2D3A3B2D25282B252A2B3A4138433A2E + 2E2B3A2C2B3A433A43322B3A2D384243424647463A433A383C444A3844444643 + 43463C463C4A4C39384E4B3B3B2C4A4E55495555555B564F575A564E535E4A49 + 4A50484A3C3C3F373F373F84378462698469909090909D9D9D9DB2A9A9A9B2B2 + B8CABBBBC8CABBBBD0CAD1D0D1D1D0CACACAD0D0D1CAD1D0D3D0CDCBD0CAD1BF + BFBFBFBFBBD0B9D0B7B7BBA5858AACB3BEB7BCBABBBBB3B3B7B4B0B0BBBBBCB7 + B3B6B3B3B3B1B3ABA5A6A2A2A2A27FA0A1A1A196A07F7D8B7D7D6652463A2B25 + 28252B31253A3A253C991E3A25253A3A3C383C423A464646464646464E464C44 + 4C44464C454C4C4C4C584C585258525C52595E595C595959645959645E646459 + 6459645964595961595961596159615961596159615361555355555555565456 + 4A3F4A3C35353535353134363536363637373781378184848487909099989F98 + 9F9F9F9FB8C5B8C5B8C5C5CDC9CCC9CCD2CCD2CCD2D6D2D6D2D2D2CCD2D6CDCC + D2CCD2D2CBCCCBD2CBCBC8C8CBC8C8CBBDBDBDBABDBDBABAB5BAB5BAB5B9B5BA + B3B5BAB3AFB5AEAEAEAEAAAAA8AAA3A3A3A1A1A1957D7D7D79795F5F41412B26 + 251A151A130B160A0B0F0A1309130913090F050A0909060A0903090903090909 + 0908090A08090A080A0B0B130B131214131201223331222525322231312B312B + 3232384A384A4F3C3A3A313A3E3C474E463C3C3A383C3A4A464A5A4B4C3E464A + 444C4C5E5E5A674E484E4A4A4A4A4C4A49524C5E5E4E564A544A483E4A54443C + 4A5B696D6363625B606967846D6963636359555B606255546254575760606260 + 6269848469909090909090919D9D9D9DB2B2B2B2B8B8B8B8C5B9CDCDD0C5CABB + CDD2D2D2D4C5CDCDCDD2D2C9D2D2D2CDCDD2CBCBCACAD1BFD0C5D3C9D0CAB8D2 + E4C49AAEBEBEC8BDBABAB9B9B7B7B1B1B9C8B9BDBBBABBB3B3B3B3B3ABA9A7A5 + A7A2A4A2A6A2A1A2A27FA09494957C6A614E4A383939393939393F3239398D3F + 325B4A3E444A46484C464C4C4C4C4C4C5E4C5E5E5E5E52525E525E5961526159 + 5E61666166666661666166676A6166616A6661716C6166666D6463666366616A + 616A61676A616161616361636763555B53625556564A3F3C3F3C353536303134 + 343434343434363737813781848487909099909F9F989F9F9FC5B8C5C5C5C5C5 + CDCCC9CCCDCCD2CCD6CCD2D6D6D2D6D2D6D2D6D2D6D2CCD6CDD2D2CCCBD2CBCB + CBCBCBCBCBC8CBBDC8BDBAC8BABABABABCBABABABABAB5BAB5B5AFB5AEAEAEAE + AAAAA3AAA1A3A1A1A17DA17D7D79795F474741332E251F141A130B0D130A0F09 + 1306130913090F091309090F0909030903090908090909090A080A0A0A0A0B0B + 120B0B120B120933312125313A3222332F3A263A32323A383C3A3B3121212626 + 253C3A3B322B21313A313A3D4E4B3B32253225394446555E5E5A4E3A253A2531 + 323A3C484A4E5E4E4C4E392525253C3C4B4A353232394A626255564A393F4A57 + 62605B6363674A5650503E353525353F3F3F60606284843F3F37378490909090 + 989D9D9D9D9DB89F9F9C989C9FC4C5B89F9B9A9FADC5D6C5AD9E9CADCCD4C5C4 + 9E9E999FC4D6C9D7D2D0D2B9AC9C999CACC5CBC5CFF78EAFCAB9B89E9A9A9A9C + B5BCB1A89A9AACB8B9B8AC9A9597ACAFA8A2A3A1A3A2947EA2A29696A6A2A07E + 9496786A5948443C3E3A3E39393932574A3E4A8D393C484A464A4C4E4E554E5E + 4E5E555E4E5E67675E615E5E5E615E615E53615961645E666166616661666666 + 6666666661666171726A61726C666164616A616164616A6166636663676A6363 + 6367635B61555656544A3F393C35353535353430313430343434343436813781 + 8184848790879899999F9F9F9FC2B8C2B8C5C5C5C5CDCCCCCCD2CCD6D2D6D4D6 + CCD6D6CCD6CCD6D8D6D6D6D2D6D2D6D2D2D2C9D2C8CCCBCBCCCBCBCBC8BDBDBD + C8BDBABDB9BDBABDBABABABAB5BAB5B5AFB5AEAEAAA8AAA3A3A3A1A1A195947D + 7D79795F885F434333262615160B130B0A0F0A0F09070B13091309090A0F0909 + 090F05030903090908090908090A080B0D0A0B0B0B0B12160B12031B1A221A19 + 1E1513131A1813102426181A152F1B050914051312271B180A120B11111F101F + 2F2C110B12121215243A38433A3B3A1212160B1214151F1E263B38383A1E1E15 + 0A0B131B2F1A120E2614263382261E1E1919193D3131254B4C3C261231262019 + 0E161A26223E35503F3530230E2020343781373798989081849D9F9884374B57 + 8299C29887828382879EC7C2865781679EAD9E8681814B8699B8CDD3D0D0C59A + 8257814F83ACC4C599C6CF8EC5B88C83824B4B679CC89A5E5A4B5B9AAD9A8C3D + 825A889B9A7D7994AA78598B967C8A5D94A07E948B957059494A3A3A2C2B262B + 312B31253B3D213A8E3A253C4A322B38383846444446444946494E884E5A4C4C + 4E5E4C4C4C5E4C5E4C5E595E5952585952595E59616159616461597261646166 + 8A61596659526366616A61616A616A636A61636D636363636362555654544A3F + 39353535213425303030303434343434343481348181818487849990999F999F + 9FC2C2B8C5C2C5C5C7C5C9CCD4CCD6CCD6CCD6D6D8D6D6D6D6D8D6D6D4D6D6D6 + D6D6D2D6CCD2D6CDD2D2CBCBCBC8CBC8CBC8CBC8BDC8BDBAC8BDBABDBDBABABD + BABABAB5B5AFB5AEAEAEA8A3AAA1A3A1A1A17DA07D7D79795F5F4F433B2C261E + 1A0B0B130D0A0A0F0913060A0A0F0913090A090F09090F0906090A090909030A + 0F0A0A090A0A0B130B120B120B14020A0B110B16120BE38F071B8FF0041F1AE1 + C00A83F9F7F7F0E0C01A1BF0FBFBFEF98313E0C11F1FC3F9F8F7F1831F2A3A28 + 4B1E15E0F1F7FBF7F18080E6831F24283B2FE0FBFFFEF087071BE3F3F5F5C680 + 1A81E3F7F7ECE0C31BC6C32E331EC3E01717C6F8F8F2C6C03A352532252527F0 + F6F8FCC33436E0C3379081EA9F999884C7F6F6F4E387988FE1F7F6EFE08FC298 + C7F4F4EB99AD9EEAF3F8F6EF9BADCDCACACDADC1EFF6F8F6E38EC4C487F1E68E + B89FC2E3F4F5F5EA88AC8CCFEFF4EA999999E3F5F7F4CF8E8DC5CC9C9579EB8A + 9694C4CE7DA17E7D7D955D5E383828282421242124211E1E212124193D8C2B21 + 283232383238322D323838384838445A464E443838444438444444444C4C5849 + 4C524C4C4C5252525258525252524C6652525861734C52525252595253596164 + 6163616A61636A6363636355635555544A4A4A39353935253530213030212030 + 342034343434348134818181848790999099999F9F9FC2B8C2C5C5C5C5C7CDCC + CCCCD4CED6D4D6D6CEDAD6D6DAD6CEDAD6D6D8CED6D6D4D6D2D6D2D6D2CCD2CC + CBD2CBCBCCCBCBCBC8CBBDC8BBBDC8BDC8BDBDC8BDBABAB5AFB5AFAEAFAAA8AA + A8A3A3A1A1A1957D7D7D79795F5F47433A2E211A15140B0B0F0A0F0A070A0F13 + 090913090A0F09090909090809090909080A0908090A090D0A0A0B0B12130B14 + 120B031B1B1516191E1AF08F171B8FF0121B1BF08F17E0C3270EC3FB8723C3F0 + 801717C1F011C3C32F2FF8802726C1F1243B2B4A3C2599F28180230FC0F6F7C6 + 333D4A3A2CC6F0801B07E0E007E0C63D8183F0C180C1E6833DC1FBC327C3C33B + 4B3DC6C317C0E18080C0FBE025353C3C4A31C6C3808080F0C334C3C3818784E1 + 9F9999C3EA9999C0E0F18FC7D9C2C7C7EACFC2C1EFC1C2F5C7C4E5ECC3C3C0E0 + E2C2C9D7CBCDC4ECE1C1C2C0F4C6AD9FC0F3F5C19DADE8E1C1C299E1DB9EC1F2 + 9E9FF4C699E0C7C09F9EEEC79CC5C99A9A88F55AA892CECE79A196949595705C + 4C4A32322B2B2532253225393C323C32253C8D394832323E4C32444844484449 + 4C4C5B6D5A675E5A52494C524C525252525E595E59595E595E595E595E596159 + 5E595E6D615E59728A59596159616461616A63616A636A6A636A636C63636361 + 53555556514A4A3E373235313521353021302030203030343434343436813781 + 84878487989998999F9FC39FC2C5B8C7C5C5C7CDCED4CCD6CEDACED6D8CEDADA + D6CEDAD6D8CEDAD6D8D6D6D8CED6D4D6CCD6D2D2CCD2CCCBCBCCCBC8CBC8CBC8 + C8C8CBC8C8CBC8BDBAC8BABDBAB5AFB5AEAEAEA8AAA3A3A3A1A195A07D8B7979 + 5F82474B3A2E261E160B160B0D0A0F0913070A0A13090F0913090F0909060A03 + 090F0909090908090A0F0A0A0A0D0B0B0B0B120B13120327332727273126E38F + 23808FF01B3B23E38F17F0C0198027F08F808F80131700C0F012C3C32F9BF080 + 278180F24B5A5A854B39C6C327802317C0F2C63D3B4B4F4B3C878307178087F0 + 80E1C0818427C3C380C3C63D863DE0C380C3C6805731C3C327C3E0808027E0C3 + 334A5B574E3CE1C0012307878181C3C3819981E1C09999C3C33687878FC08FE8 + C2C2D4C4EEE2C6C3EFC1D9E3E4C7C2C1878787C0EEC4D8D7D3D2CEC699878781 + C7CFC698E1E0E0C698B8C399818781C6C7C4C1E399C7E8D999EAC181868199C1 + 93C5C79AAC8CF583A891C6C7A1A1A396979A7C66674C4E4A3E4A384A3C3E4A3A + 3E4A574A393A568D385B3E4C5B444C525E52524C52615A856D8867675E4C615E + 5561596161666D66615F6161645E666166616661666161726D5F61738B5E6161 + 616A676A666D6C6C6D6C6D736F6C6D636C636D6361635555544A543C3E353C35 + 253130253021302022303030233434343480378181878487909998999F9F9F9F + C2C5C2B8C7C5C5C7D2CED6CED4D6D8CEDAD6DACEDBDADACEDADADACEDADACED8 + D6D8D6D4D6CED2D6D2D2D2CCD2CBD2CBCCCBC8CBC8CBC8CBC8CBC8CBC8BDC8BA + BABAAFB5AFAEAEA8AAA8A3A3A1A1A1957D7D8B79725F4F433B3A261F16140B13 + 0D0A0F0A070A130F0A13090A1309090F0909030909090F0909090908090A0A08 + 0B0A0B0B13120B0B140B0927333130263122F08F2327C0F0168017E6C016E6C0 + 1A361BF08F2713C0C3C1E0F9C380C3C32C9BF017312731274B46564E3C3AC3C3 + 0E270FE0F3F1C63D824B4A4A3D14C0C3C3C0FDC380E1C0378381E0C336C6C657 + 8657C3C380C3C180573CC3C380C3C1808036C3C33D3F544B5431E1E0C3C3C3C3 + C080C3E0818781E1C0C0C0C3F0E0E0C3C3E087E1C2C3D4C4C3C6C4C2E7C1CFCF + E2C699C2C3E0E0F6E2C7D3CDDDDDC28FC3C6E0E1EFE1C28EEFC2C1F68D988FC3 + E0E0E0F4C7C4C6E69BC7C7C69FE1E0E0E0E0C3C199C7C79B9E88F7879A93C6C6 + 95A5A2969CA37971674E4A4E4A3A3E3C3E3C4A393C563A395A4A4A2B994C5A32 + 5A5A4C564E4C4E554E676788828885675A5E5A5E5E675E5E67676D6661616161 + 6161616161666161616661886C6167738A6172616663666C676C6C6C6F6C736B + 6D736C6F636D636363615B5555544A4A3C393535253525302530302122223023 + 30233434343681368181848787879899989FC39F9FC2C5C7C5C5D4C5C7D4CED6 + CFD6DACEDACFDADADACEDBDADACFDAD8DADADADADAD8DAD6D4D6D6D6D2D6CCD2 + D2CCD2CBC9CBCBC9CBC9CBCBCCCBC8C8CBC8C8BDBABABAAFB5AFAEAEA8AAA8A3 + A19AA195958B8B725F5A473C3B2E26261A160B0E130A0F090F09130913090F13 + 090F09090909030909080909090A08090A080A0A0A0B0B0B0B0B160B120B0320 + 1E1914201E14E38F0F138FE0171B17F08F13F08F1F271AE6C01FC1F9C1E0C3C0 + 1B1BC3E02C8FF00827251414254E384A3B3AC3E60A23F0F183C3C6244B2B3231 + 25C1F7C3C3E0C02323E78F373036C3C380C3C2825735C3C323C3C3172622C3C3 + 16C3C3173016C3C3263535323921F0E0C3C3E0E0C323C3C3238180F0878787C3 + F0C3E0F0E0F087EAC1999F998E99C2C0EC8FC3C2C2C4C3F5E0F0E0E099CCDDD3 + D1D4ADE0F1E0E0E0C399C2C2EFC3C1EFC28CE1F0E0E0E0C0C29BC1F0819E9FC4 + 9FEDE0E0F0C3F0E099C3C4838E82F8808D67C6C78BABA196A3977D65723E383A + 322532253225253C3C3A2B323A253C3A328E384A2A4B384E38444E464A5A5A67 + 88828867464E4C4C4C4C524E595E67595259595E596159595E53615961595E73 + 675261728A616D6161616663666D6A6A6A636C6C636B6D636C63636161555555 + 504A4A4A393C3539313525313025222120222220233020343436813681813787 + 87908799999F9F9FC29FC2B8C2C7C5C7C9CECED4CEDACEDADADADADBDADBDADB + DADBDADBDADADADADADADAD8DAD8D6D6D6D8D2D6CCD2D2CCD2CBCCCBCBC9CBCC + CBCBCCCBC8CCCBBDBABABABAAFB5AFAEAEACAAA3A3A3A1A1957D79724F473833 + 2B2626191B14130E0A0F0A0F090F130913090A0A09090A0F09090F0906090A09 + 080909090F0A0A080B0A0B0B13120B160B14020B0B0B0E0B1409F0C00702C0FE + 130704F0C01BF08F1A121BE08F1FC3C3070706878F13C3C31F8EF007041223F7 + 2C284F282B192FE6F0F8E0131A271E2A2428242426C3C117010187C023E7C019 + 1E0BE0C336C6C63D3A3CC3E00DE0E1131311C3E023C3E0002301E0C31B252231 + 2126F08F071307E0C117C3C10F200FE0873481C3E0808181C0F099EAC1878183 + CFE1C0C2E080838F9EC2CFC3818781C0C6C7CDD3CDD8C2F1C1838787C1C6C1CF + E89FC2D9E88CF0C1838F81C39F9BC1E627838CADC2E5C3838381E0E0C1D9E13D + 3D83F98F4B4BC6CF8B7F9694A397785D67382528252421242121251E19242525 + 1E3A25212B258E4E24322B38322B383E384E4E5A5A5B4E553838484438494449 + 4C5852524C494C524C524C52524C52524C524C725E4961677161735E52615961 + 6A596C6A636B6C6A6C6C636C636A636161535B5155484A3E3935393532312530 + 253025222130222020232334233436348137818481848798989FC09F9FC2C2B8 + C7B8C7D4C7CCD4CED8CEDACFDADADBDADBDADBDBDBDADBDADBDADBDADADEDADA + DAD8DAD6D6D6D6D6D2D6D2D2D2D2D2C9D2CBD6CBD6CBD2CBCBCBC8C8BDBAB9BA + AFB3AFAFAEAEAEA8A8A3A19A958B725F5E46322B26211E1A1A160B0E130F0B0A + 0F09130613090F090A0F09090903090908090F090A09030A080A0A0A0D0A130B + 12131412130B03161B1E19191519F1FBE0C3F0F1F1C3E0F9261AE6C11D251FF3 + C11EC3F9C3C3E0F7C127C6E04126F7E0C6C3E6CF3B38382D3A2F1EC1F8C0271B + 27153B2B44463B2F2FC1F8C3C3E0F8C181C1F4C6C3E1F28F3DCFC73D8632CFC6 + 80C6F7E6C3E0F78F2787F7E0C1F1F8C32331313D333DC1FBC3C3E0F387C1F8F3 + F0E0E0F8F0E1C399F6C7C3C3F6E0C2D9EFE0D9CFF6C6C1ECF7E7F2ECD9C6D9F7 + E0C6E1F6E2C5D5D3D7CEC7F2F3E0C6E1F5C7C2F2C7D4C5C6EEC1E7F1E0CFE1F5 + C5C2E5F7EDEEEEC4C7CFF5E0C7E1F5C3C2D9F5E5CFE5F5F2CECEEFC2A3A3A396 + A8A17A6572443A3A322B312B253A252B4B2B254F252B4B323C32388D383E444A + 44324E4938565A6785826767495E4C4C52525852616167595952595252525952 + 5959595E5259618A615E726D6D738A6C616A616C736A6C6C766C766E736F6C6C + 686D63636163555555564A4A4A3C393535253525252522253031302320233036 + 343436348136818784818790879F9F9F9FC2C2C2C5C2C7C5C7D4CECED8CFDADA + DBCFDADBDBDBDBDBDBDBDBDBDBDBDBDBDBDBDADEDADADAD8DAD8DAD6D8D6D6D6 + D2D2D2D2CCD2D2CCD2D2CCCBCCCBCBC8C8BABAAFBAAFAEAEAFA8AEA8A3A1A195 + 7D79725F4F4E3A3A2C211E1B140B160B0E13080F0A0F0A0A090A090909090F09 + 0909090309090909090908090A0813090B0B0B0B16120B16121609273333263B + 3A2C8F8EC6CFC33DC0C6CF8E3B438F823843469A82434B8FCFC6CFC13A3B8E87 + 433D83C3C6CFC24F4E5E5A4C473C3BE6C127271BE082823C4E4E4E3C3D3DC0C6 + E0CF9E8484849BCECFCF9B8585989A5B5B8598995B8E99C1CFCF9B82573D87E0 + C6C1C3C6274B823D4B4B4BC0C6CFC68F8187C6E3C0C087F8C3C09990C3D9D9D9 + C7C2C5D4D4E8E9E8D9C7C6E1F4C7D9EBE2C7D9CFEEEDE5E8D9D4DCDDDFD8E2CF + E5E5EBE5E4DAD9DED8D9D4CCDACEC7E4E4EBE5D9C7C5E1EEC7CEDED8CED8DBE5 + E4E9C7CCD4C5C5DADADBADB8DCD7BAA8A5A4A3A1A5A87D708B59554C4A3E383C + 443C3E4B4A484E394A464A3E4A564C4E8D5E5E49674C5E4688888588678A6788 + 525E59615E6161615E6D72616D6661536A616A64616A616A6166678A6C6D7372 + 738A8B6D716C6C6C766C747674767A767A767676736373636363635B55544E54 + 4A4A3C393931352531253121223D222230223027233680348136368181848487 + 879F9F99C29FC2C2B8C7C5C5C7CCCED9CEDADBCFDADBDBDBDBE2DBE2DBE3DBE4 + E2DBE4DBDBDBE2DBDBDEDADBDADADADADAD8D8D6D8D6CED2D6D2D6D2CCD2D2D2 + D2C9C9C8C8B9BABAAFAEBAAFAEAEA8A8AAA89A958B79795F5F4B383325211F19 + 16160B0D130B0F0A091309130A0F0A0A090A0A0F090A08090A09080909080909 + 0F0A0B0B130B0B140B0B1A0B141209273127332B312A33283D3D2E254F4B434F + 3B2A4F4B38322A5A464A433A432F43324F432A413C4B2E823A4B4F4A4E5B5E5B + 4A3D3DE3C1051B0BEDC13B4E5A383E464B4F823B4B578962636961858888856D + 63856D676354556D54855A82824B823E5A574B823D30C6C633334B5A4A4E3C57 + 4B4B5B4B354BE0C30E8080F0C03481849F999F9FB8C5C5C5C5CDC5D4C5C7D9CF + E9C7DEDED8D8DED8E2DADADAD8DCDDDCDDD8DEDAD9DEE4DCDEDADCDED8D5D2D5 + DCCDCDDDD8DCDED4C7C7DDE8C5D4D5D5D4D4CCD8C9CCCDCDD0BBACB2AFA8AEA8 + AEABA5A3A7A3A4A2A8A87D738B59614A443E3C4A3A4A43565A4A4E3E464A384A + 4A4C4A3E678D4C494E5A5A5B8D828C858885888A5E5F595E5E5E5E67596D6D5E + 6D6161596C6161616A6161665E61618A6C678A6D738A8A6C73736C73766C746C + 76747576926E736C6F6C6D63536A615555554A4A4A4A4A3F3E3C3A3531313122 + 213D223033232236233634233636368181818487849FC0999FC2C2C2C2C2C7C5 + C7D4CEDACEDBCEDBCFDBDBDBDBDBE2DBE2E2DBDBE2E2E2E4E2E4E2DBE2DBDBDA + D9DADBD8DADADADAD6D8D6D6D8D6D4D6D2D4CCD2CCD2C9C9C8C8C8BAAFBAAFAF + AFAFAAA8A8A3A1957979885F5F4F3A3A26261E161614130E130D130A13090F0A + 0A13090F0A090F0A09090909090F090A0309090A090A0F0B0B0B13140B140B16 + 0B1400171619191E1E1E261E1A1E192F26261E3D3B24282C28283A3A283B4126 + 242C2C3D2C3AC6C6402F412E2424433A4646253A252F33C3E6F7E6F7F3261E3D + 283A323E2B823C1E4B4B5B63686363676D67636C536153615B525561485B484A + 384656324A4B3C313133CFC33C3C3239384A3A3B31253A3C333383F7F2E080C3 + F8EAC286909F9F9F9FB8B8C5B8B8C5CDCDCDD4D4DDC9D5D2D5DCD8D2D8D2D2D5 + D7D2D7D7D7D5DCD8D5D6D7D2D7D7D7D7D5D3D0D1D1D1CAD1D3D3CDD5CDCDCDD5 + B8BBD1D0D1D1D3D5D0D1CABFD1BFB1B0A9ABA9A5A3A5A2A5A6A5A3A2A8A39270 + 8B584E3A322A2C3C2E252B3D433A3A2B3B383A4A38394632394E8D4F4E384A43 + 8E4E888582885A88584C4C584C5E4C674C67675E675E52525E59595E595E5E52 + 5E525E8861728A6D72887367736D6C71736F746C746E736E7A766A6F6C636363 + 6353556155514E4A4A4A4A39353E393132313D31223322273022273620342734 + 8034348181378186879FC0999FC19FC2C2C5C5C7C7CCC7D8CFDBDBDBDBDBDBE3 + DBE2E4DBE2E2E4E3DBE4E5DBE4E4E4E8E4E2DBDEDBE2DADEDBDADADEDADADADA + D6D8D6D8D6D8D6D4D6D2CCD2C9C8C8C8BAAFBAAFBAAEAFAEA8A8A195958B8888 + 5F4F3C3B31251E1B150B160B16130D130A13090F0A0A090A090A0A090A08090A + 08090A09080909090F0A0A130B140B0B120B140B150B010B080B121514121512 + 14151E15151E1E2415151515151E1E15241E241E1E1F1E1D2C248C8E1D15241D + 242C2A2A2A2A2528243B151E838FC0832F1E3B1E2824252421381E2B5B4E5155 + 485152536D616A5353525249494C494844483848323E32323225322525318286 + 2425252B2124252B322524252521193DC08E303D87C2998484989D9D9D9FB2B2 + B8C5BBC5C5CDC5CDCDCDD5CDD2D3D2D2D2D2CDD3D2D3D3D3D5D5D7D5D5D2DCD0 + D2D3D5D7D5D3D0BBD1D1CAD1D1D3D3D5D0D0D0D0BBBBD1D1D1D1D0D0D0D1BFBB + B7BFB0B0A5A7A5A5A7A5A5A2A4A4A3A2A3A38B717A584E252A25242E25241E3A + 3B2825283A2B252432322B4A38284A8D3832385A884B8282825A678244444544 + 444952674C5E67446D4C4C49524C52525258524C584C52725E6788726D728561 + 8A6A6D6A716C6C6E6C6E7473926A73766D6A63636153535B534C5B4A444A4A32 + 3935322531353D30313D22303322302720343423363434813681818487999F99 + 99C29F9FC2C5C2C7C5CECECFCEDBCFDBDBDBDBDBDBE2E2E2E4E2E4E2E4E2E4E5 + E2E4E4E4E4E8E4E2E2DEDBE2DAE4DADADEDADADADADADADAD8DAD8D6CED6D6D2 + CCCBC8C8BABAAFBAAFAFAEAEA8A89A958B8B7988724F4B3A2E26221A16140B16 + 13160A0F0A0A1309090F0A090F090A0F09090909090A09080908090A090A130D + 0B0B13140B1412160B1408161620191E211E21212115251E25322532253A283A + 25282B323C2B253A24252B3A3838384E2A462B283838464E4C4C453238383838 + 2B3C383A2A38462B462B3839464E253E5A55676C6D616A636A6A6B595364534C + 525E5E5E5E53555548493E55483E4A323A32213A254E324A3232383238483939 + 39323C35323135573F3F606990989D9D9FB2B2B2B8BBC5C9C9CCCDD4CDD4DCD4 + DAD8DCD8D8D8D7D8DCD4D4DCDDD8D8DED4D8DDD8D2DDDCD8DEDCD5D3D3D5D0D5 + D7D5D7DCD4CDCDD3D0CAD5D3D5CDD5CDD0CDD3D1D0D1B3B1B1ABABABA5A4A7A5 + A2A4A5A2A8A3957A8A615E393932254B2B32254B5B3232324B383E3248383249 + 493E44329A39384E85828585676788724C52524C5849526D5261635273525952 + 53525959535959525953596D596A8A6D7373766C8B6A766A6E73747374737476 + 9773767A6D6D6C636C6161635B525B56484A4A48393C393132333D31314B2226 + 31222733223427303623348137378181869E999999C299C2C2C2C7C5C7C7CECE + DBCFDBDBCFDBE4DBE3DBE4E2E5E2E5E2E5E2E5E2E5E2E4E8E4E2E4E2E2E2E2E2 + DEDBDEDBDADBDADADADADADADADADAD8DACED6D6CCCCC9C8C8C4BAAFBAAFAFAE + A8AAA195958B88885F82433C3324261916130E0B130D130A0F0A0A13090A090A + 09090A090A08090A09090F090A0909080A130A0B130B140B160B141216120327 + 313331312A333A3C3A3A3A3B4A434A4A4A383A433232434A464A3A4E4A433238 + 4F5A5E4E4C464644465A5E5A5E5558445E444C5E4C4C5A4C5E4E454C5E5A4C32 + 5B4C44676D856D6D8A73768A6B76766B766C6D735F726D6161616167635B5E56 + 4C564E4E4E5A5A5A394A3E4A444A4C445A67564E4A574A4B573F396250846969 + 84939D9DB2B2B2BBCAC5D0CDD6D2D2D5D8D8DADADEE4DEDEDCDDDADCDFDAD8DE + DFE4DEDEDED8DEDDD8DEDFDEDEDEDDD6D7DDD2D7DDDDDDDED8DDD5DCD3D2D0DC + D7DDDCDCDCD7D7D0D0D1BBB3B3B1B1ABA7A4B0B0B0A7A5A7B2AA9C8B8B738549 + 5B5B395B3C3E4A4B674A564C854B5A674E494E494861674C499E325B9A5B858C + 85678A855E67615E61596173616D73618B636A616A646A6A6A6463646164618A + 637389738A768B76936C7A7A76747A76747A76929C7A768B6D76736D636D6367 + 6D55855A554A4A4A4A3C39353A3C57273D812431272136802127342336303080 + 3680378186C0999999C29F9FC2C2C5C4C7C7CED9CEDBDBCFE4E1DBDBE4E5E2E5 + E4E5E2E5E4E5E2E5E2E5E4E5E4E4E2E4E4E2E4E2E2E2E2E4DEDBDADBDEDADBDA + DBDADADBDAD8DAD6D6CCCCC8C8C8C4BABAAFBAAFAEA89A95958B7988724F4F3C + 3326261A19160B0B160A130A090F0A0A0A0A0F050A0A0F0A09090908090A090F + 09080A090A0A0F0B0B14130B140B1A140B1609272F33263A333A3A252E3C3A3A + 38435A443243384343464F434E4F4E463C2D3C444B464E5E44464C46464C4C4E + 5E674E394E4C4E5E4A4E4C4C56444E5A44384B394E395585738A8A736D6D767A + 6B736B6A6D6A6773676667666D6761615551564C4A5B5B4E4C4A4E5A4A5A4E4B + 4A4A5A5A5E4E4E3C4E573C57394B3F54565762849090989DACB2B2B1BBCAD0CD + D0D2D3D5D7DCD6DEDBDFDADDDCDCDCDCDEDED6DFDEDFDEDEDCDEDCDDDCDEDFDE + E9DEDED7DADDD7D8DFDCDEDEDCDCDCDDD3D2D2DDDCDDDCDADCD2D7D7D3D7BDB5 + B3AEA7ABABB0A7A7A5B0A5AAAFAE9C8B958885565B823C823C3C4A4B853C564B + 884B4A82444A5A5A44564E3E4C5A9B888E888C8582678C8867885E5E6D675E85 + 596D6D5E9A61666161676161666161646161618A6D888B898A858B769A769289 + 76767A7A767A7695AC768A937376896D6C76616D6D558A67574E4A564A4A393C + 3D3C83334B81253333223D36223136223627308136363781869999999E9EC19F + 9FC4C4C7C5C7C7CECFDACFE2DBDBDBE1E4E2E5E2E5E2E5E5E4E5E5E2E5E8E5E4 + E5E8E5E4E8E4E4E2E4E4E4E8E4E2E2E4DBDEDBE2DBDBDBDADBDADADACED6CCCC + C8C5BAC4BAB8AFAFAEACA1A19A8B8B88885F4F3D3C2E26221A160B160B16130A + 13090F0A13090A0F09090A0F09090A0909090F090909090A0F0A130D130B0B14 + 0B140B161214091B1E1E1F2824242424251F282A3A2B2B2B382A2A2840282D38 + 2D382A28382B3A324632394432382D322B464E4E483938323A32323238323938 + 39322B323C3A2E3C4B25556F6363636D676C6D6C636F63526153615E52615E61 + 6152514856564A39554A383E394E324E324639323A4A384A32384B4A3A253C25 + 4B32253E393E37626284939D9D9DB2B2B2BBBBD0D2D0D0D5D3D4DCDAD6DADCDC + D7DCD5D6DDDAD2DEDADFDEDEDCD5DDDCD7D8DDDADFDADED6D7DDD6D2DFDCDDDE + DCD4D6DDD0D2D2DCDCDCDCD8DCD8D7DCD3D3BCB3AEABABABB0ABB0B0A6ABA4A5 + B3AE9C8B8D738D5A5A5A2582333A4F4B834A4F4B884B435A3A4632384A2A4A46 + 4B2B4A9E8E8C8882678285675A8A464E6D5E5E6D4C67674C955A614C5E5E5E52 + 5E595859525E558A85888D738A738A739C6D958B7676747A73767693AC8A7A95 + 6D8A956D6185636D6D5B8D6D5B5A54565A4A4B4B5782873A4B8330333331333D + 302731303330228036363D8181999999999E9E9FC2C2C4C4C7C7CCCED9CFDBDB + E2E2E1DBE1E4E5E5E2E5E5E4E5E5E2E5E5E5E5EAE4E5EBE2E5E4EAE4E5E2E9E4 + E4E2E4E2E2E4E2E2E4E2E2E2DBDBDADBD4D6CCD4CCC8C5C8BAAFBAAFAFAEA39A + 95958C8B885F5A4F3B3A261B191A16141613160B130A130A0F0A0A0A0A0F0A09 + 0A090908090A0F09090F09090A130A130B160B16120B1612161202160B0B1212 + 12121A151515151E1D1E28241E24181D1E1D24242828241E1E1E1E2825252B2B + 21242128242538322B2B21241E25242825252425242425241E211E3326214855 + 51605355514C675B5363485B484448494C494849483E3E39323925322532252B + 2B282B252B252B21252525282B252525212121212125211E252135373F3F8593 + 939DB2B2B8B8B9B9C8BBD0D0D5C9D4D6D8D2DCCDDDD3CDD4D7D8D2D6DCDDDCDD + DCD7D7DCD5D7DCDCDEDADCD4D2DCD5CDD8DCD8DED5D8D5D2D7CDD5D5D8D8D5D5 + D4D5D2D2D3CBBBB1B3ABABA7A7A4A6A7A4A5A4A9BAACA88B8A858E82824B2E83 + 2F263D3D8C2F8226822F324F252B2B32383238322B5A3A82AD8382825B4F825A + 888844495A5E4C614961674C985E4E5E4C525E495252524C59524C8A858A856D + 886D6D769A76928A73766E766E8B7695AC6D8A937373935E73856361676D8585 + 4E67824A844B5B828257873D8182313D3D213D3D223130223D30233D34803681 + 868F99C09999C29EC2C2C4C7C4C7CED9CFDAE2CFE2DBE4E2E5E2E1E2E3E5E5EA + E5E5E5E5EAE5E5E5ECE5E5E5E5EBE4E5E8E5E4E4E2E4E2E2E4E2E2E4E2E4E2E2 + E2DBDBD8DBD6CECCCCC9C5C8C4BAAFAFAFAFA89AA19A8B8B88725A4B3B3A261E + 1B19161616160B0F0B130A0F0B0B0F0A0A0A090A08090A0A090A0A0809090A0F + 0A0A130A0B0B140B0B1412160B14030F131B231A1A261A1E1F1B262C2E2C3128 + 251D2C1F2E292E2E3B2C2E252C262C332F2B3B3A283A2C332C3A3C3A3C3A2F33 + 2F2E3B3B2F3A2F3A2F332E332E2F2782313584696D6969675B5685675B675B5B + 5A565A565B4E5656564A4B3C3D3C4B4B3C3C3A3A3A3C3A2C253A333A31313A39 + 3A3C33333333353131352531332536373F5790989DACADB8B8B9C9D2CCD2D2D4 + CDD4D8D9D8DEDCDDD5D4D5D4DDD4D6D8DFDEDFDDDED5DDDDD7D8DDDEDEDEDED5 + D8DDD4D5DDDEDDDFDEDDD4DDDDD5D8DDDDDFDDDEDDDDDDD5D7D3CAB2B7B3B1AB + B0B0ABA6A7A7ABB2BDAFA89A8B859A8683823D8E823D823D8E3D8C3B8C3D4388 + 3A464A465A44324A4E5A3E889E9B675A5A678C675B8D445A6D67676D5E67675E + 9A67676D675E6152595E52535253678D858D8A768A768A6D93769A927676767A + 769589959F8B8A9C7389936D8A8B63676D678D855B8585578C4A5B8682868E3D + 8382353D3D31333D313D33223D30213D3336363D81998F99999EC19EC2C4C4C4 + C7D4C7CEDBD9DBDBE2E1E2E5E2E5E5E5E5E5E5E5E5E5E7E5E5ECE5E7E7ECE5EA + E5E5E5EBE5E5EBE5E4EAE4E5E2E8E4E2E4E2E4E8E2E2E2DBDAD9D6CECCCCCCC9 + C8C5BAAFAFAFAEA8A19A958C79885A5A4B3A3326191A20161A160B130D130A13 + 0A0F0A0A0F0A0A090A09090F090A0F0A0908090A0A0F0A0B130D120E0B141315 + 0B16018080172727271B2F802F2F2F3B2F3B413D41802F413B80413B3D433B3B + 2F433B43433B823D3B3B3B433B43824F4F4343433D434F3D433D3D4B433D4F43 + 4B438083815786908685868586888885888882888282678286825B5B57825782 + 4F4B824B3D4B82814F3D82433D3D3D804B3D4B814B574B4B3D354B3D4B3D3D3D + 3D3D3D81378486989F9FB8C5C5C5CCC5CCCCD9D4D9E2E2D9E2E2E8DEE9DEDEDE + D9E9D8E2E9E9E4E8DFDEDEDFDEDEE9E8E9E8DEDED8DEDDD9DFE8DFEBE8DFDEDE + DFD4DEDEDEE8DEDFDEDEE8D8DFDCD2B8BBBBB1B3B1B4B1ABABABB3B3BDAFAC9A + 9A8D9E8C8D8E828E838C83578E578E57864B4F8C4A5B4E5E854C4A675A884A8C + 8D8C9E6D855A8A67888D4C726D61678A598A6D6D9A858A9A89676D67636C6159 + 6A6367938A918D89938A927697769795767792767A9C8B8DA88D939C73899C6D + 989A6C896D678D858585855B8D82868C82838E3D868333828125823D313D3D22 + 8131228131303D378699879E999EC29EC2C2C4C7C7CED4D9CEE2DBE2E2E2E1E2 + E5E5E5E7E5E7E5E7E5ECE5E7ECE7ECEDECE7E7E5ECE5E5ECE5EBE5E5EBE5EBE2 + E5E4E5E8E4EBE2E4E2E2E2E2DBD8D9CED6CED4CCC9C9C4BABAAFAFA89A95958B + 8888675A4A3B332626201A1616161413130B130A130F0A0A0A090A0F09090A09 + 0F090A0908090A0F0A0A0A130B0B130B140B150B1612078FC0C0C0C0C0C0C0C0 + C0C0C0C19BC1C1C0C09BC0C1C09BC1C19BC0C19BC0C09BC1C1C1C19BC1C09BC0 + C1C1C19EC1AD9BC19BC19BC19BC19BC19BC19BC19BC19BC39BC1C2C2C2C2C2C2 + C2C2C2C4ADC4ADC2C1ADC1C2C29EC2C1C29EC1C2C1C19EC1C19EC1C19BC0C0C0 + C1C0C09BC0C0999BC1C0C19EC1C19EC19EC19EC1C1C099C19EC09FC3C7C5C7DE + E4E4E9E9EBEBE4EBE5EBEEEBEBEEE2E8D4E8E2D4E2E2D9DEEBE9E9E9E9E2E9E9 + DEDEE9E9EBE8E9DEDEDFDEDEE9E8DFEBE8E8DEDEE9D8DEE9E8DFE8E9E8E8DFDE + DEDFD7B8B9D0B3B3B3B3B3B1ABB1AEB3B9B8A8AC9A8D9B8D8E8E868C838E8682 + 8E828E828C825B8E4E82854E8D4E67854A8D5A8D8D888C9E5E85858D8D8D678D + 8A67798D619388859A8A8D9A9A616D6D616D63616A63858D8A8D918A9392897A + 9C9297917A8B7B76929C8D9A9F8B9A9D6F8A9C6D9A986D9A85678D8D858C855B + 9985868E86828E818E8331835731878225813D318331318133314B8183998F9E + C09EC29EC2C2C4C4C7CECFDBD9DBCFE2E2E5E5E2E3EEE5EDE5E7E5ECE5E7E5EC + E7E7F2E7F2E7ECE7ECE7E7E5EEE5EDEBE5ECE5E5EBE5EAE4EAE5E4EBE2E5E2E2 + E2DBD9D8CEDACECCCCC8C8BAAFBAAFA8A8A1958B79725A5A4A3A2E2526221A22 + 161413140A13130D130A0A0F0A090A0A0F090A090A0A090F09090A090A0F0A0B + 0B0D0B140B1413141216000700020206020602090507101311131A110A13100A + 1112121F191212131311121F1F1A1313130A1313131F1A1F2C1E15191514140B + 140D0B0E141414191E19214B223D3731363330313A3C4B554C4C3E3A4A3A2631 + 272119222121212528211926221A0D0B16130F1307130F0F08130F0F0B13141A + 1A1E191919191A171B0A0F0D1716203D81828E9E9F9EADC2AD9FC1C1C2C2C2CE + D9CEEBE9E2DAD8DEDADFD6DAE9DEE4E9E4D8DEDEDADEDEE4E9E9DEDDD8DDDCD8 + DFDEE9E9DEE8DEDEDED8DEE9E4E9DEE9DFE8E9DADFDADCB9B9CABBB3AEB1ABAB + ABAEA9B3B9AFAC9E9A859A8C878E828C838C834B834B8E828E83828C3B88824A + 8C435A824E8C3A8C8E8C883C9E5A82678C8C5A8D8C678C8D588C6D889B678D9A + 8E5F855A5E6D4E5367556D988C9A8D898D898A919C8A93958A7A7A75899C9A9A + AC8A8DA86D899C63989A61918A5B9A8C858E8D869A57828E878C8F818E863182 + 8231868335838133833026813335813D86998F999EC19EC2C4C2C4C7C7C7CED9 + CFDBE2E2E2E5EAE5E5ECEDEDE7E5E7E5E3ECE3ECE7F2E7E7E7E7E7E7E7E7ECE7 + ECE7ECE5EEE5E5EAE5E5E5EBE5E5EAE5E4EAE2E5E2E2CFE2D9DACECECCC9C8C4 + BAAFAFAFA39A9A957972675A4A3A3325262620191614160B160A130B130A0F0A + 0A0F0A0A090A0F090A0A0F090A030A0F0A13090A0B0B0B160B0B1A0B16120007 + 07090205090502051305051118101A11111011111112121A1F1811111A10121F + 1F1A110A09020305131A1A1F411E151E19140B08090808030D140B192119313F + 21352720141414142025384E524939383C2E1915140A0B0E1926212431251516 + 160D0A0F070707010100070107010001070605131A1A151E261B151313060001 + 08000F16231E2781828C999E8C573D83828398C4CFC7C5EBDADECECCDED8CCD8 + DEE4DEE4DEDADBDED8D8DEDEDEDEDEDCD8DCD8D8DEDEE4E9E2E9E2DEE9D8DBDE + E4DFE2DFE2DEE4E2DEDEDCB9B9D0BAB3B3B2ABAEABA9A9BBBAAFACAC9A859A8E + 8C8C83838383824B834B8C4B828282832B828338884B4F883C8C2A828D82885A + 5A9B3882858C4F8D8C5A888D46888C8E9A8C8C9A988D8C675B8D55676D5B6798 + 8D988D8A8D7689898B89939589767A6F769C9A9C9E8D939E73899C63989A638D + 8A6D988D888E85859985848E8C8E87868F873C83863182833D868231833D3181 + 353C863D868F8E9EC199C2C2C3C2C7C6CECECFE2CFE2E4E5E5E5E5ECE7EDEDED + EDE7E7E5ECE3E7E3ECE7F4E7F1E7E7E7ECEDE7F2ECEDECE7ECE5ECE5E5EAE5E5 + EDEBE5E5EBE5E5E8E2E2E2DBDBDBCEDACCCCC9C8BAC4BAAFAFA8A39A8B8B885A + 825A3D3B3126201A2014140B0B130E13130D130A130A0A0F0A0A090A0F090A09 + 0809090A0A0A0A0A130B0D0B140B141A0B1602130B02050B1F0A04051A111018 + 2E18111C1F1111181C1E181D241E11181F1812242C1E0A090901020309151524 + 3A24151E261A0909060202010A120B212F215457373D22160D0F090A19253C55 + 614C4438562B0B0B0A05030914261E253A24140A080606010007070707070707 + 0707070707070213151E152126210B0B090103010101070F07131B27273D8386 + 8230272F273D8CC2E8D4C4E2E9E9D9D8D4DFD4D8DFE9DEE8E8D8DEDED8DEE8DF + E8DEDEDEDADFDAD8E8E2E9EBEBE8E4E2E9DBE2EBE9EBE8EBE9EAE9E4E4E2DEC9 + C9D0BBCABDBCB2B1AEB1AECAB9AFAFAC9A8D9B988E8E838E838C87838C838E83 + 838C828C4B888E4F8C67888C5A854B8D8F88565B675B9E885B9A869A8C67888D + 678D8D9A9B8D8E9B9A9B9A856D9A6D898963899E939A988A8D908B899276938B + 917A92767A9C9A9E9A9A9A9C89939A859A9A85918D85989A868D8D869B8C8C99 + 8C878E878E8E8687863B868E3D87833D8E813C833581863D869999C19E9BC2C2 + C4C2C7C7CFCFDBE2CFE5E4E5E5E7EDEDE7EDF2EDEDE7EDE7E7E7ECE7E7F2E7F1 + ECF1E7F2F1ECF2ECF2E7ECECE7ECE7E5ECE7ECEDECEDECEDECE5ECE5EBE2E5E2 + E2E2CFDACECCCCC8C8BABAAFAFAFA89AA18D8B8C6782823D3327192216161416 + 0B0B13130B13130A0F0B130A0A0F0A0A0A090F0A090F090A0F0A0B0A0B0B0B14 + 0B0B160B1216091B261B11121F1F12122F1F112C412C1C2E2E1D182C412C1D24 + 4141182C411D1F2C3A2615090F0203010B1B262D4F32242F3B2E130609060603 + 13171E2F4B3A57623F81221B0313060F1B334B67886A524C824B120A0F060703 + 1727333B47310B080F010000178080808780808081808180170700061A19263B + 3D2E19130F010001010C808183878780801780808027801B803D87C4D9D4C7DE + DBE9E9D4DAE9D4DFE9E9E9EBE9DEE9E9DEDFE9E9E9E9E9DFDEE9DEDEEBE9EBEE + EEEBEBEBEBE2EBEBEBEBEBEBEAEBEAEBEBE4DED2CDD2CBD3D0CBBCB9BBB5B9D3 + B9C5AFAD9A9A9B9B8E8F8C8F8F8F8C838E8C998C8E8F8C8E88868E888C858A9A + 82675A8E9A8C8C6D8488859A8C9A859A8D888A98728D9A8D9A8D9A989B9C9E8D + 899F6D899A638D9E989C9891938B9193929395918B9C937A919CAD9EAC9A9CAD + 89939E8A989C8D8D9A899A9E859B8D8E98988E998E8E998F8E99878E8E35868F + 578E87868F3D81824B86873F879999C19EC1C2C2C6C4C7C7E2E1CFE4E1E4E5E5 + E7E7EDF2EDF1EDF2EDF2E7E7E7E7F2E7ECF1F2F1F2F1E7F2E7F2E7F1ECF2F2E7 + ECE7E7ECE7ECEDECF2E7ECECECE7ECE7E5E5E4E5E2E2CFDACED6CCC9C8C8AFAF + AFA8A8A89A9C958D88854B3D33311E22191614141613130E13130B130B0F0B0F + 0A0A0F0909090A0908090A090A0F0A0B0B0B0B0B140A120B140B091A271E0A1A + 2F1F111F3B1D182C4340182C431D182C432D184182291C2E432E1D2C432E1483 + FAFBFBFBFFFB9B2F5A461E3A4F2613C0FAFEFBFBFEFB87315A575784578131C0 + FBFBFBFBFBF8988873664C66674B16E0F8FFFBFEFBF83B4B4F250A0F0787E0F0 + FCFEFCFEFFFDFBFDFAF8FDFDFFF9F0C00717163B4F3B0A030007C0C3FCFCF8FD + FBFFFAFBFDF0C38117FDFBFBFBFBF7EFD9D8D9D4DEDEE4DBDEE9DAD8E8EBEBEE + E8DEDEEBDEE8EBEBEEEBE9DFE4E9DFE2E9EBEEEFEEEEEBE5EBE4EBEEEEEBEBEB + EBEBEEEBE8E9DFDACBD7CDD2D3D2B9B9BAB9BBCBC9B9C4ACAC9A9B9B998E8E8F + 8E8F8F838F8E8F8C8E8E8C8E828E988C8C8C8C9A678C858C9B85678567855B67 + 9E98899B988D8A9A6D899A999A988D9B9A999A989A9E85909E6D9A9E9C9E9391 + 8A918B9189929393939C9C938DACAD9E9C9F9EAC9A989C9A919E8B989A989A9E + 8D9B998D9B8E8E9B8E8E99998E8F988F8E578F8E818E8E838782818683828257 + 8F999BC19F9EC3C2C6C7CFCFE1CFE5EAE5E7ECE7E7E7F2E6F2E7F1EDF1EDEDF1 + E7F2E7F1F2F2F1F2F3F2F2F2F1E7F2E7F4F1E7F2F1E7F2E7E7E7F2E7F2ECF1EC + F1ECECE7ECECE5E4E2E2E2CFDACED6CCC8C8BABAAFAFA8A89AA18D8D8567823C + 3B2622221B1916130E1314131314131613130B130A0A0A0F0A1309080A09080A + 0A0A0F0B0B13140B0B140B161216021A261209112F1F10122E1C181F401D1F1D + 2E1D111C411D181D43291C1D2E1D182E3B281381FEFBFAFFFDFBC0404F381E25 + 43240AC0FAFAFEFFFFFB8331543E3F573F8122C0F8FBFFFFFFF88F6988644C5E + 672B16E0F8FDFEFDFFFB263A3A1E0680E0FDFFFFFEFFFEFDFEFDFAFBFCFAFBFA + FDFAFFF8F08F0D26382C0B02C0F0FAFBFDF8FCFDFEFAFDFCFAF8FBF087FCFFFF + FAFFFBECDED8D4DEE9D4C5E4E4D9D6D8E9EBE1E8E8D4DEDFD9DEE8E8E5E9E8DE + DEDFDED9E9E8E8EEEBEAE5E8E5E2E8EBEBEBEBEAE5EAEAEBE8E9DAD5C5CDD5D2 + D2D2BBB8B9B8C8C9B9B8C4AC9E9A9B8F8F8E8F8E8F8E8E8C8F8E8F8C838F8C99 + 8C8C8C8888858C8D828D8C8C9A8C885A67855A4A8E9B8C849A98888D67888D9A + 9B8D989B989A9998989A898D9A84989E9E989889918A9293928D939A939F9D8D + 93AC9E9C9E9C9A9F9A9A9C8D8A9A918D9A8D9A9B989A8E98998E99998E8E8E8F + 8E8E8F8E8E818E8E81988E868C8382878286868298999B9EC1C1C2C2C6C7C7E1 + D9E1E5E1ECE7E7E7E7E7E7F2E7EDF1E7F1F2F1E7EDF1E7F2E7F1F1F1F2F3F1F2 + E7F1F2F1F1F2F2F1E7F2E7E7F2E7F2E7ECF1ECF1ECE7F4E7ECE3EAE5E5E2E2D9 + CED8CECDCCC8BAAFAFAFA8A8A19A8B8B856D5A4B332F222619161614160B130B + 1613160B13160A130A13090A0A0A0F090A080A0F0A0A0A0B0F0B0B0B140B160B + 141A02091A110210181010111F1C101C401D18182C1811182C1C181F411D101D + 2C1C18242D241283FAFEFBFDFCFBC0404E381E28382109C0FAFAFEFBFFFB8725 + 54393F57373727C0F8FFFFFDFBFB8E5B73644C585E3A0EE0F8FFFBFAFFF72628 + 3A1216E0FFF9FAF9FFFAFBF9FBFBFBFFFBF8FBF9FDFAFFFBFBF8803B41240580 + F0FDFAFFFAFCFFFBFBFBFFF8FBFBFBF8F0FAFBFFFAFFFBEEDBD4C5D9D2CCC4CC + E4DED4D2E8E8E2E8D9D8D5DFD4D9E8E8E8E2DFD8D8DED8D9DFE8E2EBEAEBE8E8 + E9E2E8E8EBEBEAE9EAE8E2EADEE8DDD5C5CAD2CDC5D2CBB9B9B9CBB9C5AFADAC + 9A9A9A8E8C838E83878383838E878E83838E838383828C82828C4F8C82828C83 + 8C8267825A88823C85889B9B8E8D6788855A8D9B8E9B989B98999A8E9A9B989A + 988D8D9E989D9891899189939393939C9C9EAC939A9D9EAC8D9C9E9C9C8D9A9A + 739A8D8D9A89989A9A998D8E98999A8E8E8E8E8E8F988F8E878C8E8C838E8786 + 8386838E81868683999B9EC1C29EC3C2C6C6CFCFE1E2E3ECE7E7E7F1ECF1E7F1 + E7F1F2F1E7F1F2E7F1F2E7F1F2F1F2F3F1F1F2F3F2F1E7F1F4F1F1F2F1E7F2F1 + ECEDF1EFF1F2F4E7F4F1ECECE7ECE5E5E2E5E2CFD9CECECCC9C8BAAFAFAFA8A8 + 9AA19A8D8A82823D3B2726221B201A160B1613160B16131314130B130A0A0F0A + 0A1309080A0A080A0A0F0A0B0A0B160B16121416140B021A270B051A2F1C051A + 2E1C181C411D1D1F2E1D111C411D182C41291C1F411D182C43241381FEFBFDFF + FAFBC0424F38252B47280BC0FAFEFFFFFBFB87355A503F62573727C0FBFBFDFF + FBF78E6D73645867673816E0FAFBFFFDFFFB26333A1AC0FEF8FBFFF9FFFFFBF8 + FBF7F7F7FBFBFBF8FEFEF9FBFBFBC327431F11C1FAFBF9FAFAFDFBF8F8F7FBFB + F8FBF7FBF8FEFBFFFDFBF8F2D9DCDED8DFDCC5C4DFE9D8DADEEBEBEADEDEDFDF + D8E8E9E8EBE9E9DEDFDFDEDEE9EBE9EEEEEBE8EBEBE4EAEBEBEEEBEEEBEEE8EA + E8E9D8D8CDCDCDC9B9CDD3CBCBCBCBB9B9B8ADAF9E9A9B998E8E8F838F8E878E + 878E8E8C838F8C8C8E82838C828C4F8C82888C8E8E868C8A8882858282868EAD + 8E9A858D9A568D9B9A999A999A999E9A9E989E9A989A90999C99939191918B93 + 93938B9C9F9C9D9A9C9C9FAC8D9E9C9A9E939A938A8D9A899A899A999C988D9A + 8E98998C998E8E998E8F9A878C8E8786838E8E8384838C838682868C999B9BC1 + C2C1C2C6C6C7CFE1E1E1E5ECE7ECF1ECF1E7F1ECF1F2F1F2F1F2F2F2F2E7F2F2 + F1F2F3F4F3F1F3F2F1F1F4F1F1F4F1F1F4E7F1E7F1ECF2F1F4F2F1F4F1ECF1EC + F1ECE7E5EAE2E2D9CFDACED6C9CCBAC4AFAFAFACA89A9A8B8A82824B3D332622 + 1B1916161613160B131613160B130B130B0A0A0F0A0A0A0A080A0A090A0A0A0D + 0B0B0B0B140B16141214091B3B150A1F2F1F1019411D182C41401D29431D1C2C + 41401D2C4F401D2941401C404F2B1A83FAFFFBFDFDF8C1435F4C283A5A3A16C0 + FCFDFFFBFAFB874B695B5084843727C0FBFBFDFEFBFB8E6D8A655967724B14E0 + FBFBFDFEFFFB2F3B4B1EC3FFFBFFF9FBFBF8F3F1E6E0E0E0E3E0FBFFFEFFFEF8 + F9FBFB1B432F06F0FFFDFFFBFAFFF7F5EDE5F4F5F2EDF7F7FBFBFBFBFAFBFBEF + E2DDD8DEDFDDB8C4DFD4DAEBEEEFEFF2E8E4E9E9E2EAEEEFEEEFEBE5EBE9E4EB + EEEEF2F4F4F2ECF2EEE5EEF2F4EFEFF4F4EFE7F4EEEBDEDAD6C9DCCDCBCDD0D2 + D0D0CBC8CBC5AFADAC9E9E9A998E998E8F8E8E8F8E9887998C8C998C8E858C8C + 678C678885828D9B8D8C8D8D8A678C858567988DAD9E8A899A6D8D9E9E9A999C + 9E9C989F98939E93989F8D9E9F9C9E91919191939393919C9D9C939C9C9A9FAC + 98AC9E9A9C9A939A8D939A8D9A989A9A9E8D989B8C98998C9A8E8E8E998C8F85 + 868E838C8C86838C83868C8386828199989BC1C2C1C2C3C6C6CFE0D9E1E7ECE7 + E7F0ECF1ECF1ECF1E7F2F1F2F1F2F2F1E7F2F0ECF2F1F3F1F3F4F1F5F4F1F1F1 + F3F3F4F1F4F1E7F4E7F1F2F4F1F4F1F5F2F1F4E7E7ECE7E5E5E5E2E2CFD9D6CE + D6C8C8C8AFAFAFAC9C9A8D8A8C855A4B3D2F2722221A16161616131616121613 + 160B130D0A13090A0A0A0A080A0A080B0D09130B0B0E0B14161516191614021A + 3312091A2F1C0A1F411E182C43291D2E4129182C43291D2C4F401C2943291D40 + 472A1380FFFBFFFDFAFBC142724C2B3A5A3816C0F9FCFFFFFBFB874B85625084 + 623780C0FAFBFEFDFBFB8E857371585E88460EE0FAFBFFFFFBFB273B3B15FBFF + F9FBFDF8FBE080273B2618262F2727C0FEFEFFFEFBFBF08F821F05F9FBF9FAFE + FAFFC39B989EDADBCFE5D9C3F0FBFBFBFDFBF8F2DEDED8E9DDDCC9CDE8D4C7E9 + F4F2E3EFE5E2EBE9E2EAEFEFEEEEEBE4EBEBE5EBECEEF2F4F4EDE5EFE5E5EFF2 + F4F4F5F4F4F2EFF4ECEEE2DADED2DCCDCBCAD0D3CBD3CBBBD2C8AFADAD9E9A99 + 8E8E998C8F878C8E8C8E8C9982828E868E8288885B8D884E85889A8E8D8C8988 + 8588898567849A8985AD8A768A898D9F9A9A9E939F9A989C98919C918D9D899F + 9E9C9893918D93938B9C909C9F97929A9C93AC9F959F9C9A9C9A899C8B939A8D + 9A9A989A9E8C8D9E8C9A9B8E998D8E998F8E9983829982878E828C87828C8C4B + 8E82579B8E9E9BC1C2C1C4C6C6CFCFE1E1E5ECE7ECE7ECF1ECF0ECF1ECF0ECF1 + F2F1E7F2F1E7E7ECF0F4F1F3F1F1F3F3F1F3F1F4F1F3F3F1F1F1F4F1F4F1F4F1 + F5F1F4F3F5F1F4F2F2E7F2ECE5E5E5E2E1DAD9D6CED2CCC8AFAFAFA89A958885 + 8282823D3D332726221B201516161A16161613160B130B130D0A0A0A0A13080A + 080A0A0A0A0D0A0B0B140B161A1619161919091A261209122F1C051A2E1C181C + 412918242E1C111F411D181F431D182C411D1D2C47281A83FCFEFBFDFBFBC141 + 674C283A4E320EC0FAFAFFFFFDF8874B5B5B5084573427C0FAFFFDFEFFF88E67 + 7364445E673B0EE0F8FFFBFFFFF8272E3312FBFAFFFFF9FBF8271B263B331E2E + 43260B09E0F9F9F9FEFDFB83801C06FEF8FFF8FAFFF183857AACCCD4DECEC7C6 + 87FBFBFBFAFBFBF2E2DED4DEDCD3B8C8D5B8ADD9EBEEE2EED8DEDFDED9E8E8EA + EAE9E9D9E9DFD9E9EBEBECEBEFEBE1EBE8E9E7ECEFEFEEECEFECECEFEAEEDED8 + DCD2D2D0C9C8CAD0BDD3CBB9C9B8ACAD9C9A999A8F868E838F8C878E8E8F868E + 833C8E829A8286824E82883A8C678E9A8E888C88855B678285888D5B679A9F6D + 9A6D8D9E9A999A989E9C9893986D9C91899C849C9E91989391939193939C9193 + 9C91899C9393AC9E959F9C8A9C9A899C8B899A8A8D9C8D9A9A678D9A868E9A8E + 9A8E8E99988C9B8C828E4B868E5A868C4B86834E8C865A998E9EC1C2C1C6C1C6 + C7CFE0D9E3EAE3E7ECE7F0ECECF1ECF0ECE7F1E7F1E7F1F2ECE7E7F0ECF1F3F1 + F6F1F3F1F1F4F0F3F1F6F1F4F3F4F1ECF1ECF3F4F3F3F5F1F3F2F3F1E7F4E7ED + E7E5EAE2E2E2CFDAD4CCCCC8C4AF9E9A9A8B8A855B5A3D3D332F272226161B14 + 1616161A1716160B0B160B0B0A0B0F0A0A0A0A0A0A0A0F0A0A0B0D0B16121619 + 161919201B20020A1A0B0410181011111F1C111C401C1F182C18101F291C1F1C + 41291C1C2E1D1D2940281381FEFDFBFAFBFB9B3B4F38283244320EC0FAFDFFFF + FBF8873557563C84623023C0FCFFFDFEFFF78E5B6D524C4E5A3C0BE0FAFBFBFF + FEFB26262C0BFBFDFFF9FBFBE017151E2E241124411E1213C0F9FEFEFDFBFB87 + 1F1A05F9FFF9FBFBF8E0399192A9D3C9D8D5C4C281FBFBFBFDFBFBE7D9DEC5E2 + DDCDAFD0D7C5ADC7E2EEEBE8C7D8DFD9D9D9EAE8E8E8DED9DFD9D9DEE8E8EAEB + EAEAD9EBE2E2EAEAECECEAECEAE1EAECE8EBD9D8D5C9CDC8BBB9CBBBB2D3B9AF + B9B8ACAC9A9A8C8E8C8283838E838386838C3D838226834A835A825A444F4E2B + 883A4F8E9A4F5B6785435B88854A8D6767986D9A98678D9A989A9A989A988D89 + 8962938D688D6F9F9C98899189918991929D8A89976F7A9C938AAC9D8D9C9A6F + AC9A739C73739C856D9C8D9A98678D9A5B85988C989B8C8E8E868E864B8C3C82 + 8E4B8C8C3A828C3C88824B8C8E9E9EC2C2C2C2C6C6CFC7E1E1E5ECECE7ECE3EC + F0ECE7E7ECF0ECE7E7E7E7E7E7E7E1E7E7F0F4F1F1F3F3F1F3F0F4F3F6F1F3F1 + F4F0F4F0F4F1F1F3F3F3F3F3F3F3F3F4F1E7E7E7ECE5E5E1E2CFDBDACECECCC8 + AFADA89A9A8B8C88824B3D3B332727262222191616161B16161A160B130B0D13 + 0B0A0A0A0F0A0A0A080B0A0D0A0A0B160B161919161920192219021B2612051A + 2F1C041A2F1C101F41291C29411D1C1C41291C2941401C1D41291D29433B1783 + FCFEFBFDFBF8C143824E313A5F390EC0FAFDF9FFF8F88781575B578487340FC0 + FCFCFFFAFBF78F568D4C4E3C823B03E0F9FDFBFBFBFB263B2F15FBFFFEFDF8FB + E01B15274B2E182C41261A0AC0F9F9FEFDFBFD83411F05F9FBFDFBFBF8E03F89 + 7EB2D3D2D7DEC5C487F6FBFFFDFBFBF1E2DECEDFDFD2AFD3DCC5C2DBD9E1EEEF + DBDEE9D9E2EAE1EFEEEBE8DBE8E2E2E9EBEEEEEEEFE5E8E5E8EBECEEEEEFEEEE + ECEAECEFEAEBDED4DDC9CDD0C9CACBCACABDCBB9CAAFAF9F9C9A989B8E83874B + 8C838E864B8E828E823D8C3B8C8282883A888244883C888E8E8288828885888C + 85888D616D858A619C8D8C9E9A988D9A98918A6D6F6D6F896F6F89999D909091 + 91919193909D9391928A929D95919C9D8A9C9C899C9C73938B769A6D899A939B + 9567988D678C9A869A98888F8D829B5B5A8C3C888E4E858E3C85823C88865A85 + 8C9EC19BC6C3C2CEC6CFC7E1E4E1EEE5E1F2ECE1EFE7F4E7E3ECE3ECE7E7E7E7 + E7E7E1E7F1E7F3F1F6F0F4F3F1F4F0F4F0F6F1F6F0F4F1F4F1F4F3F3F3F3F7F3 + F3F3F3F1F4E7F1E7E7ECE3E5E2E2CFDBCED6CCC4C4AC9BA89A8D8C8582823D3B + 31262227221B20161B161916161613140B0B130B0B0F0A0B0A0D0A0A0A080A0A + 130D0B161516191B201919201922021B261E051A2F1C111A411F181D43291D2E + 41291C2C43291D2E47401D2943291D2E4F2C1383FCF9FBF8FDFBC13B5A4B333B + 674A14C0FAFAFFF9FDFD872386813C8186230FC0FCF9FCFFF8FB873A5B824B4B + 822708E0FDF0FEFBFFFB2F3D3B1AFBFAFFFAFBF8E023272F822F1E2E431F0A13 + C0F9FEFDFEFAFB83801F05FEFBFBFBF8FBE04B8597D1D7D2D8DCC59981F8FBFF + FDFAFBF5E2DEDEDEDDCDAFD7D7B8C5EEEEE1E5EEE2E4EBD9E5ECEAEFEFEEEBE8 + EBE8E4EEEBEFEFF4F4EBECEBEBEBEEF4EFF4F4EFEFEFEFEFEEEBDED8DFD2D2D2 + D0D2D0D0CBD0D0CAC9B8ADACAC9C9B9988828E3D87828C8382998298824B8C3A + 885A888C5A8A675A8A4F889A9B8885888A85888D85859A6D63858A6AAC939A9A + 85989A639189896F6F6F6F6F6F6F909D9F9091989398939C91AC939293917A9C + 9292A89F8B9C9C89A89C8A978B769C738A9A919A9A6D9A8B5B8A9A679A8D829A + 8E5B995A4B855A868C4E828D4682674E88855A858CAD9BADC2C4C2C6C7CED9E2 + E1E2EEE5E5EEE7ECE3ECE7E1ECE7E7E3ECE7ECE5ECE7E3E7E7F4F1F1F1F3F1F1 + F1F1F0F6F1F3F3F1F6F0F4F0F4F1F3F3F7F3F6F3F3F3F3F3F1F1ECE7E7E3E1E5 + E2E1DBDBCECECCC5AFADAC9B9A8D8D8882573D3D2731262722221B19161B1616 + 1A16160B13140B0D0B0A0A0A0A0B0A0D0A090A0D0B0B0B16141A1919201E2022 + 2120091B31150B1A2F1F111E411D182C432D1D2C43241828432A1D2C462D2429 + 4F2A1D2C331E0F80FFFFFFFBFAFBC02E3D3126315B4A0EC0F8FDF9FFFBF08734 + 23333630302301C0FCFCFAFBFEFB8F203D251E33270D0FC3FCFAF8FFFBF73B3B + 3B1EFBF9FFFFFFFBE01713262F26152E2F1B0B07C0F9FEF9FAFBFB87411F02FF + FBFDFEFBFBE033869A9DADC4C29F8E8780FBFBFDFDFEFBF3E2DFE2DFDFC8B9DC + D0C5C7E4E2E2E2E2E2EBE9D9E8F4EFEFEEEEE8E9EBEAE8EEEEEEEFEFEFEEECEB + EBEBEFF4F5F4F4F4F4F4F4EFEEEBE2D8DED2D2D2D3D3D3D0D0D3D3CBD0B2AFAC + 9C9E9C9A57828C3C8C578E855798828E5B4A82485A5A678A4E67675288525B8D + 9A8588888A6D6D8A8A6D9C6D6A6F916A93769D9F769393897A776F6F75756F6F + 75906F9D9F9090939193939C919D9392937A9293928B9D9D8A9C9C8A9D9C7A95 + 956F9C8A739C8A939A6D8D8D618A9A858D8D88988D828D5B5A885A5B8C4A678C + 4C5B824C85855B858D9EADC1C4C4C2CEC4C7C7DAE2E2EAE4EAEEE5EAE3EAE3EA + E5EAE5E7E5E7E5E3E5E1E5ECE7F0ECF1F1ECF3F1F1F1F1F4F0F6F3F3F1F1F1F6 + F1F3F3F3F3F7F3F8F3F3F3F3F1E7F2E7E7E3ECE3E5E2E1DBDBD6CCC4C4ADADAC + 9A8D8D8C86824B3D33272231222720161B161B141616160B160B130B0B0A0D0A + 0B0F0B0A0A0D0A0A0B0B14161A192019221922192221021A1E1509122E181112 + 2E1D111C40291F24401F181E411D1E24412D1D24421D15181E0B0F80FAFFFBFB + FAF8C00A190E0B26563920C0FAFBFEF9FDFBC1230122160E230107E0FCFCFBFF + FBF8C11616140D13080F07FCFDFBFBFBF8FB262B4315FBFFF9FFFBFBF0000209 + 1A12020A120A0600C1FCF9FFFEFBF7872E1F05F9FBFFF8FDFFF00F1E57825783 + 8283811723FAFFFEFDFDFBF2D9D9D4DEDDB9BAD3C8B8D4E8E9E2DEC7D8E9E9D9 + E1EAEAECEEEBE2E8E8D9E2EAEBEEEAECEEEAE8EBD9EBECECEFECF4ECE7ECF4EC + EAEAD9D4DCCDD4CDD2D5D0CDD0D0D1B9C9B2ACA89A938D85565A5B2582578C84 + 4E8C4A854B32673C5A555A674C676144724C4C858D85676D6D676D8A89619263 + 63767A63756391AD6F93906B92636E6B756F7575756F6F939D69909190919193 + 909C92907A767B7A7A9097A8739C9C769C97739292719773739589739A538A76 + 676D8D738D8A5B8D8C5B855A56854A4E884A5A85464E5B49676767858DAC9BAD + C4ADC2C5C4C7CCD9D9DBE2E2E2E5E8E3E8E1E2E1E5E5E5E5EAE5E5E5EAE5E1E5 + E7E7F1F1F1F1F1ECF1F1F1F1F3F1F6F1F3F1F3F1F3F3F6F3F8F3F7F6F3F8F3F3 + F1F4F0ECE7E7E1ECE2E5DBDBDBCECCC4C4AFAD9B9A9A8C8685573D3D33273122 + 2722221B201B201716161A0E13140B0B0B0B0A0A0B0B0A0F0A0A0A0B0D0B1615 + 19201A221E222122222102131E1102111F1005111F1C181C411D1C1D411C101D + 401D1C1D40401D1D411D1F1215090781FCFEF8FDFFFAC0000F0108224B3920C0 + F8FEF9FEFDFBF88F010701010F0F87FCFCF8FDFBF8F9FB8707010F071707C0FC + FCFBFDFBF8FB242B3D1EF8FBF9FFFBFAFB8007010613090303000017E0FAFEFF + FFF8FB832E1811FBFBFAFFFFF9F881171A26272323271B80C0F9FAFDFDFDFBF2 + D4D4D4D8D3AFB8D2B2B8C5DEDEC7C7C4C5D4E9E2D9E1E1EAEEE2D9E8E2D9D9E5 + EAE5EBECEAE1E8E2E2E8EAECECECECEAEAEAEAEAE8E2D8D4D2CDCDCDCDCDCDD0 + D0CDCAB8BBACAC9D958D855A4E3A3A1E3B4B82823C5B3C5A3A323C2A32323844 + 324644324638324E67885B67826D678A8A618D6A53617663766D6F93AC89896C + 6876686B6B686B686F686F9393909090919190919097907A6F777A767A7A939C + 7A979C76959373928B6C93716A938B6395616D8A63678A618A6D4E8C8556674E + 4E67484C85444E674C4E614C67676D6D8D9EACADADADADC4C4C9C5D4CED8DBDE + E2E2E2E2E2E1E2E1E2E1E5E5E5E5E5E1E5E1E5E5ECE7F1ECF1F1E7F1F1ECF3F1 + F3F3F3F3F6F0F4F3F3F3F3F7F3F8F3F8F6F3F3F3F1F1E7F1E7E3E3E3E5E2E2DB + DBCECCC4C4ADADAC9A8D8D8C86824B3D313126302722261B221B1B201B161616 + 141314130D0B0A0B0F0B0B0B0A0A0D0B130B16191619221E222221222130021A + 1B1505112F1010122F1C111F41291C2C411D1C1C41291C2C43401D2943291A1B + 818FC0C0FDFFFBFDFAFFE0C08FC0C0C08E3520C0FBFAFFFEFDF8F8FBF0C0C0C0 + C0E0FCFDF9FDF8FBF9FBF8FBE0C1C08FC1F0FCFCFDFAFBFBFBF12E464F26F0FB + FBFBFFFFFFE0871707020002070F87C3FCFCFEF9FBFBFB80411C13F9FBFBFDFE + FDFDE0C0801B1323238081C1F0FCFBFAFDFDFBF2D9D4D5DCCDB2BDD3AFB9DDD8 + E9DED4C7D6DDCEDEECEAECECEFEBD9EBE2D9E8EBEEECEFECEEEAE5EAE2EBEEEF + EFEFEFECECECECEEEAE8DED4D2D2D5CCD2D2D2CDD0D0D0B9C9B2AC9C9395855A + 4B2D3A2B4B4B835B4B824A82383C4F3C443C465A585A5E444E5E4E5A888C886D + 6D88858A8D618B6D636C6F6C89766D9F6C9F7A6F637B6F756F756F6B906B9093 + 93909198919391939097919277927A777A9292978A979C7A8B9276928B6B9573 + 6D978973916C6D8B6D6C6D678A6D558A855A67564E5B4C5A6D4E4C5B4661675E + 6D6D73898DAC9BADADADAFC4C5C5C9D4D4D8D8DADEE2DBE2E2E2E2E2E2E2E5E5 + E2E3E2E5E2E1E5E3E7E7E7F1ECF1E7F1ECF1F1F3F4F3F3F6F1F6F0F1F3F3F6F3 + F8F3F8F3F8F6F3F3F1F1F4E7E7E7E1E3E5E1E2DBCFDACCC4C4AFAD9E9A9A8C86 + 8257813C31312231222722231B1B191B16201A1616140B0B0B0B0D0A0B0B0F0B + 0B0A0B0D0B141A1619221922212130212225021B2615051F2F1C0B1F2F1D181D + 43291D2E4329182C43291D4047402D2A4741151BC1F7FBFAFDFBFFFBF9FCFBFB + FBF8FBF7C25730C0FAFEFEFFFBFCF8FBFDFEFBFFFBFDFEFAFAFBFBF8FBF9F8F9 + FDFBF9FBF8FBFCFCFCFDFBFBFBC32E4E822DC3FEFBF9FFF9F9FDFFF9F8F9FFFF + FBFDF8FDFDF9FDFBFBFBE61F431F1AE0F9FEF8FFFDF0FDFBF8FBFFFBFBFBFBFB + FBFAFBFDFDFBF8EFD8D5DFD5B9CACBBDB9CDDFDEDFE9DACCD4DEC4D9EFF5EFE7 + EFE5E8EEEAE2ECEEEFEFF2F4F2ECEBEBE2EEF4F4F5F4F4F4F4F4F4EFEEE4E2DE + D6DCD5D6D5D2D7D2D0D3D0C8CAB8AC9D9593856D563E3A4A825688825B885A5B + 4A4E5A4E4A4C5A5E554C5E525E4E5E55888A8D6D888A8A768B6D916C7676756C + 906E89936B919D77776F777777779077779090939D6993939398939391939291 + 77927A927A9292937A93977693957A7A7A739273748B8B6D8B6D6C8B6D8A766D + 738A5B856D6767564E67556788495E674C67676D6C858A8A8BADA8ADADADC4B8 + B8C9C9CDD4D6D4DADEDAD9DEDBD9DBCFE2E2E1E2E1E2E3DBE1E2E3EAE5E7F2E7 + F1F1ECE7F1ECF1F4F3F3F3F1F0F6F1F3F1F3F3F8F3F6F8F3F6F0F6F3F3F1E7F1 + E7E7E3ECE5E2E2DBDBCECEC4C4ADAD9E9A988D85865A3D3D313031273122261B + 23261722161B161616160B160B0B0B0B130D0B0A0D130A0B0B141B1422192221 + 262225302530021B33150A1A2F1F111F412C181F47401D2E4F291F2847401E2E + 4F42292D5F412623C1F7FBFCFFFDF8FDFDFDFBFFF9FBFBF7C24B30C0FFFEFEFE + FAFAFCF8F8FFFFF9FDFBFAFFFBF8FBFBF9C0FEFBFFF9FFFBFAFBFCFCFAFBF8FB + F7C028434F3BC0F7FBFBFEFDFFF9FAFFFBFDFAFAFAFAFAF8FDFAFEFFF9FBC31F + 411F11C0FEFBFBF8FDFBFAFFFFF9F8FDFFFBFBF8FAF8FFFDFDFAFBEFD9D5DDD0 + B2CABEBAAFD7DDDEE9DEDCD2DADCC5E2E5F4F4EFEEE2EAEEE8E8EEEFEFEFF4EF + ECECEEE4E8EEEFF4F4F4F6F4F4F4F4F4EEE2DEDAD6DCD8D5D8D7D5D2D2D3D3B9 + D0B2AC9C95975B6D5A4A3E3A824E5B5B4A674B5A495A4A4E564C555E5E525E61 + 615E55676D8D8A886D8D768A916C7A6B73756A6E926F92936F77759D757B7577 + 7777776F90776F939D909198939391989197919276927B927A7A7A927A939576 + 92977A7A747A7373767A7A727A6C6D7666768A6A677355675B67554E555B4C5E + 674E61674C67616D6D73897693AC9EACA8ACB8B8AFC5C5C9CDD2D8DCD8DAD8DA + DBD8D9DBD9DBDBE2E2E2E2E1DBE1E4E3ECE7EDF2F1ECE7F1ECF1F4F1F3F3F3F1 + F1F4F0F6F1F3F3F3F8F3F6F8F3F3F8F3F3F1F4E7E7E7E1E3E5E5E2E2DBCECEC5 + C4C4AD9B9C9A8C8686574B3D332731302722221B221B23191B1619161A16130E + 0B0B0B0B0D130B130A0D0A0B160B19221B212221222530253025021A1F120911 + 2E1811122F1C18184128182C431D1C1D40291C24432D242D472D331EC1F7FBFB + FAFDFCFCFCF8FDFAF9FFFEF8C33F36C1FDF9FBFDF8F8C1FCFAFBFBFEFFFAFDFD + F9FBFBF7C383C3F9F8F8FFFDFEFFFDF9FBF8FBF7C6431F47822A1BE0F8FBFBF8 + FFFBFCFCFDFBFDFCFCFDFAFDFAFEFEF9F9E61B1B412E0427E6F8FBF8F8FDFEFA + FDFDFDFDFFF9FBFBC3FCFDFAFEFDFBF2D9D2D2BCABCAB5A8B3DCD8D9DDDFC8D2 + D7D7ADCEE8E5EFF4E5E1D9EAC7D9EBEBEFEBEEEAE1EAE8E8E2EBEBEFECECF4EC + F4ECECEBE9DEDAD8D5D2D8CDD5D6D2D2D5D2D0BBBBAFAC9C959A525738322B2B + 4B3A5A4A464A383C413C383E384A444A444C4C4C4C524C4C528D8A85678A858A + 8B63896A6B6C6B737A767A9176756F75977B777577907777776F909D9190919C + 9891939C9093937A907A7A7B7A927A7A7A7A77748B927670746C746C74736A74 + 736C646D648A76616D6D615B674C554E4C4C4E4C67444C674C676D598A768A8B + 8BACACAC9CAFA9B2B9B9CAC9CDCDD2D2D2D2D6D6D4DAD6D8DAD9DBDBDBD9DBDB + DBE1E2E3E5EAE7E7E7E7ECE3E7F1F1F1F3F4F3F1F6F0F1F3F1F6F3F8F3F8F3F8 + F3F8F3F3F1F1F1F0ECE7E7ECE1E5E2E1DBD9CCC4C4C2ADAD9B9A8E8C8682813C + 35313627302727221B26221B201916161416140B140B0B0D0B0B0B0D0B0B0B0E + 0B141A201E222122252530253035020B1A0A05111F1005111F18101C2E1C181D + 411F181D2929181D412A242A462D242EC3F3F9FEF9FAFCFDFCFCFDFAFDFEFDF5 + C23430C1F6FBF8F8F7F687C1E1F8F8FBF8F8FAF8F8F6FBC08C4B3DC1F5FBFBFF + FBF8FDFBF7F7F1C04B2B4F2E2D432627C3FBF8FBF8FBFBFCFBF8FFFBFBF8FBFD + F8F7FEFEE02F041A1F111F0A3DE0F5FBF7FBFBFEFBF8F6F7FBF7F7E187F8FDFE + FFFEFBE7D9D2BBAEB4BFAA9CB8D7C7D4DFD7B2D3D2B9C4D8E2C7CFF4E5D9E2E8 + D9D9E8EAE8EAE5E2D9EAE2D9E2E8EBEAEAECE1EAECEAEAEADBD8D4D2CCCDD2CD + D4CDCCD4CDD2CAB8B9A9A88B898A494A322528253A2B3C32322B252A282A3225 + 32322D32383244384444494449856D67676D6D6D8A53766A636A636B736B7675 + 6B6F6B6392937768776B6B6F75776991939090919091919389919076776F7576 + 7574766E757476747A9274747374716C74706A717A646A6C61736D6166674961 + 5549444948444E4C67444C674C676D63768A8A8B93ACA8ACA8ACB2AEB9B2CAC5 + CACDD0CDD2CDD2D2D2CCD4D6D8D6DACEDADADBD9CFDBE2E2E3E5ECECE7E7E7E7 + E7F1E7F1F3F1F6F1F1ECF6F1F3F3F3F6F8F3F8F3F8F3F3F3F3F1F1ECF1E7E3E3 + E1E5E2E2DBCFCEC7C4C49F9E9B988E8C86824B3D3333273327302623261B2221 + 1B201A1916160B160B140B160A0E130B0E0B0B0D151416192021212530253125 + 3525021B1B1205122E18051A2F1C112C411D18244329181D43401E2C472D2B42 + 5A382B3A9BC0C1C3F9FEFBFAFBFBE0C0C1C0C1C19E603F99C2C1C1C1C2C23784 + 8FC1E1F4F5F5F7F0D9C13F8167544B578CC2E0F2F7F7F7E3E09E81334B2D322B + 474224264B3DC1E0E0F7FBF7FBF5F7FBFBF7FBFBF5E0C0804112111B431F1215 + 334F8FC2DBE5F1F1F2EFF4EFEBCFCEC23DF8FBFBFBFBFBEED4D0BBA4BCD196A8 + D0D5D4DEDFCDB9D3D3B9C5DFEBC7C7EEEBE4D9EBC7EAEFE2EFECEEE8E5EBE8E2 + EAEEEEEEEFEFECF4ECEFEEEBE9DAD8D8D2D8D7D6DCDCD8D2DCD7C9B9BBB2A895 + 8B8955563E322B324A3856484C4A383C383C38383E384A464449464C4C4C5E52 + 5E8A856D6D8D6C899261766F6C746A7677767B897692776B6F7B97779077757B + 77906F9D9190919D919191939092916F90777A777A7A777A7A767A6E7A7A6C74 + 746C747073746A71766A6A7161736C616D665567615E555E4E524E52674C5E67 + 5E67736C8A8B7A9395ACA8ACA8B2AEB2B3B9B9BBC9CACDD0CBCDCDCDCDC9D2D4 + D6D4D6D8D6CFD8CED9DBE2E1E4E5ECE3ECE5E3E7E7E7F1F1F1F1F4F1F3F1F4F0 + F6F3F3F8F3F8F6F8F3F8F3F3F3F1F1E7F0ECE7E7E3E5E2E5CFD9CECCC4C2AD9E + 9B988E8C8357814B333336273127232623221B2222191619161416131413140B + 160B0D0B0B0E0B160B14141922222130252535303535021B2F1A051A2F1F101B + 411F181F41401F294F41182947401D2C4F422B465F453847824B2F87FEFBFEFB + FBF9C00F1623203D89683E5785844B86845B3F6284853757868181378E57303E + 8967505785843B81823D353D824B213D884A2B4667473A404F2E1E2F821E1B27 + 802E1B263B2F131B2F2715193D2E121F2F2C15248256678B9C9AA8ADC4ACADA8 + C5B8C49E82F5FBF8FBF8F7EFD4D1B1ABBFBE94ACD5D5DDDDDCCAB9D7CAC5C9DE + EBE8E2DEE2E9EBD9CFEFF4ECECF4ECEAEBEEE2EAEBEEEFEFF4F4F4F4F4F4EEEE + E9DADAD8D8D6DDDCDCDED6DCDCD7D0B9B9B2A897938B5B5550393E4A4E565A49 + 5555444A4A434A4E4E4E4E555E5A5E6167616761618D6D76888D7389976A7A76 + 75767A757A7A6F927777917B7775939D77907790917790939D90919393939197 + 9091926F7B907A927A907A777A777A76747A7474717474717471717473716C73 + 636D6C63736D61676761555E52555E5567525E6D616D73768B918B9597ACA8AF + ACB2B3B2B2BBBBB9CACDCACDD0CBCDCDCDC9CDCDD4D6D4D6D4D6D9CEDACFE2E2 + E1EBE5EAE3E5E3E7E7E7F1F2F1F1F1F1ECF6F1F1F3F3F8F3F6F8F0F8F6F8F0F3 + F3F1ECF0ECE7E7E3E3E5E5DBDBCFCEC7C4C4AD9E9B9A8C8682824B3D3D353327 + 3030262227222622221B211619161614160B14160B160B0D0B0B140B14141419 + 19222625303131313535021B2F1A05152F1D051F2F2C111D432C1D2C47401D28 + 4740242C4F42384467442D5E82823183FBF8F9FEFEFBC3170F0E16576F68605B + 6D67503F6D6939628984576286843757988421356361555B844C5767884A3C3C + 6D5B4B32564425324E38292B4F432C1F824115264326181F3B2E122F3D1F051E + 431F121F2F1D152567887194A3A3A3AAAFA8B1B2BEB9AE9E82F7FBFBFBF8F7EF + CDBBA5B1B7B38BB9D7D5D7D7D3B9BBD3BBB9DDDEE9E9DEDBD8D4EEE4E2ECF4F4 + F4F4EAE2EBEBE2EAEEEFEFF4F4F4F6F4F4F4EFEEE4DEDADAD8DCD6DCDCDCD8D8 + DDD7D0B8BBB2A8938B896151483E3E4E545555515555494A444A4C4A52544C52 + 5E53615961616A636A8A6C8576936D8B937377767574757A7A7792917A6F7792 + 907777759D77907B7791779D9D907B9D919391937B9177907A907B7A7A7A7A7A + 7A7A7A7A7A7A7A767A74717473747174716C6C736C6C666C6D7361676359615E + 555E5252615E6166617376738B92959397ACA8A9AEB2B2B3B3BBB9BBBBCACACA + CAC9D0CBC9C9CDCDCDD2CDD4D2D4CCD4D9D8CFDBE2E5E5E5E2E1E3E5E7E7F1F1 + F1F1F1F4F0ECF0F6F1F3F6F8F3F8F6F3F8F6F8F1F3F0F1ECF0E3E7E7E3E3E4E1 + DBCFD8CEC4C4C29E9A988C8C8682813D3D333131272722272227222227221B20 + 1A1616160B160B0B140B0D130D0B0B161414152019222122312531353135091A + 1B12051A2E1111122E1C1124411D1F2843401824474024284F442B4C5F583844 + 4E4E2581F7FBFBFEF9FAFBC3C081838F6968605B6D6751626F63606084633F50 + 69573F57846757325552394A8567444C67524E4A6744253967382B3A5A2B2D40 + 47291E244128181F4124182C411F18112E2C1E1E2E241112431F115A8A667DA1 + A2A6A7AAAAABA4B0B1B3B29A82F7FBFBFBFBF8EEC5B2A4B1B4A3A1C9D3D1CDD3 + D0B1BBD0B2B8DCDDDFDED9D4D4D6CCE4E4EFECE1F6EAEAE8E9DFE2E8EEEAEFEE + ECEFECECEFECEEEBDEDAD8D8D4D2D4DCD4DAD8D6DDD3C9B2B2A99D8B926D553E + 32323948444A4C3E494A3E3832383E3E3E44484C495252525252596164896173 + 6F8D6E76896E736E6E75747574777A927B77767777906B90779D90776891909D + 9390909391939192907A776F77757A7A777A7A777A757A7474747374746C746C + 706B706C6A6A6C6A6C616A676C6C526152525E5252594C525952596C616C7374 + 7A8B9592A3ACA8ACA9B2AEB2B1B2BBBBB9BBBBBBBBBBBBB9BBC8C9C9C9CDCDC9 + CDC9CDCCD4CED9DBE2E2E2E1E2E1E2E3E3E7F2F1E7F1E7F0F4F0F4F3F3F3F8F3 + F8F3F3F8F0F6F0F6F3F1F4F0E7E7E7E3E3E5E5DBCFCFCECEC7C4C29E9E988E8C + 82864B4B3D3631273130262722302627222227191719161616160B160B140B16 + 0B0D160B1A141619201E2221313131253534020B1A1105051F1105101F181018 + 2C1C182940291E1D402A1D28462D2B385E443849554A3236E0FBF8FEFEFEFDF9 + F8F7F8F59E683F4A63554854513E503F605762565B503C3F674A564A4C38324B + 8232444C5C58383E5F2B323A472B1E2A4328241E401E1F24292E15182E1D111E + 2E181F1C2F1810152C1811112C242D886D8B7894A2A0A0A3A7A3A4ABB0A5A99C + 8CFBFBFCFDFEFBEDC5A5A3B4A6A1A1CBD0BFBBD0BAB2BAB2ACB9CDD4DED8C5C5 + D4D2ACC4EBEBE1EAE1EAD9D9DFD4D8D9EAEAEAE8EAEAEAEAEAEAE8DED4CDD4CD + CDCDD4D4CCD4D8D4DCC9B8A9ACA9937A896D3E252B21283C323C322B322B282A + 28252B323232383E4438444944495252527352736D7A6D6A6B636B6A6B6A6B6B + 6B6E6B6B6F7777757777777577779D77906B6F9391779091779377916F776F75 + 6B75766E6E736E6C6E6C6E73746A746C6E656C74656A74646A6A64646A61646A + 616D4C524C4C5252494C5252525961646A717A7A7A9492969CA9A9A9A9AEA9B3 + B2B3B3B9B3BBBBBBBBBBB9BBB9BBC8CAC9C9B9CDC5C9C5CDCCD4CEDADBDBDBCF + E2E2E1E5E3E5E7E7F1E7F1E3E7F0ECF0F3F3F3F3F3F8F3F8F6F8F1F3F0F3F0EC + ECF0E5E3E5E3E3CFDBCFC7C7C5C4C4C29E9B988E8686823F3D35333130272230 + 2627302630272623221B1419161614160B16140B140B0E161615161919221922 + 312530312535021A1B120A112C18051A2F1C1818411D1D2E43401D284340282B + 5E2D38445F58494967483E35C1F6FFF9FFFEFAFAFBFBFBF79E62626285555054 + 89693E3F89625484635B3F4A85553C4B5A382B3A5A5A2B58724E384E7244283C + 5F4228414F4324285A241E243D24151F3B2C181E2F2C111F411F121E2C24181E + 41454472798B7CA1A7A4A2A7AAA5A7B0B0B0A5AC9BF7FBFDFDFBFBEDB8A8ABBC + A6A3AACBD1BFD1BEB3B3CAACA9D7D5D8DDDFD2C5D7D2C4C8DBEFEFEAECEAD9E8 + DFD8DEE2EAECEEEAEEEFEAEFEAEBEBE9D4D4D2CDCDD4DCDAD8D8D8D8DDCDCAB2 + B2A99792766D4B323225384B384E4B4A4E4B383A3A43393848444C464C4C5E5E + 5E526161618A638A8A9289766B766B766E6F74756E7A7B6F7B77777B90777790 + 7777919D9090909393909193919C909276776F776F75757A76747A7476747374 + 73747374706B716C6C6C6C706A6A6A646A6164616466535E55525E5952595259 + 59596C6C6C737A7A7E929692A5A9A9A9A9B1A9B3B1B3B2B7BBBBB3BBBBB7BBB9 + BBB9BBCACBBBC9D0C9BBCDCDCDD4D2D8DAD9DBD9DBCFE1E2E3E5E3E7E7E7E7E7 + F0E7F1F4F1F3F3F3F3F3F3F0F6F6F0F6F1F3ECF0F0ECF0E3E3E1DBDBCFCFCECC + C4C7C2AD9E9B9B8E8C8382813C3D36312731302627302627302722221B22161B + 161A161614160B160B140B1419161619221E2222212231213525021B271A051F + 2F1F111A411F181D412C1D2E4F4129415F422C388245384C725E464C7355483E + 86C3F7FBFFF9FFFBFBFBF7F59E626284736360626F696062696950698D553E62 + 8A554A4B853825325A5A444F885F384F824732438238293B822D2A3A43321E33 + 4F281E214F28151E4F1E181F3B2C121E41240B32726C6476967E95A5A4A4A2A3 + AAA5A7A7B0B0B0B2ADF1F8FBFBF7F8EFACAEB4AAA4AEBCCBD1BFD1BCB3CAAEA8 + B8D7D8DDDCDFCDB9DDD3C8CEE5F2F5F4F4EFE2E4E8E4EBEEE7F6EFF5F2F4F5F4 + F2EFEEEBDBD8D8CEDADADADEDCDAD8DADCD2BBB2B8A99C928553554A48395155 + 555B5255554E4848444A4C544C555E555E61596361646D6A6C8B6D918A8A7A76 + 7A767A76757A7792897B777B777A907B7B7B7B77917B907B9D936F9D93909393 + 939C919392897B7677767A77767A75767A7476747A7A78767A78747374717174 + 716E716C6C6C6C666A6161665E61615E615E666A716C71797A7A9492969696A5 + A5B2A9ABB1A9B1B1B1B3B3BBB2B7BBB7BBB2B7BBBBB7B9BBBBBBCAB9B9C5BBC9 + CDCDD8D8D6D4DACFD8D9DBE1E5E5E5E7E7E7E5E7ECE7F0F1F1F3F3F3F3F3F3F3 + F3F0F6F0F6E7F0ECE3E3E3E3E3E3DBE1CFCECFC7C7C4C4C29E9B988E8C844B4B + 3D3533313031222730273130272627222319231A20161B142216161614141314 + 1619221922222226213121353035091B2F1A051A2F1D051F2F1F181F43291D2C + 43402C405F422A415F44384E725E585A8852515556848FC6F3FBF7F7F8F7F7F6 + 9F896985896F606089685462896850698963505689554A57884A25325A39384E + 67474A4F674628435A422A415A43283A4B2A1E3147281E1E432B15244324121E + 411F12193A2A2B4E7378707CA1947EA2A4A4A2A3A9A5A7ABB0B0B0A9B8EFF5F5 + F6F7F4E4B2A9AEA6A2BCBECBD1BFBCABBCBEA9ACCADCD2DCDDDCC5B9DDC8C4DB + E5E2E1F7F5E1E2EBE4DAE5EFF5F4F1F4F2F5F5F4F4ECEEE4DBDACFD6DADADEDE + E4DEDCDEDDD3C9B2B2A9977A766356484839546151635B555555494A44564C4E + 4C554C5E615E616764636C6C6D926D8B938B897A897A76777A7A777A7B7A907B + 7B7B7B7B907B937B907B907B9D93909191919193939C919389777A6F7A6F747A + 7674767476747A7674737474717476786C73746C6C706C6C6A6C6A666A666161 + 615E615E666166616C71737A7A7D92949696A297A5B1A9A9ABA9B0B1B1B1B3B3 + B3B3BBB7B3B7BBB3BBBBBBBBBBBBBBBBB9BBB9C9C9CDD2D2D6D8D6CED8DAD9DB + E1E4E5E5E5E5E3E5E3ECE7F1F1F1F3F4F1F3F1F3F1F3F3F1E7F0ECE1F0ECE3E3 + E3E5DBDBCFCFCEC7C4C4C2AD9B9B988E8C83573D3D3533362731273026303127 + 30272227221B201B141B191616161616161414161A201B192219212530253525 + 3525031A271205122C1111122E1C111D411D182843401D2D5F2D2A2D5A423844 + 725842458852496163503E578E8E8F99C18E8F9B8668545B766A536073635160 + 6F6154626F67505167554A3F674A32324A28323A5A4A283C5F44253A5F442A2D + 472D242A43281E2C43241E1D3A2C181D2E2418192E1E11124138464C71786578 + A07E7D96A2A2A2A3AAA396A7A7A6A6B0ACC9C4C7CCCCC4AFAEB1A27FA2B7BDBB + BFBFB1ABBEB596A8C9D0CDD7DDD2B9C8D3BAAFDEE4C7C7EAEBE2DEDBDAD9E2EE + ECECE7ECECEFECECEBEBEADED4D4D2D4D4D6D8D8D8D8DADDDCCDB9A9B29D9276 + 63553E2B25323E4A4A4E494A4E4A38323232383E384A4C4C4C4C525E5E526166 + 6D8A6A8A8A767676766B7676757576777A7777777777777B7777907777909077 + 90909D9D9090909790937A91767A6F767574766E767473746C746C74746C746C + 746C706C746C6A706A6A656A6A646A64646A5E52595E5961645E656A66717478 + 7A7D7B7E9696A496A5ABA5B0A9ABABABB1B1B1B1B3B3B3B3B1B3B3BBB3B7BBBB + BBB2BBB3B9B9B9BBCBCDCDCDD2CCD4CCD6CEDAD9DBE4E5E2E5E5E1E5E1E5E7E7 + F1F1F1F1F1F1F1F1F1F3F1F0F4F0E7F0ECE3E3E3E5E2E1CFD9CECEC7C4C4C2C2 + 9B9B988E8682814B3D3533313130273127302731273027221B221B201B201616 + 16191614140B16141916192019212230253025343535020B1E0505121F110411 + 2C1111182E1D181D41292440472D2A2B4E422A445F4C4547795844496A534955 + 61544A5B854B3C5763635B6D896A51606D534955735350546D6248516149393C + 5B4A2B3C4E2B1E254E3924325A44283247422A2A382D241D412C181F431D181F + 401D181E2E1D12182E1E111E4F474E5E70707070947D7C96A0A2A0A3A3A3A1A7 + A7A6A6A7ABA8A8AFAFB2A8A5ABB07EA2A7B7ABBBBBB1A9A7BCA594A9CDCBCACD + D2BAA9B9BBACB9D6DFDAC7C7D9DEE9D4CCD8E9EAE1EAEAECEAECEAEAEAE8DAD4 + CCC5D4C5CDCDD4D4CED4D8D6CDB8B2A8B297926C533E32242124323E3E4A383A + 3A322A25282B32323238384444444C4C4C525952616C637676736A636B6A6E6C + 6F6E75757675757775777777777775777B7777777775909D6977909091917576 + 766F766E736B6C6E6C6E6C6C746C6E706A6C6C706A706B6C6A706A6A646A6A65 + 6A64646A646452525259595959646A6C707473747A927E967E9696A2A4A9A4A9 + A4B0A9ABABABB1B2B1B1B1AEB1B1B3B1B3BBB1BBB3B9B3B9B3B9BBB9CAC8C9C9 + C9C9C9CCCDD4CED9DBE2E4E2E4E1DBE1E4E3E7E7F1E7F1F1F2F1F1F1F1ECF1F1 + ECF0ECE3E1E3E1E3CFE3DBCFCFC7CCC6C4C4C29E9B998E8C86824B3D37333336 + 273130273127333033273026231923191B161916161616141614141A14201922 + 20212225252535253535021A1B12051A2C1105112F1C1118411D1D24472D2938 + 5F402B385F44384666584546725E4C5266525364897363636F694B826D6F6167 + 7A6A60558A67555576615456856156557249323C824A384A5F441E254A2B323D + 5A2B2B3A4F38282D4F2B1D2C412C181D4129181F411D181F4118121E411E1D43 + 885F47727D7D787DA1947DA0A0A1A0A3AAA3A3A7AAAAA6A6B3AEA9B3ABA7A2A5 + A7A27EA7B7B3B1BBBFA9A7ABB3A2A3BBCBD1CBD7CAB8BDBBAFB3CDD8DFDED8D6 + D4C5EBD8C7D8EBEEEEECEAEFEEECEEEAEBE8DED4C5CDCDCDCDD4D8D8D8D8DADC + CDB9AFA5A9A3926353483A2B32324A48554C564A463A32323232384844484C4C + 525252595964596A6A6A6C897A76766E766B74756E757A7577757777777B907B + 7B7B7B7B90777B907B909090B290779190979075767675766E6E736E736B716E + 6C6C6C6C746A706B6C6A6C706C6A706A6A6A656A6A6464646464525959595964 + 6A6A7070747A7C7A7E7E7E96A2A4A4A4A5A5A4A5B0A5B0ABABB1B1ABB1AEB1B1 + B1AEB1B3B3B3B3B3B3BBB1BBB3B9BBBBCBCBCAC9C8C9C9C9C9CCD8CEDBD9DBE2 + DBDBE2E2E1E5E5E7F1E7F1F2F1E7F1F1F1F1F0E7E7F0E1E7E3E1E3E2E1CFCFCF + CEC7C7C4C6ADC29E9B8E8C8C86823D3D3D3D3133303327342736273330273123 + 221B22162216161916191616141614161919221921222125303535353535091B + 2F1B0A1F2E1D0B1F2F2C181D41401E2A47422D465F58383C7245384C725C4C52 + 885E52668A6A616A766F6C76766D5B85896F678593766868896D5B67896D5684 + 8863566D88524A4B884E3C4E725A323A4E2B253A5F462B4B5F4228324F42242E + 43411F2C4329182C431D182E4126182E4F43385A79664D727D7D787DA3947DA1 + A2A0A2A3A7A5A5A3AEAAA7A7B4B1AEB3B0A6A6B4B0A2A0B5B6B7B3B7B7A9B6B5 + ABA3B1CBCACBCAD1BBB3CABBA7B9D7DCDDDCDCDCCCC9DCDADBE9EBEEEFEFEFF4 + EFEFEFEEEEE9D9D4CCD4D5CDD4DCD8DEDADEDEDDCDB9B2ACA99D927363554B3A + 3E4E565B675B5B5B5A4E4E4A464A554C555261616166636A6C6C6F6C6B6C768B + 897A7A76777A75777A7B777B7B7B907B7B7B7B7B7B917B937B90937B90937B9D + 909D91937B919077917A777A757A747674767473746C74737471746C70747174 + 71746C6C6C706A6A656A6A646A6464616A6A6A6C707473747A7C7A7E927E9696 + A296A4A4A4A5A9B0A5B0A9B0B0B1ABB2B1B3B1AEB1B1B3B3B3B7B9B3BBB3B3B9 + B3BBBABEBDCAC9CAC9CBC9C9CDD2D6D4DADBDADBDBDBDBE2E1E4E5E7E7E7E7F1 + E7F1F2F1E7F1E7E7F0ECE3E1E1E3E1CFE1E2CFCFCEC7CCC4C4C29E9B8E8E8C82 + 81574B3D353336273330332733273627313123262222161B1917191720162016 + 16191614192019222121303535393639373C031B2F1A051A2E1F111A411F181F + 412D1D2A5F422D4672583846724C444C7259526D895B445B8A6149637A6D6B6D + 9076566D6F6B626D916F606989695B627A6D545B89635567765E3E56675A3E4E + 725E384B822A1E284F47283B824228414F2B242A4F3A1E28432B1E24432B1E24 + 4F2C2C4388584C5E7A5D65797D7D7D7CA17E7EA0A1A2A0A2A4A4A5A5AAAAABB0 + B1A7A5AAA7B0A7ABA2A0A3BCBCB7B6B7B4ABB7B4A4A5B3CAD1D1CACAB5B3BEAE + B2CADCD8D7DCDCCDD6D6C4CCE9EEEEEAECEFEFF2F4ECEFEEEEE8D4D4D4D4CDD4 + D5D8DADCDADEDED6C5B8B2A5A8977A7363513839394A555363535B5B554E4948 + 4949494955525E616161666A6A6C6A6E736A6E7A7A76747475757A77777B777B + 7B7B7B7B7B917B7B917B7B907B7B937B77907B90776F9D9191777B6F7B7B777A + 75777A76747674736E74736C7471746C746C6C6C716C746C716C6C6C6C6C666C + 656A6A6A6C6C71747374787A7C7B7E7B7E967E7F96A2A2A4A4A4A5A6ABABABAB + ABABB1B1ABB1B1B1B1B1B3B1B3B1B3B3B3B2B3B3BBB3BBBBBDCBBBC8C8B9C8C9 + C9CDCCD4D6D8CFDADACFDBD9E4E1E5E5E3E7E7E7E7F1E7F1F1F0E7F0E3E3E1E3 + E1E1E2E1DBCFD9CFC7CCC6C4C29E9B9A8E868386823D3D3C3D33333336273627 + 3336273127302622221B22192319171916161B14161616192319202122313535 + 353F39373937021A1B11091A1F1204122F1C1118411D1F2A47422A385F453846 + 6745384972583E556355554E6D5548677360616F6D63546976605168896B6062 + 6F6251636F615057856149557153324A674C3849674532435A46242838241D2C + 4F38282E4F2A1E28432B1E1E422A1E1E462B1E244F322D465F5E585878786679 + 7D7D787CA07C7DA0A07F7EA0A2967FA2AEA3A2A7B0ABA3A7A7A6A2A2A0A2A3B5 + B4B4B4B1A7B4A7A4A2ABBBB3BEBEBEB7ABB3ABA5A9CBD2D5DCDCD2CBCDC8C4C4 + CEEEEEECECE3ECEEECECECEAE8D9D4CCCDCDCDD4CDD4DDDEDADCDCD2B8ACA896 + A592766452393232255051516755514C4A39323939323E484449495252526459 + 64636A6A6C6B6A7675746F6B6E75756E757777777777779077777B907B7B7B7B + 917B77907B907B90907B909D906F9075779075777576756F736E736B6C6C6C6B + 6C6C6C6A6A6C6A6C6A6A6C6A6A636C6C6C6D6A6C6C6C636A6A6C6B6C74767A7A + 7A7E7B947E969696A296A4A4A5A4A4A5A5A5A9A5A9A9A9A9B2A9A9A9B1A9B1AB + B1B2ABB2B1B2B2B3B2BABBB9BBBAC8B9C8B8C5BAC9C9CCD2CED4D6CEDACEDBDB + CFE2E3E3E5E6E7E3E7E7E7E7E7E6E7E7E3E3E3E1E1E3CFE1CFCFCFCEC7C7C4C4 + C29B998D8E868282573D3D3D333633362727332736273336272222221B221B20 + 191720191B2016201619162019221922253535393535353F353F02131A0B040B + 1F1005131C11111C2E1C1D2443292A425C4532385E4232385E4C44496D524849 + 6D5248546D616061896854626F5351556F6D60626D635055635348566D55484E + 725239434E442B465E422D38472D2B3246291E24421D1F24432824243B281E2C + 43241E2E4F2A1E384E4442585C5C457278655D787D7D787D947E7C94A0A07E96 + A27F7EA3A6A2A2A5A7A4A2A2A7A7A07EA2A7AAABB4B6ABA7B1ABA6A0A5B3A9B7 + CAB7B3A7BCB5A5A1B9D0B9D6D7D2B9BACBB9A8ADD8CEEFEFE1ECEAE5E8D9EAE9 + D8CDB8B9BBC5D0C5C5D4D4D8D4D6D7C9B2A9A596927A66523E2B2119253C4A3E + 564A4A3232322524252532323239443E444C4952525959536A6A636B636B6A6B + 636B6B6B6F6B756F756F7777777777777777907777907B7790776F9077906F6F + 9D90696F69686F696F686D6D696D636D636D6A6D6363636363616261625B5B5B + 5B6162635B636763676963636D686D766F7676777A7B927A9692969696979697 + A397A59DA4A5A5A9A5A5A9A9A9A9A9A9B2A9B2B2B2B2B2B2A9B2B2B2B8B8B9B9 + B9B9B9B8B8BAC5C5C9CCD6CCD6CECCCECECECFCFDBE1E5E3E3E6E3E7E7E7EDE3 + E7E7E3E3E3E1E2E1CFD9CFE2CFD9CEC7C7C5C4C29E9E9A8F8C868357814B3733 + 36333127363336313380313027302623222216221B20191616201A1B1416201A + 2022222130353535373937373F370217271005132E11051A2F18101F41291C2D + 432D2D425F5C384E5F4C38495F5E445E88615161766150566F615B69896F5168 + 85635462766F6269896355638563505B85524A556D5E3856674638465F443846 + 5F4438465F4428415A2D282B4224242C472B243A4F2D242C5F2D2A4E6745445C + 7166455D797070797D7D787EA0947D94A07EA0A1A2A096A2A3A6A0A7ABA4A2A3 + A7A77CA0A4B0AEBCB4B0A7A7B3B6A1A2AEB7B3BBBFB7ABAABCB4A0A5BBCBCDD2 + D7D2BAB9D1BAACC9DAD8E2E7E3ECE5EAEEEBE9E9D8C5C8BBB9CACDCDD4D4D8D9 + DCDCDCC9B2A99796967A6C5238323221325654565B554E56463C3C323A3C3848 + 494C4C4C5E5261596464636A6C6C6C6B6E766B6E757575757575757577777777 + 9077907B77907B7B917B907B7B90927B90776F90AC9D9F9D9FAC9F9D9F9F9D9D + 9C9D9C9D9C9C9D9CA89C9D9C9C9C9A9C9A9C9A9C9C9C9C9A9C9C9C9C9C9C9D9C + 9D9CA89DA8A89DA8A8A9A8A9ACABA9A9B2AEB2B1B2B3B2B5B9B3BBB3BBBBBBB3 + B9BBBBBBBBBBBBBEBBCABBBBCABBD0C8D0D0D3D2D1D2D0D2CBCDC9CBD2D6D2D6 + D6D6D6D8DAD8DBDBE2E5E5E5E6E5E6E5E7EDE7E7E7E6E5E3E3E5E1E2E1CFD9CF + CFC7CEC7C4C7C4C29E9B998E8C8357574B3D3D353D3627313627338031313627 + 3027222223221B20191720192016221616191420192221303535353537353739 + 373F091F3B1A101A4118051F411C181D43401D3A5F422B46795C4C4E71524C52 + 73614C67766655637A63516376636063896F686977696363896E6269926F636D + 766C5469736355637361485B7252444C7258384C7245444C6758384F885F464F + 5B38282D473828325F452A38884D44888B665965797865717D7D707D94947C7D + A0947CA1A3A094A0A2A5A1A1A7A4A3A6A7A6A3AAABA27EA3B4B4AAB3B4A7A5AA + B4A77EA7B5B7B3B3BFB7AAB4BEA7A3AECAD1D0D2D7D0B3BDD0B8AED2DDDACFEB + F2F4F4EDEEEFE5EBDACCC5C8C8C9CDC7D8D9DBDAE2DDD2B9B29DA597927B7361 + 483E483E556D636D6C636361554C4C484949494C4E5E5E616166666C6C73746C + 747474747A7475747A7774777A777B7B7B777B90777B7B907B7B907B7B7B7B7B + 907B7B7B927B92779277907A7A897A7A7A7A7A7A7A7A7D767A7A7C7A7A797A7A + 787A7A747A747A747A7478747474747A7C7A7A7C7A7A7A7E7A9494967E96A096 + 7F96A2A296A4A4A3A4A5A5A4A7A5ABA5ABA5ABABAEABAEAEB3AEB1AEB3AEB3B1 + AEB3AEB3B3BBB3BBB5BBB5B9BCB9BDCBCBCBD2D0CDC9CDCDCDD4C9D4D9DAD9E2 + E2E1E2E3E5E3E5E3E3E5E3E1CFE1CFCFD9CFCFCFCEC7CEC4C7C4C2AD9B9B988E + 8C828281573D363D313336313333363D3680313027302322221B22201B192016 + 19161B201B1416201922223125353535373937373F3F051B2F180A1F2F18101B + 411F181D43401D435F2D2D58725C445E885244527259496173636163766A5362 + 766368639076696F896C6869766D68698976686D766D53628A63556176614C5B + 885E4C58725E444E725E384C665E2A465F4742465F4638465F462D465F5C424C + 79665C8BA3795C6579705D717D78787D947E7C94A17E9494A0947EA3A27FA0A3 + A6A5A2A3A7A4A7A2A27E94A7ABABA7B3B4ABA7B3ABA2A0AEBEB7B7BBB7B3ABB4 + B4A1A2B2CAD0D0D0D3BBBABBB5AEB9D6DDE9D4D9EBEEEFE5E5ECEEDBC7C5C5C5 + C8C9CCD4C7D9D8D9DEDFD4B9B2A597967B766F56554A3E48556D6D6B6D6A6361 + 554C4C4849544C56525E616161666A6C6C6C746C7476747A757A777A7A777B7A + 7B7B7B7B7B917B7B7B907B7B7B907B917B917B917B9292929292967B9292927A + 92927A8B7A7A7A7A7A747A7C797C7A7C7A7C7A787A7C747C747C747C747C7B7C + 7E7C7E7E7B7E7E7A7E9494967E967EA07E7F967FA0967FA27FA2A2A2A4A2A4A6 + A5A6A7A4A7A7A5A7A9A7ABABABABAEABB3ABAEB1ABB3B3B3BCB3BCBCBCBCB3B5 + BAB3BABCBDBDBBC9BBBBB9B9C5CAD4CDD4DAD9DBD9E4E5E3E5E3E3E5E3E3E1DB + E1CFCFCFCFCFC7CFC7C7C4C7C4C4AD9E9B9A8E8E868281573D4B3D3633363380 + 31363D273D3D30273027222322221B2216231920162216191619201920222231 + 3530353537353F353F370313270A05131F1205132F1810182F291F2D4F402A46 + 5F58384E6745444C6745445E6D5E54617661515B6D53556289696D6989695662 + 766354628963635B8A61545A6D554C56725E445A675E384E5F5838475F463846 + 5F4438475F452D47724742425F454247724D4247795D5C799C7965707D795D79 + 7D7D7278947D7894A07D7CA0A3A0947EA2A3A0A1A3A2A0A1A6A4A3A07FA0A1AB + B4ABA7AAABA5A5A7A5A2A2B4B5B3B3B3B7ABB4B4A7A2A5BCCACABBCACAB1B3BB + A9A8BDD3D6DECCC7D9CEEBEEE8E9E9C7B8C4B8B8C5C5C9D4D4C7D4D4DCCDB8AC + 9D96977B766D554A312532324A575B5B5B564E4A3C4A3A323A3939393E4A4850 + 5255535559636363636B636B6C6B6F6B6F6B766B756F756F7577776F90759077 + 9077779077907590779077777575777B757777777A7576777674767A747A747A + 747A7A787A74787476747C747C777C747C747C747C777C7B7C7E7A7A7E7A7E7A + 967E969496967E967E96A296A2A2A2A4A2A4A5A4A5A4A5A6A5A4A5B0A4ABA5AB + ABA9ABABABB1ABABB1B1B3AEB3B3B3B3B3B3B3B3B5B3BAB9BDBDCBB9C8C5C8C5 + C9C5CDCCD4D4DACFDACFE1DBE3E1DBE1E1CFE3E1CFE1D9CFCFC7CEC7C7CCC6C4 + C4C4AD9B9B988E8C8C815A4B3D3D3733363333363D27363D3336273627222722 + 232023192319201622161920161916201922313035353535373937373F3F020B + 1B0A020B1F05050A1F1110122E1D182C4740282D5F42384E674C384C6744384E + 6D52485B736151566D5251566F61626D6F6354566D63546285635B6185674856 + 6D4C484C6758394E5F44444667452D445F382D385F422D435F422D4245422D42 + 5F452D45724D4258725D4D79A37D5C6679654D667D6571787D7C707D947C7C7C + 7C7E7C947F7E94A0A2A07EA0A2A27C7EA07EA2A3ABA7A3A4A7A4A2A3A27FA2B3 + ABB4ABB1B1A4ABA2A2A2A7B3BBB7B2CAB1AEBBA9A3A9BAD2D3D2CCD4DEC7C7E9 + E4E2D8C4C4B8C4B9B8C5C5C5C7D4CED4D4C5B2AC9D977B766D553833241E2131 + 3C4B574B4B483A333A262626262E2125312C32323938484C544C565555556762 + 6367696D6F6F696F696F6F6F906F6F906F906F906F90906F90909090906F9090 + 909090906F906F906F897676896F6F736F737373736C7371736C736D6C6C7378 + 7178737873787A797A7C8B7E8B947A948B9492948B9592959594969596949695 + 969796A397A396A397A5A397A4A3A597A5A5A5A5A9A9A5A9A9A9A9A9A9A9B2B3 + B2B2BAB2B3B2B2AFB2BAB8BAB9C5BAC8B9BAB8BAC4C9CCCCCECECECFCFCFDBCF + E1CFE5CFE1CFCFCFCFCFC7CFC7CEC7C6CCC6C4C4C4C49E9B9B988E8683824B81 + 4B353D333D363327363D3380353D3027302722272223192319201B1920162216 + 2014201922193035253535353735373E373703161F120912261805132E181018 + 41291D3A472D2A385F58384E725244556652385573525163766351606D535160 + 6D6855698963606976635462766C606D766355556D5349527152484E6D45445E + 5F584447724C444C665C3845724D4458725C425C725D455E795D585F78656579 + A39670787978707D7D787079947C787C967D7CA0A0A07EA0A2A094A1A2A094A2 + A37F7E7EA7A2A3A7ABABA3A3B0A7A2A2A2A9A7B4B3B3B3ABB4A9A7A2A6A9B4BC + BBBEB3B7B1B3AEA5A9B5CBD3D6D2D2D4DCD4C7E4EBEFEBDBDBDADBDAE4DAE4EB + E5EBE5EEE4DBDAD2C9C9C4C4ADC2C19BC1C18FC19FC1C2C2C2C1C19EC1C19BC0 + 9BC0C1C19BC1C1C1C1C2C1ADC1ADC2ADC2C2ADC2ADC2ADC2C2ADC2C2ADC2C2C2 + C2C2C2C4C2C4C2C4C2C4C2C4C4C4C4C4C2C4C2C2C2C29FC2C2C4C2C2C2ADC2C2 + ADC2C2ADC2ADC2ADADC4ADC2ADC4ADADC4ADADC4ADC4AFC4ADC4AFC4AFC4AFC4 + C4AFC4C4B8C4C4B8C4BAC4BAC5BAC4BAC4BAB9C8BAC8C8C5C8C9C8C8C9C9C8C9 + C8C9C8C8C9C9D2CCCDCBD2CCCDD2CDD2D2D2D6D2D6D7D6D6D6D6D6D6D6D6D6DA + D6D6D6D6D6D6D6D6D6D6D6DBDBDBE4E4E4E4E4E4E5E2E5E4E1E2E2CFCFCFCFCE + CFC7CCC7CCC4CCC4C4AD9B9B9A8E868C82574B4B3D3C3D363333363380313336 + 333D303127302322272217221923142216201B20191614202022223130353535 + 373937373F3E091F331A051F2F18051F2F1D112C434124425F463842665C4456 + 735952617359486185645163926C5463896360536F6F6069926F67697A6F6062 + 896F636F8A7653698A6152617364495B7259525E7959445E72584452715C455E + 725C455C715D585C7966456479705C717D70707CA17E787A7D7D6579947C787D + 967E789496967C94A09694A2A3A294A1A3A2A0A3A37E947FA7A3A3A7B1A7A5A5 + B4A5A096A5B4ABBCB4B7ABABB3B0A6A2A7B4B3B7BEB7BEB1ABBEABA1ABBDD0CB + D3D2DCD2D7DECECFDBEED8C4C7C4C4C4CCC7CEDBDBCFE4E5CECCC4AC9A9C9A89 + 88823D3D2F273D82835B86835B814B3D803D803B803B803D8082808280828282 + 8382868285828688868C8C868C8D868C8D8C8D898E8D8E908E8D8E98988E988D + 988E988E988D98988798988E9886988D8D98898E8D8D858D86898C898C898D8A + 8C8A8D858A8D8C8A8D8C8D8A8D8C8D8D9A8D9A8D958D9A958D9A959A9A9C9A9A + 9A9A9A9A9A9C9A979C9C9CA89CA89CAC9CAC9CAC9CACACACACACACACAFADACAF + ADAFADAFADAFB8B8C4B8B8B8AFB8AFB8C4B8C5C4C5CCC5C8C5C8C4C8C8CCCCCC + CECECECFCFDBDBCFDBCFE2CFDBCFCFCFCECFCECEC7CEC6CCC4C4C4C4C4AD9B9A + 9A8E8C8682814B4B3D3D3C3D36333D333633368035803027302727222319221B + 20162216201A201B201920192220312235353535353739373F370A1B2F15111A + 411A111A2F1F111D412A2C415A463844665C3E5E726152617361496173635163 + 89746062896B55686F6D606F916D686D906C60697663636D8A6C556D76615255 + 73644967735E4C5E7959585A795E495E715D445F795D58597965455C79665E66 + 7D5D66727D7C657A96967C7C7D7C6578947D787D947E7C94A17E94A0A0A094A0 + A2A094A0A3A1A0A0A07EA0A2AAA6A3AAA7A7A2AAABA47EA7ABA7B4ABBCB3A7AB + B3AB7EA2B0BCB3B7B7BEB1B1BCB3A5A0BABECBCBD3D3D2D2D7D6DCDADAC5DAC4 + AFCCC4C4C4CCC7D8DBD8CFD6CCC4ACA89C95898A675A3D3B3B333A8282858285 + 825A4B4B3D3D3D3B3B3B3D434B4F4F825A825B6767886D886D8A8A898A89898A + 89898989898989899189908D9090918D90919098909191918D91908D918D9090 + 8D908D898B8D8B898B898A898B898B8A8B8A8A8A8A7A8A8B8A768B8A8B8B8B8B + 8B8B8B8B8B958D959A9795959592979597959797979C9797A19CA39CA39DA397 + A39DA3A8A5A8A5A8A5A8A8A8A8A8A8AEACA9AEACAEACAEB2AFB2B2AFB3B2B2AF + B3B2AFB9B9B9B9B9B9B9BABABAB8C8C4C8C8CCCCCCCCCECCCED6CFD6CFD8CECF + CEC7C7CEC7C6CCC7CCC4CCC4C4C4C4ADADAD9B9A8E8C8682823D4B3D3C3D3533 + 333627363380353D3D3633273023222322231B202319162016201A2016201620 + 192230313035353437393735373F091A26120A122E12051A2F11111F4024242D + 4F422D386645444E6D5E4C537261484C6D525053766354636D6351606D685169 + 896C626D896354696F5951638A6C4C638859526172593E5A72584C587258445E + 72584652665D445C725D455C715D5858795D585E796558667878657894947C7D + 9478657D7D7C797D947C787D96947C94A07E7D7EA07E7DA0A3A07C7EA0947EA1 + A4A3A2A3A6A3A7A5A27F7CA5ABB4ABABB5A7A4A7ABA27EA4B3B6B3B3BCB7A7AB + BCA796A2B5BEBABBCBCBCBD0D7D2C9D7D2AF9CD3AFADAFADC4ADD4C7C5CCD6CC + C4AFA393928A73674E392A261E24324F4B5A5B5A4A4A3A3A2E252C2124262B25 + 3A32383846444C4C5E52616166636367636D6D6F6D6D6F76896F76896F6F896F + 906F896F896F90899089899089908990898989897A89897A89768A768A767376 + 7376737A737A797A7A8B737A7A8B797A797A798B7A8B7A8B8B94929492959492 + 94949495969495A19695A1969596A19696A197A297A297A3A297A596A397A5A5 + A3A5A5A5AAA8A9A9A8ABA9AEAEB2AEB1B2AEB3B2AEB2B3AFB3B9B5B9B9BAB9B8 + AFB9BAB8C8C5C8C9C9CCCCCCCCD6CECECECECECCC7CECCC7C5CCC4CCC4C4C4C4 + C4C4ADADAD9B9E9A8C8C86824B4B3D3C3D3C3335333336333D36333633362736 + 23232223221B2023161B20162016201619161920221930253435353535373739 + 3737020B1A0902091F0505051A1005111F1D1828432D2A2D4542383E5E4C444C + 6752384A67493E54735348566D514854635150546D62545B765548576D513E4C + 6D5E4A5A6D584C5E66453246674238445F452D465F453845664542425D4D4258 + 664D42455F5C4445715D455F79705D70947D7970787865657D785D7D7D78787D + 7D7D787DA07E7C7CA07E7DA0A17C787DA07F96A0A2A2A0A1A4A2A3A07F967FA3 + ABABA3A7B4A4A3A7A77E7FA7B4ABABB3B7ABA5B4B396A0A5BCBCB3BDCBBEB9CB + CBD0BACBB895959CCBAF9CADACC5C4C5C7C4C9BAAC9C9794767352462B241518 + 15182839384A4E3A322525241E191512151524242428282B2B383844494C524C + 595553535961536363636363636963686D68696963696F696F696F696F696F69 + 6F6F6D6F736F73736D7376737373737171737371737973797871797873737873 + 73787A797A797A797C7A7D7A7D8B7E8B94949494949494949494A19495A09595 + A19596A0A196A196A3A1A396A3A2A3A1A3A2A3A2A5A3A5A3A7A5AAA5A7A9AAA9 + AEABB2AEB3AEB3AEAEB3AEB3AFB5AFBAB3AFB3AFBAAFB3B9B9C8C8C5C8C9C9C9 + CCCCC9CCCCCCCCCCC4CCC4CCC4C5C4C4C4C4C4AFADC4ADADAC9B9A9A8C828482 + 3D4B3C3B3C3333333131312736333D363D803134273023221622231917201619 + 17201B2014162016222022223135353535353737393709132711090B1F120913 + 2F11101A2E2C182E47402D465F42384E675E445572554956675548566D63555B + 895954638560545689675B6D896D545B8963555B6D5E5567885E4C677266385A + 725E465E7258465E725E425E725D445E795D4D5E7966455C795F585E79795C72 + 797D5D73949478947D70657D9478797D947D7D7D947D7C7DA0947CA0A1A0A094 + A07C7CA0A1A0A0A2A3A294A0A7A7A07EA0A2A4AAA7ABA4AAABA7A7A7A27FA3AB + B3B4B1BCB7ABA7B1AE7F96B3BCBCBBBCCABDB9BED0CBCBCBB5A8A19CACCBADC4 + ADC4CCC5C5C9C8BAA8A397957A6C6747382C282424284B4E5A5B5B574A3C3533 + 33312626222625253A3A3A3A463E464C565255616763686769636D696D6F696F + 696F856F696F6F6F6F896F896F89896F907690896F89898989898A8A8A7A8A8B + 8B8A8B7A8A8B738B738A7976798B797D8B7D8B7D8B7A8B7D7A7D7A7D927D9492 + 7D94959495949494959496959496959695A196A196A1A197A1A1A2A396A396A3 + A3A397A4A3A3A5A3A3A4A7A5A3A5A5A7A9AAA9ABABABAEAEAEB2AEAEB3AEB5AE + B5B3BAB5AFBAB2AFB2BAB8BAB9B9C8B9C8C8C9C9C9C9CCCCCCC5CCC4C5C5C4C5 + C4C4C5C4AFADC4ADAFADADAC9B9E9A8D8C85824B4B3D3C3C3B353A3133333336 + 3380353D36333627272322222316221720162016201B20171420161920221922 + 303134353735353F37390A262F1E111A2F1D051B411F181F4140183B5F422B4E + 725832558A5952677361495B73535160736351698A6F5563896B5169766D6885 + 897660698A6361638A615E678A6452668B6652677961585E7966455F795E5861 + 7965585F79665C66797059667D715C718B7866727D78707D9494947C7D7E787A + 7D7E7D7D94947894A1947D94A07D7CA0A096947DA094A0A1A2A2A0A3A7A2A0A7 + AAA294A0A2A6A3A7B4ABAAABAAABA6A2A3A7ABB4B4B5B7B3B4ABB3A7A7A1ABB3 + B7BCB7BBBEBEBBCAD0D0CBBDA8A896A395ACD6ADC5C4C5CEC5CCC8AFA8A89796 + 8B76725B4F463A383C4E675B8585856257574B3D3D3D36333B333D3C3D4B4B5A + 575A5B5A635B6D696D6D856F6F85896F8990856F90896F909089908992899191 + 918992918D918B91919191918B91918B918B8B898B898B898A7A8B898B8B7A8B + 8B7A8B7A7A797A7A797A947A9492947A949492949694969696969596969695A1 + 97A197A196A197A197A197A297A597A3A5A3A3A5A3A3A5A3A5A5A3A5AAA8A7A8 + AAA5AAA8AEA9AEAEACAEAEB2B1AEAEB1AEB3B2B3B5B2B5B2BAB3BAB3BAB3BAB9 + BAC8BAC8C8C5C8C8C9C9C8C8C5C8C5C5BAC4BAC4B8C4AFC4AFC4AFADADAC9BAC + 9B9A9A8D8C8282573D4B3B3C3B3333313333363333363D363336272730272322 + 1B22231622161B20162016201616201420222021223035253535373537350526 + 2F15101A2F18051F2F18111D412C1E2A822D2D466758324E7359516173615161 + 855350536F63515B766353626F635060896355688A6F5562765351617361495E + 7366525E71644C617264585E7166445E725C495C715D4C5E7965585C71705859 + 797059667D705D727D7D707C94967C94967C657D947C707D7D7C7C7D94947C7D + A0947DA0A07C7D94A0A094A1A3A2A0A2A2A1A0AAA67F7EA0A7A6A3A7AAABA7A7 + AAAAA0A0A2AAA7ABB3B7ABABABB4AAA2A4A7ABBCB7B7B3B7BBBFBBBECABECAAE + AAA3A3A1AF95ACCEC4CCC4C5D6C5AFAFA89795957A6D675F43383A2B46566767 + 88855B5B4A4B4B3C3D3331333133333D3D4B3D4B5A575A5B5B676D636D856F6D + 856F6F856F896F89896F90896F90899089907A9089919189929091899189917A + 90917A907A89928B918B918B918B898B8A928B8B8B7A8B958B92948B927D927A + 947A9492949294949296949696959695969596969796A197A397A396A397A196 + A196A396A397A497A5A5A39DA4A8A5A5A8A5A8A5A8A9A8AAA9AEAEA9AEA9AEA9 + AEAEB2ABB2B3B3B3B2B5B9B3B2AEB2AFBAB9BABAB9BAB9BABAC8C8C8C8C8C8C8 + C8BAC4B9C4B8C4B8C4AFC4AFADAFADACADACAC9A9A9A9A8C88865A4B3D3C3D3C + 3B333A313331273D36333D36333627362723222322231B202316201B201B2016 + 161416201B20222021302134353535353735091B2F1109122F1105132F111018 + 2F1D182C472D2A425F58324E67524C5E6D6144566D4948546D53545B6F675555 + 856350626D5B555B8A635662855355618859485E88594C5F7964465A795E4C5E + 725D4C5F7258455E725C455F795D585E795D586679655C667D654D667D786579 + 9494947D947D7078947C707D947D7D7DA17D7D7DA1949494A07E7C7DA1A094A0 + A0A094A0A2A2A0A1A27E7EA0A7A4A3A6AAA6A2A3A7A47EA0A7A7A7AEB7B4A9A7 + B1ABA47EA7A5B0B6B3B7B0B3B7B7B1B3BBBBB596A7A17EA3A89C959ADCC5C4C5 + C8AFA8A89A957A73665A4F3A2E2C2C243A43675A88675A4C4A3A3A332E262C26 + 242C2628253A2B3A3A444A46554E5561615B616D616D6D6D6D6D6F736F857676 + 896F76896F89897A896F89899076897A898976907676897A8976767676767376 + 737673767679767A797A797A797A797A7A7A797D7D7A7D7D8B7D949294949495 + 949694959294959294969596969696A19696A196A196A196A196A3A396A3A2A3 + 97A4A3A5A2A5A3A5A5A5A5A5A5A5A5AAA9AAA9AEA9AEA9AEAEB1AEB2B3B2AEB2 + AFB2AEB2B3AFB3B9BAB9BABAB8BABAC8B9BAC8C5BAC4BAAFB8ADB8AFADAFAFAD + AFACACAD9CAC9B9C9A8D8D8C8582574B3B3C3C333A3333312E313133363D3633 + 3336273027222322231B2223162223162016161616161416201B202222222130 + 353435353535030B1A0A05051F0505091A1005111F1818182D2A282A45452B32 + 4C4438485E5E3E4E5B48394863524A546755515461553E5067514A566D553E56 + 6D55484E674C444C5F44444C725C44466758424C5F5C2D45724238456645424C + 5F4D454C72584558705D455C795D5C6679785D787D7D7D7A7D785D707D707079 + 7D7870787D7D7894A07D787C7C7C787DA07E7C94A07EA07EA1A27E7C7F7EA1A0 + A6A07FA2A5A2A0A5A7A078A2AAA6A3ABABA5A2A7ABA57F7EA7A7A5B0B6B3B0B1 + B7ABA9B1BEBEA5A0A3A2A0A3A197959AADCCC5ADB8AC9CA1957666594C44281D + 18121811242D47445F5E38382B2528241E1E181518151E1E241E28282A2B3238 + 384444494C525259615E61616A676A63676A636D636D63636D636D696D6D6F63 + 6D6D696D6D686F636F6A6D6A6C6D736C73736D736D7373737173737173717378 + 7374717378737D797A797D7A7D7D8B7D7D948B949495947A9492949492949494 + 9496949694969496969496A19696A396A396A396A196A2A196A2A2A3A2A3A4A5 + A3A5A5A5A5A5A9A8A5A9AAA9AEAEA9AEAEA9AEAEA9AEA9AEAEB2B3AFB3AFBAB2 + BAAFB9BAB9BAB8BAAFB8AFAFAFAFACAFACACACACACACAC9CAC9A9C9A9A8D8D88 + 825B4B3C3C3B3A333A3131313131333133363D31363127302322232223221B22 + 231B202314162016161416142019202022212230253035353535} + end + object Label1: TLabel + Left = 8 + Top = 112 + Width = 58 + Height = 13 + Caption = 'API Version:' + end + object lblAPIVersion: TLabel + Left = 116 + Top = 112 + Width = 62 + Height = 13 + Caption = 'lblAPIVersion' + end + object Label3: TLabel + Left = 8 + Top = 128 + Width = 61 + Height = 13 + Caption = 'DLL Version:' + end + object lblDLLVersion: TLabel + Left = 116 + Top = 128 + Width = 65 + Height = 13 + Caption = 'lblDLLVersion' + end + object Label5: TLabel + Left = 8 + Top = 168 + Width = 83 + Height = 13 + Caption = 'FSOUND Output:' + end + object Label6: TLabel + Left = 8 + Top = 184 + Width = 76 + Height = 13 + Caption = 'FSOUND Mixer:' + end + object Label7: TLabel + Left = 416 + Top = 88 + Width = 72 + Height = 13 + Alignment = taRightJustify + Caption = 'Contact Details' + end + object lblEmail: TLabel + Left = 371 + Top = 104 + Width = 117 + Height = 13 + Cursor = crHandPoint + Alignment = taRightJustify + Caption = 'mailto:support@fmod.org' + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlue + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [fsUnderline] + ParentFont = False + OnClick = lblEmailClick + end + object lblWeb: TLabel + Left = 389 + Top = 120 + Width = 99 + Height = 13 + Cursor = crHandPoint + Alignment = taRightJustify + Caption = 'http://www.fmod.org' + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlue + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [fsUnderline] + ParentFont = False + OnClick = lblEmailClick + end + object Label10: TLabel + Left = 8 + Top = 200 + Width = 77 + Height = 13 + Caption = 'FASTCD Player:' + end + object lblOutput: TLabel + Left = 116 + Top = 168 + Width = 42 + Height = 13 + Caption = 'lblOutput' + end + object lblMixer: TLabel + Left = 116 + Top = 184 + Width = 35 + Height = 13 + Caption = 'lblMixer' + end + object lblFastCD: TLabel + Left = 116 + Top = 200 + Width = 277 + Height = 41 + AutoSize = False + Caption = + 'A *non polling* player that prevents CD hardware interrupting fo' + + 'reground applications' + WordWrap = True + end + object Label2: TLabel + Left = 8 + Top = 152 + Width = 79 + Height = 13 + Caption = 'FSOUND Driver:' + end + object lblDriver: TLabel + Left = 116 + Top = 152 + Width = 38 + Height = 13 + Caption = 'lblDriver' + end + object btnClose: TButton + Left = 412 + Top = 208 + Width = 75 + Height = 25 + Cancel = True + Caption = 'Close' + Default = True + ModalResult = 1 + TabOrder = 0 + end +end diff --git a/fmodapi375win/samplesdelphi/FMod/about.pas b/fmodapi375win/samplesdelphi/FMod/about.pas new file mode 100644 index 0000000..4de1b7e --- /dev/null +++ b/fmodapi375win/samplesdelphi/FMod/about.pas @@ -0,0 +1,108 @@ +unit about; + +{$WARN UNSAFE_TYPE OFF} + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ExtCtrls; + +type + TfrmAbout = class(TForm) + lblCopyright: TLabel; + imgLogo: TImage; + Label1: TLabel; + btnClose: TButton; + lblAPIVersion: TLabel; + Label3: TLabel; + lblDLLVersion: TLabel; + Label5: TLabel; + Label6: TLabel; + Label7: TLabel; + lblEmail: TLabel; + lblWeb: TLabel; + Label10: TLabel; + lblOutput: TLabel; + lblMixer: TLabel; + lblFastCD: TLabel; + Label2: TLabel; + lblDriver: TLabel; + procedure FormShow(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure lblEmailClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + frmAbout: TfrmAbout; + +implementation + +{$R *.DFM} + +uses + fmod, fmodtypes, ShellApi; + +const + OutputTypes: array [TFSoundOutputTypes] of String = + ( + 'FSOUND_OUTPUT_NOSOUND', + 'FSOUND_OUTPUT_WINMM', + 'FSOUND_OUTPUT_DSOUND', + 'FSOUND_OUTPUT_A3D', + 'FSOUND_OUTPUT_OSS', + 'FSOUND_OUTPUT_ESD', + 'FSOUND_OUTPUT_ALSA', + 'FSOUND_OUTPUT_ASIO', + 'FSOUND_OUTPUT_XBOX', + 'FSOUND_OUTPUT_PS2', + 'FSOUND_OUTPUT_MAC', + 'FSOUND_OUTPUT_GC', + 'FSOUND_OUTPUT_NOSOUND_REALTIME' + ); + + MixerTypes: array [TFSoundMixerTypes] of String = + ( + 'FSOUND_MIXER_AUTODETECT', + 'FSOUND_MIXER_BLENDMODE', + 'FSOUND_MIXER_MMXP5', + 'FSOUND_MIXER_MMXP6', + + 'FSOUND_MIXER_QUALITY_AUTODETECT', + 'FSOUND_MIXER_QUALITY_FPU', + 'FSOUND_MIXER_QUALITY_MMXP5', + 'FSOUND_MIXER_QUALITY_MMXP6', + + 'FSOUND_MIXER_MONO', + 'FSOUND_MIXER_QUALITY_MONO', + + 'FSOUND_MIXER_MAX' + ); + +procedure TfrmAbout.FormShow(Sender: TObject); +var + Channels2D, Channels3D, ChannelsTotal: Integer; +begin + FSOUND_GetNumHWChannels(Channels2D, Channels3D, ChannelsTotal); + lblAPIVersion.Caption := Format('%3.2f', [FMOD_VERSION]); + lblDLLVersion.Caption := Format('%3.2f', [FSOUND_GetVersion]); + lblDriver.Caption := FSOUND_GetDriverName(FSOUND_GetDriver); + lblOutput.Caption := Format('%s at %dHz', [OutputTypes[FSOUND_GetOutput], FSOUND_GetOutputRate]); + lblMixer.Caption := Format('%s using up to %d channels (%d in hardware)', [MixerTypes[FSOUND_GetMixer], FSOUND_GetMaxChannels, ChannelsTotal]); +end; + +procedure TfrmAbout.FormCreate(Sender: TObject); +begin + DesktopFont := True; +end; + +procedure TfrmAbout.lblEmailClick(Sender: TObject); +begin + ShellExecute(Application.MainForm.Handle, 'open', PChar((Sender as TLabel).Caption), nil, nil, SW_SHOWNORMAL); +end; + +end. diff --git a/fmodapi375win/samplesdelphi/FMod/config.dfm b/fmodapi375win/samplesdelphi/FMod/config.dfm new file mode 100644 index 0000000..67c60d8 --- /dev/null +++ b/fmodapi375win/samplesdelphi/FMod/config.dfm @@ -0,0 +1,153 @@ +object frmConfig: TfrmConfig + Left = 191 + Top = 107 + ActiveControl = cbxOutputType + BorderStyle = bsDialog + Caption = 'FMOD Configuration' + ClientHeight = 290 + ClientWidth = 281 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + Position = poMainFormCenter + OnClose = FormClose + OnCreate = FormCreate + OnShow = FormShow + DesignSize = ( + 281 + 290) + PixelsPerInch = 96 + TextHeight = 13 + object lblOutputType: TLabel + Left = 12 + Top = 12 + Width = 55 + Height = 13 + Caption = 'Output type' + end + object lblOutputDevice: TLabel + Left = 12 + Top = 60 + Width = 67 + Height = 13 + Caption = 'Output device' + end + object lblMixerType: TLabel + Left = 12 + Top = 108 + Width = 48 + Height = 13 + Caption = 'Mixer type' + end + object lblOutputRate: TLabel + Left = 12 + Top = 156 + Width = 53 + Height = 13 + Caption = 'Output rate' + end + object btnOk: TButton + Left = 109 + Top = 256 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'Ok' + Default = True + ModalResult = 1 + TabOrder = 4 + OnClick = btnOkClick + end + object btnCancel: TButton + Left = 193 + Top = 256 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 5 + OnClick = btnCancelClick + end + object cbxOutputType: TComboBox + Left = 8 + Top = 28 + Width = 258 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + ItemHeight = 13 + TabOrder = 0 + OnChange = cbxOutputTypeChange + Items.Strings = ( + 'Window Multimedia WaveOut' + 'DirectSound' + 'A3D') + end + object cbxOutputDevice: TComboBox + Left = 8 + Top = 76 + Width = 258 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + ItemHeight = 13 + TabOrder = 1 + end + object cbxMixerType: TComboBox + Left = 8 + Top = 124 + Width = 258 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + ItemHeight = 13 + TabOrder = 2 + Items.Strings = ( + 'Auto-detect' + 'Non-MMX blendmode mixer' + 'MMX, Pentium optimized blendmode mixer' + 'MMX, PPro/P2/P3 optimized mixer' + 'Auto-detect interpolating mixer' + 'Interpolating FPU mixer' + 'Interpolating Pentium mixer' + 'Interpolating PPro/P2/P3 mixer') + end + object cbxOutputRate: TComboBox + Left = 8 + Top = 172 + Width = 258 + Height = 21 + Style = csDropDownList + Anchors = [akLeft, akTop, akRight] + ItemHeight = 13 + TabOrder = 3 + Items.Strings = ( + '48000Hz' + '44100Hz' + '22050Hz' + '11025Hz' + '8000Hz') + end + object chkSoftwareMIDI: TCheckBox + Left = 8 + Top = 204 + Width = 257 + Height = 17 + Caption = 'Force software MIDI decoding' + TabOrder = 6 + end + object chkGlobalFocus: TCheckBox + Left = 8 + Top = 228 + Width = 257 + Height = 17 + Caption = 'Global focus (DSOUND only)' + TabOrder = 7 + end +end diff --git a/fmodapi375win/samplesdelphi/FMod/config.pas b/fmodapi375win/samplesdelphi/FMod/config.pas new file mode 100644 index 0000000..08c4f83 --- /dev/null +++ b/fmodapi375win/samplesdelphi/FMod/config.pas @@ -0,0 +1,147 @@ +unit config; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, fmodtypes; + +type + TfrmConfig = class(TForm) + btnOk: TButton; + btnCancel: TButton; + lblOutputType: TLabel; + cbxOutputType: TComboBox; + lblOutputDevice: TLabel; + cbxOutputDevice: TComboBox; + lblMixerType: TLabel; + cbxMixerType: TComboBox; + lblOutputRate: TLabel; + cbxOutputRate: TComboBox; + chkSoftwareMIDI: TCheckBox; + chkGlobalFocus: TCheckBox; + procedure FormCreate(Sender: TObject); + procedure cbxOutputTypeChange(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure btnOkClick(Sender: TObject); + procedure btnCancelClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + private + OldOutputType: TFSoundOutputTypes; + OldDriverIndex: Integer; + OldMixer: TFSoundMixerTypes; + OldOutputRate: Integer; + procedure PopulateDevices; + public + end; + +var + frmConfig: TfrmConfig; + +implementation + +{$R *.DFM} + +uses + fmod; + +procedure TfrmConfig.FormCreate(Sender: TObject); +begin + DesktopFont := True; +end; + +const + OutputTypes: array [0..2] of TFSoundOutputTypes = + (FSOUND_OUTPUT_WINMM, FSOUND_OUTPUT_DSOUND, FSOUND_OUTPUT_A3D); + OutputRates: array [0..4] of Integer = (48000, 44100, 22050, 11025, 8000); + +procedure TfrmConfig.cbxOutputTypeChange(Sender: TObject); +begin + FSOUND_SetOutput(OutputTypes[cbxOutputType.ItemIndex]); + chkGlobalFocus.Enabled := OutputTypes[cbxOutputType.ItemIndex] = FSOUND_OUTPUT_DSOUND; + { Repopulate device combobox } + PopulateDevices; +end; + +procedure TfrmConfig.PopulateDevices; +var + DriverCount: Integer; + Driver: Integer; +begin + cbxOutputDevice.Items.Clear; + DriverCount := FSOUND_GetNumDrivers; + if DriverCount > 0 then + begin + for Driver := 0 to DriverCount - 1 do + cbxOutputDevice.Items.Add(FSOUND_GetDriverName(Driver)); + cbxOutputDevice.ItemIndex := 0; + end; + btnOk.Enabled := DriverCount > 0; +end; + +procedure TfrmConfig.FormShow(Sender: TObject); +begin + OldOutputType := FSOUND_GetOutput; + case OldOutputType of + FSOUND_OUTPUT_NOSOUND, + FSOUND_OUTPUT_WINMM: + cbxOutputType.ItemIndex := 0; + FSOUND_OUTPUT_DSOUND: + cbxOutputType.ItemIndex := 1; + FSOUND_OUTPUT_A3D: + cbxOutputType.ItemIndex := 2; + end; + chkGlobalFocus.Enabled := OutputTypes[cbxOutputType.ItemIndex] = FSOUND_OUTPUT_DSOUND; + PopulateDevices; + OldDriverIndex := FSOUND_GetDriver; + cbxOutputDevice.ItemIndex := OldDriverIndex; + OldMixer := FSOUND_GetMixer; + cbxMixerType.ItemIndex := Ord(OldMixer); + case FSOUND_GetOutputRate of + 8000: + cbxOutputRate.ItemIndex := 4; + 11025: + cbxOutputRate.ItemIndex := 3; + 22050: + cbxOutputRate.ItemIndex := 2; + 44100: + cbxOutputRate.ItemIndex := 1; + 48000: + cbxOutputRate.ItemIndex := 0; + end; + OldOutputRate := FSOUND_GetOutputRate; + { Now close FMOD. } + FSOUND_Close; +end; + +procedure TfrmConfig.btnOkClick(Sender: TObject); +var + Flags: Cardinal; +begin + FSOUND_SetOutput(OutputTypes[cbxOutputType.ItemIndex]); + FSOUND_SetDriver(cbxOutputDevice.ItemIndex); + FSOUND_SetMixer(TFSoundMixerTypes(cbxMixerType.ItemIndex)); + Flags := 0; + if chkSoftwareMIDI.Checked then + Flags := Flags or FSOUND_INIT_USEDEFAULTMIDISYNTH; + if chkGlobalFocus.Checked then + Flags := Flags or FSOUND_INIT_GLOBALFOCUS; + FSOUND_Init(OutputRates[cbxOutputRate.ItemIndex], 128, Flags); +end; + +procedure TfrmConfig.btnCancelClick(Sender: TObject); +begin + { Reset the old output type, driver and mixer. } + FSOUND_SetOutput(OldOutputType); + FSOUND_SetDriver(OldDriverIndex); + FSOUND_SetMixer(OldMixer); + FSOUND_Init(OldOutputRate, FSOUND_GetMaxChannels, 0); +end; + +procedure TfrmConfig.FormClose(Sender: TObject; var Action: TCloseAction); +begin + if ModalResult <> mrOk then + btnCancelClick(nil); +end; + +end. diff --git a/fmodapi375win/samplesdelphi/FMod/main.dfm b/fmodapi375win/samplesdelphi/FMod/main.dfm new file mode 100644 index 0000000..82d2da0 Binary files /dev/null and b/fmodapi375win/samplesdelphi/FMod/main.dfm differ diff --git a/fmodapi375win/samplesdelphi/FMod/main.pas b/fmodapi375win/samplesdelphi/FMod/main.pas new file mode 100644 index 0000000..978a78d --- /dev/null +++ b/fmodapi375win/samplesdelphi/FMod/main.pas @@ -0,0 +1,634 @@ +unit main; + +{$WARN UNSAFE_TYPE OFF} + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, fmodtypes, ExtCtrls, ComCtrls, spectrum; + +const + MAX_SONGS = 512; + +type + TSongType = record + Module: PFMusicModule; + Stream: PFSoundStream; + Channel: Integer; + Playing: Boolean; + end; + + TfrmMain = class(TForm) + dlgOpen: TOpenDialog; + grpFiles: TGroupBox; + lbxFiles: TListBox; + btnLoad: TButton; + btnDelete: TButton; + btnPlay: TButton; + btnStop: TButton; + btnExit: TButton; + btnAbout: TButton; + btnConfig: TButton; + grpCD: TGroupBox; + grpFilters: TGroupBox; + pnlChannels: TPanel; + pnlCPU: TPanel; + chkLowPass: TCheckBox; + chkEcho: TCheckBox; + chkReverb: TCheckBox; + chkPreverb: TCheckBox; + Label9: TLabel; + Label10: TLabel; + btnPlayCD: TButton; + btnPauseCD: TButton; + btnStopCD: TButton; + btnPrevTrack: TButton; + btnNextTrack: TButton; + btnEjectCD: TButton; + lblChannels: TLabel; + lblCPU: TLabel; + rdoContinuous: TRadioButton; + rdoRandom: TRadioButton; + rdoLooping: TRadioButton; + Label21: TLabel; + lblCDTrack: TLabel; + lblCDStatus: TLabel; + tmrMain: TTimer; + chkPlaylist: TCheckBox; + grpSongInfo: TGroupBox; + Label1: TLabel; + lblSongName: TLabel; + Label2: TLabel; + lblSongType: TLabel; + Label3: TLabel; + lblSongSpeed: TLabel; + Label4: TLabel; + lblSongBPM: TLabel; + Label5: TLabel; + lblSongOrder: TLabel; + btnPrevOrder: TButton; + btnNextOrder: TButton; + Label6: TLabel; + lblSongPattern: TLabel; + Label7: TLabel; + lblSongRow: TLabel; + Label8: TLabel; + lblSongMasterVolume: TLabel; + trkMasterVolume: TTrackBar; + pgrSong: TProgressBar; + pnlSpectrum: TPanel; + procedure btnLoadClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure btnPlayClick(Sender: TObject); + procedure btnStopClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure tmrMainTimer(Sender: TObject); + procedure lbxFilesClick(Sender: TObject); + procedure trkMasterVolumeChange(Sender: TObject); + procedure btnExitClick(Sender: TObject); + procedure btnAboutClick(Sender: TObject); + procedure btnPrevOrderClick(Sender: TObject); + procedure btnNextOrderClick(Sender: TObject); + procedure btnConfigClick(Sender: TObject); + procedure btnEjectCDClick(Sender: TObject); + procedure btnPlayCDClick(Sender: TObject); + procedure btnStopCDClick(Sender: TObject); + procedure btnPauseCDClick(Sender: TObject); + procedure btnPrevTrackClick(Sender: TObject); + procedure btnNextTrackClick(Sender: TObject); + procedure pnlSpectrumClick(Sender: TObject); + procedure btnDeleteClick(Sender: TObject); + private + FSongs: array [0..MAX_SONGS - 1] of TSongType; + FSettingMasterVolume: Boolean; + FTrackNumber: Integer; + FCDPaused: Boolean; + FCDPlaying: Boolean; + FNumTracks: Integer; + FSpectrum: TMiniSpectrum; + procedure ShowStaticSongInfo(Index: Integer); + procedure ShowDynamicSongInfo(Index: Integer); + procedure ShowCDInfo; + procedure ShowSpectrum; + public + { Public declarations } + end; + +var + frmMain: TfrmMain; + +implementation + +{$R *.DFM} + +uses + fmod, fmoderrors, about, config; + +const + MusicTypes: array [TFMusicTypes] of String = + ('None', 'Protracker/FastTracker', 'ScreamTracker 3', 'FastTracker 2', 'Impulse Tracker', 'Midi', 'FMOD Sample Bank'); + +procedure TfrmMain.btnLoadClick(Sender: TObject); +var + Index: Integer; + Module: PFMusicModule; + Stream: PFSoundStream; + SongCount: Integer; +begin + if dlgOpen.Execute then + begin + for Index := 0 to dlgOpen.Files.Count - 1 do + begin + SongCount := lbxFiles.Items.Count; + + if SongCount = MAX_SONGS then + begin + Application.MessageBox(PChar(Format('Limit of %d songs reached', [MAX_SONGS])), 'Load error', MB_OK or MB_ICONHAND); + Exit; + end; + + Stream := nil; + Module := FMUSIC_LoadSong(PChar(dlgOpen.Files[Index])); + if Module = nil then + begin + Stream := FSOUND_Stream_Open(PChar(dlgOpen.Files[Index]), FSOUND_NORMAL or FSOUND_LOOP_NORMAL, 0, 0); + end; + + if (Module = nil) and (Stream = nil) then + begin + Application.MessageBox(FMOD_ErrorString(FSOUND_GetError), 'Load error', MB_OK or MB_ICONHAND); + Continue; + end; + + if Module <> nil then + begin + FMUSIC_SetMasterVolume(Module, 255); + if (FMUSIC_GetType(Module) = FMUSIC_TYPE_MOD) or (FMUSIC_GetType(Module) = FMUSIC_TYPE_S3M) then + FMUSIC_SetPanSeperation(Module, 0.15); // 15% crossover + end; + + FSongs[SongCount].Module := Module; + FSongs[SongCount].Stream := Stream; + FSongs[SongCount].Playing := False; + + lbxFiles.Items.Add(ExtractFileName(dlgOpen.Files[Index])); + lbxFiles.ItemIndex := SongCount; + end; + end; + lbxFilesClick(nil); +end; + +procedure TfrmMain.FormCreate(Sender: TObject); +var + Index: Integer; +begin + DesktopFont := True; + + FMOD_Load(nil); + + { Check version numbers } + if FMOD_VERSION > FSOUND_GetVersion then + begin + Application.MessageBox(PChar(Format('API version %3.2f is newer than DLL version %3.2f', [FMOD_VERSION, FSOUND_GetVersion])), 'Version mismatch', MB_OK or MB_ICONERROR); + Halt; + end; + + { Initialize FSOUND } + try + if not FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND) then + raise Exception.Create('FSOUND_SetOutput failed'); + if not FSOUND_SetDriver(0) then + raise Exception.Create('FSOUND_SetDriver failed'); + if not FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT) then + raise Exception.Create('FSOUND_SetMixer failed'); + if not FSOUND_SetHWND(Handle) then + raise Exception.Create('FSOUND_SetHWND failed'); + except + Application.MessageBox(FMOD_ErrorString(FSOUND_GetError), 'Initialization', MB_OK or MB_ICONHAND); + raise; + end; + + if not FSOUND_Init(22050, 128, 0) then + begin + Application.MessageBox(FMOD_ErrorString(FSOUND_GetError), 'FSOUND_Init', MB_OK or MB_ICONHAND); + Halt; + end; + + { Initialize song list to empty } + for Index := 0 to MAX_SONGS - 1 do + begin + FSongs[Index].Module := nil; + FSongs[Index].Stream := nil; + FSongs[Index].Channel := -1; + end; + + FTrackNumber := 0; + FNumTracks := 0; + FCDPaused := False; + FCDPlaying := False; + + FSpectrum := TMiniSpectrum.Create(nil); + FSpectrum.Parent := pnlSpectrum; + FSpectrum.Align := alClient; + FSpectrum.Enabled := False; + FSpectrum.OnClick := pnlSpectrumClick; + + ShowStaticSongInfo(-1); + ShowDynamicSongInfo(-1); + ShowCDInfo; + + dlgOpen.Filter := 'All song types|*.MOD;*.S3M;*.XM;*.IT;*.MID;*.RMI;*.SGT;*.WAV;*.MP2;*.MP3;*.OGG;*.WMA;*.ASF|Microsoft WAV (*.WAV)|*.WAV|MP2/MP3 (*.MP3 *.MP2)|*.MP2;*.MP3|Ogg Vorbis (*.OGG)|*.OGG|Windows Media Format (*.WMA *.ASF)|*.WMA;*.ASF' + + '|MIDI/DirectMusic Files (*.MID,*.RMI,*.SGT)|*.MID;*.RMI;*.SGT|Impulse Tracker (*.IT)|*.IT|FastTracker2 (*.XM)|*.XM|ScreamTracker 3 (*.S3M)|*.S3M|Protracker/FastTracker (*.MOD)|*.MOD|All files (*.*)|*.*'; +end; + +procedure TfrmMain.btnPlayClick(Sender: TObject); +var + Index: Integer; +begin + Index := lbxFiles.ItemIndex; + + if Index < 0 then + Exit; + + if FSongs[Index].Playing then + btnStopClick(Sender); + + if FSongs[Index].Module <> nil then + begin + FSongs[Index].Playing := FMUSIC_PlaySong(FSongs[Index].Module); + if not FSongs[Index].Playing then + Application.MessageBox(FMOD_ErrorString(FSOUND_GetError), 'Play song', MB_OK or MB_ICONHAND); + end + else if FSongs[Index].Stream <> nil then + begin + FSongs[Index].Channel := FSOUND_Stream_Play(FSOUND_FREE, FSongs[Index].Stream); + FSongs[Index].Playing := FSongs[Index].Channel >= 0; + if not FSongs[Index].Playing then + begin + Application.MessageBox(FMOD_ErrorString(FSOUND_GetError), 'Play stream', MB_OK or MB_ICONHAND); + end + else + begin + FSOUND_SetPan(FSongs[Index].Channel, FSOUND_STEREOPAN); + FSOUND_SetVolume(FSongs[Index].Channel, 255); + end; + end; + ShowStaticSongInfo(Index); +end; + +procedure TfrmMain.btnStopClick(Sender: TObject); +var + Index: Integer; +begin + Index := lbxFiles.ItemIndex; + + if Index < 0 then + Exit; + + if FSongs[Index].Module <> nil then + FMUSIC_StopSong(FSongs[Index].Module) + else if FSongs[Index].Stream <> nil then + FSOUND_Stream_Stop(FSongs[Index].Stream); + FSongs[Index].Channel := -1; + FSongs[Index].Playing := False; +end; + +procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction); +var + Index: Integer; +begin + FMUSIC_StopAllSongs(); + for Index := 0 to MAX_SONGS - 1 do + begin + if FSongs[Index].Module <> nil then + begin + FMUSIC_FreeSong(FSongs[Index].Module); + end + else if FSongs[Index].Stream <> nil then + begin + FSOUND_Stream_Stop(FSongs[Index].Stream); + FSOUND_Stream_Close(FSongs[Index].Stream); + end; + end; + FSpectrum.Free; + + FMOD_Unload; +end; + +procedure TfrmMain.ShowStaticSongInfo(Index: Integer); +var + Module: PFMusicModule; + Stream: PFSoundStream; +begin + if Index < 0 then + begin + lblSongName.Caption := ''; + lblSongType.Caption := ''; + lblSongMasterVolume.Caption := ''; + pgrSong.Position := 0; + end + else + begin + Module := FSongs[Index].Module; + Stream := FSongs[Index].Stream; + if Module <> nil then + begin + lblSongName.Caption := FMUSIC_GetName(Module); + lblSongType.Caption := MusicTypes[FMUSIC_GetType(Module)] + Format(' (%d channel)', [FMUSIC_GetNumChannels(Module)]); + lblSongMasterVolume.Caption := Format('%3.3d', [FMUSIC_GetMasterVolume(Module)]); + FSettingMasterVolume := True; + trkMasterVolume.Position := FMUSIC_GetMasterVolume(Module); + FSettingMasterVolume := False; + pgrSong.Max := FMUSIC_GetNumOrders(Module); + end + else if Stream <> nil then + begin + lblSongName.Caption := lbxFiles.Items[Index]; + lblSongType.Caption := 'Stream'; + lblSongMasterVolume.Caption := Format('%3.3d', [FSOUND_GetVolume(FSongs[Index].Channel)]); + FSettingMasterVolume := True; + trkMasterVolume.Position := FSOUND_GetVolume(FSongs[Index].Channel); + FSettingMasterVolume := False; + pgrSong.Max := FSOUND_Stream_GetLength(Stream); + lblSongSpeed.Caption := ''; + lblSongBPM.Caption := ''; + lblSongOrder.Caption := ''; + lblSongPattern.Caption := ''; + lblSongRow.Caption := ''; + end + end; +end; + +procedure TfrmMain.tmrMainTimer(Sender: TObject); +var + Index: Integer; +begin + lblCPU.Caption := Format('%.1f%%', [FSOUND_GetCPUUsage]); + lblChannels.Caption := Format('%3.3d', [FSOUND_GetChannelsPlaying]); + Index := lbxFiles.ItemIndex; + if Index > -1 then + begin + ShowSpectrum; + ShowDynamicSongInfo(Index); + if FMUSIC_IsFinished(FSongs[Index].Module) and chkPlaylist.Checked then + begin + btnStopClick(nil); + Inc(Index); + if Index >= lbxFiles.Items.Count then + Index := 0; + lbxFiles.ItemIndex := Index; + lbxFilesClick(nil); + btnPlayClick(nil); + end; + end; + { Update CD info } + TTimer(Sender).Tag := TTimer(Sender).Tag + LongInt(TTimer(Sender).Interval); + if TTimer(Sender).Tag > 1000 then + begin + TTimer(Sender).Tag := 0; + ShowCDInfo; + end; +end; + +procedure TfrmMain.lbxFilesClick(Sender: TObject); +begin + ShowStaticSongInfo(lbxFiles.ItemIndex); +end; + +procedure TfrmMain.ShowDynamicSongInfo(Index: Integer); +var + Module: PFMusicModule; + Stream: PFSoundStream; + Channel: Integer; +begin + if Index < 0 then + begin + lblSongSpeed.Caption := ''; + lblSongBPM.Caption := ''; + lblSongOrder.Caption := ''; + lblSongPattern.Caption := ''; + lblSongRow.Caption := ''; + pgrSong.Position := 0; + end + else + begin + Module := FSongs[Index].Module; + Stream := FSongs[Index].Stream; + Channel := FSongs[Index].Channel; + if (Module <> nil) and (FMUSIC_IsPlaying(Module)) then + begin + lblSongSpeed.Caption := Format('%3.3d', [FMUSIC_GetSpeed(Module)]); + lblSongBPM.Caption := Format('%3.3d', [FMUSIC_GetBPM(Module)]); + lblSongOrder.Caption := Format('%3.3d/%3.3d', [FMUSIC_GetOrder(Module), FMUSIC_GetNumOrders(Module)]); + lblSongPattern.Caption := Format('%3.3d/%3.3d', [FMUSIC_GetPattern(Module), FMUSIC_GetNumPatterns(Module)]); + lblSongRow.Caption := Format('%3.3d/%3.3d', [FMUSIC_GetRow(Module), 64]); + pgrSong.Position := FMUSIC_GetOrder(Module); + end + else if (Stream <> nil) and (FSOUND_IsPlaying(Channel)) then + begin + pgrSong.Position := FSOUND_Stream_GetPosition(Stream); + end + end; +end; + +procedure TfrmMain.trkMasterVolumeChange(Sender: TObject); +var + Index: Integer; +begin + if not FSettingMasterVolume then + begin + Index := lbxFiles.ItemIndex; + if Index > -1 then + begin + if FSongs[Index].Module <> nil then + begin + FMUSIC_SetMasterVolume(FSongs[Index].Module, trkMasterVolume.Position); + lblSongMasterVolume.Caption := Format('%3.3d', [trkMasterVolume.Position]); + end + else if FSongs[Index].Stream <> nil then + begin + FSOUND_SetVolume(FSongs[Index].Channel, trkMasterVolume.Position); + lblSongMasterVolume.Caption := Format('%3.3d', [trkMasterVolume.Position]); + end; + end; + end; +end; + +procedure TfrmMain.btnExitClick(Sender: TObject); +begin + Close; +end; + +procedure TfrmMain.btnAboutClick(Sender: TObject); +begin + frmAbout := TfrmAbout.Create(nil); + try + frmAbout.ShowModal; + finally + frmAbout.Free; + end; +end; + +procedure TfrmMain.btnPrevOrderClick(Sender: TObject); +var + Index: Integer; + Order: DWORD; +begin + Index := lbxFiles.ItemIndex; + if Index < 0 then + Exit; + if FSongs[Index].Module = nil then + Exit; + Order := FMUSIC_GetOrder(FSongs[Index].Module); + if Order > 0 then + FMUSIC_SetOrder(FSongs[Index].Module, Order - 1); +end; + +procedure TfrmMain.btnNextOrderClick(Sender: TObject); +var + Index: Integer; + Order: Integer; +begin + Index := lbxFiles.ItemIndex; + if Index < 0 then + Exit; + if FSongs[Index].Module = nil then + Exit; + Order := FMUSIC_GetOrder(FSongs[Index].Module); + if Order < FMUSIC_GetNumOrders(FSongs[Index].Module) then + FMUSIC_SetOrder(FSongs[Index].Module, Order + 1); +end; + +procedure TfrmMain.btnConfigClick(Sender: TObject); +var + SpectrumEnabled: Boolean; +begin + SpectrumEnabled := FSpectrum.Enabled; + FSpectrum.Enabled := False; + frmConfig := TfrmConfig.Create(nil); + try + frmConfig.ShowModal; + finally + frmConfig.Free; + end; + FSpectrum.Enabled := SpectrumEnabled; +end; + +procedure TfrmMain.btnEjectCDClick(Sender: TObject); +begin + FSOUND_CD_OpenTray(0, 1); + FTrackNumber := 0; + FCDPaused := False; + FCDPlaying := False; + FNumTracks := 0; +end; + +procedure TfrmMain.btnPlayCDClick(Sender: TObject); +begin + if FTrackNumber > 0 then + begin + if FCDPaused then + FSOUND_CD_SetPaused(0, False) + else + FSOUND_CD_Play(0, FTrackNumber); + FCDPaused := False; + FCDPlaying := True; + end; +end; + +procedure TfrmMain.ShowCDInfo; +begin + FTrackNumber := FSOUND_CD_GetTrack(0); + FNumTracks := FSOUND_CD_GetNumTracks(0); + lblCDTrack.Caption := Format('%02d/%02d', [FTrackNumber, FNumTracks]); + tmrMain.Tag := 0; +end; + +procedure TfrmMain.btnStopCDClick(Sender: TObject); +begin + FSOUND_CD_Stop(0); + FCDPaused := False; + FCDPlaying := False; +end; + +procedure TfrmMain.btnPauseCDClick(Sender: TObject); +begin + if FCDPlaying then + begin + FSOUND_CD_SetPaused(0, not FCDPaused); + FCDPaused := FSOUND_CD_GetPaused(0); + end; +end; + +procedure TfrmMain.btnPrevTrackClick(Sender: TObject); +begin + if FTrackNumber > 1 then + begin + Dec(FTrackNumber); + if FCDPlaying then + FSOUND_CD_Play(0, FTrackNumber); + ShowCDInfo; + end; +end; + +procedure TfrmMain.btnNextTrackClick(Sender: TObject); +begin + if FTrackNumber < FNumTracks then + begin + Inc(FTrackNumber); + if FCDPlaying then + FSOUND_CD_Play(0, FTrackNumber); + ShowCDInfo; + end; +end; + +procedure TfrmMain.ShowSpectrum; +begin + if FSpectrum.Enabled then + FSpectrum.Draw; +end; + +procedure TfrmMain.pnlSpectrumClick(Sender: TObject); +begin + if FSpectrum.Enabled then + begin + if FSpectrum.Style = ssSmooth then + FSpectrum.Style := ssBlock + else + FSpectrum.Enabled := False; + end + else + begin + FSpectrum.Enabled := True; + FSpectrum.Style := ssSmooth; + end; +end; + +procedure TfrmMain.btnDeleteClick(Sender: TObject); +var + Index, Index2: Integer; +begin + Index := lbxFiles.ItemIndex; + if Index < 0 then + Exit; + + btnStopClick(nil); + lbxFiles.Items.Delete(Index); + // Move all following items up one position + if lbxFiles.Items.Count > 0 then + begin + if Index < lbxFiles.Items.Count - 1 then + begin + for Index2 := Index to lbxFiles.Items.Count - 2 do + FSongs[Index2] := FSongs[Index2 + 1]; + end; + if Index < lbxFiles.Items.Count then + lbxFiles.ItemIndex := Index + else + lbxFiles.ItemIndex := lbxFiles.Items.Count - 1; + end; + lbxFilesClick(nil); +end; + +end. diff --git a/fmodapi375win/samplesdelphi/FMod/spectrum.pas b/fmodapi375win/samplesdelphi/FMod/spectrum.pas new file mode 100644 index 0000000..98161f4 --- /dev/null +++ b/fmodapi375win/samplesdelphi/FMod/spectrum.pas @@ -0,0 +1,208 @@ +unit spectrum; + +interface + +uses + Windows, Classes, Controls, Messages, Graphics; + +type + TSpectrumStyle = (ssSmooth, ssBlock); + + TMiniSpectrum = class(TGraphicControl) + private + FGradient: TBitmap; + FBuffer: TBitmap; + FScale: Single; + FStyle: TSpectrumStyle; + FValues: array [0..127] of Single; + procedure SetStyle(const Value: TSpectrumStyle); + protected + procedure Paint; override; + procedure Resize; override; + procedure SetEnabled(Value: Boolean); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Draw; + published + property Align; + property Scale: Single read FScale write FScale; + property Style: TSpectrumStyle read FStyle write SetStyle; + property OnClick; + end; + +implementation + +uses + fmod, fmodtypes; + +{ TMiniSpectrum } + +constructor TMiniSpectrum.Create(AOwner: TComponent); +var + X, Y: Integer; + R, G, B: Integer; + C: TColor; +begin + inherited; + Color := clBlack; + Width := 80; + Height := 32; + FScale := 4.0; + FStyle := ssSmooth; + Enabled := False; + + // Create draw buffer + FBuffer := TBitmap.Create; + FBuffer.PixelFormat := pf32bit; + FBuffer.Width := Width; + FBuffer.Height := Height; + + // Create gradient bitmap + FGradient := TBitmap.Create; + FGradient.PixelFormat := pf32bit; + FGradient.Width := 4; + FGradient.Height := 32; + + R := 255; + G := 0; + B := 0; + + for Y := 0 to 31 do + begin + if Y > 15 then + Dec(R, 16) + else + Inc(G, 16); + if R < 0 then + R := 0; + if G > 255 then + G := 255; + C := TColor(RGB(R, G, B)); + for X := 0 to 2 do + FGradient.Canvas.Pixels[X, Y] := C; + FGradient.Canvas.Pixels[3, Y] := TColor(0); + end; +end; + +destructor TMiniSpectrum.Destroy; +begin + FGradient.Free; + FBuffer.Free; + inherited; +end; + +type + PSingleArray = ^TSingleArray; + TSingleArray = array [0..0] of Single; + +procedure TMiniSpectrum.Draw; +var + Data: PSingleArray; + PeakData: Single; + W, X, Y: Integer; + ARect: TRect; +begin + FBuffer.Canvas.Brush.Color := Color; + FBuffer.Canvas.FillRect(BoundsRect); + + if Enabled then + begin + Data := PSingleArray(FSOUND_DSP_GetSpectrum); + + // Get the peak value of each block of four values + for X := 0 to 127 do + begin + W := X * 4; + FValues[X] := Data^[W]; + if Data^[W + 1] > FValues[X] then + FValues[X] := Data^[W + 1]; + if Data^[W + 2] > FValues[X] then + FValues[X] := Data^[W + 2]; + if Data^[W + 3] > FValues[X] then + FValues[X] := Data^[W + 3]; + FValues[X] := FValues[X] * FScale; + if FValues[X] > 1.0 then + FValues[X] := 1.0; + end; + + W := Width; + if W > 128 then + W := 128; + + case FStyle of + ssSmooth: + begin + X := 0; + while X < W do + begin + if FValues[X] > 0.0 then + begin + Y := Height - Trunc(FValues[X] * 1.0 * Height); + FBuffer.Canvas.CopyRect(Rect(X, Y, X + 1, Height), FGradient.Canvas, Rect(0, Y, 1, FGradient.Height)); + end; + Inc(X); + end; + end; + ssBlock: + begin + // Sixteen values for every column + PeakData := 0; + X := 0; + while X < W do + begin + if PeakData < FValues[X] then + PeakData := FValues[X]; + if (X and 3 = 3) and (PeakData > 0.0) then + begin + Y := Height - Trunc(PeakData * 1.0 * Height); + PeakData := 0; + FBuffer.Canvas.CopyRect(Rect(X, Y, X + 4, Height), FGradient.Canvas, Rect(0, Y, 4, FGradient.Height)); + end; + Inc(X); + end; + end; + end; + end + else + begin + FBuffer.Canvas.Font.Color := clWhite; + ARect := BoundsRect; + DrawText(FBuffer.Canvas.Handle, 'Click for spectrum', -1, ARect, DT_WORDBREAK or DT_NOPREFIX or DT_VCENTER or DT_CENTER); + end; + + // Copy the buffer to the control + Canvas.Draw(0, 0, FBuffer); +end; + +procedure TMiniSpectrum.Paint; +begin + Draw; +end; + +procedure TMiniSpectrum.Resize; +begin + inherited; + if Assigned(FBuffer) then + begin + FBuffer.Width := Width; + FBuffer.Height := Height; + end; +end; + +procedure TMiniSpectrum.SetEnabled(Value: Boolean); +begin + inherited; + FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit, Value); +end; + +procedure TMiniSpectrum.SetStyle(const Value: TSpectrumStyle); +begin + if FStyle <> Value then + begin + FStyle := Value; + ZeroMemory(@FValues, SizeOf(FValues)); + end; +end; + +end. diff --git a/fmodapi375win/samplesdelphi/FMod/testbed.dpr b/fmodapi375win/samplesdelphi/FMod/testbed.dpr new file mode 100644 index 0000000..ca0e9fe --- /dev/null +++ b/fmodapi375win/samplesdelphi/FMod/testbed.dpr @@ -0,0 +1,17 @@ +program testbed; + +uses + Forms, + main in 'main.pas' {frmMain}, + about in 'about.pas' {frmAbout}, + config in 'config.pas' {frmConfig}, + spectrum in 'spectrum.pas'; + +{$R *.RES} + +begin + Application.Initialize; + Application.Title := 'FMOD'; + Application.CreateForm(TfrmMain, frmMain); + Application.Run; +end. diff --git a/fmodapi375win/samplesdelphi/FMod/testbed.res b/fmodapi375win/samplesdelphi/FMod/testbed.res new file mode 100644 index 0000000..d8a5528 Binary files /dev/null and b/fmodapi375win/samplesdelphi/FMod/testbed.res differ diff --git a/fmodapi375win/samplesdelphi/Readme.txt b/fmodapi375win/samplesdelphi/Readme.txt new file mode 100644 index 0000000..751ee9e --- /dev/null +++ b/fmodapi375win/samplesdelphi/Readme.txt @@ -0,0 +1,11 @@ +Some notes about the Delphi examples: +- The managing of the input and output (console that is) is done in a rather strange way. Don't be confused by all the Windows API calls because it's only a replacement of readkey and writeln (combined with gotoxy ...). +- The record sample has a bug in the full-duplex record stage with MMX reverb. The bug is an access violation in the DSP callback function. I have not tracked it down yet. +- The spectrum display in the FMOD testbed has some issues. These are being worked on. + +Original Delphi conversions by Dragan Bocevski +d_bocevski@yahoo.com or d_bocevski@hotpop.com. + +Updated examples and maintenance by Steve 'Sly' Williams +stevewilliams@kromestudios.com + \ No newline at end of file diff --git a/fmodapi375win/samplesdelphi/Simple/simple.dpr b/fmodapi375win/samplesdelphi/Simple/simple.dpr new file mode 100644 index 0000000..454bc41 --- /dev/null +++ b/fmodapi375win/samplesdelphi/Simple/simple.dpr @@ -0,0 +1,300 @@ +//=============================================================================================== +// SIMPLE.EXE +// Copyright (c), Firelight Multimedia, 1999-2000. +// +// This example demonstrates some fundamental FMOD usage, including device enumeration, output +// mode selection, loading and playing samples and a music file, and +// calling some runtime manipulation and information functions. +// Converted to Delphi by Bocevski Dragan mailto: d_bocevski@yahoo.com +//=============================================================================================== +// History +// +// 2001/09/09 by Steve 'Sly' Williams +// - Updated to version 3.40 +// +// 2000/12/15 by Steve 'Sly' Williams +// - Updated to version 3.30 +// +// 2000/11/14 by Steve 'Sly' Williams +// - Fixed version check +// - Added FMODErrors to uses clause +// - Added check for Delphi 4 to change wVirtualKeyCode to wVirtualScanCode +// +// 2002/02/13 by Steve 'Sly' Williams +// - Updated for FMOD 3.50 +// +// 2002/12/19 by Steve 'Sly' Williams +// - Updated for FMOD 3.61 +//=============================================================================================== +program simple; + +uses + fmod, fmodtypes, fmoderrors, Windows; + +{$APPTYPE CONSOLE} + +var + dw, key: dword; + driver: Integer; + i: Longint; + enm: TFSoundOutputTypes; + h, h1: THandle; + buf: input_record; + c: coord; + s, sorder, srow, stime, schp, scpu: string; + channel: Integer; + samp1, samp2, samp3: PFSoundSample; + mdl: PFMusicModule; + paused: Boolean; +begin + SetLength(s, 80); + SetConsoleTitle('Example Simple (song player)'); + h := GetStdHandle(STD_INPUT_HANDLE); + h1 := GetStdHandle(STD_OUTPUT_HANDLE); + Buf.EventType := Key_Event; + if FMOD_VERSION > FSOUND_GetVersion then + begin + WriteLn('Error: You are using FMOD version ', FSOUND_GetVersion: 3: 2, '. You should be using version ', FMOD_VERSION: 3: 2); + Exit; + end; + + writeln('---------------------------------------------------------'); + writeln('Output Type'); + writeln('---------------------------------------------------------'); + + writeln('1 - Direct Sound'); + writeln('2 - Windows Multimedia Waveout'); + writeln('3 - A3D'); + writeln('4 - NoSound'); + writeln('---------------------------------------------------------'); // print driver names + writeln('Press a corresponding number or ESC to quit'); + repeat + Sleep(50); + FlushConsoleInputBuffer(h); + repeat + ReadConsoleInput(h, buf, 1, dw); + until buf.Event.KeyEvent.bKeyDown = false; +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + case key of + ord('1'): FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + ord('2'): FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + ord('3'): FSOUND_SetOutput(FSOUND_OUTPUT_A3D); + ord('4'): FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); + 27: exit; + end; + until ((key >= ord('1')) and (key <= ord('4'))); + +// ========================================================================================== +// SELECT DRIVER +// ========================================================================================== + + +// The following list are the drivers for the output method selected above. + writeln('---------------------------------------------------------'); + enm := FSOUND_GetOutput(); + case enm of + FSOUND_OUTPUT_NOSOUND: write('NoSound'); + FSOUND_OUTPUT_WINMM: write('Windows Multimedia Waveout'); + FSOUND_OUTPUT_DSOUND: write('Direct Sound'); + FSOUND_OUTPUT_A3D: write('A3D'); + end; + writeln(' Driver list'); + writeln('---------------------------------------------------------'); + for i := 0 to FSOUND_GetNumDrivers() - 1 do + writeln(i + 1, ' - ', FSOUND_GetDriverName(i)); // print driver names + writeln('---------------------------------------------------------'); // print driver names + writeln('Press a corresponding number or ESC to quit'); + repeat + FlushConsoleInputBuffer(h); + repeat + ReadConsoleInput(h, buf, 1, dw); + until buf.Event.KeyEvent.bKeyDown = false; +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if (ord(key) = 27) then exit; + driver := ord(key) - ord('1'); + until ((driver > 0) or (driver <= FSOUND_GetNumDrivers())); + FSOUND_SetDriver(driver); // Select sound card (0 = default) + +// ========================================================================================== +// SELECT MIXER +// ========================================================================================== + + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT); + +// ========================================================================================== +// INITIALIZE +// ========================================================================================== + if not FSOUND_Init(44100, 64, 0) then + begin + writeln('Error! Initializing'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + +// ========================================================================================== +// LOAD SONG +// ========================================================================================== + + mdl := FMUSIC_LoadSong('../../media/invtro94.s3m'); + if mdl = nil then + begin + writeln('Error! Loading song'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + +// ========================================================================================== +// LOAD SAMPLES +// ========================================================================================== + + // 8bit mono + samp1 := FSOUND_Sample_Load(FSOUND_FREE, '../../media/jaguar.wav', FSOUND_2D, 0, 0); + if samp1 = nil then + begin + writeln('Error! Loading sample1'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + + // 16bit mono + samp2 := FSOUND_Sample_Load(FSOUND_FREE, '../../media/drumloop.wav', FSOUND_2D, 0, 0); + if samp2 = nil then + begin + writeln('Error! Loading sample2'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + + // 16bit stereo + samp3 := FSOUND_Sample_Load(FSOUND_FREE, '../../media/chimes.wav', FSOUND_2D, 0, 0); + if samp2 = nil then + begin + writeln('Error! Loading sample3'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + +// ========================================================================================== +// DISPLAY HELP +// ========================================================================================== + + write('FSOUND Output Method : '); + case (FSOUND_GetOutput()) of + FSOUND_OUTPUT_NOSOUND: writeln('FSOUND_OUTPUT_NOSOUND'); + FSOUND_OUTPUT_WINMM: writeln('FSOUND_OUTPUT_WINMM'); + FSOUND_OUTPUT_DSOUND: writeln('FSOUND_OUTPUT_DSOUND'); + FSOUND_OUTPUT_A3D: writeln('FSOUND_OUTPUT_A3D'); + end; + + write('FSOUND Mixer : '); + case (FSOUND_GetMixer()) of + FSOUND_MIXER_BLENDMODE: writeln('FSOUND_MIXER_BLENDMODE'); + FSOUND_MIXER_MMXP5: writeln('FSOUND_MIXER_MMXP5'); + FSOUND_MIXER_MMXP6: writeln('FSOUND_MIXER_MMXP6'); + FSOUND_MIXER_QUALITY_FPU: writeln('FSOUND_MIXER_QUALITY_FPU'); + FSOUND_MIXER_QUALITY_MMXP5: writeln('FSOUND_MIXER_QUALITY_MMXP5'); + FSOUND_MIXER_QUALITY_MMXP6: writeln('FSOUND_MIXER_QUALITY_MMXP6'); + end; + writeln('FSOUND Driver : ', FSOUND_GetDriverName(FSOUND_GetDriver())); + + + + writeln('========================================================================='); + writeln(' 1 Play 16bit sound at any time'); + writeln(' 2 Play 8bit sound at any time'); + writeln(' 3 Play 16bit STEREO sound at any time'); + writeln(' Left arrow Rewind mod back 1 order'); + writeln(' Right arrow FastForward mod forward 1 order'); + writeln(' SPACE Pause/unpause music at any time'); + writeln(' ESC Quit'); + writeln('========================================================================='); + writeln('Playing ...', FMUSIC_GetName(mdl)); + +// ========================================================================================== +// START PLAYING! +// ========================================================================================== + FMUSIC_PlaySong(mdl); + + FMUSIC_SetPanSeperation(mdl, 0.15); // 15% crossover + + GetConsoleMode(h, dw); + SetConsoleMode(h, dw or ENABLE_PROCESSED_OUTPUT or ENABLE_PROCESSED_INPUT); + c.X := 1; + c.Y := 24; + repeat + FlushConsoleInputBuffer(h); + Sleep(50); + dw := 0; + PeekConsoleInput(h, buf, 1, dw); + if buf.Event.KeyEvent.bKeyDown then + begin +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if dw = 1 then + if key <> 0 then + begin + if key = Ord('1') then + FSOUND_PlaySound(FSOUND_FREE, samp1) + else if key = Ord('2') then + FSOUND_PlaySound(FSOUND_FREE, samp2) + else if key = Ord('3') then + begin + channel := FSOUND_PlaySound(FSOUND_FREE, samp3); + FSOUND_SetPan(channel, FSOUND_STEREOPAN); + end + else if key = Ord(' ') then + begin + paused := FMUSIC_GetPaused(mdl); + FMUSIC_SetPaused(mdl, not paused); + end + else if key = VK_LEFT then + FMUSIC_SetOrder(mdl, FMUSIC_GetOrder(mdl) - 1) + else if key = VK_RIGHT then + FMUSIC_SetOrder(mdl, FMUSIC_GetOrder(mdl) + 1) + else if key = 27 then + begin + WriteLn; + FSOUND_Close(); + Exit; + end; + end; + end; +// key:=0; + SetConsoleCursorPosition(h1, c); + str(FMUSIC_GetOrder(mdl), sorder); + str(FMUSIC_GetRow(mdl), srow); + str((FMUSIC_GetTime(mdl) / 1000): 6: 3, stime); + str(FSOUND_GetChannelsPlaying(), schp); + str(FSOUND_GetCPUUsage(): 7: 5, scpu); + s := 'order = ' + sorder + ' row = ' + srow + ' time = ' + stime + ' channels playing = ' + schp + ' cpu usage = ' + scpu; + WriteConsole(h1, pchar(s), length(s) - 1, dw, nil); + s := ' '; + until false; + +// ========================================================================================== +// CLEANUP AND SHUTDOWN +// ========================================================================================== + + FSOUND_Sample_Free(samp1); + FSOUND_Sample_Free(samp2); + FSOUND_Sample_Free(samp3); + FMUSIC_FreeSong(mdl); + FSOUND_Close(); +end. + diff --git a/fmodapi375win/samplesdelphi/Simplest/simplest.dpr b/fmodapi375win/samplesdelphi/Simplest/simplest.dpr new file mode 100644 index 0000000..41241d1 --- /dev/null +++ b/fmodapi375win/samplesdelphi/Simplest/simplest.dpr @@ -0,0 +1,126 @@ +//=============================================================================================== +// SIMPLEST.EXE +// Copyright (c), Firelight Multimedia, 1999-2000. +// +// This is the simplest way to play a song through FMOD. It is basically Init, Load, Play! +// Converted to Delphi by Bocevski Dragan mailto: d_bocevski@yahoo.com +//=============================================================================================== +// History +// +// 2001/09/09 by Steve 'Sly' Williams +// - Updated to version 3.40 +// +// 2000/11/14 by Steve 'Sly' Williams +// - Fixed version check +// - Added FMODErrors to uses clause +// - Added check for Delphi 4 to change wVirtualKeyCode to wVirtualScanCode +// +// 2002/02/13 by Steve 'Sly' Williams +// - Updated for FMOD 3.50 +// +// 2002/12/19 by Steve 'Sly' Williams +// - Updated for FMOD 3.61 +//=============================================================================================== +program simplest; + +uses + fmod, fmodtypes, fmoderrors, Windows; + +{$APPTYPE CONSOLE} + +var + key: DWORD; + dw: dword; + h, h1: THandle; + buf: input_record; + c: coord; + s, sorder, srow, schp, scpu: string; + mdl: PFMusicModule; +begin + SetLength(s, 80); + SetConsoleTitle(pchar('Example Simplest (song player)')); + h := GetStdHandle(STD_INPUT_HANDLE); + h1 := GetStdHandle(STD_OUTPUT_HANDLE); + Buf.EventType := Key_Event; + if FMOD_VERSION > FSOUND_GetVersion then + begin + WriteLn('Error: You are using FMOD version ', FSOUND_GetVersion: 3: 2, '. You should be using version ', FMOD_VERSION: 3: 2); + Exit; + end; + +// ========================================================================================== +// INITIALIZE +// ========================================================================================== + if not FSOUND_Init(44100, 32, 0) then + begin + writeln('Error! Initializing'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + +// ========================================================================================== +// LOAD SONG +// ========================================================================================== + + mdl := FMUSIC_LoadSong('../../media/invtro94.s3m'); {can be xm, s3m...} + if mdl = nil then + begin + writeln('Error! Loading song'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + +// ========================================================================================== +// START PLAYING! +// ========================================================================================== + FMUSIC_PlaySong(mdl); + writeln('Press ESC to quit'); + writeln('Playing ...', FMUSIC_GetName(mdl)); + + GetConsoleMode(h, dw); + SetConsoleMode(h, dw or ENABLE_PROCESSED_OUTPUT or ENABLE_PROCESSED_INPUT); + c.X := 1; + c.Y := 4; + repeat + FlushConsoleInputBuffer(h); + Sleep(50); + dw := 0; + PeekConsoleInput(h, buf, 1, dw); + if buf.Event.KeyEvent.bKeyDown then + begin +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if dw = 1 then //can be done much more elegant cause it just + if key <> 0 then //reads if ESC has been pressed. + begin //don't let be confused by all the windows raw API code + if key = 27 then //I couldn't find the READKEY function :) + begin + writeln; + FSOUND_Close(); + exit; + end; + end; + end; + SetConsoleCursorPosition(h1, c); + str(FMUSIC_GetOrder(mdl), sorder); + str(FMUSIC_GetRow(mdl), srow); + str(FSOUND_GetChannelsPlaying(), schp); + str(FSOUND_GetCPUUsage(): 7: 5, scpu); + s := 'order = ' + sorder + ' row = ' + srow + ' channels playing = ' + schp + ' cpu usage = ' + scpu; + WriteConsole(h1, pchar(s), length(s) - 1, dw, nil); + s := ' '; + until false; + +// ========================================================================================== +// CLEANUP AND SHUTDOWN +// ========================================================================================== + + FMUSIC_FreeSong(mdl); + FSOUND_Close(); +end. + diff --git a/fmodapi375win/samplesdelphi/Stream1/stream1.dpr b/fmodapi375win/samplesdelphi/Stream1/stream1.dpr new file mode 100644 index 0000000..99cd962 --- /dev/null +++ b/fmodapi375win/samplesdelphi/Stream1/stream1.dpr @@ -0,0 +1,189 @@ +//=============================================================================================== +// STREAM.EXE +// Copyright (c), Firelight Multimedia, 1999-2000. +// +// This example takes a command line parameter, an mp3 file, and uses the streamer system to play +// it back. +// Converted to Delphi by Bocevski Dragan mailto: d_bocevski@yahoo.com +//=============================================================================================== +// History +// +// 2001/09/09 by Steve 'Sly' Williams +// - Updated to version 3.40 +// +// 2000/12/15 by Steve 'Sly' Williams +// - Updated to version 3.30 +// +// 2000/11/14 by Steve 'Sly' Williams +// - Fixed version check +// - Added FMODErrors to uses clause +// - Added check for Delphi 4 to change wVirtualKeyCode to wVirtualScanCode +// +// 2002/12/19 by Steve 'Sly' Williams +// - Updated to version 3.61 +//=============================================================================================== +program stream1; + +uses + fmod, fmodtypes, fmoderrors, Windows; + +{$APPTYPE CONSOLE} + +var + stream: PFSoundStream; + channel: Integer; + key: DWORD; + dw: dword; + driver: Integer; + i: Longint; + enm: TFSoundOutputTypes; + h, h1: THandle; + buf: input_record; + c: coord; + s, position, time, cpu: string; +begin + SetLength(s, 80); + SetConsoleTitle('Example Stream1 (mp3 player)'); + h := GetStdHandle(STD_INPUT_HANDLE); + h1 := GetStdHandle(STD_OUTPUT_HANDLE); + Buf.EventType := Key_Event; + if FMOD_VERSION > FSOUND_GetVersion then + begin + WriteLn('Error: You are using FMOD version ', FSOUND_GetVersion: 3: 2, '. You should be using version ', FMOD_VERSION: 3: 2); + Exit; + end; + if (paramcount < 1) then + begin + writeln('-------------------------------------------------------------'); + writeln('FMOD MP3 Streamer example.'); + writeln('Copyright (c) Firelight Multimedia, 1999.'); + writeln('-------------------------------------------------------------'); + writeln('Syntax: stream infile.mp3'); + writeln; + exit; + end; +// FSOUND_SetOutput(FSOUND_OUTPUT_A3D); +// FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + +// ========================================================================================== +// SELECT DRIVER +// ========================================================================================== + + +// The following list are the drivers for the output method selected above. + writeln('---------------------------------------------------------'); + enm := FSOUND_GetOutput(); + case enm of + + FSOUND_OUTPUT_NOSOUND: write('NoSound'); + FSOUND_OUTPUT_WINMM: write('Windows Multimedia Waveout'); + FSOUND_OUTPUT_DSOUND: write('Direct Sound'); + FSOUND_OUTPUT_A3D: write('A3D'); + end; + writeln(' Driver list'); + writeln('---------------------------------------------------------'); + for i := 0 to FSOUND_GetNumDrivers() - 1 do + writeln(i + 1, ' - ', FSOUND_GetDriverName(i)); // print driver names + writeln('---------------------------------------------------------'); // print driver names + writeln('Press a corresponding number or ESC to quit'); + repeat + FlushConsoleInputBuffer(h); + repeat + ReadConsoleInput(h, buf, 1, dw); + until buf.Event.KeyEvent.bKeyDown = false; +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if (ord(key) = 27) then exit; + driver := ord(key) - ord('1'); + until ((driver > 0) or (driver <= FSOUND_GetNumDrivers())); + FSOUND_SetDriver(driver); // Select sound card (0 = default) + +// ========================================================================================== +// INITIALIZE +// ========================================================================================== + if not FSOUND_Init(44100, 16, 0) then + begin + writeln('Error! Initializing'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + +// ========================================================================================== +// OPEN STREAM +// ========================================================================================== + stream := FSOUND_Stream_Open(PChar(ParamStr(1)), FSOUND_LOOP_NORMAL or FSOUND_NORMAL, 0, 0); + if stream = nil then + begin + writeln('Error! Opening file'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + +// ========================================================================================== +// PLAY STREAM +// ========================================================================================== + channel := FSOUND_Stream_Play(FSOUND_FREE, stream); + if channel < 0 then + begin + writeln('Error! Play'); + writeln(FMOD_ErrorString(FSOUND_GetError())); + FSOUND_Close(); + exit; + end; + writeln; + writeln('========================================================================='); + writeln('Press SPACE to pause/unpause'); + writeln('Press ESC to quit'); + writeln('========================================================================='); + writeln('Playing stream...'); + GetConsoleMode(h, dw); + SetConsoleMode(h, dw or ENABLE_PROCESSED_OUTPUT or ENABLE_PROCESSED_INPUT); + c.X := 1; + c.Y := 20; + repeat + FlushConsoleInputBuffer(h); + Sleep(50); + dw := 0; + PeekConsoleInput(h, buf, 1, dw); + if buf.Event.KeyEvent.bKeyDown then + begin +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if dw = 1 then + if key <> 0 then + if key = 32 then + begin + FSOUND_SetPaused(channel, not FSOUND_GetPaused(channel)); + key := 0; + end else if key = 27 then + begin + writeln; + FSOUND_Stream_Close(stream); + FSOUND_Close(); + exit; + end; + end; + SetConsoleCursorPosition(h1, c); + str(FSOUND_Stream_GetPosition(stream): 7, position); + str((FSOUND_Stream_GetTime(stream) / 1000): 6: 3, time); + str(FSOUND_GetCPUUsage(): 7: 5, cpu); + if FSOUND_GetPaused(channel) then + s := 'position = ' + position + ' time = ' + time + ' PAUSED ' + ' cpu usage = ' + cpu + else s := 'position = ' + position + ' time = ' + time + ' cpu usage = ' + cpu + ' '; + WriteConsole(h1, pchar(s), length(s) - 1, dw, nil); + s := ' '; + until key = 27; + writeln; + FSOUND_Stream_Close(stream); + FSOUND_Close(); +end. + diff --git a/fmodapi375win/samplesdelphi/simplegui/main.dfm b/fmodapi375win/samplesdelphi/simplegui/main.dfm new file mode 100644 index 0000000..d66e6e3 --- /dev/null +++ b/fmodapi375win/samplesdelphi/simplegui/main.dfm @@ -0,0 +1,176 @@ +object frmMain: TfrmMain + Left = 206 + Top = 122 + ActiveControl = lbxOutput + BorderIcons = [biSystemMenu] + BorderStyle = bsSingle + Caption = 'FMOD Simple Sample' + ClientHeight = 320 + ClientWidth = 353 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + OldCreateOrder = False + OnClose = FormClose + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object lblOutput: TLabel + Left = 12 + Top = 12 + Width = 32 + Height = 13 + Caption = '&Output' + FocusControl = lbxOutput + end + object lblDriver: TLabel + Left = 184 + Top = 12 + Width = 28 + Height = 13 + Caption = '&Driver' + FocusControl = lbxDriver + end + object lblCPUUsage: TLabel + Left = 12 + Top = 260 + Width = 25 + Height = 13 + Caption = 'CPU:' + end + object lblCPU: TLabel + Left = 52 + Top = 260 + Width = 3 + Height = 13 + end + object lblPlaySound: TLabel + Left = 16 + Top = 172 + Width = 57 + Height = 13 + Caption = 'Play sounds' + end + object pnlButtons: TPanel + Left = 0 + Top = 279 + Width = 353 + Height = 41 + Align = alBottom + BevelOuter = bvNone + TabOrder = 6 + object bvlButtons: TBevel + Left = 0 + Top = 0 + Width = 353 + Height = 2 + Align = alTop + end + object btnClose: TButton + Left = 260 + Top = 8 + Width = 75 + Height = 25 + Cancel = True + Caption = 'Close' + TabOrder = 0 + OnClick = btnCloseClick + end + end + object lbxOutput: TListBox + Left = 8 + Top = 28 + Width = 161 + Height = 97 + ItemHeight = 13 + TabOrder = 0 + OnClick = lbxOutputClick + end + object lbxDriver: TListBox + Left = 180 + Top = 28 + Width = 161 + Height = 97 + ItemHeight = 13 + TabOrder = 1 + end + object btnInit: TButton + Left = 12 + Top = 136 + Width = 75 + Height = 25 + Caption = '&Init' + TabOrder = 2 + OnClick = btnInitClick + end + object btnDeinit: TButton + Left = 96 + Top = 136 + Width = 75 + Height = 25 + Caption = 'D&einit' + Enabled = False + TabOrder = 3 + OnClick = btnDeinitClick + end + object btnPlay: TButton + Left = 180 + Top = 136 + Width = 75 + Height = 25 + Caption = '&Play' + Enabled = False + TabOrder = 4 + OnClick = btnPlayClick + end + object btnStop: TButton + Left = 264 + Top = 136 + Width = 75 + Height = 25 + Caption = '&Stop' + Enabled = False + TabOrder = 5 + OnClick = btnStopClick + end + object btn16bit: TButton + Left = 12 + Top = 192 + Width = 75 + Height = 25 + Caption = '16bit' + Enabled = False + TabOrder = 7 + OnClick = btn16bitClick + end + object btn8bit: TButton + Left = 96 + Top = 192 + Width = 75 + Height = 25 + Caption = '8bit' + Enabled = False + TabOrder = 8 + OnClick = btn8bitClick + end + object btn16bitstereo: TButton + Left = 180 + Top = 192 + Width = 75 + Height = 25 + Caption = '16bit stereo' + Enabled = False + TabOrder = 9 + OnClick = btn16bitstereoClick + end + object tmrMain: TTimer + Enabled = False + Interval = 100 + OnTimer = tmrMainTimer + Left = 304 + Top = 180 + end +end diff --git a/fmodapi375win/samplesdelphi/simplegui/main.pas b/fmodapi375win/samplesdelphi/simplegui/main.pas new file mode 100644 index 0000000..e6ac4b1 --- /dev/null +++ b/fmodapi375win/samplesdelphi/simplegui/main.pas @@ -0,0 +1,369 @@ +unit main; + +{ Disable warning for unsafe types in Delphi 7 } +{$IFDEF VER150} +{$WARN UNSAFE_TYPE OFF} +{$ENDIF} + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, ExtCtrls, fmod, fmodtypes; + +type + TfrmMain = class(TForm) + pnlButtons: TPanel; + btnClose: TButton; + bvlButtons: TBevel; + lblOutput: TLabel; + lbxOutput: TListBox; + lbxDriver: TListBox; + lblDriver: TLabel; + btnInit: TButton; + btnDeinit: TButton; + btnPlay: TButton; + btnStop: TButton; + lblCPUUsage: TLabel; + lblCPU: TLabel; + tmrMain: TTimer; + btn16bit: TButton; + btn8bit: TButton; + btn16bitstereo: TButton; + lblPlaySound: TLabel; + procedure FormCreate(Sender: TObject); + procedure lbxOutputClick(Sender: TObject); + procedure btnInitClick(Sender: TObject); + procedure btnDeinitClick(Sender: TObject); + procedure tmrMainTimer(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure btnPlayClick(Sender: TObject); + procedure btnStopClick(Sender: TObject); + procedure btn16bitClick(Sender: TObject); + procedure btn8bitClick(Sender: TObject); + procedure btn16bitstereoClick(Sender: TObject); + procedure btnCloseClick(Sender: TObject); + private + FInitialised: Boolean; + FPlaying: Boolean; + FMusic: PFMusicModule; + FSound1: PFSoundSample; + FSound2: PFSoundSample; + FSound3: PFSoundSample; + function Load: Boolean; + procedure Unload; + public + { Public declarations } + end; + +var + frmMain: TfrmMain; + +implementation + +uses + fmoderrors; + +{$R *.dfm} + +type + TOutput = record + Value: TFSoundOutputTypes; + Name: String; + end; + +const +{$IFDEF MSWINDOWS} + Output: array [0..4] of TOutput = + ( + ( Value: FSOUND_OUTPUT_DSOUND; Name: 'DirectSound' ), + ( Value: FSOUND_OUTPUT_WINMM; Name: 'Windows Multimedia' ), + ( Value: FSOUND_OUTPUT_A3D; Name: 'A3D' ), + ( Value: FSOUND_OUTPUT_ASIO; Name: 'ASIO' ), + ( Value: FSOUND_OUTPUT_NOSOUND; Name: 'No sound' ) + ); +{$ELSE} +{$IFDEF LINUX} + Output: array [0..3] of TOutput = + ( + ( Value: FSOUND_OUTPUT_OSS; Name: 'Open Sound System' ), + ( Value: FSOUND_OUTPUT_ESD; Name: 'Enlightenment Sound Daemon' ), + ( Value: FSOUND_OUTPUT_ALSA; Name: 'ALSA' ), + ( Value: FSOUND_OUTPUT_NOSOUND; Name: 'No sound' ) + ); +{$ENDIF} +{$ENDIF} + +procedure TfrmMain.FormCreate(Sender: TObject); +var + Index: Integer; +begin + { Use the default Windows desktop font } + DesktopFont := True; + + FMOD_Load(nil); + + { Populate the list of output types with both the name and enumeration value } + { Use a typecasting trick to store an integer value as an object } + for Index := Low(Output) to High(Output) do + lbxOutput.Items.AddObject(Output[Index].Name, TObject(Output[Index].Value)); + + { Pre-select the first output type in the list } + lbxOutput.ItemIndex := 0; + lbxOutputClick(nil); +end; + +procedure TfrmMain.lbxOutputClick(Sender: TObject); +var + Index: Integer; +begin + { Clear the existing list } + lbxDriver.Items.Clear; + + { If no output type is selected, then exit } + if lbxOutput.ItemIndex < 0 then + Exit; + + { Set the output type } + FSOUND_SetOutput(TFSoundOutputTypes(lbxOutput.Items.Objects[lbxOutput.ItemIndex])); + + { Get the list of available drivers } + for Index := 0 to FSOUND_GetNumDrivers - 1 do + lbxDriver.Items.Add(FSOUND_GetDriverName(Index)); + + { Select the first driver in the list } + if lbxDriver.Items.Count > 0 then + lbxDriver.ItemIndex := 0; +end; + +procedure TfrmMain.btnInitClick(Sender: TObject); +begin + { Make sure an output type is selected } + if lbxOutput.ItemIndex < 0 then + begin + MessageDlg('Must select an output type', mtError, [mbOk], 0); + lbxOutput.SetFocus; + Exit; + end; + + { Make sure a driver is selected } + if lbxDriver.ItemIndex < 0 then + begin + MessageDlg('Must select a driver', mtError, [mbOk], 0); + lbxDriver.SetFocus; + Exit; + end; + + { Set the output type } + FSOUND_SetOutput(TFSoundOutputTypes(lbxOutput.Items.Objects[lbxOutput.ItemIndex])); + + { Set the driver } + FSOUND_SetDriver(lbxDriver.ItemIndex); + + { Set the mixer } + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_AUTODETECT); + + { Initialise FMOD at 22.5kHz, 32 software channels and no special flags } + FInitialised := FSOUND_Init(22500, 32, 0); + + if not FInitialised then + begin + MessageDlg('FMOD initialisation failed'#13 + FMOD_ErrorString(FSOUND_GetError), mtError, [mbOk], 0); + Exit; + end; + + { Set the enabled state of the buttons } + btnInit.Enabled := False; + btnDeinit.Enabled := True; + btnPlay.Enabled := True; + btnStop.Enabled := False; + lbxOutput.Enabled := False; + lbxDriver.Enabled := False; + + { Enable the timer to display song and CPU usage information } + tmrMain.Enabled := True; +end; + +procedure TfrmMain.btnDeinitClick(Sender: TObject); +begin + if not FInitialised then + Exit; + + { Press the stop button } + btnStopClick(nil); + + { Close FMOD } + FSOUND_Close; + FInitialised := False; + + { Set the enabled state of the buttons } + btnInit.Enabled := True; + btnDeinit.Enabled := False; + btnPlay.Enabled := False; + btnStop.Enabled := False; + lbxOutput.Enabled := True; + lbxDriver.Enabled := True; + + { Stop the timer since we do not need the song and CPU information any more } + tmrMain.Enabled := False; + lblCPU.Caption := ''; +end; + +procedure TfrmMain.tmrMainTimer(Sender: TObject); +begin + { What percentage of CPU is FMOD using? } + lblCPU.Caption := Format('%0.1f%%', [FSOUND_GetCPUUsage]); +end; + +procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction); +begin + { If the form is being closed, then act as if the stop and deinit buttons + have been pressed } + btnStopClick(nil); + btnDeinitClick(nil); +end; + +procedure TfrmMain.btnPlayClick(Sender: TObject); +begin + if FPlaying then + Exit; + + { Load the music and samples } + if not Load then + Exit; + + { Play the music } + FMUSIC_PlaySong(FMusic); + FMUSIC_SetPanSeperation(FMusic, 0.15); { 15% crossover } + + FPlaying := True; + + { Set the enabled state of the buttons } + btnPlay.Enabled := False; + btnStop.Enabled := True; + btn16bit.Enabled := True; + btn8bit.Enabled := True; + btn16bitstereo.Enabled := True; +end; + +procedure TfrmMain.btnStopClick(Sender: TObject); +begin + if not FPlaying then + Exit; + + { Unload the music and samples } + Unload; + + FPlaying := False; + + { Set the enabled state of the buttons } + btnPlay.Enabled := True; + btnStop.Enabled := False; + btn16bit.Enabled := False; + btn8bit.Enabled := False; + btn16bitstereo.Enabled := False; +end; + +function TfrmMain.Load: Boolean; +begin + { Assume it will fail } + Result := False; + + { Music } + FMusic := FMUSIC_LoadSong('../../media/invtro94.s3m'); + if FMusic = nil then + begin + MessageDlg('Failed to load music'#13 + FMOD_ErrorString(FSOUND_GetError), mtError, [mbOk], 0); + Unload; + Exit; + end; + + { 16bit sound } + FSound1 := FSOUND_Sample_Load(FSOUND_FREE, '../../media/jaguar.wav', FSOUND_2D, 0, 0); + if FSound1 = nil then + begin + MessageDlg('Failed to load jaguar.wav'#13 + FMOD_ErrorString(FSOUND_GetError), mtError, [mbOk], 0); + Unload; + Exit; + end; + + { 8bit sound } + FSound2 := FSOUND_Sample_Load(FSOUND_FREE, '../../media/drumloop.wav', FSOUND_2D, 0, 0); + if FSound2 = nil then + begin + MessageDlg('Failed to load drumloop.wav'#13 + FMOD_ErrorString(FSOUND_GetError), mtError, [mbOk], 0); + Unload; + Exit; + end; + + { 16bit stereo sound } + FSound3 := FSOUND_Sample_Load(FSOUND_FREE, '../../media/chimes.wav', FSOUND_2D, 0, 0); + if FSound3 = nil then + begin + MessageDlg('Failed to load chimes.wav'#13 + FMOD_ErrorString(FSOUND_GetError), mtError, [mbOk], 0); + Unload; + Exit; + end; + + { We got this far, so it all succeeded } + Result := True; +end; + +procedure TfrmMain.Unload; +begin + { Free the music } + if FMusic <> nil then + begin + FMUSIC_FreeSong(FMusic); + FMusic := nil; + end; + + { Free the 16bit sample } + if FSound1 <> nil then + begin + FSOUND_Sample_Free(FSound1); + FSound1 := nil; + end; + + { Free the 8bit sample } + if FSound2 <> nil then + begin + FSOUND_Sample_Free(FSound2); + FSound2 := nil; + end; + + { Free the 16bit stereo sample } + if FSound2 <> nil then + begin + FSOUND_Sample_Free(FSound2); + FSound2 := nil; + end; +end; + +procedure TfrmMain.btn16bitClick(Sender: TObject); +begin + { Play the 16bit sound } + FSOUND_PlaySound(FSOUND_FREE, FSound1) +end; + +procedure TfrmMain.btn8bitClick(Sender: TObject); +begin + { Play the 8bit sound } + FSOUND_PlaySound(FSOUND_FREE, FSound2) +end; + +procedure TfrmMain.btn16bitstereoClick(Sender: TObject); +var + Channel: Integer; +begin + { Play the 16bit stereo sound } + Channel := FSOUND_PlaySound(FSOUND_FREE, FSound3); + FSOUND_SetPan(Channel, FSOUND_STEREOPAN); +end; + +procedure TfrmMain.btnCloseClick(Sender: TObject); +begin + Close; +end; + +end. diff --git a/fmodapi375win/samplesdelphi/simplegui/simple.dpr b/fmodapi375win/samplesdelphi/simplegui/simple.dpr new file mode 100644 index 0000000..3a27da0 --- /dev/null +++ b/fmodapi375win/samplesdelphi/simplegui/simple.dpr @@ -0,0 +1,13 @@ +program simple; + +uses + Forms, + main in 'main.pas' {frmMain}; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TfrmMain, frmMain); + Application.Run; +end. diff --git a/fmodapi375win/samplesdelphi/stream2/stream2.dpr b/fmodapi375win/samplesdelphi/stream2/stream2.dpr new file mode 100644 index 0000000..e2c0951 --- /dev/null +++ b/fmodapi375win/samplesdelphi/stream2/stream2.dpr @@ -0,0 +1,271 @@ +//=============================================================================================== +// STREAM2.EXE +// Copyright (c), Firelight Multimedia, 1999-2000. +// +// This sample specifically demonstrates the user callback streaming facility, and generates a +// very strange noise! :) +// Converted to Delphi by Steve 'Sly' Williams +//=============================================================================================== +// History +// +// 2001/09/09 by Steve 'Sly' Williams +// - Updated to version 3.40 +// +// 2000/12/15 by Steve 'Sly' Williams +// - Updated to version 3.30 +// +// 2000/11/13 by Steve 'Sly' Williams +// - Fixed version check +// - Updated to use FMODErrors.pas +// - Added check for Delphi 4 to change wVirtualKeyCode to wVirtualScanCode +// +// 2000/06/04 by Steve 'Sly' Williams +// - Conversion of stream2 +// +// 2002/02/13 by Steve 'Sly' Williams +// - Updated for Delphi 6 compatability (writeable constants) +// +// 2002/12/19 by Steve 'Sly' Williams +// - Updated to version 3.61 +//=============================================================================================== + +program stream2; + +uses + Windows, fmod, fmodtypes, fmoderrors, SysUtils; + +{$APPTYPE CONSOLE} + +{$IFDEF VER140} +{$DEFINE COMPILER6_UP} +{$ELSE} + {$IFDEF VER150} + {$DEFINE COMPILER6_UP} + {$ENDIF} +{$ENDIF} + +type + PSmallInt = ^SmallInt; + +var + h: THandle; + dw: DWORD; + Status, Time, CPU, LenStr, BuffStr: String; + +function StreamCallback(Stream: PFSoundStream; Buff: Pointer; Len, Param: Integer): ByteBool; stdcall; +{$IFDEF COMPILER6_UP}{$J+}{$ENDIF} +const + Time1: Single = 0.0; + Time2: Single = 0.0; + Velocity1: Single = 0.0; + Velocity2: Single = 0.0; +{$IFDEF COMPILER6_UP}{$J-}{$ENDIF} +var + Count: Integer; + Buffer: PChar; +begin + Buffer := PChar(Buff); + Count := 0; + + while Count < (Len shr 2) do { >>2 = 16bit stereo (4 bytes per sample) } + begin + PSmallInt(Buffer)^ := Trunc(Sin(Time1) * 32767.0); { Left channel } + Inc(Buffer, 2); + PSmallInt(Buffer)^ := Trunc(Sin(Time2) * 32767.0); { Right channel } + Inc(Buffer, 2); + + Time1 := Time1 + 0.1 + Velocity1; + Time2 := Time2 + 0.142 + Velocity2; + Velocity1 := Velocity1 + (Sin(Time1) * 0.02); + Velocity2 := Velocity2 + (Sin(Time2) * 0.02); + + Inc(Count); + end; + + Str(FSOUND_Stream_GetTime(Stream) / 1000: 6: 3, Time); + Str(FSOUND_GetCPUUsage: 7: 5, CPU); + Str(Integer(Buff), BuffStr); + Str(Len, LenStr); + Status := 'Callback: Buff=' + BuffStr + ' Len=' + LenStr + ' Time=' + Time + ' CPU=' + CPU; + WriteLn(Status); + + // Must return true for the stream to continue + Result := True; +end; + +const + OutputTypes: array [0..3] of String = + ('Direct Sound', 'Windows Multimedia Waveout', 'A3D', 'NoSound'); +var + Stream: PFSoundStream; + Channel: Integer; + Key: DWORD; + Output, Driver: Integer; + Index: Longint; + Buf: input_record; +begin + SetConsoleTitle('Example Stream2 (streaming callback)'); + h := GetStdHandle(STD_INPUT_HANDLE); + Buf.EventType := Key_Event; + if FMOD_VERSION > FSOUND_GetVersion then + begin + WriteLn('Error: You are using FMOD version ', FSOUND_GetVersion:3:2, '. You should be using version ', FMOD_VERSION:3:2); + Exit; + end; + + WriteLn('-------------------------------------------------------------'); + WriteLn('FSOUND Streamer example.'); + WriteLn('Copyright (c) Firelight Multimedia, 1999.'); + WriteLn('-------------------------------------------------------------'); + +// ========================================================================================== +// SELECT OUTPUT +// ========================================================================================== + + WriteLn('---------------------------------------------------------'); + WriteLn('Output Type'); + WriteLn('---------------------------------------------------------'); + WriteLn('1 - ', OutputTypes[0]); + WriteLn('2 - ', OutputTypes[1]); + WriteLn('3 - ', OutputTypes[2]); + WriteLn('4 - ', OutputTypes[3]); + WriteLn('---------------------------------------------------------'); + WriteLn('Press a corresponding number or ESC to quit'); + + Output := High(Output); + repeat + FlushConsoleInputBuffer(h); + repeat + ReadConsoleInput(h, buf, 1, dw); + until not buf.Event.KeyEvent.bKeyDown; +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if Ord(Key) = 27 then + Exit; + if Key >= Ord('1') then + begin + Output := Ord(Key) - Ord('1'); + case Output of + 0: FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); + 1: FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); + 2: FSOUND_SetOutput(FSOUND_OUTPUT_A3D); + 3: FSOUND_SetOutput(FSOUND_OUTPUT_NOSOUND); + end; + end; + until Output < 4; + +// ========================================================================================== +// SELECT DRIVER +// ========================================================================================== + +// The following list are the drivers for the output method selected above. + WriteLn('---------------------------------------------------------'); + case FSOUND_GetOutput of + FSOUND_OUTPUT_NOSOUND: Write(OutputTypes[3]); + FSOUND_OUTPUT_WINMM: Write(OutputTypes[1]); + FSOUND_OUTPUT_DSOUND: Write(OutputTypes[0]); + FSOUND_OUTPUT_A3D: Write(OutputTypes[2]); + end; + WriteLn(' Driver list'); + WriteLn('---------------------------------------------------------'); + for Index := 0 to FSOUND_GetNumDrivers - 1 do + WriteLn(Index + 1, ' - ', FSOUND_GetDriverName(Index)); // print driver names + WriteLn('---------------------------------------------------------'); // print driver names + WriteLn('Press a corresponding number or ESC to quit'); + + Driver := High(Driver); + repeat + FlushConsoleInputBuffer(h); + repeat + ReadConsoleInput(h, buf, 1, dw); + until not buf.Event.KeyEvent.bKeyDown; +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if Ord(Key) = 27 then + Exit; + if Key >= Ord('1') then + begin + Driver := Ord(Key) - Ord('1'); + if Driver < FSOUND_GetNumDrivers then + FSOUND_SetDriver(Driver); // Select sound card (0 = default) + end; + until Driver < FSOUND_GetNumDrivers; + +// ========================================================================================== +// INITIALIZE +// ========================================================================================== + if not FSOUND_Init(44100, 16, 0) then + begin + WriteLn('Error! Initializing'); + WriteLn(FMOD_ErrorString(FSOUND_GetError)); + FSOUND_Close; + Exit; + end; + +// ========================================================================================== +// OPEN STREAM +// ========================================================================================== + Stream := FSOUND_Stream_Create(StreamCallback, 1000 * 2 * 2, FSOUND_NORMAL or FSOUND_16BITS or FSOUND_STEREO, 22050, 12345); + if Stream = nil then + begin + WriteLn('Error! Opening stream'); + WriteLn(FMOD_ErrorString(FSOUND_GetError)); + FSOUND_Close; + Exit; + end; + +// ========================================================================================== +// PLAY STREAM +// ========================================================================================== + WriteLn; + WriteLn('========================================================================='); + WriteLn('Press SPACE to pause/unpause'); + WriteLn('Press ESC to quit'); + WriteLn('========================================================================='); + WriteLn('Playing stream...'); + + Channel := FSOUND_Stream_Play(FSOUND_FREE, Stream); + if Channel < 0 then + begin + WriteLn; + WriteLn('Error! Play'); + WriteLn(FMOD_ErrorString(FSOUND_GetError)); + FSOUND_Close; + Exit; + end; + + GetConsoleMode(h, dw); + SetConsoleMode(h, dw or ENABLE_PROCESSED_OUTPUT or ENABLE_PROCESSED_INPUT); + repeat + FlushConsoleInputBuffer(h); + Sleep(50); + dw := 0; + PeekConsoleInput(h, buf, 1, dw); + if buf.Event.KeyEvent.bKeyDown then + begin +{$IFDEF VER120} + Key := buf.Event.KeyEvent.wVirtualScanCode; +{$ELSE} + Key := buf.Event.KeyEvent.wVirtualKeyCode; +{$ENDIF} + if dw = 1 then + begin + if Key = 32 then + begin + FSOUND_SetPaused(Channel, not FSOUND_GetPaused(Channel)); + Key := 0; + end; + end; + end; + until Key = 27; + WriteLn; + FSOUND_Stream_Close(Stream); + FSOUND_Close; +end. + diff --git a/fmodapi375win/samplesvb/simplest/Form1.frm b/fmodapi375win/samplesvb/simplest/Form1.frm new file mode 100644 index 0000000..5868a96 --- /dev/null +++ b/fmodapi375win/samplesvb/simplest/Form1.frm @@ -0,0 +1,441 @@ +VERSION 5.00 +Object = "{F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.2#0"; "Comdlg32.ocx" +Begin VB.Form Form1 + Caption = "FMod VB Example - Simplest" + ClientHeight = 5355 + ClientLeft = 60 + ClientTop = 375 + ClientWidth = 8550 + LinkTopic = "Form1" + ScaleHeight = 5355 + ScaleWidth = 8550 + StartUpPosition = 3 'Windows Default + Begin MSComDlg.CommonDialog CommonDialog1 + Left = 1320 + Top = 2640 + _ExtentX = 847 + _ExtentY = 847 + _Version = 393216 + End + Begin VB.Frame Frame5 + Caption = "2c. Samples (wav, mp3, ogg, wma)" + Height = 1455 + Left = 2280 + TabIndex = 12 + Top = 3600 + Width = 3855 + Begin VB.CommandButton cmdCloseSample + Caption = "4 - Close Sample" + Enabled = 0 'False + Height = 375 + Left = 240 + TabIndex = 18 + Top = 840 + Width = 1455 + End + Begin VB.CommandButton cmdstopSample + Caption = "3 - Stop Sample" + Enabled = 0 'False + Height = 375 + Left = 2040 + TabIndex = 15 + Top = 840 + Width = 1455 + End + Begin VB.CommandButton cmdPlaySample + Caption = "2 - Play Sample" + Enabled = 0 'False + Height = 375 + Left = 2040 + TabIndex = 14 + Top = 360 + Width = 1455 + End + Begin VB.CommandButton cmdOpenSample + Caption = "1 - Open Sample" + Enabled = 0 'False + Height = 375 + Left = 240 + TabIndex = 13 + Top = 360 + Width = 1455 + End + End + Begin VB.Frame Frame4 + Caption = "3. Close FMod" + Height = 975 + Left = 6360 + TabIndex = 10 + Top = 240 + Width = 1935 + Begin VB.CommandButton cmdClose + Caption = "FSOUND_Close" + Enabled = 0 'False + Height = 375 + Left = 240 + TabIndex = 11 + Top = 360 + Width = 1455 + End + End + Begin VB.Frame Frame3 + Caption = "2b. Streams (wav, mp3, ogg, wma)" + Height = 1455 + Left = 2280 + TabIndex = 6 + Top = 1920 + Width = 3855 + Begin VB.CommandButton cmdCloseStream + Caption = "4 - Close Stream" + Enabled = 0 'False + Height = 375 + Left = 240 + TabIndex = 17 + Top = 840 + Width = 1455 + End + Begin VB.CommandButton cmdOpenStream + Caption = "1 - Open Stream" + Enabled = 0 'False + Height = 375 + Left = 240 + TabIndex = 9 + Top = 360 + Width = 1455 + End + Begin VB.CommandButton cmdPlayStream + Caption = "2 - Play Stream" + Enabled = 0 'False + Height = 375 + Left = 2040 + TabIndex = 8 + Top = 360 + Width = 1455 + End + Begin VB.CommandButton cmdStopStream + Caption = "3 - Stop Stream" + Enabled = 0 'False + Height = 375 + Left = 2040 + TabIndex = 7 + Top = 840 + Width = 1455 + End + End + Begin VB.Frame Frame2 + Caption = "2a. Songs (s3m, it, xm, mod)" + Height = 1455 + Left = 2280 + TabIndex = 2 + Top = 240 + Width = 3855 + Begin VB.CommandButton cmdCloseSong + Caption = "4 - Close Song" + Enabled = 0 'False + Height = 375 + Left = 240 + TabIndex = 16 + Top = 840 + Width = 1455 + End + Begin VB.CommandButton cmdStopSong + Caption = "3 - Stop Song" + Enabled = 0 'False + Height = 375 + Left = 2040 + TabIndex = 5 + Top = 840 + Width = 1455 + End + Begin VB.CommandButton cmdPlaySong + Caption = "2 - Play Song" + Enabled = 0 'False + Height = 375 + Left = 2040 + TabIndex = 4 + Top = 360 + Width = 1455 + End + Begin VB.CommandButton cmdOpenSong + Caption = "1 - Open Song" + Enabled = 0 'False + Height = 375 + Left = 240 + TabIndex = 3 + Top = 360 + Width = 1455 + End + End + Begin VB.Frame Frame1 + Caption = "1. Initialize FMod" + Height = 975 + Left = 240 + TabIndex = 0 + Top = 240 + Width = 1935 + Begin VB.CommandButton cmdInit + Caption = "FSOUND_Init" + Height = 375 + Left = 240 + TabIndex = 1 + Top = 360 + Width = 1455 + End + End +End +Attribute VB_Name = "Form1" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False +Option Explicit + +'Public declarations of variables holding songs, samples and streams +Dim songHandle As Long +Dim sampleHandle As Long +Dim sampleChannel As Long +Dim streamHandle As Long +Dim streamChannel As Long + +Private Sub cmdClose_Click() +'You always have to close fmod before exiting your program +FSOUND_Close + +'Switch which buttons are enabled +cmdInit.Enabled = True +cmdClose.Enabled = False +cmdOpenSong.Enabled = False +cmdPlaySong.Enabled = False +cmdStopSong.Enabled = False +cmdCloseSong.Enabled = False +cmdOpenStream.Enabled = False +cmdPlayStream.Enabled = False +cmdStopStream.Enabled = False +cmdCloseStream.Enabled = False +cmdOpenSample.Enabled = False +cmdPlaySample.Enabled = False +cmdstopSample.Enabled = False +cmdCloseSample.Enabled = False +End Sub + +Private Sub cmdCloseSample_Click() +FSOUND_Sample_Free sampleHandle +'You should manually set the handle to 0 after closing the song +'This way, you can see if the song is loaded or not +sampleHandle = 0 + +cmdCloseSample.Enabled = False +cmdOpenSample.Enabled = True +cmdPlaySample.Enabled = False +cmdstopSample.Enabled = False +End Sub + +Private Sub cmdCloseSong_Click() +FMUSIC_FreeSong songHandle +'You should manually set the handle to 0 after closing the song +'This way, you can see if the song is loaded or not +songHandle = 0 + +cmdCloseSong.Enabled = False +cmdOpenSong.Enabled = True +cmdPlaySong.Enabled = False +cmdStopSong.Enabled = False +End Sub + +Private Sub cmdCloseStream_Click() +FSOUND_Stream_Close streamHandle +'You should manually set the handle to 0 after closing the song +'This way, you can see if the song is loaded or not +streamHandle = 0 + +cmdCloseStream.Enabled = False +cmdOpenStream.Enabled = True +cmdPlayStream.Enabled = False +cmdStopStream.Enabled = False +End Sub + +Private Sub cmdInit_Click() +'This is the first thing you have to do before you can start working with fmod +Dim result As Boolean +result = FSOUND_Init(44100, 32, 0) +If result Then + 'Successfully initialized + 'Update buttons + cmdInit.Enabled = False + cmdClose.Enabled = True + cmdOpenSong.Enabled = True + cmdOpenStream.Enabled = True + cmdOpenSample.Enabled = True +Else + 'An error occured + MsgBox "An error occured initializing fmod!" & vbCrLf & _ + FSOUND_GetErrorString(FSOUND_GetError), vbOKOnly +End If + +End Sub + +Private Sub cmdOpenSample_Click() +'Samples should be used for things such as sound effects +'Samples are completely loaded into memory when loading +'When you load a compressed file such as an mp3 as a sample +'it will be decompressed first, and then stored to memory + +CommonDialog1.Filter = "All Supported Samples (*.wav, *.mp3, *.ogg, *.wma)|*.wav;*.ogg;*.mp3;*.wma" +CommonDialog1.ShowOpen + +If Not FileExist(CommonDialog1.filename) Then + MsgBox "File doesn't exist or no file selected" + Exit Sub +End If + +sampleHandle = FSOUND_Sample_Load(fsound_free, CommonDialog1.filename, FSOUND_NORMAL, 0, 0) + +If sampleHandle <> 0 Then + 'Loading was successful + cmdCloseSample.Enabled = True + cmdOpenSample.Enabled = False + cmdPlaySample.Enabled = True +Else + 'Something went wrong + MsgBox "An error occured opening the sample!" & vbCrLf & _ + FSOUND_GetErrorString(FSOUND_GetError), vbOKOnly +End If + +End Sub + +Private Sub cmdOpenSong_Click() +'The FMUSIC_* part of fmod handles modules or music files +CommonDialog1.Filter = "All Supported Modules (*.s3m, *.it, *.xm, *.mod)|*.s3m;*.it;*.xm;*.mod" +CommonDialog1.ShowOpen + +If Not FileExist(CommonDialog1.filename) Then + MsgBox "File doesn't exist or no file selected" + Exit Sub +End If + +songHandle = FMUSIC_LoadSong(CommonDialog1.filename) +If songHandle <> 0 Then + 'Loading was successful + cmdCloseSong.Enabled = True + cmdOpenSong.Enabled = False + cmdPlaySong.Enabled = True +Else + 'Something went wrong + MsgBox "An error occured opening the song!" & vbCrLf & _ + FSOUND_GetErrorString(FSOUND_GetError), vbOKOnly +End If + +End Sub + +Private Sub cmdOpenStream_Click() +'Streams are not loaded completely into memory +'When playing a stream, fmod loads only the part that is currently playing into memory +'It should be used if you want to play music with fmod + +CommonDialog1.Filter = "All Supported Streams (*.wav, *.mp3, *.ogg, *.wma)|*.wav;*.ogg;*.mp3;*.wma" +CommonDialog1.ShowOpen + +If Not FileExist(CommonDialog1.filename) Then + MsgBox "File doesn't exist or no file selected" + Exit Sub +End If + +streamHandle = FSOUND_Stream_Open(CommonDialog1.filename, FSOUND_NORMAL, 0, 0) + +If streamHandle <> 0 Then + 'Loading was successful + cmdCloseStream.Enabled = True + cmdOpenStream.Enabled = False + cmdPlayStream.Enabled = True +Else + 'Something went wrong + MsgBox "An error occured opening the stream!" & vbCrLf & _ + FSOUND_GetErrorString(FSOUND_GetError), vbOKOnly +End If + +End Sub + +Private Sub cmdPlaySample_Click() +'You should always use FSOUND_FREE as the first paramter +'This lets fmod choose a free channel and play the sample in it +'Each sample can be played more than once if necessary +'If you need to keep track of each sample that is playing, +'You will need as much variables as times you want to play the sample +'to store the sample channels in +sampleChannel = FSOUND_PlaySound(fsound_free, sampleHandle) + +If sampleChannel <> 0 Then + 'Playing + cmdPlaySample.Enabled = False + cmdstopSample.Enabled = True +Else + 'Something went wrong + MsgBox "An error occured playing the sample!" & vbCrLf & _ + FSOUND_GetErrorString(FSOUND_GetError), vbOKOnly +End If +End Sub + +Private Sub cmdPlaySong_Click() +Dim result As Boolean +result = FMUSIC_PlaySong(songHandle) +If result Then + 'Playing + cmdPlaySong.Enabled = False + cmdStopSong.Enabled = True +Else + 'Something went wrong + MsgBox "An error occured playing the song!" & vbCrLf & _ + FSOUND_GetErrorString(FSOUND_GetError), vbOKOnly +End If +End Sub + +Private Sub cmdPlayStream_Click() +'You should always use FSOUND_FREE as the first paramter +'This lets fmod choose a free channel and play the stream in it +'Each stream can be played only once +streamChannel = FSOUND_Stream_Play(fsound_free, streamHandle) + +If streamChannel <> 0 Then + 'Playing + cmdPlayStream.Enabled = False + cmdStopStream.Enabled = True +Else + 'Something went wrong + MsgBox "An error occured playing the stream!" & vbCrLf & _ + FSOUND_GetErrorString(FSOUND_GetError), vbOKOnly +End If +End Sub + +Private Sub cmdstopSample_Click() +FSOUND_StopSound sampleChannel +'After a sample has been stopped, the channel is not active anymore +sampleChannel = 0 + +cmdPlaySample.Enabled = True +cmdstopSample.Enabled = False +End Sub + +Private Sub cmdStopSong_Click() +FMUSIC_StopSong songHandle +cmdPlaySong.Enabled = True +cmdStopSong.Enabled = False +End Sub + +Private Function FileExist(ByVal FileN As String) As Boolean +'This function checks if the given file exists +On Error GoTo errorhandler +If Dir$(FileN) = vbNullString Then FileExist = False Else FileExist = True +If FileN = "" Then FileExist = False +Exit Function +errorhandler: +FileExist = False +End Function + +Private Sub cmdStopStream_Click() +FSOUND_Stream_Stop streamHandle +'After a stream has been stopped, the channel is not active anymore +streamChannel = 0 + +cmdPlayStream.Enabled = True +cmdStopStream.Enabled = False +End Sub diff --git a/fmodapi375win/samplesvb/simplest/Project1.vbp b/fmodapi375win/samplesvb/simplest/Project1.vbp new file mode 100644 index 0000000..80801aa --- /dev/null +++ b/fmodapi375win/samplesvb/simplest/Project1.vbp @@ -0,0 +1,35 @@ +Type=Exe +Form=Form1.frm +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINDOWS\System32\STDOLE2.TLB#OLE Automation +Module=FMod; ..\..\API\vb\fmod.bas +Object={F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.2#0; Comdlg32.ocx +Startup="Form1" +ExeName32="Simplest.exe" +Command32="" +Name="Simplest" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="Interbrew" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/fmodapi375win/tools/FSBANK.HLP b/fmodapi375win/tools/FSBANK.HLP new file mode 100644 index 0000000..e9d66b0 Binary files /dev/null and b/fmodapi375win/tools/FSBANK.HLP differ diff --git a/fmodapi375win/tools/asioconfig.exe b/fmodapi375win/tools/asioconfig.exe new file mode 100644 index 0000000..eeead27 Binary files /dev/null and b/fmodapi375win/tools/asioconfig.exe differ diff --git a/fmodapi375win/tools/fsbank.exe b/fmodapi375win/tools/fsbank.exe new file mode 100644 index 0000000..3c117ae Binary files /dev/null and b/fmodapi375win/tools/fsbank.exe differ diff --git a/fmodapi375win/tools/fsbankcl.exe b/fmodapi375win/tools/fsbankcl.exe new file mode 100644 index 0000000..cd3e575 Binary files /dev/null and b/fmodapi375win/tools/fsbankcl.exe differ diff --git a/fmodapi375win/tools/fsbanklib/drumloop.wav b/fmodapi375win/tools/fsbanklib/drumloop.wav new file mode 100644 index 0000000..b35e216 Binary files /dev/null and b/fmodapi375win/tools/fsbanklib/drumloop.wav differ diff --git a/fmodapi375win/tools/fsbanklib/example.cpp b/fmodapi375win/tools/fsbanklib/example.cpp new file mode 100644 index 0000000..58e308f --- /dev/null +++ b/fmodapi375win/tools/fsbanklib/example.cpp @@ -0,0 +1,71 @@ +#include "fsbanklib.h" + +#include + +#define NUMFILES 2 + +char *files[NUMFILES] = +{ + "jbtennis.wav", + "drumloop.wav" +}; + +void __stdcall Update(int index, int memused, void *userdata) +{ + printf("UPDATE : File %s, memory used %d kb\n", files[index], memused / 1024); +} + +void __stdcall Debug(const char *debugstring, void *userdata) +{ + printf("DEBUG : %s\n", debugstring); +} + +void main() +{ + FSBANK_RESULT result; + + result = FSBank_Init(); + if (result != FSBANK_OK) + { + printf("ERROR\n"); + return; + } + + result = FSBank_SetUpdateCallback(Update, 0); + if (result != FSBANK_OK) + { + printf("ERROR\n"); + return; + } + + result = FSBank_SetDebugCallback(Debug, 0); + if (result != FSBANK_OK) + { + printf("ERROR\n"); + return; + } + +#if 1 + /* + This version compiles the wavs into 1 fsb. + */ + result = FSBank_Build(FSBANK_BUILDMODE_SINGLE, FSBANK_FORMAT_PCM, FSBANK_PLATFORM_CROSS, 0, "test.fsb", NUMFILES, &files[0], 0, 0, 0, 1, 0); +#else + /* + This version compiles the wavs into their own fsb. 1 each. + */ + result = FSBank_Build(FSBANK_BUILDMODE_MULTI, FSBANK_FORMAT_PCM, FSBANK_PLATFORM_CROSS, 0, ".", NUMFILES, &files[0], 0, 0, 0, 1, 0); +#endif + if (result != FSBANK_OK) + { + printf("ERROR\n"); + return; + } + + result = FSBank_Close(); + if (result != FSBANK_OK) + { + printf("ERROR\n"); + return; + } +} \ No newline at end of file diff --git a/fmodapi375win/tools/fsbanklib/example.dsp b/fmodapi375win/tools/fsbanklib/example.dsp new file mode 100644 index 0000000..8344a0a --- /dev/null +++ b/fmodapi375win/tools/fsbanklib/example.dsp @@ -0,0 +1,90 @@ +# Microsoft Developer Studio Project File - Name="example" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=example - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "example.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "example.mak" CFG="example - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "example - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "example - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +CPP=cwcl.exe +RSC=rc.exe + +!IF "$(CFG)" == "example - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "example___Win32_Release" +# PROP BASE Intermediate_Dir "example___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0xc09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=cwlink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 fsbanklibMT.lib wsock32.lib msacm32.lib user32.lib advapi32.lib winmm.lib ole32.lib comdlg32.lib shell32.lib comctl32.lib ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /machine:I386 /out:"example.exe" + +!ELSEIF "$(CFG)" == "example - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "example___Win32_Debug" +# PROP BASE Intermediate_Dir "example___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0xc09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=cwlink.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 fsbanklibMT.lib wsock32.lib msacm32.lib user32.lib advapi32.lib winmm.lib ole32.lib comdlg32.lib shell32.lib comctl32.lib ..\..\api\lib\fmodvc.lib /nologo /subsystem:console /debug /machine:I386 /out:"example.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "example - Win32 Release" +# Name "example - Win32 Debug" +# Begin Source File + +SOURCE=.\example.cpp +# End Source File +# End Target +# End Project diff --git a/fmodapi375win/tools/fsbanklib/fsbanklib.chm b/fmodapi375win/tools/fsbanklib/fsbanklib.chm new file mode 100644 index 0000000..fab9b61 Binary files /dev/null and b/fmodapi375win/tools/fsbanklib/fsbanklib.chm differ diff --git a/fmodapi375win/tools/fsbanklib/fsbanklib.h b/fmodapi375win/tools/fsbanklib/fsbanklib.h new file mode 100644 index 0000000..c8eed6e --- /dev/null +++ b/fmodapi375win/tools/fsbanklib/fsbanklib.h @@ -0,0 +1,149 @@ +#ifndef _FSBANKLIB_H +#define _FSBANKLIB_H + +/* +[ENUM] +[ + [DESCRIPTION] + Errorcode returned by all FSBank commands + + [SEE_ALSO] +] +*/ +typedef enum FSBANK_RESULT +{ + FSBANK_OK, + FSBANK_ERR_INIT, // Failed to initialize + FSBANK_ERR_UNINITIALIZED, // FSBank_Init hasnt been called yet. + FSBANK_ERR_FILE_DIRNOTFILE, // The target is an existing file. The specified build mode requires a destination directory, not a file. + FSBANK_ERR_FILE_DESTFILE, // Cannot create destination file. File may be in use or read only + FSBANK_ERR_FILE_WORKING, // Cannot create working file. File may be in use or read only + FSBANK_ERR_FILE_HEADER, // Cannot create destination c header file. File may be in use or read only + FSBANK_ERR_FILE_EOF, // End of file was encountered unexpectedly. + FSBANK_ERR_FILE_OS, // An operating system based file error was encountered. Could cause corruption or failure of FSB to be created. + FSBANK_ERR_INVALID_PARAM, // An invalid parameter was passed to this function + FSBANK_ERR_INVALID_FORMAT, // A dll was missing for this format or the environment wasnt set up properly. + FSBANK_ERR_CANCELLED, // The build process was cancelled during compilation by the user. + FSBANK_ERR_COMPILATION_ABORTED // Compilation aborted due to error +} FSBANK_RESULT; + + +/* +[ENUM] +[ + [DESCRIPTION] + Describes the target build type or method of creating the FSB file(s). + + [SEE_ALSO] + FSBank_Build +] +*/ +typedef enum FSBANK_BUILDMODE +{ + FSBANK_BUILDMODE_SINGLE = 0, // This creates a single FSB file with multiple sounds in it, or a standard sound bank. + FSBANK_BUILDMODE_MULTI, // This creates multiple FSB files with 1 sound in each. The destfile_or_dir parameter of FSBank_Build is then interpreted as a directory and not a file. + FSBANK_BUILDMODE_INTERLEAVED, // This creates a single FSB file with a single sound in it, but with all the source files interleaved/multiplexed into it so that when it is played, all files play at once, and are given a channel each. +} FSBANK_BUILDMODE; + + +/* +[ENUM] +[ + [DESCRIPTION] + Describes the target platform. + + [SEE_ALSO] + FSBank_Build +] +*/ +typedef enum FSBANK_PLATFORM +{ + FSBANK_PLATFORM_PS2 = 0, // Sony PlayStation 2 + FSBANK_PLATFORM_GC, // Nintendo GameCube + FSBANK_PLATFORM_XBOX, // Microsoft XBox + FSBANK_PLATFORM_CROSS, // Cross platform. Only PCM is truly supported on all platforms. + FSBANK_PLATFORM_MAX +} FSBANK_PLATFORM; + + +/* +[ENUM] +[ + [DESCRIPTION] + Describes the target format. + + [SEE_ALSO] + FSBank_Build +] +*/ +typedef enum FSBANK_FORMAT +{ + FSBANK_FORMAT_VAG = 0, // VAG (SPU2) (3.5:1) PlayStation 2 Only. Hardware decompression, no cpu hit. + FSBANK_FORMAT_GCADPCM, // GCADPCM (3.5:1) GameCube Only. Hardware decompression, no cpu hit. + FSBANK_FORMAT_XADPCM, // XADPCM (3.5:1) XBox only. Hardware decompression, no cpu hit. + FSBANK_FORMAT_PCM, // PCM (1:1) All Platforms. + FSBANK_FORMAT_SOURCE, // Retain original format. All platforms (except PlayStation 2 unless using pcm wav files). + FSBANK_FORMAT_IMAADPCM, // IMA ADPCM (3.5:1) All platforms except PlayStation 2. + FSBANK_FORMAT_MAX, +} FSBANK_FORMAT; + + +/* +[STRUCTURE] +[ + [DESCRIPTION] + Structure containing default values for various sample attributes. + + [SEE_ALSO] + FSBank_Build +] +*/ +typedef struct _FSBANK_SAMPLE_DEFAULTS +{ + float mindistance; // Minimum volume distance in "units" + float maxdistance; // Maximum volume distance in "units" + int deffreq; // Sample default speed in hz + int defvol; // Sample default volume + int defpan; // Sample default pan + int defpri; // Sample priority. 0 = low priority, 255=high priority + int varfreq; // Frequency variation in hz + int varvol; // Volume variation + int varpan; // Pan variation + unsigned int mode; // FSOUND_MODES bits. Bits allowed are FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI, FSOUND_2D, FSOUND_HW2D and FSOUND_HW3D + +} FSBANK_SAMPLE_DEFAULTS; + + +typedef void (__stdcall *FSBANK_UPDATECALLBACK)(int index, int memused, void *userdata); +typedef void (__stdcall *FSBANK_DEBUGCALLBACK)(const char *debugstring, void *userdata); + + +#ifdef __cplusplus +extern "C" { +#endif + +FSBANK_RESULT FSBank_Init(); +FSBANK_RESULT FSBank_Close(); +FSBANK_RESULT FSBank_IsFormatAllowed(FSBANK_FORMAT format); +FSBANK_RESULT FSBank_Build(FSBANK_BUILDMODE buildmode, + FSBANK_FORMAT format, + FSBANK_PLATFORM platform, + int basicheaders, + const char *destfile_or_dir, + int numsrcfiles, + char **srcfile, + FSBANK_SAMPLE_DEFAULTS **defaults, + int dupdirstructure, + const char *srcdir, + int createincludes, + int abortonerror); +FSBANK_RESULT FSBank_SetUpdateCallback(FSBANK_UPDATECALLBACK callback, void *userdata); +FSBANK_RESULT FSBank_SetDebugCallback(FSBANK_DEBUGCALLBACK callback, void *userdata); +FSBANK_RESULT FSBank_SetBuildCancel(int cancel); +FSBANK_RESULT FSBank_GetBuildCancel(int *cancel); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/fmodapi375win/tools/fsbanklib/fsbanklib.txt b/fmodapi375win/tools/fsbanklib/fsbanklib.txt new file mode 100644 index 0000000..54ffad2 --- /dev/null +++ b/fmodapi375win/tools/fsbanklib/fsbanklib.txt @@ -0,0 +1,5 @@ +FSBank library is for msvc or msvc compatible linkers only. + +fsbanklibMT.lib - fsbank library MULTITHREADED. (c runtime linked statically) +fsbanklibMTD.lib - fsbank library MULTITHREADED DLL. (c runtime linked dynamically) + diff --git a/fmodapi375win/tools/fsbanklib/fsbanklibMT.lib b/fmodapi375win/tools/fsbanklib/fsbanklibMT.lib new file mode 100644 index 0000000..7518cb2 Binary files /dev/null and b/fmodapi375win/tools/fsbanklib/fsbanklibMT.lib differ diff --git a/fmodapi375win/tools/fsbanklib/fsbanklibMTD.lib b/fmodapi375win/tools/fsbanklib/fsbanklibMTD.lib new file mode 100644 index 0000000..cdb24fb Binary files /dev/null and b/fmodapi375win/tools/fsbanklib/fsbanklibMTD.lib differ diff --git a/fmodapi375win/tools/fsbanklib/jbtennis.wav b/fmodapi375win/tools/fsbanklib/jbtennis.wav new file mode 100644 index 0000000..77e710c Binary files /dev/null and b/fmodapi375win/tools/fsbanklib/jbtennis.wav differ diff --git a/fmodapi375win/tools/readme.txt b/fmodapi375win/tools/readme.txt new file mode 100644 index 0000000..d784a2f --- /dev/null +++ b/fmodapi375win/tools/readme.txt @@ -0,0 +1,192 @@ + + -------------------------------- + FMOD Sample Bank/Stream Compiler + v1.27 + Copyright Firelight Technologies 2002-2004. + -------------------------------- + +Index. +------ + +1. Introduction. +2. Using it to generate 1 FSB file, or multiple single FSB files! +3. Hit 'Build' and notice the RAM usage bar graph. +4. Error dialog box +5. Using FSB files in your program. + 5.1 As a static sample bank. + 5.2 For streaming. +6. Using list files +7. Command line options +8. Support + + + + +1. Introduction. +---------------- +This tool takes wav files, mp3 files, ogg files, aiff files etc, and converts them +to the .FSB format (FMOD Sample Bank). +It will compress them in the native format of the machine. + + +2. Using it to generate 1 FSB file, or multiple single FSB files! +-------------------------------------------------------------- +If you look to the top of the dialog, you will see a menu item called 'Build Mode'. +In this you can tell FSBank to write out 1 packed FSB file with all your sounds in it, +or alternatively write out 1 FSB for each sound you provide. This is useful for streams. + +- The default mode is 'Generate Single FSB File' + +This means if you provide a source directory to compile from, it will compile every sound +in that directory structure recursively, into a single .FSB file. +This is mainly used for sample banks, or packing streams into a single file for indexed streaming. + +- The second mode type is 'Generate Multiple FSB Files' + +This mode means that for every sound in your specified source directory, it will generate +an equivalent FSB file in the specified destination directory. This would only realistically be +used for streams, as a sort of 'batch converter'. +It will build all files into the directory you specify by default. If you want to recreate +the directory structure from the source directory, click 'Rebuild source directory tree to +destination' + +- The third mode is 'Generate Single Interleaved FSB file' + +This mode means it will take all input files, and interleave them into one FSB file. +For example, a normal stereo stream is interleaved as LRLRLRLR etc. +This is what it would look like if you provided 2 mono files or 1 stereo file as the source. +If you specify more, for example 4 mono files, and a stereo file, the resulting FSB looks like +this : 123456123456123456. +What this means is multiple audio tracks can be played back as one stream, and seeking is eliminated. +Each channel within this multitrack stream can have its attributes modified (ie volume/pan) so you +can use this feature for interactive music, or mood based ambiences. Many other uses could be found. + + + + +3. Hit 'Build' and notice the RAM usage bar graph. +----------------------------------------------- +Press the big 'Build' button and it will start compiling. + +Notice the RAM usage bar graph below. If you intend to load the FSB into ram for sample +playback (not streamed), then you will have to make sure the graph does not go red. This +means you will have overflowed sound ram and you will not fit all of your sounds in. + +On PlayStation 2, SPU2 ram has 1,790kb available for sound if you are using full reverb. +If you uncheck 'Reverb Core0 enabled' or 'Reverb Core1 enabled' you gain 128k to give 1,918kb free. +If you uncheck 'Reverb Core1 enabled' and 'Reverb Core0 enabled' you gain 256k to give 2,046kb free. +Note disabling reverb has to be coupled in the code by using FSOUND_REVERB_FLAGS_CORE0 and/or +FSOUND_REVERB_FLAGS_CORE1 in the call to FSOUND_Init. + +If you intend to use the FSB file(s) for streaming purposes, ignore the ram usage warnings as +streams can be of unlimited size. + + + + +4. Error dialog box +-------------------- + +When the build has completed, a list of warnings will appear. + + +'Memory for this platform has been exceeded' + +If your usage is intended for static loading into memory for sample playback. You have overrun +the hardware memory. +If you intend to use the file(s) for streaming then ignore this message. On PlayStation 2, Streams +use 4k of SPU2 memory if targeted for SPU2 (and not IOP). + + + + +5. Using FSB files in your program. +----------------------------------- + +5.1 As a static sample bank. +---------------------------- +To load a bank use FMUSIC_LoadSong. + +To get access to the individual samples (FSOUND_SAMPLE) use FMUSIC_GetSample. + +The C header contains #defines to reference the sound from your code with FMUSIC_GetSample. + +You can even preview a .FSB file from your program with FMUSIC_PlaySong! +It will simply play through all sounds in the bank sequentially and then stop. + +5.2 For streaming. +------------------ + +To open an FSB file as a stream use FSOUND_Stream_OpenFile. + +call FSOUND_Stream_Play to play the first stream in the FSB file. + +call FSOUND_Stream_SetSubStream to make the stream seek to the relevant file. +use the #defines generated by FSBank in this function. +calling this will stop the stream if it is already playing. + +FSOUND_Stream_SetSubStreamSentence can be used to 'stitch', or 'sentence' multiple substreams together. + + + + +6. Using list files +------------------------ + +You can specify a text file for the build source rather than a directory. This text file must contain +a list of the files you want to build into an FSB. Each file must start on a new line. You can also +specify sample defaults for each file in the list by appending them to the filename in a comma-seperated +list. Here's an example list file : + +jungle.wav +goonie.wav, deffreq=22050, defvol=128, defpan=128, defpri= 128, varfreq=2000, varvol=128 +freddo.wav, deffreq=44100, varfreq=4000, mindistance=500.0 +blarg.wav, fsound_2d, fsound_loop_normal + + +The defaults that you can specify are : + +deffreq Frequency in hz e.g. deffreq = 44100 +defvol Volume (0 - 255) e.g. defvol = 255 +defpan Pan (0 - 255) e.g. defpan = 128 +defpri Priority (0 - 255) e.g. defpri = 128 +varfreq Frequency variation in hz e.g. varfreq = 2000 +varvol Volume variation (0 - 255) e.g. varvol = 128 +varpan Pan variation (0 - 255) e.g. varpan = 64 +fsound_2d See FSOUND_2D mode bit e.g. fsound_2d +fsound_hw2d See FSOUND_HW2D mode bit e.g. fsound_hw2d +fsound_hw3d See FSOUND_HW3D mode bit e.g. fsound_hw3d +fsound_loop_normal See FSOUND_LOOP_NORMAL mode bit e.g. fsound_loop_normal +fsound_loop_bidi See FSOUND_LOOP_BIDI mode bit e.g. fsound_loop_bidi +mindistance Minimum volume distance in "units" (See FSOUND_Sample_SetMinMaxDistance) e.g. mindistance = 1.0 +maxdistance Maximum volume distance in "units" (See FSOUND_Sample_SetMinMaxDistance) e.g. maxdistance = 1000.0 + + + + +7. Command Line Options +------------------------ + +Usage: fsbank <-o dest> [-p ps2|gc|xbox|cross] [-f vag|gcadpcm|xadpcm|pcm|source] [-m s|m|i] [-d] [-r 0|1] [-h] [-b] [-?] [-a] + + -o dest Destination FSB file/directory + source Source directory or list file + -p ps2|gc|xbox|cross Target platform (default = cross) + -f vag|gcadpcm|xadpcm|pcm|source|adpcm Target format (default = pcm) + -m s|m|i Build mode : + s = Single FSB (default) + m = Multiple FSBs + i = single Interleaved FSB + -d Rebuild dir structure (Multiple FSB only) (default = off) + -r 0|1 Disable reverbcore 0 or 1 (ps2 only) (default = both enabled) + -h Hidden mode - don't display the FSBank window at all (default = off) + -b Use small headers (default = off) + -a Abort compilation if an error is encountered (default = off) + -? Display command line help + +OutputDebugString is used to display errors and progress while in hidden mode. + + +8. Support +---------- +Write to support@fmod.org for questions and help. diff --git a/freeimage241/Docs/10.html b/freeimage241/Docs/10.html new file mode 100644 index 0000000..fe8b3b8 --- /dev/null +++ b/freeimage241/Docs/10.html @@ -0,0 +1,184 @@ + +

Plugin functions + +

+ +

From version 2.1.0 on FreeImage provides a new, simplified interface besides the old style API. + +

+ +

The new API, known as the plugin API, treats bitmap formats and their accompanied loader and saver routines as plugin modules. A new series of functions provides access to these plugins. For example the new functions provide the means to retrieve a list of supported bitmap formats, as well as their descriptions and their possible file extensions. The new API has many advantages over the old one. + +

+ +

For a start the plugin interface will enable FreeImage's hot swap technology: a feature that allows you to compile and link the library only once in your program making instantly profit from bug fixes, newly supported bitmap formats and more without ever recompiling again. Second it opens the way to use plugins. You won't have these advantages when you use the standard API. + +

+

Subsections

+ + + +

FreeImage_GetFIFByIndex + +

+ +

FREE_IMAGE_FORMAT FreeImage_GetFIFByIndex(int index); + +

+ +

Returns the needed plugin id in the plugin list. The plugin list is sorted on the format string. + +

FreeImage_GetFIFCount + +

+ +

int FreeImage_GetFIFCount(); + +

+ +

Returns the number of supported bitmap formats. + +

FreeImage_GetFIFFromFormat + +

+ +

FREE_IMAGE_FORMAT FreeImage_GetFIFFromFormat(const char *format); + +

+ +

Returns the FreeImage format ID for the given format string. + +

FreeImage_GetFormatFromFIF + +

+ +

const char *FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); + +

+ +

Returns a format string for the given FreeImage Format ID. + +

FreeImage_GetFIFExtensionList + +

+ +

const char *FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); + +

+ +

Returns a list of possible file extension for the given FreeImage Format ID. The extension list is a string containing one or more comma separated file extensions. + +

+FreeImage_GetFIFDescription + +

+ +

const char *FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif); + +

+ +

Returns a descriptive string for the given FreeImage Format ID. + +

FreeImage_GetFIFRegExpr + +

+ +

const char *FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif); + +

+ +

Returns a regular expression for the given FreeImage Format ID, assisting external libraries to identify the bitmap format. Currently FreeImageQt uses this function. + +

+FreeImage_GetFIFFromFilename + +

+ +

FREE_IMAGE_FORMAT FreeImage_GetFIFFromFilename(const char *filename); + +

+ +

Tries to identify a bitmap type by looking at the filename or a file extension. FreeImage_GetFIFFromFilename returns a valid FreeImage Format ID on success and FIF_UNKNOWN on failure. + +

+FreeImage_FIFSupportsReading + +

+ +

BOOL FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif); + +

+ +

Returns true if the plugin belonging to this FreeImage Format ID supports reading, false otherwise. + +

FreeImage_FIFSupportsWriting + +

+ +

BOOL FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); + +

+ +

Returns true if the plugin belonging to this FreeImage Format ID supports writing, false otherwise. + +

FreeImage_LoadFromHandle + +

+ +

FIBITMAP * FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); + +

+ +

Loads a bitmap file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadFromHandle returns NULL. + +

+ +

The fif parameter specifies the desired bitmap format to be loaded. The parameter accepts any valid FreeImage Format ID, such as FIF_BMP or FIF_JPEG, or an integer value obtained from any of the plugin interface functions. + +

+FreeImage_Load + +

+ +

FIBITMAP *DLL_CALLCONV FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags FI_DEFAULT(0)); + +

+ +

Loads the bitmap file into a FreeImage bitmap. If the bitmap is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the bitmap couldn't be loaded, FreeImage_Load returns NULL. + +

FreeImage_SaveToHandle + +

+ +

BOOL FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); + +

+ +

Saves the FreeImage DIB to a bitmap file of the given type. + +

FreeImage_Save + +

+ +

BOOL FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(0)); + +

+ +

Saves the FreeImage DIB to a bitmap file of the given type. + +

diff --git a/freeimage241/Docs/102.html b/freeimage241/Docs/102.html new file mode 100644 index 0000000..ba47ea0 --- /dev/null +++ b/freeimage241/Docs/102.html @@ -0,0 +1,25 @@ + +

Extra functions + +

+ +

FreeImage supports a number of additional functions you can use to manipulate FIBITMAPs. + +

+

Subsections

+ + + +

FreeImage_Combine + +

+ +

void FreeImage_Combine(FIBITMAP *target, FIBITMAP *source, int x, int y, int alpha FI_DEFAULT(255)); + +

+ +

Combines the source and target bitmap and stores the result in the target bitmap. Optionally an alpha blend value can be specified to blend the two bitmaps together. + +

diff --git a/freeimage241/Docs/104.html b/freeimage241/Docs/104.html new file mode 100644 index 0000000..bec247a --- /dev/null +++ b/freeimage241/Docs/104.html @@ -0,0 +1,30 @@ + +

FreeImageQt functions + +

+

Subsections

+ + + + diff --git a/freeimage241/Docs/105.html b/freeimage241/Docs/105.html new file mode 100644 index 0000000..5b555aa --- /dev/null +++ b/freeimage241/Docs/105.html @@ -0,0 +1,12 @@ + +

Introduction + +

+ +

FreeImageQt is the binding of the DLL to TrollTech's Qt library. Qt is a sophisticated c++ programming framework for Windows and Unix, used primarily for the creation of graphical user interface. The framework many powerful objects, better known as widgets, which make programming GUIs considerably easier. + +

+ +

Qt provides several objects used to deal with graphics. The most interesting objects to FreeImage are Qimage and QimageIO, because these are the objects that FreeImage hooks. By hooking these two objects, FreeImage provides its enormous list of supported bitmap types to Qt, while keeping the generic interface for loading bitmaps in that library intact. As a Qt programmer you won't notice that you are using FreeImage. And that is the strength of it. + +

diff --git a/freeimage241/Docs/106.html b/freeimage241/Docs/106.html new file mode 100644 index 0000000..be50fd6 --- /dev/null +++ b/freeimage241/Docs/106.html @@ -0,0 +1,180 @@ + +

+Functions + +

+ +

FreeImageQt supports the following functions. Note that in average use you only need FIQT_Register to use this library. + +

+

Subsections

+ + + +

FIQT_Register + +

+ +

bool FIQT_Register(bool new_formats_only = false); + +

+ +

Registers the FreeImage load functions in Qt and returns true if successful. If new_formats_only is true, only the bitmap formats not supported by Qt are registered. Else all bitmap formats supported by FreeImage are registered. You have to call this function to take advantage of FreeImage. + +

FIQT_Unregister + +

+ +

void FIQT_Unregister(); + +

+ +

Removes all binding between FreeImage and Qt. You shouldn't normally have to call this function. It is called automatically on program exit. + +

FIQT_IsLoaded + +

+ +

Bool FIQT_IsLoaded(); + +

+ +

Returns true if FreeImage was successfully registered into Qt's bitmap functionality handler, false otherwise. + +

FIQT_GetVersion + +

+ +

const char *FIQT_GetVersion(); + +

+ +

Returns the version string of the library. + +

FIQT_GetCopyrightMessage + +

+ +

const char *FIQT_GetVersion(); + +

+ +

Returns a short copyright message you can include in your program. + +

FIQT_GetFIFCount + +

+ +

int FIQT_GetFIFCount(); + +

+ +

Returns the number of supported bitmap formats. + +

FIQT_GetFIFFromFormat + +

+ +

FREE_IMAGE_FORMAT FIQT_GetFIFFromFormat(const char *format); + +

+ +

Returns the FreeImage format ID for the given format string. + +

FIQT_GetFormatFromFIF + +

+ +

const char *FIQT_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); + +

+ +

Returns a format string for the given FreeImage Format ID. + +

FIQT_GetFIFExtensionList + +

+ +

const char *FIQT_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); + +

+ +

Returns a list of possible file extension for the given FreeImage Format ID. The extension list is a string containing one or more comma separated file extensions. + +

FIQT_GetFIFDescription + +

+ +

const char *FIQT_GetFIFDescription(FREE_IMAGE_FORMAT fif); + +

+ +

Returns a descriptive string for the given FreeImage Format ID. + +

FIQT_GetFIFFromFilename + +

+ +

FREE_IMAGE_FORMAT FIQT_GetFIFFromFilename(const char *filename); + +

+ +

Tries to identify a bitmap type by looking at the filename or a file extension. FreeImage_GetFIFFromFilename returns a valid FreeImage Format ID on success and FIF_UNKNOWN on failure. + +

FIQT_FIFSupportsReading + +

+ +

BOOL FIQT_FIFSupportsReading(FREE_IMAGE_FORMAT fif); + +

+ +

Returns true if the plugin belonging to this FreeImage Format ID supports reading, false otherwise. + +

FIQT_FIFSupportsWriting + +

+ +

BOOL FIQT_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); + +

+ +

Returns true if the plugin belonging to this FreeImage Format ID supports writing, false otherwise. + +

FIQT_GetFileTypeFromFormat + +

+ +

const char *FIQT_GetFileTypeFromFormat(FREE_IMAGE_FORMAT fif); + +

+ +

This function is deprecated. FIQT_GetFIFFromFormat has replaced its functionality. + +

FIQT_GetFormatFromExtension + +

+ +

const char *FIQT_GetFormatFromExtension(const char *extension); + +

+ +

Returns a FreeImage Format string for the given file extension. + +

diff --git a/freeimage241/Docs/122.html b/freeimage241/Docs/122.html new file mode 100644 index 0000000..8a8766e --- /dev/null +++ b/freeimage241/Docs/122.html @@ -0,0 +1,4 @@ + +

Index

+[ A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z ]

+ \ No newline at end of file diff --git a/freeimage241/Docs/2.html b/freeimage241/Docs/2.html new file mode 100644 index 0000000..c14f4bc --- /dev/null +++ b/freeimage241/Docs/2.html @@ -0,0 +1,148 @@ + +

+FreeImage functions + +

+

Subsections

+ + + + diff --git a/freeimage241/Docs/25.html b/freeimage241/Docs/25.html new file mode 100644 index 0000000..13483e3 --- /dev/null +++ b/freeimage241/Docs/25.html @@ -0,0 +1,271 @@ + +

Simple load functions + +

+

Subsections

+ + + +

FreeImage_LoadBMP + +

+ +

FIBITMAP *FreeImage_LoadBMP(const char *filename, int flags = BMP_DEFAULT); + +

+ +

Loads the given Windows Bitmap file or OS/2 Bitmap file into a FreeImage bitmap. If the bitmap is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the bitmap couldn't be loaded, FreeImage_LoadBMP returns NULL. + +

+ +

FIBITMAP *dib = FreeImage_LoadBMP("test.bmp"); + +

FreeImage_LoadICO + +

+ +

FIBITMAP *FreeImage_LoadICO(const char *filename, int flags = ICO_DEFAULT); + +

+ +

Loads the given Windows ICON file into a FreeImage bitmap. If the icon is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the bitmap couldn't be loaded, FreeImage_LoadICO returns NULL. + +

+ +

Flags defaults to ICO_DEFAULT. The following parameters can be passed to change the behaviour of the load routine: + +

+ +

FIBITMAP *dib = FreeImage_LoadICO("test.ico");
FIBITMAP *dib = FreeImage_LoadICO("test.ico", ICO_SECOND); + +

+ +

+ +

+ +

+

+
Value Meaning
ICO_FIRST Loads the first icon in the cabinet
ICO_SECOND Loads the second icon in the cabinet
ICO_THIRD Loads the third icon in the cabinet

+ +

FreeImage_LoadJPEG + +

+ +

FIBITMAP *FreeImage_LoadJPEG(const char *filename, int flags = JPEG_DEFAULT); + +

+ +

Loads the given JPEG or JIF file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadJPEG returns NULL. + +

+ +

Flags defaults to JPEG_DEFAULT. The following parameters can be passed to the flags parameter to change the behaviour of the load routine: + +

+ +

FIBITMAP *dib = FreeImage_LoadJPEG("test.jpg");
FIBITMAP *dib = FreeImage_LoadJPEG("test.jpg", JPEG_ACCURATE); + +

+ +

+ +

+ +

+

Value Meaning
JPEG_FAST Loads the file as fast as possible, sacrificing some quality.
JPEG_ACCURATE Loads the file as accurate as possible, sacrificing some speed.

+ +

FreeImage_LoadKOALA + +

+ +

FIBITMAP *FreeImage_LoadKOALA(const char *filename, int flags = KOALA_DEFAULT); + +

+ +

Loads the given KOALA file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadKOALA returns NULL + +

+ +

KOALA is a 4-bit bitmap format developed for and supported by ancient commodore 64 computers and emulators. The format is supported for nostalgic reasons of the author. + +

+ +

FIBITMAP *dib = FreeImage_LoadKOALA("test.koa"); + +

FreeImage_LoadLBM + +

+ +

FIBITMAP *FreeImage_LoadLBM(const char *filename, int flags = LBM_DEFAULT); + +

+ +

Loads the given Deluxe Paint LBM file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadLBM returns NULL + +

+FreeImage_LoadMNG + +

+ +

FIBITMAP *FreeImage_LoadMNG(const char *filename, int flags = MNG_DEFAULT); + +

+ +

Loads the given Multi Network Graphics (MNG) or JPEG Network Graphics (JNG) file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadMNG returns NULL + +

FreeImage_LoadPCD + +

+ +

FIBITMAP *FreeImage_LoadPCD(const char *filename, int flags = PCD_DEFAULT); + +

+ +

Loads the given Kodak PhotoCD file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPCD returns NULL. + +

+ +

PhotoCD images are so called cabinet files, where several versions of the same bitmap exist in one file. By default FreeImage loads the image marked in the flags as PCD_BASE. By using the flags parameter other image versions can be obtained: + +

+ +

FIBITMAP *dib = FreeImage_LoadPCD("test.pcd");
FIBITMAP *dib = FreeImage_LoadPCX("test.pcd", PCD_BASEDIV16); + +

+ +

+ +

+ +

+

+
Value Meaning
PCD_BASE 24-bit, 768 x 512 pixels
PCD_BASEDIV4 24-bit, 192 x 128 pixels
PCD_BASEDIV16 24-bit. 384 x 256 pixels

+ +

FreeImage_LoadPCX + +

+ +

FIBITMAP *FreeImage_LoadPCX(const char *filename, int flags = PCX_DEFAULT); + +

+ +

Loads the given PCX file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPCX returns NULL. + +

+ +

FIBITMAP *dib = FreeImage_LoadPCX("test.pcx"); + +

FreeImage_LoadPNM + +

+ +

FIBITMAP *FreeImage_LoadPNM(const char *filename, PNMFlags flags = PNM_DEFAULT); + +

+ +

Loads one of the PNM supported bitmap files into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPNM returns NULL. + +

+ +

PNM is a descriptive name for a collection of ASCII based bitmap types: PBM, PGM and PPM. PBM (Portable Bitmap format) is a 1-bit, black and white bitmap type, PGM (Portable Greymap format) is an 8-bit greyscale bitmap type and PPM (Portable Pixelmap format) is a 24-bit full colour bitmap. FreeImage automatically detects if you are dealing with a PBM, PGM or PPM bitmap and will load it in the default bit depth of that particular image. + +

+ +

FIBITMAP *dib = FreeImage_LoadPNM("test.ppm");
FIBITMAP *dib = FreeImage_LoadPNM("test.pgm");
FIBITMAP *dib = FreeImage_LoadPNM("test.pbm"); + +

FreeImage_LoadPNG + +

+ +

FIBITMAP *FreeImage_LoadPNG(const char *filename, int flags = PNG_DEFAULT); + +

+ +

Loads the given PNG file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPNG returns NULL. + +

+ +

FIBITMAP *dib = FreeImage_LoadPNG("test.png"); + +

FreeImage_LoadRAS + +

+ +

FIBITMAP *FreeImage_LoadRAS(const char *filename, int flags = RAS_DEFAULT); + +

+ +

Loads the given Sun rasterfile into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadRAS returns NULL. + +

+ +

FIBITMAP *dib = FreeImage_LoadRAS("test.ras"); + +

FreeImage_LoadTARGA + +

+ +

FIBITMAP *FreeImage_LoadTARGA(const char *filename, int flags = TARGA_DEFAULT); + +

+ +

Loads the given TARGA file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadTARGA returns NULL. + +

+ +

Flags defaults to TARGA_DEFAULT. The flags parameter can be passed the following values to change the behaviour of the load plugin: + +

+ +

FIBITMAP *dib = FreeImage_LoadTARGA("test.tga");
FIBITMAP *dib = FreeImage_LoadTARGA("test.tga", TARGA_LOAD_RGB888); + +

+ +

+ +

+ +

+

Value Meaning
TARGA_LOAD_RGB888 If the TARGA file is 16 or 32-bit, it is automatically converted to 24-bit.

+ +

FreeImage_LoadTIFF + +

+ +

FIBITMAP *FreeImage_LoadTIFF(const char *filename, int flags = TIFF_DEFAULT); + +

+ +

Loads the given TIFF file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadTIFF returns NULL. + +

+ +

FIBITMAP *dib = FreeImage_LoadTIFF("test.tiff"); + +

FreeImage_LoadWBMP + +

+ +

FIBITMAP *FreeImage_LoadWBMP(const char *filename, int flags = WBMP_DEFAULT); + +

+ +

Loads the given WBMP or WAP file into a FreeImage bitmap. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadWBMP returns NULL. + +

diff --git a/freeimage241/Docs/3.html b/freeimage241/Docs/3.html new file mode 100644 index 0000000..5edae25 --- /dev/null +++ b/freeimage241/Docs/3.html @@ -0,0 +1,37 @@ + +

Initialisation + +

+ +

When the FreeImage is loaded, there has to be allocated data internally to address the various plugins. The initialisation functions are responsible for that task. Note that in the precompiled DLL version the initialisation functions are automatically called. You normally don't need to initialise FreeImage (but it doesn't hurt when you do) + +

+

Subsections

+ + + +

+FreeImage_Initialise + +

+ +

void FreeImage_Initialise(); + +

+ +

Initialises the library. + +

FreeImage_DeInitialise + +

+ +

void FreeImage_DeInitialise(); + +

+ +

DeInitialises the library. + +

diff --git a/freeimage241/Docs/40.html b/freeimage241/Docs/40.html new file mode 100644 index 0000000..ab824be --- /dev/null +++ b/freeimage241/Docs/40.html @@ -0,0 +1,297 @@ + +

+Advanced load functions + +

+ +

FreeImage_LoadFromHandle functions are slightly more advanced than the simple load functions, but still quite easy to use. The idea of these functions is that FreeImage doesn't care how it gets its data as long as it gets it. It shouldn't matter if the bitmap is loaded from file, memory or the Internet since data is data not matter where it comes from. + +

+ +

To make this idea of data abstraction work a new, abstract file I/O system is used: FreeImageIO . FreeImageIO is a structure containing pointers to 4 functions: a read function, write function, seek function and tell function. All these functions have to be implemented so that data is delivered. The handle representing the data is made abstract as well and is named fi_handle . + +

+ +

Loading a bitmap using the ...FromHandle functions involves four things. First the 4 file I/O functions are implemented and a FreeImageIO structure is filled with the pointers. Then the file is opened (that is, if we are in fact dealing with a file). After that one of the ...LoadFromHandle functions can be called. If the bitmap is successfully loaded the file has to be closed. + +

+ +

unsigned + +

+ +

_ReadProc(FIBITMAP *buffer, unsigned s, unsigned c, fi_handle handle) { + +

+ +

return fread(buffer, s, c, (FILE *)handle); + +

+ +

} + +

+ +

unsigned + +

+ +

_WriteProc(FIBITMAP *buffer, unsigned s, unsigned c, fi_handle handle){ + +

+ +

return fwrite(buffer, s, c, (FILE *)handle); + +

+ +

} + +

+ +

int + +

+ +

_SeekProc(fi_handle handle, long offset, int origin) { + +

+ +

return fseek((FILE *)handle, offset, origin); + +

+ +

} + +

+ +

long + +

+ +

_TellProc(fi_handle handle) { + +

+ +

return ftell((FILE *)handle); + +

+ +

} + +

+ +

FreeImageIO io; + +

+ +

io.read_proc = _ReadProc; + +

+ +

io.write_proc = _WriteProc; + +

+ +

io.seek_proc = _SeekProc; + +

+ +

io.tell_proc = _TellProc; + +

+ +

FILE *file = fopen("test.bmp", "rb"); + +

+ +

if (file != NULL) { + +

+ +

FIBITMAP *dib = FreeImage_LoadBMPFromHandle(&io, (fi_handle)file); + +

+ +

FreeImage_Free(dib); + +

+ +

fclose(file); + +

+ +

} + +

+

Subsections

+ + + +

FreeImage_LoadBMPFromHandle + +

+ +

FIBITMAP *FreeImage_LoadBMPFromHandle(FreeImageIO *io, fi_handle handle, int flags = BMP_DEFAULT); + +

+ +

Loads the given BMP file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadBMPFromHandle returns NULL. + +

+FreeImage_LoadICOFromHandle + +

+ +

FIBITMAP *FreeImage_LoadICOFromHandle(FreeImageIO *io, fi_handle handle, int flags = ICO_DEFAULT); + +

+ +

Loads the given ICO file into a FreeImage bitmap using the given FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadICOFromHandle returns NULL. + +

FreeImage_LoadJPEGFromHandle + +

+ +

FIBITMAP *FreeImage_LoadJPEGFromHandle(FreeImageIO *io, fi_handle handle, int flags = JPEG_DEFAULT); + +

+ +

Loads the given JPEG file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadJPEGFromHandle returns NULL. + +

+FreeImage_LoadKOALAFromHandle + +

+ +

FIBITMAP *FreeImage_LoadKOALAFromHandle(FreeImageIO *io, fi_handle handle, int flags = KOALA_DEFAULT); + +

+ +

Loads the given KOALA file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadKOALAFromHandle returns NULL. + +

+FreeImage_LoadLBMFromHandle + +

+ +

FIBITMAP *FreeImage_LoadLBMFromHandle(FreeImageIO *io, fi_handle handle, int flags = LBM_DEFAULT); + +

+ +

Loads the given Deluxe Paint LBM file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadLBMFromHandle returns NULL. + +

+FreeImage_LoadMNGFromHandle + +

+ +

FIBITMAP *FreeImage_LoadMNGFromHandle(FreeImageIO *io, fi_handle handle, int flags = MNG_DEFAULT); + +

+ +

Loads the Multi Network Graphics (MNG) or JPEG Network Graphics (JNG) file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadMNGFromHandle returns NULL. + +

+FreeImage_LoadPCDFromHandle + +

+ +

FIBITMAP *FreeImage_LoadPCDFromHandle(FreeImageIO *io, fi_handle handle, int flags = PCD_DEFAULT); + +

+ +

Loads the given Kodak PhotoCD file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPCDFromHandle returns NULL. + +

+FreeImage_LoadPCXFromHandle + +

+ +

FIBITMAP *FreeImage_LoadPCXFromHandle(FreeImageIO *io, fi_handle handle, int flags = PCX_DEFAULT); + +

+ +

Loads the given PCX file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPCXFromHandle returns NULL. + +

+FreeImage_LoadPNMFromHandle + +

+ +

FIBITMAP *FreeImage_LoadPNMFromHandle(FreeImageIO *io, fi_handle handle, int flags = PNM_DEFAULT); + +

+ +

Loads the given PBM, PGM or PPM file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPNMFromHandle returns NULL. + +

+FreeImage_LoadPNGFromHandle + +

+ +

FIBITMAP *FreeImage_LoadPNGFromHandle(FreeImageIO *io, fi_handle handle, int flags = PNG_DEFAULT); + +

+ +

Loads the given PNG file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadPNGFromHandle returns NULL. + +

+FreeImage_LoadRASFromHandle + +

+ +

FIBITMAP *FreeImage_LoadRASFromHandle(FreeImageIO *io, fi_handle handle, int flags = RAS_DEFAULT); + +

+ +

Loads the given Sun Rasterfile into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadRASFromHandle returns NULL. + +

+FreeImage_LoadTARGAFromHandle + +

+ +

FIBITMAP *FreeImage_LoadTARGAFromHandle(FreeImageIO *io, fi_handle handle, int flags = TARGA_DEFAULT); + +

+ +

Loads the given TARGA file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadTARGAFromHandle returns NULL. + +

+FreeImage_LoadTIFFFromHandle + +

+ +

FIBITMAP *FreeImage_LoadTIFFFromHandle(FreeImageIO *io, fi_handle handle, int flags = TIFF_DEFAULT); + +

+ +

Loads the given TIFF file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadTIFFFromHandle returns NULL. + +

+FreeImage_LoadWBMPFromHandle + +

+ +

FIBITMAP *FreeImage_LoadWBMPFromHandle(FreeImageIO *io, fi_handle handle, int flags = WBMP_DEFAULT); + +

+ +

Loads the given WBMP file into a FreeImage bitmap using the specified FreeImageIO struct and fi_handle. If the file is loaded successfully, memory for it is allocated and a bitmap pointer is returned. If the file couldn't be loaded, FreeImage_LoadWBMPFromHandle returns NULL. + +

diff --git a/freeimage241/Docs/55.html b/freeimage241/Docs/55.html new file mode 100644 index 0000000..d5acded --- /dev/null +++ b/freeimage241/Docs/55.html @@ -0,0 +1,105 @@ + +

+Simple save functions + +

+

Subsections

+ + + +

FreeImage_SaveBMP + +

+ +

bool FreeImage_SaveBMP(FIBITMAP *dib, const char *filename, int flags = BMP_DEFAULT); + +

+ +

Saves the FreeImage DIB to a Windows Bitmap file. The BMP file is always saved in the Windows format. No compression is used. + +

+ +

FIBITMAP *dib = FreeImage_LoadBMP("test.bmp");
if (dib != NULL) {
FreeImage_SaveBMP("saved.bmp");
FreeImage_Free(dib);
} + +

FreeImage_SaveJPEG + +

+ +

bool FreeImage_SaveJPEG(FIBITMAP *dib, const char *filename, int flags = JPEG_DEFAULT); + +

+ +

Saves the FreeImage DIB to a JPEG file. . Only 24-bit bitmaps can be saved as JPEG. Bitmaps in bit depths will have to be converted. + +

+ +

FIBITMAP *dib = FreeImage_LoadBMP("test.bmp");
if (dib != NULL) {
FreeImage_SaveJPEG("saved.jpg");
FreeImage_Free(dib);
} + +

FreeImage_SavePNG + +

+ +

bool FreeImage_SavePNG(FIBITMAP *dib, const char *filename, int flags = PNG_DEFAULT); + +

+ +

Saves the FreeImage DIB to a PNG file. + +

+ +

FIBITMAP *dib = FreeImage_LoadBMP("test.bmp");
if (dib != NULL) {
FreeImage_SavePNG("saved.png");
FreeImage_Free(dib);
} + +

FreeImage_SavePNM + +

+ +

bool FreeImage_SavePNM(FIBITMAP *dib, const char *filename, PNMFlags flags = PNM_DEFAULT); + +

+ +

Saves the FreeImage DIB to a PNM file. PNM is a descriptive name for a collection of ASCII based bitmap types: PBM, PGM and PPM. If the bitmap has a bit depth of 1, the file is saved as a PBM file. If the bitmap has a bit depth of 8, the file is saved as a PGM file. If the bitmap has a bit depth of 24, the file is saved as a PPM file. Other bit depths are not supported. + +

+ +

FIBITMAP *dib = FreeImage_LoadBMP("test.bmp"); + +

+ +

if (dib != NULL) {
switch(FreeImage_GetBPP(dib)) {
case 1 :
FreeImage_SavePNM("saved.pbm");
break;
case 8 :
FreeImage_SavePNM("saved.pgm");
break;
case 24 :
FreeImage_SavePNM("saved.ppm");
break;
}
FreeImage_Free(dib);
} + +

FreeImage_SaveTIFF + +

+ +

bool FreeImage_SaveTIFF(FIBITMAP *dib, const char *filename, int flags = TIFF_DEFAULT); + +

+ +

Saves the FreeImage DIB to a TIFF file. + +

+ +

FIBITMAP *dib = FreeImage_LoadBMP("test.bmp");
if (dib != NULL) {
FreeImage_SaveTIFF("saved.tiff");
FreeImage_Free(dib);
} + +

FreeImage_SaveWBMP + +

+ +

bool FreeImage_SaveWBMP(FIBITMAP *dib, const char *filename, int flags = WBMP_DEFAULT); + +

+ +

Saves the FreeImage DIB to a WBMP file. + +

+ +

FIBITMAP *dib = FreeImage_LoadBMP("test.bmp");
if (dib != NULL) {
FreeImage_SaveWBMP("saved.wbmp");
FreeImage_Free(dib);
} + +

diff --git a/freeimage241/Docs/6.html b/freeimage241/Docs/6.html new file mode 100644 index 0000000..b67be96 --- /dev/null +++ b/freeimage241/Docs/6.html @@ -0,0 +1,43 @@ + +

Bitmap Allocation functions + +

+

Subsections

+ + + +

FreeImage_Allocate + +

+ +

FIBITMAP *FreeImage_Allocate(int width, int height, int bpp, int red_mask = 0, int green_mask = 0, int blue_mask = 0); + +

+ +

Allocates a new FreeImage bitmap using the given width, height and bits per pixel and optional red, green and blue mask. The mask is stored in BGR order. + +

FreeImage_Free + +

+ +

void FreeImage_Free(FIBITMAP *dib); + +

+ +

Disposes the given bitmap from memory. + +

FreeImage_Unload + +

+ +

void FreeImage_Unload(FIBITMAP *dib); + +

+ +

Alias for FreeImage_Free. + +

diff --git a/freeimage241/Docs/62.html b/freeimage241/Docs/62.html new file mode 100644 index 0000000..144530d --- /dev/null +++ b/freeimage241/Docs/62.html @@ -0,0 +1,196 @@ + +

Advanced save functions + +

+ +

Saving bitmaps using the ...SaveToHandle functions is almost identical to loading bitmap via the ...LoadFromHandle functions. Information about the FreeImageIO and fi_handle can therefore be obtained from the information belonging to these functions. + +

+ +

unsigned + +

+ +

_ReadProc(FIBITMAP *buffer, unsigned s, unsigned c, fi_handle handle) { + +

+ +

return fread(buffer, s, c, (FILE *)handle); + +

+ +

} + +

+ +

unsigned + +

+ +

_WriteProc(FIBITMAP *buffer, unsigned s, unsigned c, fi_handle handle){ + +

+ +

return fwrite(buffer, s, c, (FILE *)handle); + +

+ +

} + +

+ +

int + +

+ +

_SeekProc(fi_handle handle, long offset, int origin) { + +

+ +

return fseek((FILE *)handle, offset, origin); + +

+ +

} + +

+ +

long + +

+ +

_TellProc(fi_handle handle) { + +

+ +

return ftell((FILE *)handle); + +

+ +

} + +

+ +

FreeImageIO io; + +

+ +

io.read_proc = _ReadProc; + +

+ +

io.write_proc = _WriteProc; + +

+ +

io.seek_proc = _SeekProc; + +

+ +

io.tell_proc = _TellProc; + +

+ +


FILE *file = fopen("test.bmp", "rb"); + +

+ +

FIBITMAP *dib = FreeImage_LoadBMPFromHandle(&io, (fi_handle)file); + +

+ +

+
fclose(file);
+ +

+ +

if (dib != NULL) { + +

+ +

file = fopen("saved.bmp", "wb"); +
+ +

+ +

FreeImage_SavePNGToHandle(dib, &io, (fi_handle)file); +
fclose(file);
}
+ +

+ +

FreeImage_Free(dib); + +

+

Subsections

+ + + +

FreeImage_SaveBMPToHandle + +

+ +

bool FreeImage_SaveBMPToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags = BMP_DEFAULT); + +

+ +

Saves the FreeImage DIB to a Windows Bitmap file. The BMP file is always saved in the Windows format. No compression is used. + +

FreeImage_SaveJPEGToHandle + +

+ +

bool FreeImage_SaveJPEGToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags = JPEG_DEFAULT); + +

+ +

Saves the FreeImage DIB to a JPEG file. Only 24-bit bitmaps can be saved as JPEG. Bitmaps in bit depths will have to be converted. + +

FreeImage_SavePNGToHandle + +

+ +

bool FreeImage_SavePNGToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags = PNG_DEFAULT); + +

+ +

Saves the FreeImage DIB to a PNG file. + +

FreeImage_SavePNMToHandle + +

+ +

bool FreeImage_SavePNMToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags = PNM_DEFAULT); + +

+ +

Saves the FreeImage DIB to a PNM file. PNM is a descriptive name for a collection of ASCII based bitmap types: PBM, PGM and PPM. If the bitmap has a bitdepth of 1, the file is saved as a PBM file. If the bitmap has a bitdepth of 8, the file is saved as a PGM file. If the bitmap has a bitdepth of 24, the file is saved as a PPM file. Other bitdepths are not supported. + +

+FreeImage_SaveTIFFToHandle + +

+ +

bool FreeImage_SaveTIFFToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags = TIFF_DEFAULT); + +

+ +

Saves the FreeImage DIB to a TIFF file. + +

FreeImage_SaveWBMPToHandle + +

+ +

bool FreeImage_SaveWBMPToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags = WBMP_DEFAULT); + +

+ +

Saves the FreeImage DIB to a WBMP file. + +

diff --git a/freeimage241/Docs/69.html b/freeimage241/Docs/69.html new file mode 100644 index 0000000..1a25e21 --- /dev/null +++ b/freeimage241/Docs/69.html @@ -0,0 +1,149 @@ + +

Filetype functions + +

+

Subsections

+ + + +

FreeImage_GetFileType + +

+ +

FREE_IMAGE_FORMAT FreeImage_GetFileType(const char *filename, int size); + +

+ +

Investigates the bitmap data from the given bitmap and returns the FreeImage Format ID for it. FreeImage_GetFileType will read the first size bytes of the file but not more than 16. FreeImage_GetFileType will return one of the following values: + +

+ +

+ +

+ +

+

+ + +
Type Bitmap
FIF_UNKNOWN Unidentified bitmap type
FIF_BMP Windows or OS/2 Bitmap
FIF_ICO Windows Icon
FIF_JPEG JPEG - JFIF Compliant
FIF_JNG JPEG Network Graphics
FIF_KOALA C64 Koala Graphics
FIF_LBM +Deluxe Paint LBM
FIF_MNG Multiple Network Graphics
FIF_PBM Portable Bitmap
FIF_PCD Kodak PhotoCD
FIF_PCX Zsoft Paintbrush
FIF_PGM Portable Greymap
FIF_PNG Portable Network Graphics +
FIF_PPM Portable Pixmap
FIF_RAS Sun Raster Image
FIF_TARGA Truevision Targa
FIF_TIFF Tagged Image File Format
FIF_WBMP Wireless Bitmap

+ +

FreeImage_GetFileTypeFromHandle + +

+ +

FREE_IMAGE_FORMAT FreeImage_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size); + +

+ +

Investigates the bitmap data from the given bitmap and returns the FreeImage Format ID for it. Code example: + +

+ +

unsigned + +

+ +

_ReadProc(FIBITMAP *buffer, unsigned s, unsigned c, fi_handle handle) { + +

+ +

return fread(buffer, s, c, (FILE *)handle); + +

+ +

} + +

+ +

unsigned + +

+ +

_WriteProc(FIBITMAP *buffer, unsigned s, unsigned c, fi_handle handle){ + +

+ +

return fwrite(buffer, s, c, (FILE *)handle); + +

+ +

} + +

+ +

int + +

+ +

_SeekProc(fi_handle handle, long offset, int origin) { + +

+ +

return fseek((FILE *)handle, offset, origin); + +

+ +

} + +

+ +

long + +

+ +

_TellProc(fi_handle handle) { + +

+ +

return ftell((FILE *)handle); + +

+ +

} + +

+ +

FreeImageIO io; + +

+ +

io.read_proc = _ReadProc; + +

+ +

io.write_proc = _WriteProc; + +

+ +

io.seek_proc = _SeekProc; + +

+ +

io.tell_proc = _TellProc; + +

+ +


FILE *file = fopen("test.bmp", "rb"); + +

+ +

FREE_IMAGE_TYPE type;
type = FreeImage_GetFileTypeFromHandle(&io, (fi_handle)file, 16); + +

FreeImage_GetFileTypeFromExt + +

+ +

FREE_IMAGE_FORMAT FreeImage_GetFileTypeFromExt(const char *ext); + +

+ +

This function is deprecated. FreeImage_GetFIFFromFilename has replaced its functionality. + +

diff --git a/freeimage241/Docs/73.html b/freeimage241/Docs/73.html new file mode 100644 index 0000000..064c3e0 --- /dev/null +++ b/freeimage241/Docs/73.html @@ -0,0 +1,77 @@ + +

FreeImage bitmap information functions + +

+

Subsections

+ + + +

FreeImage_GetRedMask + +

+ +

unsigned FreeImage_GetRedMask(FIBITMAP *dib); + +

+ +

Returns the red bitmask for the bitmap. If the bitmap is palletised 0 is returned. + +

FreeImage_GetGreenMask + +

+ +

unsigned FreeImage_GetGreenMask(FIBITMAP *dib); + +

+ +

Returns the green bitmask for the bitmap. If the bitmap is palletised 0 is returned. + +

FreeImage_GetBlueMask + +

+ +

unsigned FreeImage_GetBlueMask(FIBITMAP *dib); + +

+ +

Returns the blue bitmask for the bitmap. If the bitmap is palletised 0 is returned. + +

FreeImage_GetTransparencyCount + +

+ +

BYTE FreeImage_GetTransparencyCount(FIBITMAP *dib); + +

+ +

Returns the number of transparent colours stored into the transparency colour table of the given bitmap. Every palletised bitmap includes a transparency table containing up to 256 alpha values. + +

+FreeImage_GetTransparencyTable + +

+ +

BYTE *FreeImage_GetTransparencyTable(FIBITMAP *dib); + +

+ +

Returns the transparency table assigned to this bitmap. If the bitmap doesn't contain a transparency table NULL is returned. + +

FreeImage_SetTransparencyTable + +

+ +

void FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, BYTE count); + +

+ +

Assigns a new transparency table to the bitmap. A transparency table consists of up to 256 bytes in an array, where a value of 0xFF in that table stands for completely opaque and 0x00 stands for completely invisible. The transparency table is used in TrollTech Qt to draw transparent bitmaps on a widget. + +

diff --git a/freeimage241/Docs/80.html b/freeimage241/Docs/80.html new file mode 100644 index 0000000..64935ce --- /dev/null +++ b/freeimage241/Docs/80.html @@ -0,0 +1,175 @@ + +

+DIB information functions + +

+

Subsections

+ + + +

FreeImage_GetColorsUsed + +

+ +

unsigned FreeImage_GetColorsUsed(FIBITMAP *dib); + +

+ +

Retrieves the number of colours used in the bitmap. If the bitmap is non-palletised, 0 is returned. + +

FreeImage_GetBits + +

+ +

BYTE * FreeImage_GetBits(FIBITMAP *dib); + +

+ +

Returns a pointer to the bitmap bits. + +

FreeImage_GetBitsRowCol + +

+ +

BYTE * FreeImage_GetBitsRowCol(FIBITMAP *dib, int col, int row); + +

+ +

Returns a pointer to the bitmap bits on the given column and row. + +

FreeImage_GetScanLine + +

+ +

BYTE * FreeImage_GetScanLine(FIBITMAP *dib, int scanline); + +

+ +

Returns a pointer to the beginning of the bits of the given scanline. + +

FreeImage_GetBPP + +

+ +

unsigned FreeImage_GetBPP(FIBITMAP *dib); + +

+ +

Returns the bitdepth of the bitmap. + +

FreeImage_GetWidth + +

+ +

unsigned FreeImage_GetWidth(FIBITMAP *dib); + +

+ +

Returns the width of the bitmap in pixels. + +

FreeImage_GetHeight + +

+ +

unsigned FreeImage_GetHeight(FIBITMAP *dib); + +

+ +

Returns the height of the bitmap in pixels. + +

FreeImage_GetLine + +

+ +

unsigned FreeImage_GetLine(FIBITMAP *dib); + +

+ +

Returns the width of the bitmap in bytes. + +

FreeImage_GetPitch + +

+ +

unsigned FreeImage_GetPitch(FIBITMAP *dib); + +

+ +

Returns the width of the bitmap in bytes rounded to the nearest DWORD. + +

FreeImage_GetDIBSize + +

+ +

unsigned FreeImage_GetDIBSize(FIBITMAP *dib); + +

+ +

Returns the size of the bitmap in bytes. The size of the bitmap is the BITMAPINFOHEADER + the size of the palette + the size of the bitmap data. + +

FreeImage_GetPalette + +

+ +

RGBQUAD *FreeImage_GetPalette(FIBITMAP *dib); + +

+ +

Returns a pointer to the bitmap's palette. If the bitmap doesn't have a palette, FreeImage_GetPalette returns NULL. + +

FreeImage_GetInfoHeader + +

+ +

BITMAPINFOHEADER *FreeImage_GetInfoHeader(FIBITMAP *dib); + +

+ +

Returns a pointer to the bitmap's BITMAPINFOHEADER. + +

FreeImage_GetInfo + +

+ +

BITMAPINFO *FreeImage_GetInfo(FIBITMAP *dib); + +

+ +

Returns a pointer to the bitmap's BITMAPINFO header. + +

FreeImage_GetColorType + +

+ +

FREE_IMAGE_COLOR_TYPE FreeImage_GetColorType(FIBITMAP *dib); + +

+ +

Investigates the colour type of the bitmap and returns one of the following values: + +

+ +

+ +

+ +

+

+
Value Description
FIC_MINISWHITE 1-bit bitmap. The min value is white
FIC_MINISBLACK 1-bit bitmap. The min value is black 8-bit grayscale. The min value is black
FIC_RGB 24/32-bit RGB
FIC_PALETTE 1/4/8-bit palletised

+ +

diff --git a/freeimage241/Docs/95.html b/freeimage241/Docs/95.html new file mode 100644 index 0000000..ca560fa --- /dev/null +++ b/freeimage241/Docs/95.html @@ -0,0 +1,93 @@ + +

Conversion functions + +

+ +

Bitmaps in FreeImage are always loaded in their default bit depth. If you want the bitmap to be stored in another bit depth, the library provides several conversion functions. + +

+

Subsections

+ + + +

FreeImage_ConvertTo8Bits + +

+ +

FIBITMAP *FreeImage_ConvertTo8Bits(FIBITMAP *dib); + +

+ +

Converts the given bitmap to 8 bits. If the bitmap is 24 or 32-bit RGB, the colour values are converted to greyscale. + +

FreeImage_ConvertTo16Bits 555 + +

+ +

FIBITMAP *FreeImage_ConvertTo16Bits555(FIBITMAP *dib); + +

+ +

Converts the given bitmap to 16 bits. The resulting bitmap has a layout of 5 bits red, 5 bits green, 5 bits red and 1 unused bit. + +

FreeImage_ConvertTo16Bits565 + +

+ +

FIBITMAP *FreeImage_ConvertTo16Bits565(FIBITMAP *dib); + +

+ +

Converts the given bitmap to 16 bits. The resulting bitmap has a layout of 5 bits red, 6 bits green and 5 bits red. + +

FreeImage_ConvertTo24Bits + +

+ +

FIBITMAP *FreeImage_ConvertTo24Bits(FIBITMAP *dib); + +

+ +

Converts the given bitmap to 24 bits. + +

FreeImage_ConvertTo32Bits + +

+ +

FIBITMAP *FreeImage_ConvertTo32Bits(FIBITMAP *dib); + +

+ +

Converts the given bitmap to 32 bits. + +

FreeImage_ColorQuantize + +

+ +

FIBITMAP *FreeImage_ColorQuantize(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize); + +

+ +

Quantizes a full colour 24-bit bitmap to a palletised 8-bit bitmap. The quantize parameter specifies which colour reduction algorithm should be used. + +

+ +

+ +

+ +

+

+ +

+ +

Parameter Description
FIQ_WUQUANT Wu's color quantization algorithm
FIQ_NNQUANT NeuQuant quantization algorithm

+ +

diff --git a/freeimage241/Docs/contents.xml b/freeimage241/Docs/contents.xml new file mode 100644 index 0000000..3f85eb6 --- /dev/null +++ b/freeimage241/Docs/contents.xml @@ -0,0 +1,249 @@ + + + + FreeImage functions + Initialisation + FreeImage_Initialise + + FreeImage_DeInitialise + + + Bitmap Allocation functions + FreeImage_Allocate + + FreeImage_Free + + FreeImage_Unload + + + Plugin functions + FreeImage_GetFIFByIndex + + FreeImage_GetFIFCount + + FreeImage_GetFIFFromFormat + + FreeImage_GetFormatFromFIF + + FreeImage_GetFIFExtensionList + + FreeImage_GetFIFDescription + + FreeImage_GetFIFRegExpr + + FreeImage_GetFIFFromFilename + + FreeImage_FIFSupportsReading + + FreeImage_FIFSupportsWriting + + FreeImage_LoadFromHandle + + FreeImage_Load + + FreeImage_SaveToHandle + + FreeImage_Save + + + Simple load functions + FreeImage_LoadBMP + + FreeImage_LoadICO + + FreeImage_LoadJPEG + + FreeImage_LoadKOALA + + FreeImage_LoadLBM + + FreeImage_LoadMNG + + FreeImage_LoadPCD + + FreeImage_LoadPCX + + FreeImage_LoadPNM + + FreeImage_LoadPNG + + FreeImage_LoadRAS + + FreeImage_LoadTARGA + + FreeImage_LoadTIFF + + FreeImage_LoadWBMP + + + Advanced load functions + FreeImage_LoadBMPFromHandle + + FreeImage_LoadICOFromHandle + + FreeImage_LoadJPEGFromHandle + + FreeImage_LoadKOALAFromHandle + + FreeImage_LoadLBMFromHandle + + FreeImage_LoadMNGFromHandle + + FreeImage_LoadPCDFromHandle + + FreeImage_LoadPCXFromHandle + + FreeImage_LoadPNMFromHandle + + FreeImage_LoadPNGFromHandle + + FreeImage_LoadRASFromHandle + + FreeImage_LoadTARGAFromHandle + + FreeImage_LoadTIFFFromHandle + + FreeImage_LoadWBMPFromHandle + + + Simple save functions + FreeImage_SaveBMP + + FreeImage_SaveJPEG + + FreeImage_SavePNG + + FreeImage_SavePNM + + FreeImage_SaveTIFF + + FreeImage_SaveWBMP + + + Advanced save functions + FreeImage_SaveBMPToHandle + + FreeImage_SaveJPEGToHandle + + FreeImage_SavePNGToHandle + + FreeImage_SavePNMToHandle + + FreeImage_SaveTIFFToHandle + + FreeImage_SaveWBMPToHandle + + + Filetype functions + FreeImage_GetFileType + + FreeImage_GetFileTypeFromHandle + + FreeImage_GetFileTypeFromExt + + + FreeImage bitmap information functions + FreeImage_GetRedMask + + FreeImage_GetGreenMask + + FreeImage_GetBlueMask + + FreeImage_GetTransparencyCount + + FreeImage_GetTransparencyTable + + FreeImage_SetTransparencyTable + + + DIB information functions + FreeImage_GetColorsUsed + + FreeImage_GetBits + + FreeImage_GetBitsRowCol + + FreeImage_GetScanLine + + FreeImage_GetBPP + + FreeImage_GetWidth + + FreeImage_GetHeight + + FreeImage_GetLine + + FreeImage_GetPitch + + FreeImage_GetDIBSize + + FreeImage_GetPalette + + FreeImage_GetInfoHeader + + FreeImage_GetInfo + + FreeImage_GetColorType + + + Conversion functions + FreeImage_ConvertTo8Bits + + FreeImage_ConvertTo16Bits 555 + + FreeImage_ConvertTo16Bits565 + + FreeImage_ConvertTo24Bits + + FreeImage_ConvertTo32Bits + + FreeImage_ColorQuantize + + + Extra functions + FreeImage_Combine + + + + FreeImageQt functions + Introduction + + Functions + FIQT_Register + + FIQT_Unregister + + FIQT_IsLoaded + + FIQT_GetVersion + + FIQT_GetCopyrightMessage + + FIQT_GetFIFCount + + FIQT_GetFIFFromFormat + + FIQT_GetFormatFromFIF + + FIQT_GetFIFExtensionList + + FIQT_GetFIFDescription + + FIQT_GetFIFFromFilename + + FIQT_FIFSupportsReading + + FIQT_FIFSupportsWriting + + FIQT_GetFileTypeFromFormat + + FIQT_GetFormatFromExtension + + + + Index + + + + + diff --git a/freeimage241/Docs/index.html b/freeimage241/Docs/index.html new file mode 100644 index 0000000..3587278 --- /dev/null +++ b/freeimage241/Docs/index.html @@ -0,0 +1,190 @@ + + + +FreeImage 2.3.0 + + + +

Thank you for downloading FreeImage, an Open Source image library for multimedia and game programmers. The goal of FreeImage is to create a sophisticated, easy to use library to serve all your bitmap manipulation needs. The library is already in use by many companies and individuals, and the user base is still rapidly growing. + +

+ +

If you have any questions about this manual, or about FreeImage, please don't hesitate to send an e-mail to freeimage@6ixsoft.com . You can also browse the FreeImage forum or sign up on the FreeImage mailing list via the FreeImage website: http://www.6ixsoft.com + +

+ +

Floris + +

+

Subsections

+ + + + diff --git a/freeimage241/Examples/Generic/BatchLoad.cpp b/freeimage241/Examples/Generic/BatchLoad.cpp new file mode 100644 index 0000000..6c0dcd7 --- /dev/null +++ b/freeimage241/Examples/Generic/BatchLoad.cpp @@ -0,0 +1,150 @@ +// ========================================================== +// Batch loader +// +// Design and implementation by Floris van den Berg +// +// This file is part of FreeImage +// +// Use at own risk! +// ========================================================== +// +// This example shows how to easily batch load a directory +// full of images. Because not all formats can be identified +// by their header (some images don't have a header or one +// at the end of the file) we make use of the +// FreeImage_GetFileTypeFromExt function. This function +// receives a file extension, for example BMP, and returns +// a FREE_IMAGE_TYPE enum which identifies that bitmap. +// +// ========================================================== + +#include +#include +#include +#include +#include + +#include "FreeImage.h" + +// ---------------------------------------------------------- + +int __cdecl +main(int argc, char *argv[]) { + FIBITMAP *dib = NULL; + int id = 1; + + printf(FreeImage_GetVersion()); + printf(FreeImage_GetCopyrightMessage()); + + // open the log file + + FILE *log_file = fopen("log_file.txt", "w"); + + // batch convert all supported bitmaps + + _finddata_t finddata; + + long handle; + + if ((handle = _findfirst("d:\\images\\*.*", &finddata)) != -1) { + do { + // grab the extension + + char *ext = new char[4]; + ext[3] = 0; + strncpy(ext, finddata.name + strlen(finddata.name) - 3, 3); + + // make a path to a directory + + char *directory = new char[128]; + strcpy(directory, "d:\\images\\"); + strcat(directory, finddata.name); + + // make a unique filename + + char *unique = new char[128]; + itoa(id, unique, 10); + strcat(unique, ".bmp"); + + // open the file + + switch(FreeImage_GetFileTypeFromExt(ext)) { + case FIF_BMP : + dib = FreeImage_LoadBMP(directory); + break; + + case FIF_ICO : + dib = FreeImage_LoadICO(directory); + break; + + case FIF_JPEG : + dib = FreeImage_LoadJPEG(directory); + break; + + case FIF_KOALA : + dib = FreeImage_LoadKOALA(directory); + break; + + case FIF_PCD : + dib = FreeImage_LoadPCD(directory); + break; + + case FIF_PCX : + dib = FreeImage_LoadPCX(directory); + break; + + case FIF_PNG : + dib = FreeImage_LoadPNG(directory); + break; + + case FIF_PBM : + dib = FreeImage_LoadPNM(directory); + break; + + case FIF_PGM : + dib = FreeImage_LoadPNM(directory); + break; + + case FIF_PPM : + dib = FreeImage_LoadPNM(directory); + break; + + case FIF_RAS : + dib = FreeImage_LoadRAS(directory); + break; + + case FIF_TARGA : + dib = FreeImage_LoadTARGA(directory); + break; + + case FIF_TIFF : + dib = FreeImage_LoadTIFF(directory); + break; + }; + + if (dib != NULL) { + FreeImage_SaveBMP(dib, unique); + + FreeImage_Free(dib); + + fwrite(unique, strlen(unique), 1, log_file); + fwrite(" >> ", 4, 1, log_file); + fwrite(directory, strlen(directory), 1, log_file); + fwrite("\n", 1, 1, log_file); + + id++; + } + + delete [] unique; + delete [] directory; + delete [] ext; + + } while (_findnext(handle, &finddata) == 0); + + _findclose(handle); + } + + fclose(log_file); + + return 0; +} \ No newline at end of file diff --git a/freeimage241/Examples/Generic/LoadFromHandle.cpp b/freeimage241/Examples/Generic/LoadFromHandle.cpp new file mode 100644 index 0000000..498b1f5 --- /dev/null +++ b/freeimage241/Examples/Generic/LoadFromHandle.cpp @@ -0,0 +1,66 @@ +// ========================================================== +// Load From Handle Example +// +// Design and implementation by Floris van den Berg +// +// This file is part of FreeImage +// +// Use at own risk! +// ========================================================== +// +// This example shows how to load a bitmap from a +// user allocated FILE pointer. +// +// ========================================================== + +#include +#include +#include + +#include "FreeImage.h" + +// ---------------------------------------------------------- + +unsigned +_ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + return fread(buffer, size, count, (FILE *)handle); +} + +unsigned +_WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + return fwrite(buffer, size, count, (FILE *)handle); +} + +int +_SeekProc(fi_handle handle, long offset, int origin) { + return fseek((FILE *)handle, offset, origin); +} + +long +_TellProc(fi_handle handle) { + return ftell((FILE *)handle); +} + +// ---------------------------------------------------------- + +int __cdecl +main(int argc, char *argv[]) { + FreeImageIO io; + + io.read_proc = _ReadProc; + io.write_proc = _WriteProc; + io.seek_proc = _SeekProc; + io.tell_proc = _TellProc; + + FILE *file = fopen("d:\\images\\money-256.bmp", "rb"); + + if (file != NULL) { + FIBITMAP *dib = FreeImage_LoadBMPFromHandle(&io, (fi_handle)file); + + FreeImage_Free(dib); + + fclose(file); + } + + return 0; +} \ No newline at end of file diff --git a/freeimage241/Examples/Generic/LoadFromMemory.cpp b/freeimage241/Examples/Generic/LoadFromMemory.cpp new file mode 100644 index 0000000..72acc73 --- /dev/null +++ b/freeimage241/Examples/Generic/LoadFromMemory.cpp @@ -0,0 +1,112 @@ +// ========================================================== +// Load From Memory Example +// +// Design and implementation by Floris van den Berg +// +// This file is part of FreeImage +// +// Use at own risk! +// ========================================================== +// +// This example shows how to load a bitmap from memory +// rather than from a file. To do this we make use of the +// FreeImage_LoadXXXFromHandle functions where we override +// the i/o functions to simulate FILE* access in memory. +// +// For seeking purposes the fi_handle passed to the i/o +// functions contain the start of the data block where the +// bitmap is stored. +// +// ========================================================== + +#include +#include +#include + +#include "FreeImage.h" + +// ---------------------------------------------------------- + +fi_handle g_load_address; + +// ---------------------------------------------------------- + +inline unsigned +_ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + BYTE *tmp = (BYTE *)buffer; + + for (unsigned c = 0; c < count; c++) { + memcpy(tmp, g_load_address, size); + + g_load_address = (BYTE *)g_load_address + size; + + tmp += size; + } + + return count; +} + +inline unsigned +_WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + // there's not much use for saving the bitmap into memory now, is there? + + return size; +} + +inline int +_SeekProc(fi_handle handle, long offset, int origin) { + assert(origin != SEEK_END); + + if (origin == SEEK_SET) { + g_load_address = (BYTE *)handle + offset; + } else { + g_load_address = (BYTE *)g_load_address + offset; + } + + return 0; +} + +inline long +_TellProc(fi_handle handle) { + assert((int)handle > (int)g_load_address); + + return ((int)g_load_address - (int)handle); +} + +// ---------------------------------------------------------- + +int __cdecl +main(int argc, char *argv[]) { + FreeImageIO io; + + io.read_proc = _ReadProc; + io.write_proc = _WriteProc; + io.tell_proc = _TellProc; + io.seek_proc = _SeekProc; + + // allocate some memory for the bitmap + + BYTE *test = new BYTE[159744]; + + if (test != NULL) { + // load the bitmap into memory. ofcourse you can do this any way you want + + FILE *file = fopen("e:\\projects\\images\\money-256.tif", "rb"); + fread(test, 159744, 1, file); + fclose(file); + + // we store the load address of the bitmap for internal reasons + + g_load_address = test; + + // convert the bitmap + + FIBITMAP *dib = FreeImage_LoadTIFFFromHandle(&io, (fi_handle)test); + + FreeImage_Free(dib); + + delete [] test; + } + + return 0; +} \ No newline at end of file diff --git a/freeimage241/Examples/Linux/Makefile b/freeimage241/Examples/Linux/Makefile new file mode 100644 index 0000000..10282ab --- /dev/null +++ b/freeimage241/Examples/Linux/Makefile @@ -0,0 +1,26 @@ +include ../../Makefile.cfg + + + +INCLUDE = -I../../Source +VGALIBRARIES = -lfreeimage -lvga +GTKLIBRARIES = -lfreeimage -lgtk -lgdk +GTKINCLUDE = -I/usr/lib/glib/include +CFLAGS = $(COMPILERFLAGS) $(INCLUDE) + + + +all: default + +default: linux-svgalib linux-gtk + +linux-svgalib: linux-svgalib.c + $(CC) $(CFLAGS) $< -o $@ $(VGALIBRARIES) + strip $@ + +linux-gtk: linux-gtk.c + $(CC) $(CFLAGS) $< -o $@ $(GTKLIBRARIES) $(GTKINCLUDE) + strip $@ + +clean: + rm -f core linux-svgalib linux-gtk diff --git a/freeimage241/Examples/Linux/linux-gtk.c b/freeimage241/Examples/Linux/linux-gtk.c new file mode 100644 index 0000000..016acc3 --- /dev/null +++ b/freeimage241/Examples/Linux/linux-gtk.c @@ -0,0 +1,91 @@ +#include +#include "FreeImage.h" + +void destroy(GtkWidget * widget, gpointer data) { + gtk_main_quit(); +} + +int main(int argc, char *argv[]) +{ + GtkWidget *window, *imagebox; + GdkVisual *visual; + GdkImage *image; + FIBITMAP *dib; + int y; + + dib = FreeImage_LoadPNG("freeimage.png",PNG_DEFAULT); + + gtk_init(&argc, &argv); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(destroy), NULL); + + visual = gdk_visual_get_system(); + + image = gdk_image_new(GDK_IMAGE_NORMAL,visual, + FreeImage_GetWidth(dib),FreeImage_GetHeight(dib)); + + g_print("picture: %d bpp\n" + "system: %d bpp byteorder: %d\n" + " redbits: %d greenbits: %d bluebits: %d\n" + "image: %d bpp %d bytes/pixel\n", + FreeImage_GetBPP(dib), + visual->depth,visual->byte_order, + visual->red_prec,visual->green_prec,visual->blue_prec, + image->depth,image->bpp ); + + if (FreeImage_GetBPP(dib) != (image->bpp << 3)) { + FIBITMAP *ptr; + + switch (image->bpp) { + case 1: + ptr = FreeImage_ConvertTo8Bits(dib); + break; + + case 2: + if (image->depth == 15) { + ptr = FreeImage_ConvertTo16Bits555(dib); + } else { + ptr = FreeImage_ConvertTo16Bits565(dib); + } + + break; + case 3: + ptr = FreeImage_ConvertTo24Bits(dib); + break; + + default: + case 4: + ptr = FreeImage_ConvertTo32Bits(dib); + break; + } + + FreeImage_Free(dib); + dib = ptr; + } + +//makes it upside down :( +// memcpy(image->mem, FreeImage_GetBits(dib), image->bpl * image->height); + + BYTE *ptr = FreeImage_GetBits(dib); + + for (y = 0; y < image->height; y++) { + memcpy(image->mem + (y * image->bpl), + ptr + ((image->height - y - 1) * image->bpl), + image->bpl); + } + + FreeImage_Free(dib); + + imagebox = gtk_image_new(image, NULL); + gtk_container_add(GTK_CONTAINER(window), imagebox); + + gtk_widget_show(imagebox); + gtk_widget_show(window); + + gtk_main(); + + return 0; +} diff --git a/freeimage241/Examples/Linux/linux-svgalib.c b/freeimage241/Examples/Linux/linux-svgalib.c new file mode 100644 index 0000000..820329b --- /dev/null +++ b/freeimage241/Examples/Linux/linux-svgalib.c @@ -0,0 +1,91 @@ +#include +#include "FreeImage.h" + +int main(void) +{ + FIBITMAP *dib,*ptr; + vga_modeinfo *inf; + int length,height,bpp,y; + + dib = FreeImage_LoadPNG("freeimage.png",PNG_DEFAULT); + + vga_init(); + vga_setmode(vga_getdefaultmode()); + + inf = vga_getmodeinfo(vga_getcurrentmode()); + + switch(inf->colors) { + default: + printf("Must be at least 256color mode!\n"); + return; + + case 1 << 8: + bpp = 8; + break; + + case 1 << 15: + bpp = 15; + break; + + case 1 << 16: + bpp = 16; + break; + + case 1 << 24: + if( inf->bytesperpixel == 3 ) { + bpp = 24; + } else { + bpp = 32; + } + break; + } + + if(FreeImage_GetBPP(dib) != bpp) { + switch(bpp) { + case 8: + ptr = FreeImage_ConvertTo8Bits(dib); + break; + + case 15: + ptr = FreeImage_ConvertTo16Bits555(dib); + break; + + case 16: + ptr = FreeImage_ConvertTo16Bits565(dib); + break; + + case 24: + ptr = FreeImage_ConvertTo24Bits(dib); + break; + + default: + case 32: + ptr = FreeImage_ConvertTo32Bits(dib); + break; + } + + FreeImage_Free(dib); + dib = ptr; + } + + length = FreeImage_GetWidth(dib); + if( inf->width < length ) { + length = inf->width; + } + height = FreeImage_GetHeight(dib); + if( inf->height < height ) { + height = inf->height; + } + + for(y = 0; y < height; y++) { + vga_drawscansegment(FreeImage_GetScanLine(dib, y), + 0,y,length); + } + + FreeImage_Free(dib); + + vga_getch(); + vga_setmode(TEXT); + + return 0; +} diff --git a/freeimage241/Examples/Plugin/PluginCradle.cpp b/freeimage241/Examples/Plugin/PluginCradle.cpp new file mode 100644 index 0000000..f082efd --- /dev/null +++ b/freeimage241/Examples/Plugin/PluginCradle.cpp @@ -0,0 +1,130 @@ +// ========================================================== +// Loader/Saver Plugin Cradle +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include +#include + +#include "FreeImage.h" +#include "Utilities.h" + +// ========================================================== + +BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH : + case DLL_PROCESS_DETACH : + case DLL_THREAD_ATTACH : + case DLL_THREAD_DETACH : + break; + } + + return TRUE; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "CRADLE"; +} + +static const char * DLL_CALLCONV +Description() { + return "Here comes the description for your image loader/saver"; +} + +// the extension list is always a chain of extensions +// seperated by commas. no spaces or whatsoever are allowed. + +static const char * DLL_CALLCONV +Extension() { + return "ext1,ext2"; +} + +// RegExpr is only needed for the Qt wrapper +// It allows the Qt mechanism for loading bitmaps to identify the bitmap + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +// FreeImage's internal way of seeing if a bitmap is of the desired type. +// When the type of a bitmap is to be retrieved, FreeImage runs Validate +// for each registered plugin until one returns true. If a plugin doesn't +// have a validate function, a return value of false is assumed. +// +// You can always force to use a particular plugin by directly specifying +// it on the command line, but this can result in a dead DLL if the plugin +// was not made for the bitmap. + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + return FALSE; +} + +// ---------------------------------------------------------- + +// NEVER EVER use direct function calls to FreeImage when writing +// a plugin. Always use the function pointers provides in the FreeImage +// structure. Using this indirect approach ensures that plugins run +// from the FreeImage DLL, an external DLL or within the application +// code with a simple recompile. Also NEVER EVER allocate memory in +// a plugin and return it. Memory allocated in one DLL can't be freed +// in another DLL unless they share the same c runtime library (which +// usually is not the case). Always use freeimage.allocate_proc to +// allocate memory for a bitmap. + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + return NULL; +} + +static BOOL DLL_CALLCONV +Save(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + return FALSE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +Init(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.save_proc = Save; + plugin.validate_proc = Validate; +} diff --git a/freeimage241/Examples/Plugin/PluginCradle.h b/freeimage241/Examples/Plugin/PluginCradle.h new file mode 100644 index 0000000..ec0b8f6 --- /dev/null +++ b/freeimage241/Examples/Plugin/PluginCradle.h @@ -0,0 +1,45 @@ +// ========================================================== +// JBIG Plugin +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef PLUGINCRADLE_H +#define PLUGINCRADLE_H + +#ifdef PLUGINCRADLE_EXPORTS +#define PLUGIN_API __declspec(dllexport) +#else +#define PLUGIN_API __declspec(dllimport) +#endif + +// ---------------------------------------------------------- + +struct Plugin; + +// ---------------------------------------------------------- + +#define DLL_CALLCONV __stdcall + +// ---------------------------------------------------------- + +extern "C" { + PLUGIN_API void DLL_CALLCONV Init(Plugin &plugin, int format_id); +} + +#endif diff --git a/freeimage241/FreeImage.dsp b/freeimage241/FreeImage.dsp new file mode 100644 index 0000000..1f752c9 --- /dev/null +++ b/freeimage241/FreeImage.dsp @@ -0,0 +1,274 @@ +# Microsoft Developer Studio Project File - Name="FreeImage" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=FreeImage - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "FreeImage.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "FreeImage.mak" CFG="FreeImage - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "FreeImage - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "FreeImage - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "FreeImage - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FREEIMAGE_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "Source" /I "Source\ZLib" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FREEIMAGE_EXPORTS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD 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 /dll /machine:I386 +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy Release\FreeImage.dll Dist copy Release\FreeImage.lib Dist copy Source\FreeImage.h Dist +# End Special Build Tool + +!ELSEIF "$(CFG)" == "FreeImage - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FREEIMAGE_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "Source" /I "Source\ZLib" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FREEIMAGE_EXPORTS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD 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 /dll /debug /machine:I386 /out:"Debug/FreeImaged.dll" /pdbtype:sept +# SUBTRACT LINK32 /incremental:no +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy Debug\FreeImaged.dll Dist copy Debug\FreeImaged.lib Dist copy Source\FreeImage.h Dist +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "FreeImage - Win32 Release" +# Name "FreeImage - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "Plugins" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Source\FreeImage\Plugin.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginBMP.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginICO.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginIFF.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginJPEG.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginKOALA.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginMNG.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginPCD.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginPCX.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginPNG.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginPNM.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginPSD.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginRAS.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginTARGA.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginTIFF.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\PluginWBMP.cpp +# End Source File +# End Group +# Begin Group "Conversion" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Source\FreeImage\Conversion.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\Conversion16_555.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\Conversion16_565.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\Conversion24.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\Conversion32.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\Conversion8.cpp +# End Source File +# End Group +# Begin Group "Quantizers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Source\FreeImage\NNQuantizer.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\WuQuantizer.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Source\FreeImage\BitmapAccess.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\FreeImage.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\FreeImageIO.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\GetType.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImage\LoadFunctions.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\Source\FreeImage.h +# End Source File +# Begin Source File + +SOURCE=.\Source\FreeImageIO.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Plugin.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Quantizers.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Utilities.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\KnownBugs.txt +# End Source File +# Begin Source File + +SOURCE=.\Todo.txt +# End Source File +# Begin Source File + +SOURCE=.\Whatsnew.txt +# End Source File +# End Target +# End Project diff --git a/freeimage241/FreeImage.dsw b/freeimage241/FreeImage.dsw new file mode 100644 index 0000000..0ddecc0 --- /dev/null +++ b/freeimage241/FreeImage.dsw @@ -0,0 +1,158 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "FreeImage"=.\FreeImage.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibJPEG + End Project Dependency + Begin Project Dependency + Project_Dep_Name LibPNG + End Project Dependency + Begin Project Dependency + Project_Dep_Name LibTIFF + End Project Dependency + Begin Project Dependency + Project_Dep_Name ZLib + End Project Dependency + Begin Project Dependency + Project_Dep_Name LibMNG + End Project Dependency +}}} + +############################################################################### + +Project: "FreeImageLib"=.\SOURCE\FreeImageLib\FreeImageLib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name LibJPEG + End Project Dependency + Begin Project Dependency + Project_Dep_Name LibMNG + End Project Dependency + Begin Project Dependency + Project_Dep_Name LibPNG + End Project Dependency + Begin Project Dependency + Project_Dep_Name LibTIFF + End Project Dependency +}}} + +############################################################################### + +Project: "FreeImageQt"=.\Source\FreeImageQt\FreeImageQt.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "LibJPEG"=.\Source\LibJPEG\LibJPEG.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "LibMNG"=.\Source\LibMNG\LibMNG.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name ZLib + End Project Dependency +}}} + +############################################################################### + +Project: "LibPNG"=.\Source\LibPNG\LibPNG.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "LibTIFF"=.\Source\LibTIFF\LibTIFF.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "Test"=.\Source\Test\Test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name FreeImage + End Project Dependency +}}} + +############################################################################### + +Project: "ZLib"=.\Source\ZLib\ZLib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/freeimage241/KnownBugs.txt b/freeimage241/KnownBugs.txt new file mode 100644 index 0000000..fb8e85e --- /dev/null +++ b/freeimage241/KnownBugs.txt @@ -0,0 +1,27 @@ +Known bugs for FreeImage + +- PHOTOSHOP AND ALPHA-CHANNELED TIFF ------------------------------------ + +LibTIFF doesn't load the alpha channel when that file is created +with Adobe Photoshop. This is a bug in Photoshop as it writes +the TIFF in a non-standard, non-documented way. According to +the LibTIFF mailing list: + +"Photoshop's PSD file format allows for a number of layers, alpha +channels, etc. In such a sceme, there is no such thing as a single alpha +channel, but only a number of channels, some of which represent colors +in layers, or in a global picture, others alpha's that can have just +about any local layers or global image meaning and must even considered +to be editable and enablable/disablable by users all the time. I guess +this makes adobe reluctant to define such a thing as a single alpha +channel, including when they write out other formats that allow for +something else/more than a single alpha." + +On the same libTIFF mailing a semi-solution is provided: + +"If I create a 32-bit (24-bit + 8 bit alpha) TGA image in another +program, and load it into Photoshop, Photoshop shows it as RGBA. +If I then save it to TIFF, Photoshop properly flags it as an Alpha +channel, and TIFFReadRGBAImage reads it fine. I'm not sure what +Photoshop does differently when you create an Alpha channel by hand +versus loading it with the image." diff --git a/freeimage241/Makefile b/freeimage241/Makefile new file mode 100644 index 0000000..f9e2275 --- /dev/null +++ b/freeimage241/Makefile @@ -0,0 +1,38 @@ + +# configure your options in Makefile.cfg + +include Makefile.cfg + + + +all: default + +default: dist examples + +dist: FreeImage + cp Source/FreeImage/*.a Dist + cp Source/FreeImage/*.so Dist + +examples: FreeImage + make -C Examples/Linux all + +FreeImage: + @if [ ! -f .nodos2unix ]; then \ + $(DOS2UNIX) Source/*.[ch]* Source/FreeImage/*.[ch]* \ + Source/LibJPEG/*.[ch]* Source/LibMNG/*.[ch]* Source/LibPNG/*.[ch]* \ + Source/LibTIFF/*.[ch]* Source/ZLib/*.[ch]* \ + Examples/Linux/*.[ch]* ; \ + touch .nodos2unix; \ + fi + make -C Source/FreeImage all + +refix: + rm .nodos2unix + +install: + make -C Source/FreeImage install + +clean: + rm -f Dist/* u2dtmp* .nodos2unix + make -C Source/FreeImage clean + make -C Examples clean diff --git a/freeimage241/Makefile.cfg b/freeimage241/Makefile.cfg new file mode 100644 index 0000000..7d2ee8e --- /dev/null +++ b/freeimage241/Makefile.cfg @@ -0,0 +1,10 @@ +CC = gcc +CPP = g++ + +INSTALLDIR = /usr/lib + +#converts cr/lf to just lf +DOS2UNIX = dos2unix + +COMPILERFLAGS = -O3 +LIBRARIES = -ljpeg -lpng -ltiff -lmng diff --git a/freeimage241/README.linux b/freeimage241/README.linux new file mode 100644 index 0000000..de3b83a --- /dev/null +++ b/freeimage241/README.linux @@ -0,0 +1,23 @@ +Check Makefile.cfg and set the variables in there if things dont work. +This compiles with no warnings at all with the default options on +Redhat 6.2 / Linux-2.2.16 with glibc6 and the pre-installed libjpeg, +libpng, libtiff, and libz libraries that were already installed in my +/usr/lib directory. +I tested the GTK example I wrote under X11R6 running 1024x768x24bit but +the machine I was using does not allow switching to other modes, so +I am unsure if the picture would be displayed properly in other video +modes. +You should be able to link progams with the -lfreeimage options after +it is compiled and installed, which will require that libjpeg, libpng, +libtiff, and libz are installed as well. If you statically link with +libfreeimage.a you must also link with libjpeg.a, libpng.a, libtiff.a, +and libz.a. +If you unzip a new snapshot over old code, it will need to be reran +thru dos2unix to strip the CR's from it. `make refix` or just +rm .nodos2unix yourself to allow make to rerun dos2unix next time +the library is build. +Please let me know how this works for you under Linux or any other *nix + +- Ryan "Ark" Rubley +- ark@lhq.com / rubleyr@csis.gvsu.edu + diff --git a/freeimage241/README.txt b/freeimage241/README.txt new file mode 100644 index 0000000..e69de29 diff --git a/freeimage241/Source/FreeImage/BitmapAccess.cpp b/freeimage241/Source/FreeImage/BitmapAccess.cpp new file mode 100644 index 0000000..5c51426 --- /dev/null +++ b/freeimage241/Source/FreeImage/BitmapAccess.cpp @@ -0,0 +1,323 @@ +// ========================================================== +// FreeImage implementation +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#pragma warning (disable : 4786) + +#include + +#include "FreeImage.h" +#include "FreeImageIO.h" +#include "Utilities.h" + +// ---------------------------------------------------------- + +FI_STRUCT (FREEIMAGEHEADER) { + unsigned red_mask; + unsigned green_mask; + unsigned blue_mask; + BOOL transparent; + BYTE transparency_count; + BYTE transparent_table[256]; + BYTE filler[3]; +}; + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { + FIBITMAP *bitmap = (FIBITMAP *)malloc(sizeof(FIBITMAP)); + + if (bitmap != NULL) { + height = abs(height); + + int dib_size = sizeof(FREEIMAGEHEADER) + sizeof(BITMAPINFOHEADER); + dib_size += sizeof(RGBQUAD) * CalculateUsedColors(bpp); + dib_size += CalculatePitch(CalculateLine(width, bpp)) * height; + + bitmap->data = (BYTE *)malloc(dib_size); + + if (bitmap->data != NULL) { + memset(bitmap->data, 0, dib_size); + + // write out the FREEIMAGEHEADER + + FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)bitmap->data; + fih->red_mask = red_mask; + fih->green_mask = green_mask; + fih->blue_mask = blue_mask; + fih->transparent = FALSE; + fih->transparency_count = 0; + + // write out the BITMAPINFOHEADER + + BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(bitmap); + bih->biSize = sizeof(BITMAPINFOHEADER); + bih->biWidth = width; + bih->biHeight = height; + bih->biPlanes = 1; + bih->biCompression = 0; + bih->biBitCount = bpp; + bih->biClrUsed = CalculateUsedColors(bpp); + bih->biClrImportant = bih->biClrUsed; + + return bitmap; + } else { + free(bitmap); + } + } + + return NULL; +} + +void DLL_CALLCONV +FreeImage_Free(FIBITMAP *dib) { + if (dib != NULL) { + if (dib->data != NULL) + free(dib->data); + + free(dib); + } +} + +void DLL_CALLCONV +FreeImage_Unload(FIBITMAP *dib) { + FreeImage_Free(dib); +} + +// ---------------------------------------------------------- + +FREE_IMAGE_COLOR_TYPE DLL_CALLCONV +FreeImage_GetColorType(FIBITMAP *dib) { + RGBQUAD *rgb; + + switch (FreeImage_GetBPP(dib)) { + case 1: + { + rgb = FreeImage_GetPalette(dib); + + if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { + rgb++; + + if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) + return FIC_MINISBLACK; + } + + if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { + rgb++; + + if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) + return FIC_MINISWHITE; + } + + return FIC_PALETTE; + } + + case 4: + case 8: // Check if the DIB has a color or a greyscale palette + { + rgb = FreeImage_GetPalette(dib); + + for (unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) { + if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) + return FIC_PALETTE; + + // The DIB has a color palette if the greyscale isn't a linear ramp + + if (rgb->rgbRed != i) + return FIC_PALETTE; + + rgb++; + } + + return FIC_MINISBLACK; + } + + case 16: + case 24: + return FIC_RGB; + + case 32: + { + for (unsigned y = 0; y < FreeImage_GetHeight(dib); ++y) { + rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y); + + for (unsigned x = 0; x < FreeImage_GetWidth(dib); ++x) + if (rgb[x].rgbReserved != 0) + return FIC_RGBALPHA; + } + + return FIC_RGB; + } + + default : + return FIC_MINISBLACK; + } +} + +// ---------------------------------------------------------- + +unsigned DLL_CALLCONV +FreeImage_GetRedMask(FIBITMAP *dib) { + return dib ? ((FREEIMAGEHEADER *)dib->data)->red_mask : 0; +} + +unsigned DLL_CALLCONV +FreeImage_GetGreenMask(FIBITMAP *dib) { + return dib ? ((FREEIMAGEHEADER *)dib->data)->green_mask : 0; +} + +unsigned DLL_CALLCONV +FreeImage_GetBlueMask(FIBITMAP *dib) { + return dib ? ((FREEIMAGEHEADER *)dib->data)->blue_mask : 0; +} + +BOOL DLL_CALLCONV +FreeImage_IsTransparent(FIBITMAP *dib) { + return (dib != NULL) ? ((FREEIMAGEHEADER *)dib->data)->transparent : FALSE; +} + +BYTE * DLL_CALLCONV +FreeImage_GetTransparencyTable(FIBITMAP *dib) { + return dib ? ((FREEIMAGEHEADER *)dib->data)->transparent_table : NULL; +} + +void DLL_CALLCONV +FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled) { + if (dib) { + if ((FreeImage_GetBPP(dib) == 8) || (FreeImage_GetBPP(dib) == 32)) { + ((FREEIMAGEHEADER *)dib->data)->transparent = enabled; + } else { + ((FREEIMAGEHEADER *)dib->data)->transparent = FALSE; + } + } +} + +unsigned DLL_CALLCONV +FreeImage_GetTransparencyCount(FIBITMAP *dib) { + return dib ? ((FREEIMAGEHEADER *)dib->data)->transparency_count : 0; +} + +void DLL_CALLCONV +FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, BYTE count) { + if (dib) { + if (FreeImage_GetBPP(dib) == 8) { + ((FREEIMAGEHEADER *)dib->data)->transparent = TRUE; + ((FREEIMAGEHEADER *)dib->data)->transparency_count = count; + + if (table != NULL) { + memcpy(((FREEIMAGEHEADER *)dib->data)->transparent_table, table, count); + } else { + memset(((FREEIMAGEHEADER *)dib->data)->transparent_table, 0xff, count); + } + } else { + ((FREEIMAGEHEADER *)dib->data)->transparency_count = 0; + } + } +} + +// ---------------------------------------------------------- + +unsigned DLL_CALLCONV +FreeImage_GetWidth(FIBITMAP *dib) { + return dib ? FreeImage_GetInfoHeader(dib)->biWidth : 0; +} + +unsigned DLL_CALLCONV +FreeImage_GetHeight(FIBITMAP *dib) { + return (dib) ? FreeImage_GetInfoHeader(dib)->biHeight : 0; +} + +unsigned DLL_CALLCONV +FreeImage_GetBPP(FIBITMAP *dib) { + return dib ? FreeImage_GetInfoHeader(dib)->biBitCount : 0; +} + +unsigned DLL_CALLCONV +FreeImage_GetLine(FIBITMAP *dib) { + return dib ? ((FreeImage_GetWidth(dib) * FreeImage_GetBPP(dib)) + 7) / 8 : 0; +} + +unsigned DLL_CALLCONV +FreeImage_GetPitch(FIBITMAP *dib) { + return dib ? FreeImage_GetLine(dib) + 3 & ~3 : 0; +} + +unsigned DLL_CALLCONV +FreeImage_GetColorsUsed(FIBITMAP *dib) { + return dib ? FreeImage_GetInfoHeader(dib)->biClrUsed : 0; +} + +BYTE * DLL_CALLCONV +FreeImage_GetBits(FIBITMAP *dib) { + return dib ? ((BYTE *)FreeImage_GetInfoHeader(dib) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetInfoHeader(dib)->biClrUsed) : NULL; +} + +BYTE * DLL_CALLCONV +FreeImage_GetBitsRowCol(FIBITMAP *dib, int col, int row) { + if (dib) { + int width = FreeImage_GetWidth(dib); + + if (FreeImage_GetBPP(dib) == 4) + width /= 2; + else if (FreeImage_GetBPP(dib) == 1) + width /= 8; + + return FreeImage_GetBits(dib) + ((FreeImage_GetHeight(dib) - row - 1) * FreeImage_GetPitch(dib)) + (col * FreeImage_GetBPP(dib) / 8); + } else { + return NULL; + } +} + +BYTE * DLL_CALLCONV +FreeImage_GetScanLine(FIBITMAP *dib, int scanline) { + return (dib) ? CalculateScanLine(FreeImage_GetBits(dib), FreeImage_GetPitch(dib), scanline) : NULL; +} + +unsigned DLL_CALLCONV +FreeImage_GetDIBSize(FIBITMAP *dib) { + return (dib) ? sizeof(BITMAPINFOHEADER) + (FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)) + (FreeImage_GetPitch(dib) * FreeImage_GetHeight(dib)) : 0; +} + +RGBQUAD * DLL_CALLCONV +FreeImage_GetPalette(FIBITMAP *dib) { + return (dib && FreeImage_GetBPP(dib) < 16) ? (RGBQUAD *)((BYTE *)dib->data + sizeof(FREEIMAGEHEADER) + sizeof(BITMAPINFOHEADER)) : NULL; +} + +unsigned DLL_CALLCONV +FreeImage_GetDotsPerMeterX(FIBITMAP *dib) { + return FreeImage_GetInfoHeader(dib)->biXPelsPerMeter; +} + +unsigned DLL_CALLCONV +FreeImage_GetDotsPerMeterY(FIBITMAP *dib) { + return (dib) ? FreeImage_GetInfoHeader(dib)->biYPelsPerMeter : 0; +} + +BITMAPINFOHEADER * DLL_CALLCONV +FreeImage_GetInfoHeader(FIBITMAP *dib) { + return (dib) ? (BITMAPINFOHEADER *)((BYTE *)dib->data + sizeof(FREEIMAGEHEADER)) : NULL; +} + +BITMAPINFO * DLL_CALLCONV +FreeImage_GetInfo(FIBITMAP *dib) { + return (dib) ? (BITMAPINFO *)((BYTE *)dib->data + sizeof(FREEIMAGEHEADER)) : NULL; +} diff --git a/freeimage241/Source/FreeImage/Conversion.cpp b/freeimage241/Source/FreeImage/Conversion.cpp new file mode 100644 index 0000000..a6b148d --- /dev/null +++ b/freeimage241/Source/FreeImage/Conversion.cpp @@ -0,0 +1,185 @@ +// ========================================================== +// Bitmap conversion routines +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Jani Kajala (janik@remedy.fi) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include + +#include "FreeImage.h" +#include "Quantizers.h" + +// ---------------------------------------------------------- + +#define CONVERT(from, to) case to : FreeImage_ConvertLine##from##To##to(bits, scanline, FreeImage_GetWidth(dib)); break; +#define CONVERTWITHPALETTE(from, to) case to : FreeImage_ConvertLine##from##To##to(bits, scanline, FreeImage_GetWidth(dib), FreeImage_GetPalette(dib)); break; + +#define CONVERTTO16(from) \ + case 16 : \ + if ((red_mask == 0x7C00) && (green_mask == 0x3E0) && (blue_mask == 0x1F)) { \ + FreeImage_ConvertLine##from##To16_555(bits, scanline, FreeImage_GetWidth(dib)); \ + } else { \ + FreeImage_ConvertLine##from##To16_565(bits, scanline, FreeImage_GetWidth(dib)); \ + } \ + break; + +#define CONVERTTO16WITHPALETTE(from) \ + case 16 : \ + if ((red_mask == 0x7C00) && (green_mask == 0x3E0) && (blue_mask == 0x1F)) { \ + FreeImage_ConvertLine##from##To16_555(bits, scanline, FreeImage_GetWidth(dib), FreeImage_GetPalette(dib)); \ + } else { \ + FreeImage_ConvertLine##from##To16_565(bits, scanline, FreeImage_GetWidth(dib), FreeImage_GetPalette(dib)); \ + } \ + break; + +// ========================================================== + +FIBITMAP * DLL_CALLCONV +FreeImage_ColorQuantize(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize) { + if (dib) { + if (FreeImage_GetBPP(dib) == 24) { + switch(quantize) { + case FIQ_WUQUANT : + try { + WuQuantizer Q (dib); + return (FIBITMAP *) Q.Quantize(); + } catch (char *) { + return NULL; + } + + case FIQ_NNQUANT : + return NNQuantizer(dib, 15); + } + } + } + + return NULL; +} + +// ========================================================== + +FIBITMAP * DLL_CALLCONV +FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) { + FIBITMAP *dib = FreeImage_Allocate(width, height, bpp, red_mask, green_mask, blue_mask); + + if (dib != NULL) { + if (topdown) { + for (int i = 0; i < height; ++i) { + memcpy(FreeImage_GetScanLine(dib, i), bits, FreeImage_GetLine(dib)); + + bits += pitch; + } + } else { + for (int i = height - 1; i >= 0; --i) { + memcpy(FreeImage_GetScanLine(dib, i), bits, FreeImage_GetLine(dib)); + + bits += pitch; + } + } + } + + return dib; +} + +void DLL_CALLCONV +FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown) { + if ((dib != NULL) && (bits != NULL)) { + for (unsigned i = 0; i < FreeImage_GetHeight(dib); ++i) { + BYTE *scanline; + + if (topdown) { + scanline = FreeImage_GetScanLine(dib, i); + } else { + scanline = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - i - 1); + } + + if ((bpp == 16) && (FreeImage_GetBPP(dib) == 16)) { + // convert 555 to 565 or vice versa + + if ((red_mask == 0x7C00) && (green_mask == 0x3E0) && (blue_mask == 0x1F)) { + if ((FreeImage_GetRedMask(dib) == 0xF800) && (FreeImage_GetGreenMask(dib) == 0x7E0) && (FreeImage_GetBlueMask(dib) == 0x1F)) { + FreeImage_ConvertLine16_555_To16_565(bits, scanline, FreeImage_GetWidth(dib)); + } else { + memcpy(bits, scanline, FreeImage_GetLine(dib)); + } + } else { + if ((FreeImage_GetRedMask(dib) == 0x7C00) && (FreeImage_GetGreenMask(dib) == 0x3E0) && (FreeImage_GetBlueMask(dib) == 0x1F)) { + FreeImage_ConvertLine16_565_To16_555(bits, scanline, FreeImage_GetWidth(dib)); + } else { + memcpy(bits, scanline, FreeImage_GetLine(dib)); + } + } + } else if (FreeImage_GetBPP(dib) != bpp) { + switch(FreeImage_GetBPP(dib)) { + case 1 : + switch(bpp) { + CONVERT(1, 8) + CONVERTTO16WITHPALETTE(1) + CONVERTWITHPALETTE(1, 24) + CONVERTWITHPALETTE(1, 32) + }; + + break; + + case 4 : + switch(bpp) { + CONVERT(4, 8) + CONVERTTO16WITHPALETTE(4) + CONVERTWITHPALETTE(4, 24) + CONVERTWITHPALETTE(4, 32) + }; + + break; + + case 8 : + switch(bpp) { + CONVERTTO16WITHPALETTE(8) + CONVERTWITHPALETTE(8, 24) + CONVERTWITHPALETTE(8, 32) + }; + + break; + + case 24 : + switch(bpp) { + CONVERT(24, 8) + CONVERTTO16(24) + CONVERT(24, 32) + }; + + break; + + case 32 : + switch(bpp) { + CONVERT(32, 8) + CONVERTTO16(32) + CONVERT(32, 24) + }; + + break; + }; + } else { + memcpy(bits, scanline, FreeImage_GetLine(dib)); + } + + bits += pitch; + } + } +} diff --git a/freeimage241/Source/FreeImage/Conversion16_555.cpp b/freeimage241/Source/FreeImage/Conversion16_555.cpp new file mode 100644 index 0000000..9f5ded5 --- /dev/null +++ b/freeimage241/Source/FreeImage/Conversion16_555.cpp @@ -0,0 +1,211 @@ +// ========================================================== +// Bitmap conversion routines +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Jani Kajala (janik@remedy.fi) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- + +#define RGB555(r, g, b) (((r) >> 3) | (((g) >> 3) << 5) | (((b) >> 3) << 10)) + +// ---------------------------------------------------------- +// internal conversions X to 16 bits (555) +// ---------------------------------------------------------- + +void DLL_CALLCONV +FreeImage_ConvertLine1To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + int index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0; + + new_bits[cols] = RGB555(palette[index].rgbBlue, palette[index].rgbGreen, palette[index].rgbRed); + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine4To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + WORD *new_bits = (WORD *)target; + BOOL lonibble = FALSE; + int x = 0; + + for (int cols = 0; cols < width_in_pixels; cols++) { + RGBQUAD *grab_palette; + + if (lonibble) { + grab_palette = palette + LOWNIBBLE(source[x++]); + } else { + grab_palette = palette + (HINIBBLE(source[x]) >> 4); + } + + new_bits[cols] = RGB555(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed); + + lonibble = !lonibble; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine8To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + RGBQUAD *grab_palette = palette + source[cols]; + + new_bits[cols] = RGB555(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed); + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16_565_To16_555(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *src_bits = (WORD *)source; + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + new_bits[cols] = RGB555((((src_bits[cols] & 0x7C00) >> 10) * 0xFF) / 0x1F, + (((src_bits[cols] & 0x3E0) >> 5) * 0xFF) / 0x1F, + ((src_bits[cols] & 0x1F) * 0xFF) / 0x1F); + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine24To16_555(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + new_bits[cols] = RGB555(source[0], source[1], source[2]); + + source += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine32To16_555(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + new_bits[cols] = RGB555(source[0], source[1], source[2]); + + source += 4; + } +} + +// ---------------------------------------------------------- +// smart convert X to 16 bits +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_ConvertTo16Bits555(FIBITMAP *dib) { + if (dib != NULL) { + int width = FreeImage_GetWidth(dib); + int height = FreeImage_GetHeight(dib); + + switch (FreeImage_GetBPP(dib)) { + case 1 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x3E0, 0x7C00); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine1To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + break; + } + + case 4 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x3E0, 0x7C00); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine4To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + break; + } + + case 8 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x3E0, 0x7C00); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine8To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + break; + } + + case 16 : + { + + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x3E0, 0x7C00); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine16_565_To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + return new_dib; + } + + break; + } + + case 24 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x3E0, 0x7C00); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine24To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + return new_dib; + } + + break; + } + + case 32 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x3E0, 0x7C00); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine32To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + return new_dib; + } + + break; + } + } + } + + return NULL; +} diff --git a/freeimage241/Source/FreeImage/Conversion16_565.cpp b/freeimage241/Source/FreeImage/Conversion16_565.cpp new file mode 100644 index 0000000..6529c28 --- /dev/null +++ b/freeimage241/Source/FreeImage/Conversion16_565.cpp @@ -0,0 +1,214 @@ +// ========================================================== +// Bitmap conversion routines +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Jani Kajala (janik@remedy.fi) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- + +#define RGB565(r, g, b) (((r) >> 3) | (((g) >> 2) << 5) | (((b) >> 3) << 11)) + +// ---------------------------------------------------------- +// internal conversions X to 16 bits (565) +// ---------------------------------------------------------- + +void DLL_CALLCONV +FreeImage_ConvertLine1To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + int index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0; + + new_bits[cols] = RGB565(palette[index].rgbBlue, palette[index].rgbGreen, palette[index].rgbRed); + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine4To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + WORD *new_bits = (WORD *)target; + BOOL lonibble = FALSE; + int x = 0; + + for (int cols = 0; cols < width_in_pixels; cols++) { + RGBQUAD *grab_palette; + + if (lonibble) { + grab_palette = palette + LOWNIBBLE(source[x++]); + } else { + grab_palette = palette + (HINIBBLE(source[x]) >> 4); + } + + new_bits[cols] = RGB565(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed); + + lonibble = !lonibble; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine8To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + RGBQUAD *grab_palette = palette + source[cols]; + + new_bits[cols] = RGB565(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed); + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16_555_To16_565(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + RGBQUAD quad; + + quad.rgbBlue = (((source[cols] & 0xF800) >> 11) * 0xFF) / 0x1F; + quad.rgbGreen = (((source[cols] & 0x7E0) >> 5) * 0xFF) / 0x3F; + quad.rgbRed = ((source[cols] & 0x1F) * 0xFF) / 0x1F; + + new_bits[cols] = RGB565(quad.rgbBlue, quad.rgbGreen, quad.rgbRed); + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine24To16_565(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + new_bits[cols] = RGB565(source[0], source[1], source[2]); + + source += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine32To16_565(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *new_bits = (WORD *)target; + + for (int cols = 0; cols < width_in_pixels; cols++) { + new_bits[cols] = RGB565(source[0], source[1], source[2]); + + source += 4; + } +} + +// ---------------------------------------------------------- +// smart convert X to 16 bits (565) +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_ConvertTo16Bits565(FIBITMAP *dib) { + if (dib != NULL) { + int width = FreeImage_GetWidth(dib); + int height = FreeImage_GetHeight(dib); + + switch (FreeImage_GetBPP(dib)) { + case 1 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x7E0, 0xF800); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine1To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + break; + } + + case 4 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x7E0, 0xF800); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine4To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + break; + } + + case 8 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x7E0, 0xF800); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine8To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + break; + } + + case 16 : + { + + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x7E0, 0xF800); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine16_555_To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + return new_dib; + } + + break; + } + + case 24 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x7E0, 0xF800); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine24To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + return new_dib; + } + + break; + } + + case 32 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, 0x1F, 0x7E0, 0xF800); + + if (new_dib) { + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine32To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + return new_dib; + } + + break; + } + } + } + + return NULL; +} diff --git a/freeimage241/Source/FreeImage/Conversion24.cpp b/freeimage241/Source/FreeImage/Conversion24.cpp new file mode 100644 index 0000000..fad494a --- /dev/null +++ b/freeimage241/Source/FreeImage/Conversion24.cpp @@ -0,0 +1,193 @@ +// ========================================================== +// Bitmap conversion routines +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Dale Larson (dlarson@norsesoft.com) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Jani Kajala (janik@remedy.fi) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// internal conversions X to 24 bits +// ---------------------------------------------------------- + +void DLL_CALLCONV +FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + for (int cols = 0; cols < width_in_pixels; cols++) { + BYTE index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0; + + target[0] = palette[index].rgbBlue; + target[1] = palette[index].rgbGreen; + target[2] = palette[index].rgbRed; + + target += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + BOOL low_nibble = FALSE; + int x = 0; + + for (int cols = 0; cols < width_in_pixels; ++cols ) { + if (low_nibble) { + target[0] = palette[LOWNIBBLE(source[x])].rgbBlue; + target[1] = palette[LOWNIBBLE(source[x])].rgbGreen; + target[2] = palette[LOWNIBBLE(source[x])].rgbRed; + + x++; + } else { + target[0] = palette[HINIBBLE(source[x]) >> 4].rgbBlue; + target[1] = palette[HINIBBLE(source[x]) >> 4].rgbGreen; + target[2] = palette[HINIBBLE(source[x]) >> 4].rgbRed; + } + + low_nibble = !low_nibble; + + target += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + for (int cols = 0; cols < width_in_pixels; cols++) { + target[0] = palette[source[cols]].rgbBlue; + target[1] = palette[source[cols]].rgbGreen; + target[2] = palette[source[cols]].rgbRed; + + target += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *bits = (WORD *)source; + + for (int cols = 0; cols < width_in_pixels; cols++) { + target[2] = (((bits[cols] & 0x7C00) >> 10) * 0xFF) / 0x1F; + target[1] = (((bits[cols] & 0x3E0) >> 5) * 0xFF) / 0x1F; + target[0] = ((bits[cols] & 0x1F) * 0xFF) / 0x1F; + + target += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *bits = (WORD *)source; + + for (int cols = 0; cols < width_in_pixels; cols++) { + target[2] = (((bits[cols] & 0xF800) >> 11) * 0xFF) / 0x1F; + target[1] = (((bits[cols] & 0x7E0) >> 5) * 0xFF) / 0x3F; + target[0] = ((bits[cols] & 0x1F) * 0xFF) / 0x1F; + + target += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels) { + for (int cols = 0; cols < width_in_pixels; cols++) { + target[0] = source[0]; + target[1] = source[1]; + target[2] = source[2]; + + target += 3; + source += 4; + } +} + +// ---------------------------------------------------------- +// smart convert X to 24 bits +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_ConvertTo24Bits(FIBITMAP *dib) { + if (dib != NULL) { + int width = FreeImage_GetWidth(dib); + int height = FreeImage_GetHeight(dib); + + switch (FreeImage_GetBPP(dib)) { + case 1 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine1To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + case 4 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine4To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + case 8 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine8To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + case 16 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) { + for (int rows = 0; rows < height; rows++) { + if ((FreeImage_GetRedMask(dib) == 0x1F) && (FreeImage_GetGreenMask(dib) == 0x3E0) && (FreeImage_GetBlueMask(dib) == 0x7C00)) { + FreeImage_ConvertLine16To24_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } else { + FreeImage_ConvertLine16To24_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } + } + } + + return new_dib; + } + + case 32 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine32To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + return new_dib; + } + } + } + + return NULL; +} diff --git a/freeimage241/Source/FreeImage/Conversion32.cpp b/freeimage241/Source/FreeImage/Conversion32.cpp new file mode 100644 index 0000000..b7c45da --- /dev/null +++ b/freeimage241/Source/FreeImage/Conversion32.cpp @@ -0,0 +1,214 @@ +// ========================================================== +// Bitmap conversion routines +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Jani Kajala (janik@remedy.fi) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// internal conversions X to 32 bits +// ---------------------------------------------------------- + +void DLL_CALLCONV +FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + for (int cols = 0; cols < width_in_pixels; cols++) { + int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0; + + target[0] = palette[index].rgbBlue; + target[1] = palette[index].rgbGreen; + target[2] = palette[index].rgbRed; + + target += 4; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + BOOL low_nibble = FALSE; + int x = 0; + + for (int cols = 0 ; cols < width_in_pixels ; ++cols) { + if (low_nibble) { + target[0] = palette[LOWNIBBLE(source[x])].rgbBlue; + target[1] = palette[LOWNIBBLE(source[x])].rgbGreen; + target[2] = palette[LOWNIBBLE(source[x])].rgbRed; + + x++; + } else { + target[0] = palette[HINIBBLE(source[x]) >> 4].rgbBlue; + target[1] = palette[HINIBBLE(source[x]) >> 4].rgbGreen; + target[2] = palette[HINIBBLE(source[x]) >> 4].rgbRed; + } + + low_nibble = !low_nibble; + + target += 4; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { + for (int cols = 0; cols < width_in_pixels; cols++) { + target[0] = palette[source[cols]].rgbBlue; + target[1] = palette[source[cols]].rgbGreen; + target[2] = palette[source[cols]].rgbRed; + + target += 4; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *bits = (WORD *)source; + + for (int cols = 0; cols < width_in_pixels; cols++) { + target[2] = (((bits[cols] & 0x7C00) >> 10) * 0xFF) / 0x1F; + target[1] = (((bits[cols] & 0x3E0) >> 5) * 0xFF) / 0x1F; + target[0] = ((bits[cols] & 0x1F) * 0xFF) / 0x1F; + + target += 4; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *bits = (WORD *)source; + + for (int cols = 0; cols < width_in_pixels; cols++) { + target[2] = ((bits[cols] & 0xF800) >> 11) << 3; + target[1] = ((bits[cols] & 0x7E0) >> 5) << 2; + target[0] = (bits[cols] & 0x1F) << 3; + + target += 4; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) { + for (int cols = 0; cols < width_in_pixels; cols++) { +// *(DWORD *)target = *(DWORD *) source & 0x00FFFFFF; //this does an extra READ! + target[0]=source[0]; + target[1]=source[1]; + target[2]=source[2]; + target[3]=0; + target += 4; + source += 3; + } +} + +// ---------------------------------------------------------- + +static void DLL_CALLCONV +MapTransparentTableToAlpha(RGBQUAD *target, BYTE *source, BYTE *table, int transparent_pixels, int width_in_pixels) { + for (int cols = 0; cols < width_in_pixels; cols++) { + target[cols].rgbReserved = (source[cols] < transparent_pixels) ? table[source[cols]] : 255; + } +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_ConvertTo32Bits(FIBITMAP *dib) { + if (dib != NULL) { + int width = FreeImage_GetWidth(dib); + int height = FreeImage_GetHeight(dib); + + switch (FreeImage_GetBPP(dib)) { + case 1 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine1To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + return new_dib; + } + + case 4 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) { + for (int rows = 0; rows < height; rows++) { + FreeImage_ConvertLine4To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + if (FreeImage_IsTransparent(dib)) { + MapTransparentTableToAlpha((RGBQUAD *)FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), width); + } + } + + return new_dib; + } + } + + case 8 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) { + for (int rows = 0; rows < height; rows++) { + FreeImage_ConvertLine8To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); + + if (FreeImage_IsTransparent(dib)) { + MapTransparentTableToAlpha((RGBQUAD *)FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), width); + } + } + + return new_dib; + } + } + + case 16 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL) { + for (int rows = 0; rows < height; rows++) { + if ((FreeImage_GetRedMask(dib) == 0x1F) && (FreeImage_GetGreenMask(dib) == 0x3E0) && (FreeImage_GetBlueMask(dib) == 0x7C00)) { + FreeImage_ConvertLine16To32_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } else { + FreeImage_ConvertLine16To32_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } + } + } + + return new_dib; + } + + case 24 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + + if (new_dib != NULL){ + for (int rows = 0; rows < height; rows++){ + FreeImage_ConvertLine24To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } + } + + return new_dib; + } + } + } + + return NULL; +} diff --git a/freeimage241/Source/FreeImage/Conversion8.cpp b/freeimage241/Source/FreeImage/Conversion8.cpp new file mode 100644 index 0000000..b3196ef --- /dev/null +++ b/freeimage241/Source/FreeImage/Conversion8.cpp @@ -0,0 +1,245 @@ +// ========================================================== +// Bitmap conversion routines +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Jani Kajala (janik@remedy.fi) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" + +// ---------------------------------------------------------- + +#define GREY1(r,g,b) (BYTE)(((WORD)r*77 + (WORD)g*150 + (WORD)b*29) >> 8) // .299R + .587G + .114B +#define GREY2(r,g,b) (BYTE)(((WORD)r*169 + (WORD)g*256 + (WORD)b*87) >> 9) // .33R + 0.5G + .17B + +// ---------------------------------------------------------- +// internal conversions X to 8 bits +// ---------------------------------------------------------- + +void DLL_CALLCONV +FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels) { + for (int cols = 0; cols < width_in_pixels; cols++) + target[cols] = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0; +} + +void DLL_CALLCONV +FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels) { + int count_new = 0; + int count_org = 0; + BOOL hinibble = TRUE; + + while (count_new < width_in_pixels) { + if (hinibble) { + target[count_new] = (source[count_org] & 0xf0) >> 4; + } else { + target[count_new] = (source[count_org] & 0x0f); + + count_org++; + } + + hinibble = !hinibble; + + count_new++; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *bits = (WORD *)source; + + for (int cols = 0; cols < width_in_pixels; cols++) { + target[cols] = GREY1((((bits[cols] & 0x7C00) >> 10) * 0xFF) / 0x1F, + (((bits[cols] & 0x3E0) >> 5) * 0xFF) / 0x1F, + ((bits[cols] & 0x1F) * 0xFF) / 0x1F); + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels) { + WORD *bits = (WORD *)source; + + for (int cols = 0; cols < width_in_pixels; cols++) + target[cols] = GREY1((((bits[cols] & 0xF800) >> 11) * 0xFF) / 0x1F, + (((bits[cols] & 0x7E0) >> 5) * 0xFF) / 0x3F, + ((bits[cols] & 0x1F) * 0xFF) / 0x1F); +} + +void DLL_CALLCONV +FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels) { + for (int cols = 0; cols < width_in_pixels; cols++) { + target[cols] = GREY1(source[2], source[1], source[0]); + + source += 3; + } +} + +void DLL_CALLCONV +FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels) { + for (int cols = 0; cols < width_in_pixels; cols++) { + target[cols] = GREY1(source[2], source[1], source[0]); + + source += 4; + } +} + +// ---------------------------------------------------------- +// smart convert X to 8 bits +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_ConvertTo8Bits(FIBITMAP *dib) { + if(dib) { + int width = FreeImage_GetWidth(dib); + int height = FreeImage_GetHeight(dib); + + switch(FreeImage_GetBPP(dib)) { + case 1: + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8); + + if (new_dib != NULL) { + // Copy the palette + + RGBQUAD *new_pal = FreeImage_GetPalette(new_dib); + RGBQUAD *old_pal = FreeImage_GetPalette(dib); + + for (int i = 0; i < 2; i++) { + new_pal[i].rgbRed = old_pal[i].rgbRed; + new_pal[i].rgbGreen = old_pal[i].rgbGreen; + new_pal[i].rgbBlue = old_pal[i].rgbBlue; + } + + // Expand and copy the bitmap data + + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine1To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + + } + + return new_dib; + } + + case 4 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8); + + if (new_dib != NULL) { + // Copy the palette + + RGBQUAD *new_pal = FreeImage_GetPalette(new_dib); + RGBQUAD *old_pal = FreeImage_GetPalette(dib); + + for (int i = 0; i < 16; i++) { + new_pal[i].rgbRed = old_pal[i].rgbRed; + new_pal[i].rgbGreen = old_pal[i].rgbGreen; + new_pal[i].rgbBlue = old_pal[i].rgbBlue; + } + + // Expand and copy the bitmap data + + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine4To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } + + return new_dib; + } + + case 16 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8); + + if (new_dib != NULL) { + // Build a greyscale palette + + RGBQUAD *new_pal = FreeImage_GetPalette(new_dib); + + for (int i = 0; i < 256; i++) { + new_pal[i].rgbRed = i; + new_pal[i].rgbGreen = i; + new_pal[i].rgbBlue = i; + } + + // Expand and copy the bitmap data + + for (int rows = 0; rows < height; rows++) { + if ((FreeImage_GetRedMask(dib) == 0x1F) && (FreeImage_GetGreenMask(dib) == 0x3E0) && (FreeImage_GetBlueMask(dib) == 0x7C00)) { + FreeImage_ConvertLine16To8_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } else { + FreeImage_ConvertLine16To8_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } + } + + return new_dib; + } + + return NULL; + } + + case 24 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8); + + if (new_dib != NULL) { + // Build a greyscale palette + + RGBQUAD *new_pal = FreeImage_GetPalette(new_dib); + + for (int i = 0; i < 256; i++) { + new_pal[i].rgbRed = i; + new_pal[i].rgbGreen = i; + new_pal[i].rgbBlue = i; + } + + // Expand and copy the bitmap data + + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine24To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } + + return new_dib; + } + + case 32 : + { + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8); + + if (new_dib != NULL) { + // Build a greyscale palette + + RGBQUAD *new_pal = FreeImage_GetPalette(new_dib); + + for (int i = 0; i < 256; i++) { + new_pal[i].rgbRed = i; + new_pal[i].rgbGreen = i; + new_pal[i].rgbBlue = i; + } + + // Expand and copy the bitmap data + + for (int rows = 0; rows < height; rows++) + FreeImage_ConvertLine32To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); + } + + return new_dib; + } + } + } + + return NULL; +} diff --git a/freeimage241/Source/FreeImage/FreeImage.cpp b/freeimage241/Source/FreeImage/FreeImage.cpp new file mode 100644 index 0000000..b56ca59 --- /dev/null +++ b/freeimage241/Source/FreeImage/FreeImage.cpp @@ -0,0 +1,83 @@ +// ========================================================== +// FreeImage implementation +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifdef WIN32 +#include +#endif + +#include "FreeImage.h" + +//---------------------------------------------------------------------- + +static const char *s_version = "2.4.1"; +static const char *s_copyright = "This program uses FreeImage, an open source image library supporting all common bitmap formats. Get your free copy now from http://www.6ixsoft.com."; + +//---------------------------------------------------------------------- + +#ifdef WIN32 +#ifndef _LIB +BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH : + FreeImage_Initialise(FALSE); + break; + + case DLL_PROCESS_DETACH : + FreeImage_DeInitialise(); + break; + + case DLL_THREAD_ATTACH : + case DLL_THREAD_DETACH : + break; + } + + return TRUE; +} +#endif +#endif + +//---------------------------------------------------------------------- + +const char * DLL_CALLCONV +FreeImage_GetVersion() { + return s_version; +} + +const char * DLL_CALLCONV +FreeImage_GetCopyrightMessage() { + return s_copyright; +} + +//---------------------------------------------------------------------- + +FreeImage_OutputMessageFunction FreeImage_OutputMessageProc = NULL; + +void DLL_CALLCONV +FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf) { + FreeImage_OutputMessageProc = omf; +} + +void DLL_CALLCONV +FreeImage_OutputMessage(int fif, const char *message) { + if (FreeImage_OutputMessageProc != NULL) + FreeImage_OutputMessageProc((FREE_IMAGE_FORMAT)fif, message); +} diff --git a/freeimage241/Source/FreeImage/FreeImageIO.cpp b/freeimage241/Source/FreeImage/FreeImageIO.cpp new file mode 100644 index 0000000..d64d704 --- /dev/null +++ b/freeimage241/Source/FreeImage/FreeImageIO.cpp @@ -0,0 +1,56 @@ +// ========================================================== +// Input/Output functions +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include + +#include "FreeImageIO.h" + +// ---------------------------------------------------------- + +unsigned +_ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + return fread(buffer, size, count, (FILE *)handle); +} + +unsigned +_WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + return fwrite(buffer, size, count, (FILE *)handle); +} + +int +_SeekProc(fi_handle handle, long offset, int origin) { + return fseek((FILE *)handle, offset, origin); +} + +long +_TellProc(fi_handle handle) { + return ftell((FILE *)handle); +} + +// ---------------------------------------------------------- + +void +SetDefaultIO(FreeImageIO *io) { + io->read_proc = _ReadProc; + io->seek_proc = _SeekProc; + io->tell_proc = _TellProc; + io->write_proc = _WriteProc; +} diff --git a/freeimage241/Source/FreeImage/GetType.cpp b/freeimage241/Source/FreeImage/GetType.cpp new file mode 100644 index 0000000..dbada96 --- /dev/null +++ b/freeimage241/Source/FreeImage/GetType.cpp @@ -0,0 +1,74 @@ +// ========================================================== +// GetType +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include +#include + +#include "FreeImage.h" +#include "FreeImageIO.h" +#include "Plugin.h" + +// ---------------------------------------------------------- + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_GetFileType(const char *filename, int size) { + FreeImageIO io; + SetDefaultIO(&io); + + FILE *handle = fopen(filename, "rb"); + + if (handle != NULL) { + FREE_IMAGE_FORMAT format = FreeImage_GetFileTypeFromHandle(&io, (fi_handle)handle, size); + + fclose(handle); + + return format; + } else { + return FIF_UNKNOWN; + } +} + +// ---------------------------------------------------------- + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size) { + if (handle != NULL) { + for (int i = FreeImage_GetFIFCount() - 1; i >= 0; --i) { + if (FreeImage_Validate((FREE_IMAGE_FORMAT)i, *io, handle)) { + return (FREE_IMAGE_FORMAT)i; + } + } + } + + return FIF_UNKNOWN; +} + +// ALIASES FOR BACKWARDS COMPATIBILITY ---------------------- + +const char * DLL_CALLCONV +FreeImage_GetFileTypeFromFormat(FREE_IMAGE_FORMAT fif) { + return FreeImage_GetFormatFromFIF(fif); +} + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_GetFileTypeFromExt(const char *filename) { + return FreeImage_GetFIFFromFilename(filename); +} diff --git a/freeimage241/Source/FreeImage/LoadFunctions.cpp b/freeimage241/Source/FreeImage/LoadFunctions.cpp new file mode 100644 index 0000000..98dec3e --- /dev/null +++ b/freeimage241/Source/FreeImage/LoadFunctions.cpp @@ -0,0 +1,274 @@ +// ========================================================== +// Simplified load functions +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadBMP(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("BMP"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadBMPFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("BMP"), io, handle, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveBMP(FIBITMAP *dib, const char *filename, int flags) { + return FreeImage_Save(FreeImage_GetFIFFromFormat("BMP"), dib, filename, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveBMPToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_SaveToHandle(FreeImage_GetFIFFromFormat("BMP"), dib, io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadICO(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("ICO"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadICOFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("ICO"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadIFF(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("IFF"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadIFFFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("IFF"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadJPEG(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("JPEG"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadJPEGFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("JPEG"), io, handle, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveJPEG(FIBITMAP *dib, const char *filename, int flags) { + return FreeImage_Save(FreeImage_GetFIFFromFormat("JPEG"), dib, filename, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveJPEGToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_SaveToHandle(FreeImage_GetFIFFromFormat("JPEG"), dib, io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadKOALA(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("KOALA"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadKOALAFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("KOALA"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadLBM(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("IFF"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadLBMFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("IFF"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadMNG(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("MNG"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadMNGFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("MNG"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPCD(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("PCD"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPCDFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("PCD"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPCX(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("PCX"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPCXFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("PCX"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPNG(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("PNG"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPNGFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("PNG"), io, handle, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SavePNG(FIBITMAP *dib, const char *filename, int flags) { + return FreeImage_Save(FreeImage_GetFIFFromFormat("PNG"), dib, filename, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SavePNGToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_SaveToHandle(FreeImage_GetFIFFromFormat("PNG"), dib, io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPNM(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("PGM"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPNMFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("PGM"), io, handle, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SavePNM(FIBITMAP *dib, const char *filename, int flags) { + return FreeImage_Save(FreeImage_GetFIFFromFormat("PGM"), dib, filename, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SavePNMToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_SaveToHandle(FreeImage_GetFIFFromFormat("PGM"), dib, io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPSD(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("PSD"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadPSDFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("PSD"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadRAS(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("RAS"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadRASFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("RAS"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadTARGA(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("TARGA"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadTARGAFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("TARGA"), io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadTIFF(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("TIFF"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadTIFFFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("TIFF"), io, handle, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveTIFF(FIBITMAP *dib, const char *filename, int flags) { + return FreeImage_Save(FreeImage_GetFIFFromFormat("TIFF"), dib, filename, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveTIFFToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_SaveToHandle(FreeImage_GetFIFFromFormat("TIFF"), dib, io, handle, flags); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadWBMP(const char *filename, int flags) { + return FreeImage_Load(FreeImage_GetFIFFromFormat("WBMP"), filename, flags); +} + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadWBMPFromHandle(FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_LoadFromHandle(FreeImage_GetFIFFromFormat("WBMP"), io, handle, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveWBMP(FIBITMAP *dib, const char *filename, int flags) { + return FreeImage_Save(FreeImage_GetFIFFromFormat("WBMP"), dib, filename, flags); +} + +BOOL DLL_CALLCONV +FreeImage_SaveWBMPToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) { + return FreeImage_SaveToHandle(FreeImage_GetFIFFromFormat("WBMP"), dib, io, handle, flags); +} diff --git a/freeimage241/Source/FreeImage/Makefile b/freeimage241/Source/FreeImage/Makefile new file mode 100644 index 0000000..461dd59 --- /dev/null +++ b/freeimage241/Source/FreeImage/Makefile @@ -0,0 +1,43 @@ +include ../../Makefile.cfg + +INCLUDE = -I../ +CFLAGS = $(COMPILERFLAGS) $(INCLUDE) + +TARGET = freeimage +VER_MAJOR = 2 +VER_MINOR = 0.0 +MODULES = BitmapAccess.o Conversion.o Conversion16_555.o Conversion16_565.o \ + Conversion24.o Conversion32.o Conversion8.o FreeImage.o GetType.o Plugin.o \ + PluginBMP.o PluginICO.o PluginJPEG.o PluginKOALA.o PluginMNG.o PluginPCD.o \ + PluginPCX.o PluginPNG.o PluginPNM.o PluginRAS.o PluginTARGA.o PluginTIFF.o \ + PluginWBMP.o PluginLBM.o OldLoadFunctions.o NNQuantizer.o WuQuantizer.o Combine.o + +STATICLIB = lib$(TARGET).a +SHAREDLIB = lib$(TARGET)-$(VER_MAJOR).$(VER_MINOR).so +LIBNAME = lib$(TARGET).so.$(VER_MAJOR) + +all: default + +default: $(STATICLIB) $(SHAREDLIB) + +.c.o: + $(CC) $(CFLAGS) -c $< + +.cpp.o: + $(CPP) $(CFLAGS) -c $< + +$(STATICLIB): $(MODULES) + ar r $@ $? + +$(SHAREDLIB): $(MODULES) + $(CC) -s -shared -Wl,-soname,$(LIBNAME) -o $@ $? $(LIBRARIES) + ln -sf $(SHAREDLIB) $(LIBNAME) + +install: $(STATICLIB) $(SHAREDLIB) + install -m 644 -o root -g root $(STATICLIB) $(INSTALLDIR) + install -m 755 -o root -g root $(SHAREDLIB) $(INSTALLDIR) + ln -sf $(SHAREDLIB) $(INSTALLDIR)/$(LIBNAME) + ldconfig + +clean: + rm -f *.o core d2utmp* $(STATICLIB) $(SHAREDLIB) $(LIBNAME) diff --git a/freeimage241/Source/FreeImage/NNQuantizer.cpp b/freeimage241/Source/FreeImage/NNQuantizer.cpp new file mode 100644 index 0000000..7dcf930 --- /dev/null +++ b/freeimage241/Source/FreeImage/NNQuantizer.cpp @@ -0,0 +1,510 @@ +// NeuQuant Neural-Net Quantization Algorithm +// ------------------------------------------ +// +// Copyright (c) 1994 Anthony Dekker +// +// NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. +// See "Kohonen neural networks for optimal colour quantization" +// in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. +// for a discussion of the algorithm. +// +// Any party obtaining a copy of these files from the author, directly or +// indirectly, is granted, free of charge, a full and unrestricted irrevocable, +// world-wide, paid up, royalty-free, nonexclusive right and license to deal +// in this software and documentation files (the "Software"), including without +// limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons who receive +// copies from any such party to do so, with the only requirement being +// that this copyright notice remain intact. + +/////////////////////////////////////////////////////////////////////// +// History +// ------- +// January 2001: Adaptation of the Neural-Net Quantization Algorithm +// for the FreeImage 2 library +// Author: Hervé Drolon (drolon@infonie.fr) +/////////////////////////////////////////////////////////////////////// + +#include "FreeImage.h" + +const int netsize = 256; // number of colours used + + +// For 256 colours, fixed arrays need 8kb, plus space for the image +// ---------------------------------------------------------------- + + +// Four primes near 500 - assume no image has a length so large +// that it is divisible by all four primes +// ========================================================== + +#define prime1 499 +#define prime2 491 +#define prime3 487 +#define prime4 503 + +// Prototypes +// ========================================================== + +static void initnet(BYTE *thepic, DWORD len, int sample); +static void unbiasnet(); // can edit this function to do output of colour map +static void inxbuild(); +static int inxsearch(int b, int g, int r); +static int contest(int b, int g, int r); +static void altersingle(int alpha, int i, int b, int g, int r); +static void alterneigh(int rad, int i, int b, int g, int r); +static void learn(); + +// Network Definitions +// ========================================================== + +#define maxnetpos (netsize-1) +#define netbiasshift 4 // bias for colour values +#define ncycles 100 // no. of learning cycles + +// defs for freq and bias + +#define intbiasshift 16 // bias for fractions +#define intbias (((int) 1)<>betashift) // beta = 1 / 1024 +#define betagamma (intbias<<(gammashift-betashift)) + +// defs for decreasing radius factor + +#define initrad (netsize>>3) // for 256 cols, radius starts +#define radiusbiasshift 6 // at 32.0 biased by 6 bits +#define radiusbias (((int) 1)<>= netbiasshift; + } + network[i][3] = i; // record colour no + } +} + +////////////////////////////////////////////////////////////////////////////////// +// Insertion sort of network and building of netindex[0..255] (to do after unbias) +// ------------------------------------------------------------------------------- + +static void inxbuild() +{ + int i,j,smallpos,smallval; + int *p,*q; + int previouscol,startpos; + + previouscol = 0; + startpos = 0; + for (i = 0; i < netsize; i++) { + p = network[i]; + smallpos = i; + smallval = p[1]; // index on g + // find smallest in i..netsize-1 + for (j = i+1; j < netsize; j++) { + q = network[j]; + if (q[1] < smallval) { // index on g + smallpos = j; + smallval = q[1]; // index on g + } + } + q = network[smallpos]; + // swap p (i) and q (smallpos) entries + if (i != smallpos) { + j = q[0]; q[0] = p[0]; p[0] = j; + j = q[1]; q[1] = p[1]; p[1] = j; + j = q[2]; q[2] = p[2]; p[2] = j; + j = q[3]; q[3] = p[3]; p[3] = j; + } + // smallval entry is now in position i + if (smallval != previouscol) { + netindex[previouscol] = (startpos+i)>>1; + for (j = previouscol+1; j < smallval; j++) + netindex[j] = i; + previouscol = smallval; + startpos = i; + } + } + netindex[previouscol] = (startpos+maxnetpos)>>1; + for (j = previouscol+1; j < 256; j++) + netindex[j] = maxnetpos; // really 256 +} + +/////////////////////////////////////////////////////////////////////////////// +// Search for BGR values 0..255 (after net is unbiased) and return colour index +// ---------------------------------------------------------------------------- + +static int inxsearch(int b, int g, int r) +{ + int i, j, dist, a, bestd; + int *p; + int best; + + bestd = 1000; // biggest possible dist is 256*3 + best = -1; + i = netindex[g]; // index on g + j = i-1; // start at netindex[g] and work outwards + + while ((i < netsize) || (j >= 0)) { + if (i < netsize) { + p = network[i]; + dist = p[1] - g; // inx key + if (dist >= bestd) + i = netsize; // stop iter + else { + i++; + if (dist < 0) + dist = -dist; + a = p[0] - b; + if (a < 0) + a = -a; + dist += a; + if (dist < bestd) { + a = p[2] - r; + if (a<0) + a = -a; + dist += a; + if (dist < bestd) { + bestd = dist; + best = p[3]; + } + } + } + } + if (j >= 0) { + p = network[j]; + dist = g - p[1]; // inx key - reverse dif + if (dist >= bestd) + j = -1; // stop iter + else { + j--; + if (dist < 0) + dist = -dist; + a = p[0] - b; + if (a<0) + a = -a; + dist += a; + if (dist < bestd) { + a = p[2] - r; + if (a<0) + a = -a; + dist += a; + if (dist < bestd) { + bestd = dist; + best = p[3]; + } + } + } + } + } + return best; +} + +/////////////////////////////// +// Search for biased BGR values +// ---------------------------- + +static int contest(int b, int g, int r) +{ + // finds closest neuron (min dist) and updates freq + // finds best neuron (min dist-bias) and returns position + // for frequently chosen neurons, freq[i] is high and bias[i] is negative + // bias[i] = gamma*((1/netsize)-freq[i]) + + int i,dist,a,biasdist,betafreq; + int bestpos,bestbiaspos,bestd,bestbiasd; + int *p,*f, *n; + + bestd = ~(((int) 1)<<31); + bestbiasd = bestd; + bestpos = -1; + bestbiaspos = bestpos; + p = bias; + f = freq; + + for (i = 0; i < netsize; i++) { + n = network[i]; + dist = n[0] - b; + if (dist < 0) + dist = -dist; + a = n[1] - g; + if (a < 0) + a = -a; + dist += a; + a = n[2] - r; + if (a < 0) + a = -a; + dist += a; + if (dist < bestd) { + bestd = dist; + bestpos = i; + } + biasdist = dist - ((*p)>>(intbiasshift-netbiasshift)); + if (biasdist < bestbiasd) { + bestbiasd = biasdist; + bestbiaspos = i; + } + betafreq = (*f >> betashift); + *f++ -= betafreq; + *p++ += (betafreq << gammashift); + } + freq[bestpos] += beta; + bias[bestpos] -= betagamma; + return bestbiaspos; +} + +/////////////////////////////////////////////////////// +// Move neuron i towards biased (b,g,r) by factor alpha +// ---------------------------------------------------- + +static void altersingle(int alpha, int i, int b, int g, int r) +{ + int *n; + + n = network[i]; // alter hit neuron + *n -= (alpha * (*n - b)) / initalpha; + n++; + *n -= (alpha * (*n - g)) / initalpha; + n++; + *n -= (alpha * (*n - r)) / initalpha; +} + +//////////////////////////////////////////////////////////////////////////////////// +// Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|] +// --------------------------------------------------------------------------------- + +static void alterneigh(int rad, int i, int b, int g, int r) +{ + int j, k, lo, hi, a; + int *p, *q; + + lo = i - rad; if (lo < -1) lo = -1; + hi = i + rad; if (hi > netsize) hi = netsize; + + j = i+1; + k = i-1; + q = radpower; + while ((j < hi) || (k > lo)) { + a = (*(++q)); + if (j < hi) { + p = network[j]; + *p -= (a * (*p - b)) / alpharadbias; + p++; + *p -= (a * (*p - g)) / alpharadbias; + p++; + *p -= (a * (*p - r)) / alpharadbias; + j++; + } + if (k > lo) { + p = network[k]; + *p -= (a * (*p - b)) / alpharadbias; + p++; + *p -= (a * (*p - g)) / alpharadbias; + p++; + *p -= (a * (*p - r)) / alpharadbias; + k--; + } + } +} + +///////////////////// +// Main Learning Loop +// ------------------ + +static void learn() +{ + int i, j, b, g, r; + int radius, rad, alpha, step, delta, samplepixels; + int alphadec; // biased by 10 bits + BYTE *p; + BYTE *lim; + + alphadec = 30 + ((samplefac - 1) / 3); + p = thepicture; + lim = thepicture + lengthcount; + samplepixels = lengthcount / (3*samplefac); + delta = samplepixels / ncycles; + alpha = initalpha; + radius = initradius; + + rad = radius >> radiusbiasshift; + if (rad <= 1) rad = 0; + for (i = 0; i < rad; i++) + radpower[i] = alpha*(((rad*rad - i*i)*radbias)/(rad*rad)); + + if ((lengthcount % prime1) != 0) + step = 3*prime1; + else { + if ((lengthcount % prime2) != 0) + step = 3*prime2; + else { + if ((lengthcount % prime3) != 0) + step = 3*prime3; + else + step = 3*prime4; + } + } + + i = 0; + while (i < samplepixels) { + b = p[0] << netbiasshift; + g = p[1] << netbiasshift; + r = p[2] << netbiasshift; + j = contest(b,g,r); + + altersingle(alpha,j,b,g,r); + if (rad) alterneigh(rad,j,b,g,r); // alter neighbours + + p += step; + if (p >= lim) p -= lengthcount; + + i++; + if (i % delta == 0) { + alpha -= alpha / alphadec; + radius -= radius / radiusdec; + rad = radius >> radiusbiasshift; + if (rad <= 1) rad = 0; + for (j = 0; j < rad; j++) + radpower[j] = alpha * (((rad*rad - j*j) * radbias) / (rad*rad)); + } + } +} + +/////////////////////////// +// FreeImage implementation +// ------------------------ + +// Input parameters: +// - void* dib: DIB 24-bit to be quantized +// - int sampling: a sampling factor in range 1..30 +// 1 => slower, 30 => faster. Default value is 15 +// Return value: +// - NULL if the DIB is not valid or if it's not a 24-bit DIB +// - the quantized 8-bit (color palette) DIB otherwise + +FIBITMAP * +NNQuantizer(FIBITMAP *dib, int sampling) +{ + LONG width, height; + BYTE *dib_bits; // the input image itself + DWORD length; + + if ((!dib) || (FreeImage_GetBPP(dib) != 24)) { + return NULL; + } + + // 1) select a sampling factor in range 1..30 (input parameter 'sampling') + // 1 => slower, 30 => faster. Default value is 15 + + + // 2) Get DIB parameters + + width = FreeImage_GetWidth(dib); // DIB width + height = FreeImage_GetHeight(dib); // DIB height + dib_bits = FreeImage_GetBits(dib); // pointer to DIB pixels + length = 3L * width * height; // image size in bytes + + // 3) Initialize the network and apply the learning algorithm + + initnet(dib_bits, length, sampling); + learn(); + unbiasnet(); + + // 4) Allocate a new 8-bit DIB + + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8); + + if (new_dib == NULL) + return NULL; + + // 5) Write the quantized palette + + RGBQUAD *new_pal = FreeImage_GetPalette(new_dib); + + for (int j = 0; j < netsize; j++) { + new_pal[j].rgbBlue = (BYTE)network[j][0]; + new_pal[j].rgbGreen = (BYTE)network[j][1]; + new_pal[j].rgbRed = (BYTE)network[j][2]; + } + + inxbuild(); + + // 6) Write output image using inxsearch(b,g,r) + + for (WORD rows = 0; rows < height; rows++) { + BYTE *new_bits = FreeImage_GetScanLine(new_dib, rows); + BYTE *bits = FreeImage_GetScanLine(dib, rows); + + for (WORD cols = 0; cols < FreeImage_GetWidth(dib); cols++) { + new_bits[cols] = (BYTE)inxsearch(bits[0], bits[1], bits[2]); + + bits += 3; + } + } + + return (FIBITMAP*) new_dib; +} diff --git a/freeimage241/Source/FreeImage/Plugin.cpp b/freeimage241/Source/FreeImage/Plugin.cpp new file mode 100644 index 0000000..02cb47c --- /dev/null +++ b/freeimage241/Source/FreeImage/Plugin.cpp @@ -0,0 +1,713 @@ +// ===================================================================== +// FreeImage Plugin Interface +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Rui Lopes (ruiglopes@yahoo.com) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ================== =================================================== + +#ifdef WIN32 +#pragma warning (disable : 4786) +#include +#else +#include +#endif + +#include +#include +#include +#include +#include + +#include "FreeImage.h" +#include "FreeImageIO.h" +#include "Plugin.h" + +// ===================================================================== + +using namespace std; + +// ===================================================================== +// Plugin search list +// ===================================================================== + +const char * +s_search_list[] = { + "", + "plugins\\", +}; + +static int s_search_list_size = sizeof(s_search_list) / sizeof(char *); + +// ===================================================================== +// Reimplementation of stricmp (it is not supported on some systems) +// ===================================================================== + +int +FreeImage_stricmp(const char *s1, const char *s2) { + int c1, c2; + + do { + c1 = tolower(*s1++); + c2 = tolower(*s2++); + } while (c1 && c1 == c2); + + return c1 - c2; +} + +// ===================================================================== +// Declaration of the FreeImage function pointer structure +// ===================================================================== + +static FreeImage s_freeimage; + +// ===================================================================== +// Plugin Node +// ===================================================================== + +FI_STRUCT (PluginNode) { + int m_id; + void *m_instance; + Plugin *m_plugin; + PluginNode *m_next; + BOOL m_enabled; + + const char *m_format; + const char *m_description; + const char *m_extension; + const char *m_regexpr; +}; + +// ===================================================================== +// Internal Plugin List +// ===================================================================== + +class PluginList { +public : + PluginList(); + ~PluginList(); + + FREE_IMAGE_FORMAT AddNode(FI_InitProc proc, void *instance = NULL, const char *format = 0, const char *description = 0, const char *extension = 0, const char *regexpr = 0); + PluginNode *FindNodeFromFormat(const char *format); + PluginNode *FindNodeFromMime(const char *mime); + PluginNode *FindNodeFromFIF(int node_id); + + int Size() const; + BOOL IsEmpty() const; + +private : + map m_plugin_map; + int m_node_count; +}; + +// --------------------------------------------------------------------- + +PluginList::PluginList() : +m_plugin_map() { +} + +FREE_IMAGE_FORMAT +PluginList::AddNode(FI_InitProc init_proc, void *instance, const char *format, const char *description, const char *extension, const char *regexpr) { + if (init_proc != NULL) { + PluginNode *node = new PluginNode; + Plugin *plugin = new Plugin; + memset(plugin, 0, sizeof(Plugin)); + + // fill-in the plugin structure + + init_proc(*plugin, m_plugin_map.size()); + + // get the format string (two possible ways) + + const char *the_format = NULL; + + if (format != NULL) + the_format = format; + else if (plugin->format_proc != NULL) + the_format = plugin->format_proc(); + + // add the node if it wasn't there already + + if (the_format != NULL) { + if (FindNodeFromFormat(the_format) == NULL) { + node->m_id = m_plugin_map.size(); + node->m_instance = instance; + node->m_plugin = plugin; + node->m_format = format; + node->m_description = description; + node->m_extension = extension; + node->m_regexpr = regexpr; + node->m_next = NULL; + node->m_enabled = TRUE; + + m_plugin_map[m_plugin_map.size()] = node; + + return (FREE_IMAGE_FORMAT)node->m_id; + } + } + + // something went wrong while allocating the plugin... cleanup + + delete plugin; + delete node; + } + + return FIF_UNKNOWN; +} + +PluginNode * +PluginList::FindNodeFromFormat(const char *format) { + int count = 0; + + for (map::iterator i = m_plugin_map.begin(); i != m_plugin_map.end(); ++i) { + const char *the_format = ((*i).second->m_format != NULL) ? (*i).second->m_format : (*i).second->m_plugin->format_proc(); + + if (strcmp(the_format, format) == 0) + return (*i).second; + + count++; + } + + return NULL; +} + +PluginNode * +PluginList::FindNodeFromMime(const char *mime) { + int count = 0; + + for (map::iterator i = m_plugin_map.begin(); i != m_plugin_map.end(); ++i) { + const char *the_mime = ((*i).second->m_plugin->mime_proc != NULL) ? (*i).second->m_plugin->mime_proc() : ""; + + if (strcmp(the_mime, mime) == 0) + return (*i).second; + + count++; + } + + return NULL; +} + +PluginNode * +PluginList::FindNodeFromFIF(int node_id) { + map::iterator i = m_plugin_map.find(node_id); + + if (i != m_plugin_map.end()) + return (*i).second; + + return NULL; +} + +int +PluginList::Size() const { + return m_plugin_map.size(); +} + +BOOL +PluginList::IsEmpty() const { + return m_plugin_map.empty(); +} + +PluginList::~PluginList() { + for (map::iterator i = m_plugin_map.begin(); i != m_plugin_map.end(); ++i) { +#ifdef WIN32 + if ((*i).second->m_instance != NULL) + FreeLibrary((HINSTANCE)(*i).second->m_instance); +#endif + delete (*i).second->m_plugin; /*CORRECTED*/ + delete ((*i).second); + } +} + +// ===================================================================== +// Plugin System Initialization +// ===================================================================== + +static PluginList *s_plugins = NULL; +static int s_plugin_reference_count = 0; + +// --------------------------------------------------------------------- + +void DLL_CALLCONV +FreeImage_Initialise(BOOL load_local_plugins_only) { + if (s_plugin_reference_count++ == 0) { + // initialize the freeimage function pointer table + + s_freeimage.allocate_proc = FreeImage_Allocate; + s_freeimage.free_proc = FreeImage_Free; + s_freeimage.get_bits_proc = FreeImage_GetBits; + s_freeimage.get_bits_row_col_proc = FreeImage_GetBitsRowCol; + s_freeimage.get_blue_mask_proc = FreeImage_GetBlueMask; + s_freeimage.get_bpp_proc = FreeImage_GetBPP; + s_freeimage.get_color_type_proc = FreeImage_GetColorType; + s_freeimage.get_colors_used_proc = FreeImage_GetColorsUsed; + s_freeimage.get_dib_size_proc = FreeImage_GetDIBSize; + s_freeimage.get_dots_per_meter_x_proc = FreeImage_GetDotsPerMeterX; + s_freeimage.get_dots_per_meter_y_proc = FreeImage_GetDotsPerMeterY; + s_freeimage.get_green_mask_proc = FreeImage_GetGreenMask; + s_freeimage.get_height_proc = FreeImage_GetHeight; + s_freeimage.get_info_header_proc = FreeImage_GetInfoHeader; + s_freeimage.get_info_proc = FreeImage_GetInfo; + s_freeimage.get_line_proc = FreeImage_GetLine; + s_freeimage.get_palette_proc = FreeImage_GetPalette; + s_freeimage.get_pitch_proc = FreeImage_GetPitch; + s_freeimage.get_red_mask_proc = FreeImage_GetRedMask; + s_freeimage.get_scanline_proc = FreeImage_GetScanLine; + s_freeimage.get_transparency_count_proc = FreeImage_GetTransparencyCount; + s_freeimage.get_transparency_table_proc = FreeImage_GetTransparencyTable; + s_freeimage.get_width_proc = FreeImage_GetWidth; + s_freeimage.output_message_proc = FreeImage_OutputMessage; + s_freeimage.set_transparency_table_proc = FreeImage_SetTransparencyTable; + s_freeimage.is_transparent_proc = FreeImage_IsTransparent; + s_freeimage.set_transparent_proc = FreeImage_SetTransparent; + s_freeimage.unload_proc = FreeImage_Unload; + s_freeimage.convert_line1to8_proc = FreeImage_ConvertLine1To8; + s_freeimage.convert_line_4to8_proc = FreeImage_ConvertLine4To8; + s_freeimage.convert_line_16to8_555_proc = FreeImage_ConvertLine16To8_555; + s_freeimage.convert_line_16to8_565_proc = FreeImage_ConvertLine16To8_565; + s_freeimage.convert_line_24to8_proc = FreeImage_ConvertLine24To8; + s_freeimage.convert_line_32to8_proc = FreeImage_ConvertLine32To8; + s_freeimage.convert_line_1to16_555_proc = FreeImage_ConvertLine1To16_555; + s_freeimage.convert_line_4to16_555_proc = FreeImage_ConvertLine4To16_555; + s_freeimage.convert_line_8to16_555_proc = FreeImage_ConvertLine8To16_555; + s_freeimage.convert_line_16_565_to_16_555_proc = FreeImage_ConvertLine16_565_To16_555; + s_freeimage.convert_line_24to16_555_proc = FreeImage_ConvertLine24To16_555; + s_freeimage.convert_line_32to16_555_proc = FreeImage_ConvertLine32To16_555; + s_freeimage.convert_line_1to16_565_proc = FreeImage_ConvertLine1To16_565; + s_freeimage.convert_line_4to16_565_proc = FreeImage_ConvertLine4To16_565; + s_freeimage.convert_line_8to16_565_proc = FreeImage_ConvertLine8To16_565; + s_freeimage.convert_line_16_555_to_16_565_proc = FreeImage_ConvertLine16_555_To16_565; + s_freeimage.convert_line_24to16_565_proc = FreeImage_ConvertLine24To16_565; + s_freeimage.convert_line_32to16_565_proc = FreeImage_ConvertLine32To16_565; + s_freeimage.convert_line_1to24_proc = FreeImage_ConvertLine1To24; + s_freeimage.convert_line_4to24_proc = FreeImage_ConvertLine4To24; + s_freeimage.convert_line_8to24_proc = FreeImage_ConvertLine8To24; + s_freeimage.convert_line_16to24_555_proc = FreeImage_ConvertLine16To24_555; + s_freeimage.convert_line_16to24_565_proc = FreeImage_ConvertLine16To24_565; + s_freeimage.convert_line_32to24_proc = FreeImage_ConvertLine32To24; + s_freeimage.convert_line_1to32_proc = FreeImage_ConvertLine1To32; + s_freeimage.convert_line_4to32_proc = FreeImage_ConvertLine4To32; + s_freeimage.convert_line_8to32_proc = FreeImage_ConvertLine8To32; + s_freeimage.convert_line_16to32_555_proc = FreeImage_ConvertLine16To32_555; + s_freeimage.convert_line_16to32_565_proc = FreeImage_ConvertLine16To32_565; + s_freeimage.convert_line_24to32_proc = FreeImage_ConvertLine24To32; + + // internal plugin initialization + + s_plugins = new PluginList; + + s_plugins->AddNode(InitBMP); +// s_plugins->AddNode(InitICO); + s_plugins->AddNode(InitJPEG); +// s_plugins->AddNode(InitMNG, NULL, "JNG", "JPEG Network Graphics", "jng", ""); +// s_plugins->AddNode(InitKOALA); + s_plugins->AddNode(InitIFF); +// s_plugins->AddNode(InitMNG); +// s_plugins->AddNode(InitPNM, NULL, "PBM", "Portable Bitmap (ASCII)", "pbm", "^P1"); +// s_plugins->AddNode(InitPNM, NULL, "PBMRAW", "Portable Bitmap (RAW)", "pbm", "^P4"); +// s_plugins->AddNode(InitPCD); + s_plugins->AddNode(InitPCX); +// s_plugins->AddNode(InitPNM, NULL, "PGM", "Portable Greymap (ASCII)", "pgm", "^P2"); +// s_plugins->AddNode(InitPNM, NULL, "PGMRAW", "Portable Greymap (RAW)", "pgm", "^P5"); + s_plugins->AddNode(InitPNG); +// s_plugins->AddNode(InitPNM, NULL, "PPM", "Portable Pixelmap (ASCII)", "ppm", "^P3"); +// s_plugins->AddNode(InitPNM, NULL, "PPMRAW", "Portable Pixelmap (RAW)", "ppm", "^P6"); +// s_plugins->AddNode(InitRAS); + s_plugins->AddNode(InitTARGA); +// s_plugins->AddNode(InitTIFF); +// s_plugins->AddNode(InitWBMP); +// s_plugins->AddNode(InitPSD); + + // external plugin initialization + +#ifdef WIN32 + if (!load_local_plugins_only) { + int count = 0; + char buffer[MAX_PATH + 200]; + + while (count < s_search_list_size) { + _finddata_t find_data; + long find_handle; + + strcpy(buffer, s_search_list[count]); + strcat(buffer, "*.fip"); + + if ((find_handle= _findfirst(buffer, &find_data)) != -1L) { + do { + strcpy(buffer, s_search_list[count]); + strncat(buffer, find_data.name, MAX_PATH + 200); + + HINSTANCE instance = LoadLibrary(buffer); + + if (instance != NULL) { + FARPROC proc_address = GetProcAddress(instance, "_Init@8"); + + if (proc_address != NULL) + s_plugins->AddNode((FI_InitProc)proc_address, (void *)instance); + else + FreeLibrary(instance); + } + } while (_findnext(find_handle, &find_data) != -1L); + + _findclose(find_handle); + } + + count++; + } + } +#endif + } +} + +void DLL_CALLCONV +FreeImage_DeInitialise() { + --s_plugin_reference_count; + + if (s_plugin_reference_count == 0) + delete s_plugins; +} + +// ===================================================================== +// Plugin System Load/Save Functions +// ===================================================================== + +FIBITMAP * DLL_CALLCONV +FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags) { + if ((fif >= 0) && (fif < FreeImage_GetFIFCount())) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + if (node != NULL) { + if (node->m_enabled) { + FIBITMAP *bitmap = NULL; + + if (node->m_plugin->open_proc != NULL) { + void *data = node->m_plugin->open_proc(*io, handle, TRUE); + + bitmap = node->m_plugin->load_proc(s_freeimage, *io, handle, -1, flags, data); + + if (node->m_plugin->close_proc != NULL) + node->m_plugin->close_proc(*io, handle, data); + + return bitmap; + } else { + return node->m_plugin->load_proc(s_freeimage, *io, handle, -1, flags, NULL); + } + } + } + } + + return NULL; +} + +FIBITMAP * DLL_CALLCONV +FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags) { + FreeImageIO io; + SetDefaultIO(&io); + + FILE *handle = fopen(filename, "rb"); + + if (handle) { + FIBITMAP *bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)handle, flags); + + fclose(handle); + + return bitmap; + } + + return NULL; +} + +BOOL DLL_CALLCONV +FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) { + if ((fif >= 0) && (fif < FreeImage_GetFIFCount())) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + if (node != NULL) { + if (node->m_enabled) { + BOOL result = FALSE; + + if (node->m_plugin->open_proc != NULL) { + void *data = node->m_plugin->open_proc(*io, handle, FALSE); + + result = node->m_plugin->save_proc(s_freeimage, *io, dib, handle, -1, flags, data); + + if (node->m_plugin->close_proc != NULL) + node->m_plugin->close_proc(*io, handle, data); + } else { + result = node->m_plugin->save_proc(s_freeimage, *io, dib, handle, -1, flags, NULL); + } + + return result; + } + } + } + + return NULL; +} + + +BOOL DLL_CALLCONV +FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags) { + FreeImageIO io; + SetDefaultIO(&io); + + FILE *handle = fopen(filename, "wb"); + + if (handle) { + BOOL success = FreeImage_SaveToHandle(fif, dib, &io, (fi_handle)handle, flags); + + fclose(handle); + + return success; + } + + return FALSE; +} + +// ===================================================================== +// Plugin Creation / Enabling Functions +// ===================================================================== + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_RegisterLocalPlugin(FI_InitProc proc_address, const char *format, const char *description, const char *extension, const char *regexpr) { + return s_plugins->AddNode(proc_address, NULL, format, description, extension, regexpr); +} + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_RegisterExternalPlugin(const char *path, const char *format, const char *description, const char *extension, const char *regexpr) { + if (path != NULL) { + HINSTANCE instance = LoadLibrary(path); + + if (instance != NULL) { + FARPROC proc_address = GetProcAddress(instance, "_Init@8"); + + FREE_IMAGE_FORMAT result = s_plugins->AddNode((FI_InitProc)proc_address, (void *)instance, format, description, extension, regexpr); + + if (result == FIF_UNKNOWN) + FreeLibrary(instance); + + return result; + } + } + + return FIF_UNKNOWN; +} + +int DLL_CALLCONV +FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif, BOOL enable) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + if (node != NULL) { + BOOL previous_state = node->m_enabled; + + node->m_enabled = enable; + + return previous_state; + } + } + + return -1; +} + +int DLL_CALLCONV +FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + return (node != NULL) ? node->m_enabled : FALSE; + } + + return -1; +} + +// ===================================================================== +// Plugin Access Functions +// ===================================================================== + +int DLL_CALLCONV +FreeImage_GetFIFCount() { + return (s_plugins != NULL) ? s_plugins->Size() : 0; +} + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_GetFIFFromFormat(const char *format) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFormat(format); + + return (node != NULL) ? (node->m_enabled) ? (FREE_IMAGE_FORMAT)node->m_id : FIF_UNKNOWN : FIF_UNKNOWN; + } + + return FIF_UNKNOWN; +} + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_GetFIFFromMime(const char *mime) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromMime(mime); + + return (node != NULL) ? (node->m_enabled) ? (FREE_IMAGE_FORMAT)node->m_id : FIF_UNKNOWN : FIF_UNKNOWN; + } + + return FIF_UNKNOWN; +} + +const char * DLL_CALLCONV +FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + return (node != NULL) ? (node->m_format != NULL) ? node->m_format : node->m_plugin->format_proc() : NULL; + } + + return NULL; +} + +const char * DLL_CALLCONV +FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + return (node != NULL) ? (node->m_extension != NULL) ? node->m_extension : (node->m_plugin->extension_proc != NULL) ? node->m_plugin->extension_proc() : NULL : NULL; + } + + return NULL; +} + +const char * DLL_CALLCONV +FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + return (node != NULL) ? (node->m_description != NULL) ? node->m_description : (node->m_plugin->description_proc != NULL) ? node->m_plugin->description_proc() : NULL : NULL; + } + + return NULL; +} + +const char * DLL_CALLCONV +FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + return (node != NULL) ? (node->m_regexpr != NULL) ? node->m_regexpr : (node->m_plugin->regexpr_proc != NULL) ? node->m_plugin->regexpr_proc() : NULL : NULL; + } + + return NULL; +} + +BOOL DLL_CALLCONV +FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + return (node != NULL) ? (node->m_enabled) ? node->m_plugin->load_proc != NULL : FALSE : FALSE; + } + + return FALSE; +} + +BOOL DLL_CALLCONV +FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif) { + if (s_plugins != NULL) { + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + return (node != NULL) ? (node->m_enabled) ? node->m_plugin->save_proc != NULL : FALSE : FALSE; + } + + return FALSE; +} + +FREE_IMAGE_FORMAT DLL_CALLCONV +FreeImage_GetFIFFromFilename(const char *filename) { + if (filename != NULL) { + const char *extension; + + // get the proper extension if we received a filename + + char *place = strrchr((char *)filename, '.'); + + if (place != NULL) + extension = ++place; + else + extension = filename; + + // look for the extension in the plugin table + + for (int i = 0; i < FreeImage_GetFIFCount(); ++i) { + // compare the format id with the extension + + if (FreeImage_stricmp(FreeImage_GetFormatFromFIF((FREE_IMAGE_FORMAT)i), extension) == 0) { + if (s_plugins->FindNodeFromFIF(i)->m_enabled) { + return (FREE_IMAGE_FORMAT)i; + } else { + return FIF_UNKNOWN; + } + } else { + // make a copy of the extension list and split it + + char *copy = (char *)malloc(strlen(FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i)) + 1); + memset(copy, 0, strlen(FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i)) + 1); + memcpy(copy, FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i), strlen(FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i))); + + // get the first token + + char *token = strtok(copy, ","); + + while (token != NULL) { + if (FreeImage_stricmp(token, extension) == 0) { + free(copy); + + if (s_plugins->FindNodeFromFIF(i)->m_enabled) { + return (FREE_IMAGE_FORMAT)i; + } else { + return FIF_UNKNOWN; + } + } + + token = strtok(NULL, ","); + } + + // free the copy of the extension list + + free(copy); + } + } + } + + return FIF_UNKNOWN; +} + +BOOL DLL_CALLCONV +FreeImage_Validate(FREE_IMAGE_FORMAT fif, FreeImageIO &io, fi_handle handle) { + if (s_plugins != NULL) { + BOOL validated = FALSE; + + PluginNode *node = s_plugins->FindNodeFromFIF(fif); + + if (node) { + long tell = io.tell_proc(handle); + + validated = (node != NULL) ? (node->m_enabled) ? (node->m_plugin->validate_proc != NULL) ? node->m_plugin->validate_proc(io, handle) : FALSE : FALSE : FALSE; + + io.seek_proc(handle, tell, SEEK_SET); + } + + return validated; + } + + return FALSE; +} diff --git a/freeimage241/Source/FreeImage/PluginBMP.cpp b/freeimage241/Source/FreeImage/PluginBMP.cpp new file mode 100644 index 0000000..13979f2 --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginBMP.cpp @@ -0,0 +1,1031 @@ + // ========================================================== +// BMP Loader and Writer +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Markus Loibl (markus.loibl@epost.de) +// - Martin Weber (martweb@gmx.net) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +const RLE_COMMAND = 0; +const RLE_ENDOFLINE = 0; +const RLE_ENDOFBITMAP = 1; +const RLE_DELTA = 2; + +#define BI_RGB 0L +#define BI_RLE8 1L +#define BI_RLE4 2L +#define BI_BITFIELDS 3L + +// ---------------------------------------------------------- + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct tagBITMAPCOREHEADER { + DWORD bcSize; + WORD bcWidth; + WORD bcHeight; + WORD bcPlanes; + WORD bcBitCnt; +} BITMAPCOREHEADER, *PBITMAPCOREHEADER; + +typedef struct tagBITMAPINFOOS2_1X_HEADER { + DWORD biSize; + WORD biWidth; + WORD biHeight; + WORD biPlanes; + WORD biBitCount; +} BITMAPINFOOS2_1X_HEADER, *PBITMAPINFOOS2_1X_HEADER; + +typedef struct tagBITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +} BITMAPFILEHEADER, *PBITMAPFILEHEADER; + +typedef struct tagRGBTRIPLE { + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; +} RGBTRIPLE; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Internal functions +// ========================================================== + +static FIBITMAP * +LoadWindowsBMP(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { + FIBITMAP *dib; + + try { + // load the info header + + BITMAPINFOHEADER bih; + + io.read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle); + + // keep some general information about the bitmap + + int used_colors = bih.biClrUsed; + int width = bih.biWidth; + int height = bih.biHeight; + int bit_count = bih.biBitCount; + int compression = bih.biCompression; + int pitch = CalculatePitch(CalculateLine(width, bit_count)); + + switch (bit_count) { + case 1 : + case 4 : + case 8 : + { + if ((used_colors <= 0) || (used_colors > CalculateUsedColors(bit_count))) + used_colors = CalculateUsedColors(bit_count); + + // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette + + dib = freeimage.allocate_proc(width, height, bit_count); + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; + pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; + + // load the palette + + io.read_proc(freeimage.get_palette_proc(dib), used_colors * sizeof(RGBQUAD), 1, handle); + + // seek to the actual pixel data. + // this is needed because sometimes the palette is larger than the entries it contains predicts + + if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * sizeof(RGBQUAD)))) + io.seek_proc(handle, bitmap_bits_offset, SEEK_SET); + + // read the pixel data + + switch (compression) { + case BI_RGB : + if (height > 0) { + io.read_proc((void *)freeimage.get_bits_proc(dib), height * pitch, 1, handle); + } else { + for (int c = 0; c < abs(height); ++c) { + io.read_proc((void *)freeimage.get_scanline_proc(dib, height - c - 1), pitch, 1, handle); + } + } + + return dib; + + case BI_RLE4 : + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + BOOL low_nibble = FALSE; + + for (;;) { + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_COMMAND : + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + low_nibble = FALSE; + break; + + case RLE_ENDOFBITMAP : + return (FIBITMAP *)dib; + + case RLE_DELTA : + { + // read the delta values + + BYTE delta_x; + BYTE delta_y; + + io.read_proc(&delta_x, sizeof(BYTE), 1, handle); + io.read_proc(&delta_y, sizeof(BYTE), 1, handle); + + // apply them + + bits += delta_x / 2; + scanline += delta_y; + break; + } + + default : + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + BYTE *sline = freeimage.get_scanline_proc(dib, scanline); + + for (int i = 0; i < status_byte; i++) { + if (low_nibble) { + *(sline + bits) |= LOWNIBBLE(second_byte); + + if (i != status_byte - 1) + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + bits++; + } else { + *(sline + bits) |= HINIBBLE(second_byte); + } + + low_nibble = !low_nibble; + } + + if (((status_byte / 2) & 1 )== 1) + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + break; + }; + + break; + + default : + { + BYTE *sline = freeimage.get_scanline_proc(dib, scanline); + + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + for (unsigned i = 0; i < status_byte; i++) { + if (low_nibble) { + *(sline + bits) |= LOWNIBBLE(second_byte); + + bits++; + } else { + *(sline + bits) |= HINIBBLE(second_byte); + } + + low_nibble = !low_nibble; + } + } + + break; + }; + } + + break; + } + + case BI_RLE8 : + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + + for (;;) { + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_COMMAND : + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + break; + + case RLE_ENDOFBITMAP : + return (FIBITMAP *)dib; + + case RLE_DELTA : + { + // read the delta values + + BYTE delta_x; + BYTE delta_y; + + io.read_proc(&delta_x, sizeof(BYTE), 1, handle); + io.read_proc(&delta_y, sizeof(BYTE), 1, handle); + + // apply them + + bits += delta_x; + scanline += delta_y; + break; + } + + default : + io.read_proc((void *)(freeimage.get_scanline_proc(dib, scanline) + bits), sizeof(BYTE) * status_byte, 1, handle); + + // align run length to even number of bytes + + if ((status_byte & 1) == 1) + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + bits += status_byte; + + break; + }; + + break; + + default : + BYTE *sline = freeimage.get_scanline_proc(dib, scanline); + + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + for (unsigned i = 0; i < status_byte; i++) { + *(sline + bits) = second_byte; + + bits++; + } + + break; + }; + } + + break; + } + + default : + throw "compression type not supported"; + } + + break; + } + + case 16 : + { + if (bih.biCompression == BI_BITFIELDS) { + DWORD bitfields[3]; + + io.read_proc(bitfields, 3 * sizeof(DWORD), 1, handle); + + dib = freeimage.allocate_proc(width, height, bit_count, bitfields[2], bitfields[1], bitfields[0]); + } else { + dib = freeimage.allocate_proc(width, height, bit_count, 0x1F, 0x3E0, 0x7C00); + } + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; + pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; + + io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); + + return dib; + } + + case 24 : + case 32 : + { + if (bih.biCompression == BI_BITFIELDS) { + throw "bitfields in 32-bit BMPs are currently unsupported"; + } else { + dib = freeimage.allocate_proc(width, height, bit_count, 0xFF, 0xFF00, 0xFF0000); + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; + pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; + + // Skip over the optional palette + // A 24 or 32 bit DIB may contain a palette for faster color reduction + + if (pInfoHeader->biClrUsed > 0) + io.seek_proc(handle, pInfoHeader->biClrUsed * sizeof(RGBQUAD), SEEK_CUR); + + // read in the bitmap bits + + io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); + + // check if the bitmap contains transparency, if so enable it in the header + + freeimage.set_transparent_proc(dib, (freeimage.get_color_type_proc(dib) == FIC_RGBALPHA)); + + return dib; + } + } + } + } catch(const char *message) { + freeimage.output_message_proc(s_format_id, message); + } + + return NULL; +} + +static FIBITMAP * +LoadOS22XBMP(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { + FIBITMAP *dib = NULL; + + try { + // load the info header + + BITMAPINFOHEADER bih; + + io.read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle); + + // keep some general information about the bitmap + + int used_colors = bih.biClrUsed; + int width = bih.biWidth; + int height = bih.biHeight; + int bit_count = bih.biBitCount; + int compression = bih.biCompression; + int pitch = CalculatePitch(CalculateLine(width, bit_count)); + + switch (bit_count) { + case 1 : + case 4 : + case 8 : + { + if ((used_colors <= 0) || (used_colors > CalculateUsedColors(bit_count))) + used_colors = CalculateUsedColors(bit_count); + + // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette + + dib = freeimage.allocate_proc(width, height, bit_count); + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; + pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; + + // load the palette + + io.seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET); + + RGBQUAD *pal = freeimage.get_palette_proc(dib); + + for (int count = 0; count < used_colors; count++) { + RGBTRIPLE triple; + + io.read_proc(&triple, sizeof(RGBTRIPLE), 1, handle); + + pal[count].rgbRed = triple.rgbtRed; + pal[count].rgbGreen = triple.rgbtGreen; + pal[count].rgbBlue = triple.rgbtBlue; + } + + // seek to the actual pixel data. + // this is needed because sometimes the palette is larger than the entries it contains predicts + + if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) + io.seek_proc(handle, bitmap_bits_offset, SEEK_SET); + + // read the pixel data + + switch (compression) { + case BI_RGB : + if (height > 0) { + io.read_proc((void *)freeimage.get_bits_proc(dib), height * pitch, 1, handle); + } else { + for (int c = 0; c < abs(height); ++c) { + io.read_proc((void *)freeimage.get_scanline_proc(dib, height - c - 1), pitch, 1, handle); + } + } + + return dib; + + case BI_RLE4 : + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + BOOL low_nibble = FALSE; + + for (;;) { + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_COMMAND : + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + low_nibble = FALSE; + break; + + case RLE_ENDOFBITMAP : + return (FIBITMAP *)dib; + + case RLE_DELTA : + { + // read the delta values + + BYTE delta_x; + BYTE delta_y; + + io.read_proc(&delta_x, sizeof(BYTE), 1, handle); + io.read_proc(&delta_y, sizeof(BYTE), 1, handle); + + // apply them + + bits += delta_x / 2; + scanline += delta_y; + break; + } + + default : + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + BYTE *sline = freeimage.get_scanline_proc(dib, scanline); + + for (int i = 0; i < status_byte; i++) { + if (low_nibble) { + *(sline + bits) |= LOWNIBBLE(second_byte); + + if (i != status_byte - 1) + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + bits++; + } else { + *(sline + bits) |= HINIBBLE(second_byte); + } + + low_nibble = !low_nibble; + } + + if (((status_byte / 2) & 1 ) == 1) + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + break; + }; + + break; + + default : + { + BYTE *sline = freeimage.get_scanline_proc(dib, scanline); + + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + for (unsigned i = 0; i < status_byte; i++) { + if (low_nibble) { + *(sline + bits) |= LOWNIBBLE(second_byte); + + bits++; + } else { + *(sline + bits) |= HINIBBLE(second_byte); + } + + low_nibble = !low_nibble; + } + } + + break; + }; + } + + break; + } + + case BI_RLE8 : + { + BYTE status_byte = 0; + BYTE second_byte = 0; + int scanline = 0; + int bits = 0; + + for (;;) { + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_COMMAND : + io.read_proc(&status_byte, sizeof(BYTE), 1, handle); + + switch (status_byte) { + case RLE_ENDOFLINE : + bits = 0; + scanline++; + break; + + case RLE_ENDOFBITMAP : + return (FIBITMAP *)dib; + + case RLE_DELTA : + { + // read the delta values + + BYTE delta_x; + BYTE delta_y; + + io.read_proc(&delta_x, sizeof(BYTE), 1, handle); + io.read_proc(&delta_y, sizeof(BYTE), 1, handle); + + // apply them + + bits += delta_x; + scanline += delta_y; + break; + } + + default : + io.read_proc((void *)(freeimage.get_scanline_proc(dib, scanline) + bits), sizeof(BYTE) * status_byte, 1, handle); + + // align run length to even number of bytes + + if (status_byte & 1 == 1) + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + bits += status_byte; + + break; + }; + + break; + + default : + BYTE *sline = freeimage.get_scanline_proc(dib, scanline); + + io.read_proc(&second_byte, sizeof(BYTE), 1, handle); + + for (unsigned i = 0; i < status_byte; i++) { + *(sline + bits) = second_byte; + + bits++; + } + + break; + }; + } + + break; + } + + default : + throw "compression type not supported"; + } + + break; + } + + case 16 : + { + if (bih.biCompression == 3) { + DWORD bitfields[3]; + + io.read_proc(bitfields, 3 * sizeof(DWORD), 1, handle); + + dib = freeimage.allocate_proc(width, height, bit_count, bitfields[2], bitfields[1], bitfields[0]); + } else { + dib = freeimage.allocate_proc(width, height, bit_count, 0x1F, 0x3E0, 0x7C00); + } + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; + pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; + + if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) + io.seek_proc(handle, bitmap_bits_offset, SEEK_SET); + + io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); + + return dib; + } + + case 24 : + case 32 : + { + dib = freeimage.allocate_proc(width, height, bit_count, 0xFF, 0xFF00, 0xFF0000); + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = bih.biXPelsPerMeter; + pInfoHeader->biYPelsPerMeter = bih.biYPelsPerMeter; + + // Skip over the optional palette + // A 24 or 32 bit DIB may contain a palette for faster color reduction + + if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) + io.seek_proc(handle, bitmap_bits_offset, SEEK_SET); + + // read in the bitmap bits + + io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); + + // check if the bitmap contains transparency, if so enable it in the header + + if (freeimage.get_color_type_proc(dib) == FIC_RGBALPHA) + freeimage.set_transparent_proc(dib, TRUE); + else + freeimage.set_transparent_proc(dib, FALSE); + + return dib; + } + } + } catch(const char *message) { + freeimage.output_message_proc(s_format_id, message); + } + + return NULL; +} + +static FIBITMAP * +LoadOS21XBMP(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int flags, unsigned bitmap_bits_offset) { + FIBITMAP *dib = NULL; + + try { + BITMAPINFOOS2_1X_HEADER bios2_1x; + + io.read_proc(&bios2_1x, sizeof(BITMAPINFOOS2_1X_HEADER), 1, handle); + + // keep some general information about the bitmap + + int used_colors = 0; + int width = bios2_1x.biWidth; + int height = bios2_1x.biHeight; + int bit_count = bios2_1x.biBitCount; + int compression = 0; + int pitch = CalculatePitch(CalculateLine(width, bit_count)); + + switch (bit_count) { + case 1 : + case 4 : + case 8 : + { + used_colors = CalculateUsedColors(bit_count); + + // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette + + dib = freeimage.allocate_proc(width, height, bit_count); + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = 0; + pInfoHeader->biYPelsPerMeter = 0; + + // load the palette + + RGBQUAD *pal = freeimage.get_palette_proc(dib); + + for (int count = 0; count < used_colors; count++) { + RGBTRIPLE triple; + + io.read_proc(&triple, sizeof(RGBTRIPLE), 1, handle); + + pal[count].rgbRed = triple.rgbtRed; + pal[count].rgbGreen = triple.rgbtGreen; + pal[count].rgbBlue = triple.rgbtBlue; + } + + // Skip over the optional palette + // A 24 or 32 bit DIB may contain a palette for faster color reduction + + io.seek_proc(handle, bitmap_bits_offset, SEEK_SET); + + // read the pixel data + + if (height > 0) { + io.read_proc((void *)freeimage.get_bits_proc(dib), height * pitch, 1, handle); + } else { + for (int c = 0; c < abs(height); ++c) { + io.read_proc((void *)freeimage.get_scanline_proc(dib, height - c - 1), pitch, 1, handle); + } + } + + return dib; + } + + case 16 : + { + dib = freeimage.allocate_proc(width, height, bit_count, 0x1F, 0x3E0, 0x7C00); + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = 0; + pInfoHeader->biYPelsPerMeter = 0; + + io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); + + return dib; + } + + case 24 : + case 32 : + { + dib = freeimage.allocate_proc(width, height, bit_count, 0xFF, 0xFF00, 0xFF0000); + + if (dib == NULL) + throw "DIB allocation failed"; + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = 0; + pInfoHeader->biYPelsPerMeter = 0; + + // Skip over the optional palette + // A 24 or 32 bit DIB may contain a palette for faster color reduction + + io.read_proc(freeimage.get_bits_proc(dib), height * pitch, 1, handle); + + // check if the bitmap contains transparency, if so enable it in the header + + freeimage.set_transparent_proc(dib, (freeimage.get_color_type_proc(dib) == FIC_RGBALPHA)); + + return dib; + } + } + } catch(const char *message) { + freeimage.output_message_proc(s_format_id, message); + } + + return NULL; +} + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "BMP"; +} + +static const char * DLL_CALLCONV +Description() { + return "Windows or OS/2 Bitmap"; +} + +static const char * DLL_CALLCONV +Extension() { + return "bmp"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return "^BM"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE bmp_signature1[] = { 0x42, 0x4D }; + BYTE bmp_signature2[] = { 0x42, 0x41 }; + BYTE signature[2]; + + int items_read = io.read_proc(signature, 1, sizeof(bmp_signature1), handle); + + if (memcmp(bmp_signature1, signature, sizeof(bmp_signature1)) == 0) + return TRUE; + + if (memcmp(bmp_signature2, signature, sizeof(bmp_signature2)) == 0) + return TRUE; + + return FALSE; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if (handle != NULL) { + BITMAPFILEHEADER bitmapfileheader; + DWORD type = 0; + WORD magic; + + // we use this offset value to make seemingly absolute seeks relative in the file + + long offset_in_file = io.tell_proc(handle); + + // read the magic + + io.read_proc(&magic, sizeof(WORD), 1, handle); + + // compare the magic with the number we know + + while (memcmp(&magic, "BA", 2) == 0) { + io.read_proc(&bitmapfileheader.bfSize, sizeof(DWORD), 1, handle); + io.read_proc(&bitmapfileheader.bfReserved1, sizeof(WORD), 1, handle); + io.read_proc(&bitmapfileheader.bfReserved2, sizeof(WORD), 1, handle); + io.read_proc(&bitmapfileheader.bfOffBits, sizeof(DWORD), 1, handle); + io.read_proc(&magic, sizeof(WORD), 1, handle); + } + + // read the fileheader + + io.seek_proc(handle, 0 - sizeof(WORD), SEEK_CUR); + io.read_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle); + + // read the first byte of the infoheader + + io.read_proc(&type, sizeof(DWORD), 1, handle); + io.seek_proc(handle, 0 - sizeof(DWORD), SEEK_CUR); + + // call the appropriate load function for the found bitmap type + + if (type == 40) + return LoadWindowsBMP(freeimage, io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); + + if (type == 12) + return LoadOS21XBMP(freeimage, io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); + + if (type <= 64) + return LoadOS22XBMP(freeimage, io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); + } + + return NULL; +} + +// ---------------------------------------------------------- + +static BOOL DLL_CALLCONV +Save(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + if ((dib != NULL) && (handle != NULL)) { + bool bit_fields = (freeimage.get_bpp_proc(dib) == 16); + + // write the file header + + BITMAPFILEHEADER bitmapfileheader; + bitmapfileheader.bfType = 0x4D42; + bitmapfileheader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + freeimage.get_height_proc(dib) * freeimage.get_pitch_proc(dib); + bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + freeimage.get_colors_used_proc(dib) * sizeof(RGBQUAD); + bitmapfileheader.bfReserved1 = 0; + bitmapfileheader.bfReserved2 = 0; + + if (bit_fields) { + bitmapfileheader.bfSize += 3 * sizeof(DWORD); + bitmapfileheader.bfOffBits += 3 * sizeof(DWORD); + } + + if (io.write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1) + return FALSE; + + // write the info header + + BITMAPINFOHEADER bih = *freeimage.get_info_header_proc(dib); + + bih.biCompression = (bit_fields) ? 3 : 0; + bih.biBitCount = ((freeimage.get_bpp_proc(dib) == 32) && (!freeimage.is_transparent_proc(dib))) ? 24 : bih.biBitCount; + + if (io.write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1) { + return FALSE; + } + + // write the bit fields when we are dealing with a 16 bit BMP + + if (bit_fields) { + DWORD d; + + d = freeimage.get_blue_mask_proc(dib); + + if (io.write_proc(&d, sizeof(DWORD), 1, handle) != 1) + return FALSE; + + d = freeimage.get_green_mask_proc(dib); + + if (io.write_proc(&d, sizeof(DWORD), 1, handle) != 1) + return FALSE; + + d = freeimage.get_red_mask_proc(dib); + + if (io.write_proc(&d, sizeof(DWORD), 1, handle) != 1) + return FALSE; + } + + // write the palette + + if (freeimage.get_palette_proc(dib) != NULL) + if (io.write_proc(freeimage.get_palette_proc(dib), sizeof(RGBQUAD) * freeimage.get_colors_used_proc(dib), 1, handle) != 1) + return FALSE; + + // write the bitmap data + + if ((freeimage.get_bpp_proc(dib) == 32) && (!freeimage.is_transparent_proc(dib))) { + int pitch = CalculatePitch(CalculateLine(freeimage.get_width_proc(dib), 24)); + + BYTE *buffer = (BYTE *)malloc(pitch); + + for (unsigned i = 0; i < freeimage.get_height_proc(dib); ++i) { + freeimage.convert_line_32to24_proc(buffer, freeimage.get_scanline_proc(dib, i), freeimage.get_width_proc(dib)); + + if (io.write_proc(buffer, pitch, 1, handle) != 1) { + free(buffer); + return FALSE; + } + } + + free(buffer); + } else { + if (io.write_proc(freeimage.get_bits_proc(dib), freeimage.get_height_proc(dib) * freeimage.get_pitch_proc(dib), 1, handle) != 1) { + return FALSE; + } + } + + return TRUE; + } else { + return FALSE; + } +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitBMP(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.save_proc = 0; //Save; + plugin.validate_proc = Validate; +} diff --git a/freeimage241/Source/FreeImage/PluginICO.cpp b/freeimage241/Source/FreeImage/PluginICO.cpp new file mode 100644 index 0000000..2084a1e --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginICO.cpp @@ -0,0 +1,217 @@ +// ========================================================== +// ICO Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct tagIconDirectoryEntry { + BYTE bWidth; + BYTE bHeight; + BYTE bColorCount; + BYTE bReserved; + WORD wPlanes; + WORD wBitCount; + DWORD dwBytesInRes; + DWORD dwImageOffset; +} ICONDIRENTRY; + +typedef struct tagIconDir { + WORD idReserved; + WORD idType; + WORD idCount; +} ICONHEADER; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "ICO"; +} + +static const char * DLL_CALLCONV +Description() { + return "Windows Icon"; +} + +static const char * DLL_CALLCONV +Extension() { + return "ico"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + ICONHEADER icon_header; + + long read = io.read_proc(&icon_header, 1, sizeof(ICONHEADER), handle); + + return ((icon_header.idReserved == 0) && (icon_header.idType == 1)); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if (page == -1) + page = 0; + + if (handle != NULL) { + FIBITMAP *dib; + + // we use this offset value to make seemingly absolute seeks relative in the file + + long start_of_file = io.tell_proc(handle); + + // read the icon header + + ICONHEADER icon_header; + + io.read_proc(&icon_header, sizeof(ICONHEADER), 1, handle); + + if ((icon_header.idReserved == 0) && (icon_header.idType == 1)) { + // load the icon descriptions + + ICONDIRENTRY *icon_list = (ICONDIRENTRY *)malloc(icon_header.idCount * sizeof(ICONDIRENTRY)); + + io.read_proc(icon_list, icon_header.idCount * sizeof(ICONDIRENTRY), 1, handle); + + // load the specified icon + + if (page < icon_header.idCount) { + // seek to the start of the bitmap data for the icon + + io.seek_proc(handle, start_of_file, SEEK_SET); + io.seek_proc(handle, icon_list[(int)flags].dwImageOffset, SEEK_CUR); + + // load the BITMAPINFOHEADER + + BITMAPINFOHEADER header; + io.read_proc(&header, sizeof(BITMAPINFOHEADER), 1, handle); + + // allocate the bitmap + + int width = header.biWidth; + int height = header.biHeight / 2; // height == xor + and mask + int bit_count = header.biBitCount; + int line = CalculateLine(width, bit_count); + int pitch = CalculatePitch(line); + + // allocate memory for one icon + + dib = freeimage.allocate_proc(width, height, bit_count); + + if (dib == NULL) { + free(icon_list); + + return NULL; + } + + // black and white cursors look much better on white + + if (icon_header.idType == 2) + if (bit_count == 1) + memset(FreeImage_GetBits(dib), 255, pitch * height); + + // read the palette data + + io.read_proc(freeimage.get_palette_proc(dib), CalculateUsedColors(bit_count) * sizeof(RGBQUAD), 1, handle); + + // apply the AND and XOR masks + + BYTE *xor_mask = (BYTE *)malloc(pitch * height); + BYTE *and_mask = (BYTE *)malloc(pitch * height); + BYTE *copy_xor_mask = xor_mask; + BYTE *copy_and_mask = and_mask; + + io.read_proc(xor_mask, pitch * height, 1, handle); + io.read_proc(and_mask, pitch * height, 1, handle); + + for (int row = 0; row < height; row++) { + for (int column = 0; column < line; column++) { + *(freeimage.get_scanline_proc(dib, row) + column) &= copy_and_mask[column]; + *(freeimage.get_scanline_proc(dib, row) + column) ^= copy_xor_mask[column]; + } + + copy_xor_mask += pitch; + copy_and_mask += pitch; + } + + free(icon_list); + free(and_mask); + free(xor_mask); + + // bitmap has been loaded successfully! + + return (FIBITMAP *)dib; + } + } else { + freeimage.output_message_proc(s_format_id, "file is not an ICO file"); + } + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitICO(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.validate_proc = Validate; +} diff --git a/freeimage241/Source/FreeImage/PluginIFF.cpp b/freeimage241/Source/FreeImage/PluginIFF.cpp new file mode 100644 index 0000000..1adf06b --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginIFF.cpp @@ -0,0 +1,318 @@ +// ========================================================== +// Deluxe Paint Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Mark Sibly (marksibly@blitzbasic.com) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Internal typedefs and structures +// ---------------------------------------------------------- + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct { + WORD w, h; /* raster width & height in pixels */ + WORD x, y; /* position for this image */ + BYTE nPlanes; /* # source bitplanes */ + BYTE masking; /* masking technique */ + BYTE compression; /* compression algorithm */ + BYTE pad1; /* UNUSED. For consistency, put 0 here.*/ + WORD transparentColor; /* transparent "color number" */ + BYTE xAspect, yAspect; /* aspect ratio, a rational number x/y */ + WORD pageWidth, pageHeight; /* source "page" size in pixels */ +} BMHD; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// ---------------------------------------------------------- + +static BOOL big_endian = TRUE; + +// ---------------------------------------------------------- + +static WORD swapWORD( WORD n ){ + return big_endian ? (n >> 8) | (n << 8) : n; +} + +static DWORD swapDWORD( DWORD n ){ + return big_endian ? (n >> 24) | (n << 24) | ((n >> 8) & 0xff00) | ((n << 8) & 0xff0000) : n; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "IFF"; +} + +static const char * DLL_CALLCONV +Description() { + return "IFF Interleaved Bitmap"; +} + +static const char * DLL_CALLCONV +Extension() { + return "iff,lbm"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + unsigned type = 0; + + io.read_proc(&type, 4, 1, handle); + + return (swapDWORD(type) == 'FORM'); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if (handle != NULL) { + FIBITMAP *dib = 0; + + unsigned type, size; + + io.read_proc(&type, 4, 1, handle); + + if (swapDWORD(type) != 'FORM') + return NULL; + + io.read_proc( &size,4,1,handle ); + + size = swapDWORD(size); + + io.read_proc(&type, 4, 1, handle); + + if ((swapDWORD(type) != 'ILBM') && (swapDWORD(type) != 'PBM ')) + return NULL; + + size -= 4; + + unsigned width, height, planes, depth, comp; + + while (size) { + unsigned ch_type,ch_size; + + io.read_proc(&ch_type, 4, 1, handle); + ch_type = swapDWORD(ch_type); + + io.read_proc(&ch_size,4,1,handle ); + ch_size = swapDWORD(ch_size); + + unsigned ch_end = io.tell_proc(handle) + ch_size; + + if (ch_type == 'BMHD') { + if (dib) + FreeImage_Unload(dib); + + BMHD bmhd; + + io.read_proc(&bmhd, sizeof(bmhd), 1, handle); + + width = swapWORD(bmhd.w); + height = swapWORD(bmhd.h); + planes = bmhd.nPlanes; + comp = bmhd.compression; + + if (planes > 8 && planes != 24) + return NULL; + + depth = planes > 8 ? 24 : 8; + + unsigned mask = planes > 8 ? 0xff : 0; + + dib = freeimage.allocate_proc(width, height, depth, mask << 16, mask << 8, mask); + } else if (ch_type == 'CMAP') { + if (!dib) + return NULL; + + RGBQUAD *pal = freeimage.get_palette_proc(dib); + + for (unsigned k = 0; k < ch_size / 3;++k ){ + io.read_proc(&pal[k].rgbRed, 1, 1, handle ); + io.read_proc(&pal[k].rgbGreen, 1, 1, handle ); + io.read_proc(&pal[k].rgbBlue, 1, 1, handle ); + } + + } else if (ch_type == 'BODY') { + if (!dib) + return NULL; + + if (swapDWORD(type) == 'PBM ') { + // NON INTERLACED (LBM) + + unsigned line = freeimage.get_line_proc(dib) + 1 & ~1; + + for (unsigned i = 0; i < freeimage.get_height_proc(dib); ++i) { + BYTE *bits = freeimage.get_scanline_proc(dib, freeimage.get_height_proc(dib) - i - 1); + + if (comp == 1) { + // use RLE compression + + DWORD number_of_bytes_written = 0; + BYTE rle_count; + BYTE byte; + + while (number_of_bytes_written < line) { + io.read_proc(&rle_count, 1, 1, handle); + + if (rle_count < 128) { + for (int k = 0; k < rle_count + 1; k++) { + io.read_proc(&byte, 1, 1, handle); + + bits[number_of_bytes_written++] += byte; + } + } else if (rle_count > 128) { + io.read_proc(&byte, 1, 1, handle); + + for (int k = 0; k < 257 - rle_count; k++) { + bits[number_of_bytes_written++] += byte; + } + } + } + } else { + // don't use compression + + io.read_proc(bits, line, 1, handle); + } + } + + return dib; + } else { + // INTERLACED (ILBM) + + unsigned pixel_size = depth/8; + unsigned n_width=(width+15)&~15; + unsigned plane_size = n_width/8; + unsigned src_size = plane_size * planes; + unsigned char *src = (unsigned char*)malloc(src_size); + unsigned char *dest = freeimage.get_bits_proc(dib); + + dest += freeimage.get_pitch_proc(dib) * height; + + for (unsigned y = 0; y < height; ++y) { + dest -= freeimage.get_pitch_proc(dib); + + // read all planes in one hit, + // 'coz PSP compresses across planes... + + if (comp) { + for(unsigned x = 0; x < src_size;){ + signed char t; + + io.read_proc(&t, 1, 1, handle); + + if (t >= 0) { + ++t; + + io.read_proc(src + x, t, 1, handle); + + x += t; + } else if( t!=-128 ){ + signed char b; + + io.read_proc( &b,1,1,handle ); + + t =- t +1; + + memset(src + x, b, t); + + x += t; + } + } + } else { + io.read_proc(src, src_size, 1, handle); + } + + // lazy planar->chunky... + + for (unsigned x = 0; x < width; ++x) { + for (unsigned n = 0; n < planes; ++n) { + char bit = src[n * plane_size + (x / 8)] >> ((x^7) & 7); + dest[x * pixel_size + (n / 8)] |= (bit & 1) << (n & 7); + } + } + + if (depth == 24){ + for(unsigned x = 0; x < width; ++x){ + char t = dest[x * 3]; + dest[x * 3] = dest[x * 3 + 2]; + dest[x * 3 + 2] = t; + } + } + } + + free(src); + + return dib; + } + } + + io.seek_proc(handle, ch_end - io.tell_proc(handle), SEEK_CUR); + + size -= ch_size+8; + } + + if (dib) + freeimage.unload_proc(dib); + } + + return 0; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitIFF(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.validate_proc = Validate; +} diff --git a/freeimage241/Source/FreeImage/PluginJPEG.cpp b/freeimage241/Source/FreeImage/PluginJPEG.cpp new file mode 100644 index 0000000..4e39c2b --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginJPEG.cpp @@ -0,0 +1,625 @@ +// ========================================================== +// JPEG Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Jan L. Nauta (jln@magentammt.com) +// - Markus Loibl (markus.loibl@epost.de) +// +// Based on code developed by The Independent JPEG Group +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +extern "C" { +#define XMD_H +#undef FAR +#include +#include "../LibJPEG/jpeglib.h" +} + +// ---------------------------------------------------------- + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + +typedef struct my_error_mgr * my_error_ptr; + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +METHODDEF(void) +jpeg_error_exit (j_common_ptr cinfo) { + (*cinfo->err->output_message)(cinfo); + + jpeg_destroy(cinfo); + + throw FIF_JPEG; +} + +METHODDEF(void) +jpeg_output_message (j_common_ptr cinfo) { + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message)(cinfo, buffer); + + //FreeImage_OutputMessage(FreeImage_GetFIFFromFormat("JPEG"), buffer); +} + +//=========================================================== +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +#include "../libjpeg/jinclude.h" +#include "../libjpeg/jpeglib.h" +#include "../libjpeg/jerror.h" + +// Expanded data source object for stdio input -------------- + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +// ---------------------------------------------------------- + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + fi_handle infile; /* source stream */ + FreeImageIO *m_io; + + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + fi_handle outfile; /* destination stream */ + FreeImageIO *m_io; + + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +// ---------------------------------------------------------- + +typedef my_source_mgr * freeimage_src_ptr; +typedef my_destination_mgr * freeimage_dst_ptr; + +// ---------------------------------------------------------- + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) { + freeimage_src_ptr src = (freeimage_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + + src->start_of_file = TRUE; +} + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) { + freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest; + + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +// ---------------------------------------------------------- + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) { + freeimage_src_ptr src = (freeimage_src_ptr) cinfo->src; + + size_t nbytes = src->m_io->read_proc(src->buffer, 1, INPUT_BUF_SIZE, src->infile); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + + WARNMS(cinfo, JWRN_JPEG_EOF); + + /* Insert a fake EOI marker */ + + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) { + freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest; + + if (dest->m_io->write_proc(dest->buffer, 1, OUTPUT_BUF_SIZE, dest->outfile) != OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) { + freeimage_src_ptr src = (freeimage_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + + (void) fill_input_buffer(cinfo); + + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) { + /* no work necessary here */ +} + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) { + freeimage_dst_ptr dest = (freeimage_dst_ptr) cinfo->dest; + + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + + if (datacount > 0) { + if (dest->m_io->write_proc(dest->buffer, 1, datacount, dest->outfile) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } +} + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_freeimage_src (j_decompress_ptr cinfo, fi_handle infile, FreeImageIO &io) { + freeimage_src_ptr src; + + // allocate memory for the buffer. is released automatically in the end + + if (cinfo->src == NULL) { + cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_source_mgr)); + + src = (freeimage_src_ptr) cinfo->src; + + src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + // initialize the jpeg pointer struct with pointers to functions + + src = (freeimage_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->m_io = &io; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +GLOBAL(void) +jpeg_freeimage_dst (j_compress_ptr cinfo, fi_handle outfile, FreeImageIO &io) { + freeimage_dst_ptr dest; + + if (cinfo->dest == NULL) { + cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_destination_mgr)); + } + + dest = (freeimage_dst_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; + dest->m_io = &io; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "JPEG"; +} + +static const char * DLL_CALLCONV +Description() { + return "JPEG - JFIF Compliant"; +} + +static const char * DLL_CALLCONV +Extension() { + return "jpg,jif,jpeg"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return "^\377\330\377"; +} + +static const char * DLL_CALLCONV +MimeType() { + return "image/jpeg"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE jpeg_signature[] = { 0xFF, 0xD8 }; + BYTE signature[2] = { 0, 0 }; + + io.read_proc(signature, 1, sizeof(jpeg_signature), handle); + + return (memcmp(jpeg_signature, signature, sizeof(jpeg_signature)) == 0); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if (handle) { + FIBITMAP *dib = NULL; + + try { + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + // Step 1: allocate and initialize JPEG decompression object + + cinfo.err = jpeg_std_error(&jerr); + + jerr.error_exit = jpeg_error_exit; + jerr.output_message = jpeg_output_message; + + jpeg_create_decompress(&cinfo); + + // Step 2: specify data source (eg, a handle) + + jpeg_freeimage_src(&cinfo, handle, io); + + // Step 3: read handle parameters with jpeg_read_header() + + jpeg_read_header(&cinfo, TRUE); + + // Step 4a: set parameters for decompression + + if ((flags != JPEG_ACCURATE)) { + cinfo.dct_method = JDCT_IFAST; + cinfo.do_fancy_upsampling = FALSE; + } + + // Step 4b: allocate dib and init header + + dib = freeimage.allocate_proc(cinfo.image_width, cinfo.image_height, 8 * cinfo.num_components, 0xFF00, 0xFF, 0xFF0000); + + if (cinfo.num_components == 1) { + RGBQUAD *colors = freeimage.get_palette_proc(dib); + + for (int i = 0; i < 256; i++) { + colors[i].rgbRed = i; + colors[i].rgbGreen = i; + colors[i].rgbBlue = i; + } + } + + // Step 4c: handle metrices + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + + if (cinfo.density_unit == 1) { + // dots/inch + + pInfoHeader->biXPelsPerMeter = (int) (((float)cinfo.X_density) / 0.0254000 + 0.5); + pInfoHeader->biYPelsPerMeter = (int) (((float)cinfo.Y_density) / 0.0254000 + 0.5); + } else if (cinfo.density_unit == 2) { + // dots/cm + + pInfoHeader->biXPelsPerMeter = cinfo.X_density * 100; + pInfoHeader->biYPelsPerMeter = cinfo.Y_density * 100; + } + + // Step 5: start decompressor + + jpeg_start_decompress(&cinfo); + + // Step 6: while (scan lines remain to be read) jpeg_read_scanlines(...); + + while (cinfo.output_scanline < cinfo.output_height) { + JSAMPROW b = freeimage.get_scanline_proc(dib, cinfo.output_height - cinfo.output_scanline - 1); + + jpeg_read_scanlines(&cinfo, &b, 1); + } + + // Step 7: finish decompression + + jpeg_finish_decompress(&cinfo); + + // Step 8: release JPEG decompression object + + jpeg_destroy_decompress(&cinfo); + + return (FIBITMAP *)dib; + } catch (...) { + freeimage.unload_proc(dib); + } + } + + return NULL; +} + +static BOOL DLL_CALLCONV +Save(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + if ((dib) && (handle)) { + try { + // Check dib format + + WORD bpp = freeimage.get_bpp_proc(dib); + + if ((bpp == 32) && (freeimage.is_transparent_proc(dib))) + throw "JPEG does not support alpha channels"; + else if (((bpp != 24) && (bpp != 32)) && (!((bpp == 8) && (FreeImage_GetColorType(dib) == FIC_MINISBLACK)))) + throw "only 24-bit highcolor or 8-bit greyscale bitmaps can be saved as JPEG"; + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + // Step 1: allocate and initialize JPEG compression object + + cinfo.err = jpeg_std_error(&jerr); + + jerr.error_exit = jpeg_error_exit; + jerr.output_message = jpeg_output_message; + + /* Now we can initialize the JPEG compression object. */ + + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + + jpeg_freeimage_dst(&cinfo, handle, io); + + /* Step 3: set parameters for compression */ + + cinfo.image_width = freeimage.get_width_proc(dib); + cinfo.image_height = freeimage.get_height_proc(dib); + + switch(FreeImage_GetColorType(dib)) { + case FIC_MINISBLACK : + cinfo.in_color_space = JCS_GRAYSCALE; + cinfo.input_components = 1; + break; + + default : + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; + break; + } + + jpeg_set_defaults(&cinfo); + + // Set JFIF density parameters from the DIB data + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + cinfo.X_density = (WORD)(pInfoHeader->biXPelsPerMeter / 100.0F + 0.5); + cinfo.Y_density = (WORD)(pInfoHeader->biYPelsPerMeter / 100.0F + 0.5); + cinfo.density_unit = 2; // dots / cm + + // Step 4: set quality + // the first 7 bits are reserved for low level quality settings + // the other bits are high level (i.e. enum-ish) + + int quality; + + if ((flags & JPEG_QUALITYBAD) == JPEG_QUALITYBAD) { + quality = 10; + } else if ((flags & JPEG_QUALITYAVERAGE) == JPEG_QUALITYAVERAGE) { + quality = 25; + } else if ((flags & JPEG_QUALITYNORMAL) == JPEG_QUALITYNORMAL) { + quality = 50; + } else if ((flags & JPEG_QUALITYGOOD) == JPEG_QUALITYGOOD) { + quality = 75; + } else if ((flags & JPEG_QUALITYSUPERB) == JPEG_QUALITYSUPERB) { + quality = 100; + } else { + if ((flags & 0x7F) == 0) { + quality = 75; + } else { + quality = flags & 0x7F; + } + } + + jpeg_set_quality(&cinfo, quality, TRUE); /* limit to baseline-JPEG values */ + + /* Step 5: Start compressor */ + + jpeg_start_compress(&cinfo, TRUE); + + /* Step 6: while (scan lines remain to be written) */ + + if (freeimage.get_bpp_proc(dib) == 32) { + int pitch = CalculatePitch(CalculateLine(freeimage.get_width_proc(dib), 24)); + + JSAMPROW b = (BYTE *)malloc(pitch); + + for (unsigned i = 0; i < freeimage.get_height_proc(dib); ++i) { + freeimage.convert_line_32to24_proc(b, freeimage.get_scanline_proc(dib, freeimage.get_height_proc(dib) - cinfo.next_scanline - 1), freeimage.get_width_proc(dib)); + + jpeg_write_scanlines(&cinfo, &b, 1); + } + + free(b); + } else { + while (cinfo.next_scanline < cinfo.image_height) { + JSAMPROW b = freeimage.get_scanline_proc(dib, freeimage.get_height_proc(dib) - cinfo.next_scanline - 1); + + jpeg_write_scanlines(&cinfo, &b, 1); + } + } + + /* Step 7: Finish compression */ + + jpeg_finish_compress(&cinfo); + + /* Step 8: release JPEG compression object */ + + jpeg_destroy_compress(&cinfo); + + return TRUE; + + } catch (char *text) { + freeimage.output_message_proc(s_format_id, text); + + return FALSE; + } catch (FREE_IMAGE_FORMAT) { + return FALSE; + } + } + + return FALSE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitJPEG(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.save_proc = 0; //Save; + plugin.validate_proc = Validate; + plugin.mime_proc = MimeType; +} diff --git a/freeimage241/Source/FreeImage/PluginKOALA.cpp b/freeimage241/Source/FreeImage/PluginKOALA.cpp new file mode 100644 index 0000000..d369169 --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginKOALA.cpp @@ -0,0 +1,218 @@ +// ========================================================== +// KOALA Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct tagKOALA { + BYTE image[8000]; // pixmap image + BYTE colour1[1000]; // first colourmap (colour 1 and 2) + BYTE colour2[1000]; // second colourmap (colour 3) + BYTE background; // background colour +} koala_t; + +struct colour_t { + int r; + int g; + int b; +}; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// ---------------------------------------------------------- + +#define CBM_WIDTH 320 +#define CBM_HEIGHT 200 + +// ---------------------------------------------------------- + +const colour_t c64colours[16] = { + { 0, 0, 0 }, // Black + { 255, 255, 255 }, // White + { 170, 17, 17 }, // Red + { 12, 204, 204 }, // Cyan + { 221, 51, 221 }, // Purple + { 0, 187, 0 }, // Green + { 0, 0, 204 }, // Blue + { 255, 255, 140 }, // Yellow + { 204, 119, 34 }, // Orange + { 136, 68, 0 }, // Brown + { 255, 153, 136 }, // Light red + { 92, 92, 92 }, // Gray 1 + { 170, 170, 170 }, // Gray 2 + { 140, 255, 178 }, // Light green + { 39, 148, 255 }, // Light blue + { 196, 196, 196 } // Gray 3 +}; + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +const char * DLL_CALLCONV +Format() { + return "KOALA"; +} + +const char * DLL_CALLCONV +Description() { + return "C64 Koala Graphics"; +} + +const char * DLL_CALLCONV +Extension() { + return "koa"; +} + +const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE koala_signature[] = { 0x00, 0x60 }; + BYTE signature[2] = { 0, 0 }; + + int items_read = io.read_proc(signature, 1, sizeof(koala_signature), handle); + + return (memcmp(koala_signature, signature, sizeof(koala_signature)) == 0); +} + +// ---------------------------------------------------------- + +FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if (handle) { + koala_t image; + + // read the load address + + unsigned char load_address[2]; // highbit, lowbit + io.read_proc(&load_address, 1, 2, handle); + + // if the load address is correct, skip it. otherwise ignore the load address + + if ((load_address[0] != 0x00) || (load_address[1] != 0x60)) { + ((BYTE *)&image)[0] = load_address[0]; + ((BYTE *)&image)[1] = load_address[1]; + + io.read_proc((BYTE *)&image + 2, 1, 10001 - 2, handle); + } else { + io.read_proc(&image, 1, 10001, handle); + } + + // build DIB in memory + + FIBITMAP *dib = freeimage.allocate_proc(CBM_WIDTH, CBM_HEIGHT, 4); + + if (dib) { + // write out the commodore 64 color palette + + RGBQUAD *palette = freeimage.get_palette_proc(dib); + + for (int i = 0; i < 16; i++) { + palette[i].rgbBlue = c64colours[i].b; + palette[i].rgbGreen = c64colours[i].g; + palette[i].rgbRed = c64colours[i].r; + } + + // write out bitmap data + + BYTE pixel_mask[4] = { 0xc0, 0x30, 0x0c, 0x03 }; + BYTE pixel_displacement[4] = { 6, 4, 2, 0 }; + int pixel, index, colourindex; + unsigned char found_color = 0; + + for (int y = 0; y < 200; y++) { + for (int x = 0; x < 160; x++) { + // Get value of pixel at (x,y) + + index = (x / 4) * 8 + (y % 8) + (y / 8) * CBM_WIDTH; + colourindex = (x / 4) + (y / 8) * 40; + pixel = (image.image[index] & pixel_mask[x % 4]) >> pixel_displacement[x % 4]; + + // Retrieve RGB values + + switch (pixel) { + case 0: // Background + found_color = image.background; + break; + + case 1: // Colour 1 + found_color = image.colour1[colourindex] >> 4; + break; + + case 2: // Colour 2 + found_color = image.colour1[colourindex] & 0xf; + break; + + case 3: // Colour 3 + found_color = image.colour2[colourindex] & 0xf; + break; + }; + + *(freeimage.get_scanline_proc(dib, CBM_HEIGHT - y - 1) + x) = (found_color << 4) | found_color; + } + } + + return dib; + } + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitKOALA(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.validate_proc = Validate; +} diff --git a/freeimage241/Source/FreeImage/PluginMNG.cpp b/freeimage241/Source/FreeImage/PluginMNG.cpp new file mode 100644 index 0000000..3f8b8d9 --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginMNG.cpp @@ -0,0 +1,235 @@ +// ========================================================== +// MNG Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +#include +#include + +#include "../LibMNG/libmng.h" + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +typedef struct { + FIBITMAP *bitmap; // pointer to the bitmap data + FreeImage &freeimage; // pointer to the freeimage access functions + FreeImageIO &io; // pointer to the io functions + fi_handle file; // pointer to the file we're decoding +} mngstuff; + +// ---------------------------------------------------------- +// Callbacks for the mng decoder +// ---------------------------------------------------------- + +mng_ptr +mymngalloc(mng_uint32 size) { + return (mng_ptr)calloc(1, size); +} + +void +mymngfree(mng_ptr p, mng_uint32 size) { + free(p); +} + +mng_bool +mymngopenstream(mng_handle mng) { + // since the user is responsible for opening and closing the file, + // we leave the default implementation open + + return MNG_TRUE; +} + +mng_bool +mymngclosestream(mng_handle mng) { + // since the user is responsible for opening and closing the file, + // we leave the default implementation open + + return MNG_TRUE; +} + +mng_bool +mymngreadstream(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread) { + mngstuff *mymng = (mngstuff *)mng_get_userdata(mng); + + *bytesread = mymng->io.read_proc(buffer, 1, size, mymng->file); + + return MNG_TRUE; +} + +mng_bool +mymngprocessheader(mng_handle mng, mng_uint32 width, mng_uint32 height) { + // allocate a bitmap with the given dimensions + + FreeImage &freeimage = ((mngstuff *)mng_get_userdata(mng))->freeimage; + + ((mngstuff *)mng_get_userdata(mng))->bitmap = freeimage.allocate_proc(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + + // tell the mng decoder about our bit-depth choice + + mng_set_canvasstyle(mng, MNG_CANVAS_BGR8); + + return MNG_TRUE; +} + +mng_ptr +mymnggetcanvasline(mng_handle mng, mng_uint32 line) { + FreeImage &freeimage = ((mngstuff *)mng_get_userdata(mng))->freeimage; + + FIBITMAP *bitmap = ((mngstuff *)mng_get_userdata(mng))->bitmap; + + return freeimage.get_scanline_proc(bitmap, freeimage.get_height_proc(bitmap) - line - 1); +} + +mng_bool +mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h) { + return MNG_TRUE; +} + +mng_uint32 +mymnggetticks(mng_handle mng) { + return 0; +} + +mng_bool +mymngsettimer(mng_handle mng, mng_uint32 msecs) { + return MNG_TRUE; +} + +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) { + throw (const char *)text; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "MNG"; +} + +static const char * DLL_CALLCONV +Description() { + return "Multiple Network Graphics"; +} + +static const char * DLL_CALLCONV +Extension() { + return "mng"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +// ---------------------------------------------------------- + +static void * DLL_CALLCONV +Open(FreeImageIO &io, fi_handle handle, BOOL read) { + mngstuff *mymng = (mngstuff *)calloc(1, sizeof(*mymng)); + mymng->io = io; + mymng->file = handle; + + return mymng; +} + +static void DLL_CALLCONV +Close(FreeImageIO &io, fi_handle handle, void *data) { + free((mngstuff *)data); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if (handle != NULL) { + try { + // allocate our stream data structure + + mngstuff *mymng = (mngstuff *)data; + + // set up the mng decoder for our stream + + mng_handle mng = mng_initialize(mymng, mymngalloc, mymngfree, MNG_NULL); + + if (mng == MNG_NULL) + throw "could not initialize libmng"; + + // set the callbacks + + mng_setcb_errorproc(mng, mymngerror); + mng_setcb_openstream(mng, mymngopenstream); + mng_setcb_closestream(mng, mymngclosestream); + mng_setcb_readdata(mng, mymngreadstream); + mng_setcb_processheader(mng, mymngprocessheader); + mng_setcb_getcanvasline(mng, mymnggetcanvasline); + mng_setcb_refresh(mng, mymngrefresh); + mng_setcb_gettickcount(mng, mymnggetticks); + mng_setcb_settimer(mng, mymngsettimer); + + // read in the bitmap + + mng_readdisplay(mng); + + // temp store the newly created bitmap + + FIBITMAP *bitmap = mymng->bitmap; + + // cleanup and return the temp stored bitmap + + mng_cleanup(&mng); + + return bitmap; + } catch (const char *message) { + freeimage.output_message_proc(s_format_id, message); + } + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitMNG(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.open_proc = Open; + plugin.close_proc = Close; + plugin.load_proc = Load; +} diff --git a/freeimage241/Source/FreeImage/PluginPCD.cpp b/freeimage241/Source/FreeImage/PluginPCD.cpp new file mode 100644 index 0000000..71042ba --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginPCD.cpp @@ -0,0 +1,207 @@ +// ========================================================== +// Kodak PhotoCD Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// Based on pascal code developed by Alex Kwak +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#pragma warning (disable : 4244) + +#include +#include + +#include "FreeImage.h" +#include "Utilities.h" + +// ========================================================== +// Internal functions +// ========================================================== + +inline float +fix(float a) { + return (a < 0) ? 0 : (a > 255) ? 255 : a; +} + +static void +YUV2RGB(int y, int cb, int cr, int &r, int &g, int &b) { + const float c = 256; + + float c11 = 0.0054980 * c; + float c12 = 0.0000001 * c; + float c13 = 0.0051681 * c; + float c21 = 0.0054980 * c; + float c22 = -0.0015446 * c; + float c23 = -0.0026325 * c; + float c31 = 0.0054980 * c; + float c32 = 0.0079533 * c; + float c33 = 0.0000001 * c; + + r = fix(round(c11 * y + c12 * (cb - 156) + c13 * (cr - 137))); + g = fix(round(c21 * y + c22 * (cb - 156) + c23 * (cr - 137))); + b = fix(round(c31 * y + c32 * (cb - 156) + c33 * (cr - 137))); +} + +static BOOL +VerticalOrientation(FreeImageIO &io, fi_handle handle) { + char buffer[128]; + + io.read_proc(buffer, 128, 1, handle); + + return (buffer[72] & 63) == 8; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "PCD"; +} + +static const char * DLL_CALLCONV +Description() { + return "Kodak PhotoCD"; +} + +static const char * DLL_CALLCONV +Extension() { + return "pcd"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + int width; + int height; + int line; + int pitch; + int bpp = 24; + int scan_line_add = 1; + int start_scan_line = 0; + + // to make absolute seeks possible we store the current position in the file + + long offset_in_file = io.tell_proc(handle); + long seek; + + switch (flags) { + case PCD_BASEDIV4 : + seek = 0x2000; + width = 192; + height = 128; + line = CalculateLine(width, bpp); + pitch = CalculatePitch(line); + break; + + case PCD_BASEDIV16 : + seek = 0xB800; + width = 384; + height = 256; + line = CalculateLine(width, bpp); + pitch = CalculatePitch(line); + break; + + default : + seek = 0x30000; + width = 768; + height = 512; + line = CalculateLine(width, bpp); + pitch = CalculatePitch(line); + break; + } + + // allocate the dib and write out the header + + FIBITMAP *dib = freeimage.allocate_proc(width, height, bpp, 0xFF, 0xFF00, 0xFF0000); + + // check if the PCD is bottom-up + + if (VerticalOrientation(io, handle)) { + scan_line_add = -1; + start_scan_line = height - 1; + } + + // temporary stuff to load PCD + + BYTE *y1 = (BYTE *)malloc(width); + BYTE *y2 = (BYTE *)malloc(width); + BYTE *cbcr = (BYTE *)malloc(width); + BYTE *yl[] = { y1, y2 }; + + // seek to the part where the bitmap data begins + + io.seek_proc(handle, offset_in_file, SEEK_SET); + io.seek_proc(handle, seek, SEEK_CUR); + + // read the data + + for (int y = 0; y < height / 2; ++y) { + io.read_proc(y1, width, 1, handle); + io.read_proc(y2, width, 1, handle); + io.read_proc(cbcr, width, 1, handle); + + for (int i = 0; i < 2; ++i) { + for (int x = 0; x < width; ++x) { + int r, g, b; + + YUV2RGB(yl[i][x], cbcr[x / 2], cbcr[(width / 2) + (x / 2)], r, g, b); + + *(freeimage.get_scanline_proc(dib, start_scan_line) + (x * 3) + 0) = b; + *(freeimage.get_scanline_proc(dib, start_scan_line) + (x * 3) + 1) = g; + *(freeimage.get_scanline_proc(dib, start_scan_line) + (x * 3) + 2) = r; + } + + start_scan_line += scan_line_add; + } + } + + free(cbcr); + free(y2); + free(y1); + + return dib; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitPCD(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; +} diff --git a/freeimage241/Source/FreeImage/PluginPCX.cpp b/freeimage241/Source/FreeImage/PluginPCX.cpp new file mode 100644 index 0000000..1d65b73 --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginPCX.cpp @@ -0,0 +1,398 @@ +// ========================================================== +// PCX Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Jani Kajala (janik@remedy.fi) +// - Markus Loibl (markus.loibl@epost.de) +// - Hervé Drolon (drolon@infonie.fr) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct tagPCXHEADER { + BYTE manufacturer; // Magic number (0x0A = ZSoft Z) + BYTE version; // Version 0 == 2.5 + // 2 == 2.8 with palette info + // 3 == 2.8 without palette info + // 5 == 3.0 with palette info + BYTE encoding; // Encoding: 0 = uncompressed, 1 = PCX rle compressed + BYTE bpp; // Bits per pixel per plane (only 1 or 8) + WORD window[4]; // left, upper, right,lower pixel coord. + WORD hdpi; // Horizontal resolution + WORD vdpi; // Vertical resolution + BYTE color_map[48]; // Colormap for 16-color images + BYTE reserved; + BYTE planes; // Number of planes (1, 3 or 4) + WORD bytes_per_line; // Bytes per row (always even) + WORD palette_info; // Palette information (1 = color or b&w; 2 = gray scale) + WORD h_screen_size; + WORD v_screen_size; + BYTE filler[54]; // Reserved filler +} PCXHEADER; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// ========================================================== +// Internal functions +// ========================================================== + +static WORD +readline(FreeImageIO &io, fi_handle handle, BYTE *buffer, WORD length, BOOL rle) { + // -----------------------------------------------------------// + // Read either run-length encoded or normal image data // + // // + // THIS IS HOW RUNTIME LENGTH ENCODING WORKS IN PCX: // + // // + // 1) If the upper 2 bits of a byte are set, // + // the lower 6 bits specify the count for the next byte // + // // + // 2) If the upper 2 bits of the byte are clear, // + // the byte is actual data with a count of 1 // + // // + // Note that a scanline always has an even number of bytes // + // ------------------------------------------------------------- + + BYTE count = 0, value = 0; + WORD written = 0; + + if (rle) { + // run-length encoded read + + while (length--) { + if (count == 0) { + io.read_proc(&value, 1, 1, handle); + + if ((value & 0xC0) == 0xC0) { + count = value & 0x3F; + io.read_proc(&value, 1, 1, handle); + } else { + count = 1; + } + } + + count--; + + *(buffer + written++) = value; + } + } else { + // normal read + + written = io.read_proc(buffer, length, 1, handle); + } + + return written; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "PCX"; +} + +static const char * DLL_CALLCONV +Description() { + return "Zsoft Paintbrush"; +} + +static const char * DLL_CALLCONV +Extension() { + return "pcx"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE pcx_signature = 0x0A; + BYTE signature = 0; + + io.read_proc(&signature, 1, 1, handle); + + return (pcx_signature == signature); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + FIBITMAP *dib = NULL; + BYTE *bits; // Pointer to dib data + RGBQUAD *pal; // Pointer to dib palette + BYTE *line = NULL; // PCX raster line + WORD linelength; // Length of raster line in bytes + WORD pitch; // Length of DIB line in bytes + BOOL rle; // True if the file is run-length encoded + + if (handle) { + try { + // process the header + + PCXHEADER header; + + io.read_proc(&header, sizeof(PCXHEADER), 1, handle); + + // check PCX identifier + + if ((header.manufacturer != 0x0A) || (header.version > 5)) + throw "Invalid PCX file"; + + // allocate a new DIB + + WORD width = header.window[2] - header.window[0] + 1; + WORD height = header.window[3] - header.window[1] + 1; + WORD bitcount = header.bpp * header.planes; + + if (bitcount == 24) + dib = freeimage.allocate_proc(width, height, bitcount, 0xFF, 0xFF00, 0xFF0000); + else + dib = freeimage.allocate_proc(width, height, bitcount); + + // if the dib couldn't be allocated, throw an error + + if (!dib) + throw "DIB allocation failed"; + + // metrics handling code + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + pInfoHeader->biXPelsPerMeter = (int) (((float)header.hdpi) / 0.0254000 + 0.5); + pInfoHeader->biYPelsPerMeter = (int) (((float)header.vdpi) / 0.0254000 + 0.5); + + // Set up the palette if needed + // ---------------------------- + + switch(bitcount) { + case 1: + { + pal = freeimage.get_palette_proc(dib); + pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; + pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; + break; + } + + case 4: + { + pal = freeimage.get_palette_proc(dib); + + BYTE *pColormap = &header.color_map[0]; + + for(int i = 0; i < 16; i++) { + pal[i].rgbRed = pColormap[0]; + pal[i].rgbGreen = pColormap[1]; + pal[i].rgbBlue = pColormap[2]; + pColormap += 3; + } + + break; + } + + case 8: + { + BYTE palette_id; + + io.seek_proc(handle, -769L, SEEK_END); + io.read_proc(&palette_id, 1, 1, handle); + + if (palette_id == 0x0C) { + BYTE *cmap = (BYTE*)malloc(768 * sizeof(BYTE)); + io.read_proc(cmap, 768, 1, handle); + + pal = freeimage.get_palette_proc(dib); + BYTE *pColormap = &cmap[0]; + + for(int i = 0; i < 256; i++) { + pal[i].rgbRed = pColormap[0]; + pal[i].rgbGreen = pColormap[1]; + pal[i].rgbBlue = pColormap[2]; + pColormap += 3; + } + + free(cmap); + } + + // wrong palette ID, perhaps a gray scale is needed ? + + else if (header.palette_info == 2) { + pal = freeimage.get_palette_proc(dib); + + for(int i = 0; i < 256; i++) { + pal[i].rgbRed = i; + pal[i].rgbGreen = i; + pal[i].rgbBlue = i; + } + } + + io.seek_proc(handle, (long)sizeof(PCXHEADER), SEEK_SET); + } + break; + } + + // calculate the line length for the PCX and the DIB + + linelength = header.bytes_per_line * header.planes; + pitch = freeimage.get_pitch_proc(dib); + + // run-length encoding ? + + rle = (header.encoding == 1) ? TRUE : FALSE; + + // load image data + // --------------- + + line = (BYTE*) malloc(linelength * sizeof(BYTE)); + bits = freeimage.get_scanline_proc(dib, height - 1); + + if ((header.planes == 1) && ((header.bpp == 1) || (header.bpp == 8))) { + BYTE skip; + WORD written; + + for (WORD y = 0; y < height; y++) { + written = readline(io, handle, line, linelength, rle); + memcpy(bits, line, linelength); + + // skip trailing garbage at the end of the scanline + + for (int count = written; count < linelength; count++) + io.read_proc(&skip, sizeof(BYTE), 1, handle); + + bits -= pitch; + } + } + else if ((header.planes == 4) && (header.bpp == 1)) { + BYTE bit, index, mask, skip; + BYTE *buffer; + WORD x, y, written; + buffer = (BYTE*)malloc(width * sizeof(BYTE)); + + for (y = 0; y < height; y++) { + written = readline(io, handle, line, linelength, rle); + + // build a nibble using the 4 planes + + memset(buffer, 0, width * sizeof(BYTE)); + + for(int plane = 0; plane < 4; plane++) { + bit = 1 << plane; + + for(x = 0; x < width; x++) { + index = (x / 8) + plane * header.bytes_per_line; + mask = 0x80 >> (x & 0x07); + buffer[x] |= (line[index] & mask) ? bit : 0; + } + } + + // then write the DIB row + + for (x = 0; x < width / 2; x++) + bits[x] = (buffer[2*x] << 4) | buffer[2*x+1]; + + // skip trailing garbage at the end of the scanline + + for (int count = written; count < linelength; count++) + io.read_proc(&skip, sizeof(BYTE), 1, handle); + + bits -= pitch; + } + + free(buffer); + } else if((header.planes == 3) && (header.bpp == 8)) { + BYTE *pline; + + for (WORD y = 0; y < height; y++) { + readline(io, handle, line, linelength, rle); + + // convert the plane stream to BGR (RRRRGGGGBBBB -> BGRBGRBGRBGR) + + pline = line; + + for (int plane = 2; plane >= 0; plane--) { + for (WORD x = 0; x < width; x++) + bits[x * 3 + plane] = pline[x]; + + pline += header.bytes_per_line; + } + + bits -= pitch; + } + } else { + throw "Unable to read this file"; + } + + free(line); + return dib; + + } catch (char *text) { + // free allocated memory + + if (dib != NULL) + freeimage.free_proc(dib); + + if (line != NULL) + free(line); + + freeimage.output_message_proc(s_format_id, text); + + return NULL; + } + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitPCX(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.validate_proc = Validate; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; +} diff --git a/freeimage241/Source/FreeImage/PluginPNG.cpp b/freeimage241/Source/FreeImage/PluginPNG.cpp new file mode 100644 index 0000000..d42fbc8 --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginPNG.cpp @@ -0,0 +1,610 @@ +// ========================================================== +// PNG Loader and Writer +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Herve Drolon (drolon@infonie.fr) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +#include +#include + +// ---------------------------------------------------------- + +#define PNG_ASSEMBLER_CODE_SUPPORTED +#define PNG_BYTES_TO_CHECK 8 + +// ---------------------------------------------------------- + +#include "../LibPNG/png.h" + +// ---------------------------------------------------------- + +static FreeImageIO *s_io; +static fi_handle s_handle; + +///////////////////////////////////////////////////////////////////////////// +// libpng interface +// + +static void +_ReadProc(struct png_struct_def *, unsigned char *data, unsigned int size) { + s_io->read_proc(data, size, 1, s_handle); +} + +static void +_WriteProc(struct png_struct_def *, unsigned char *data, unsigned int size) { + s_io->write_proc(data, size, 1, s_handle); +} + +static void +_FlushProc(png_structp png_ptr) { + // empty flush implementation +} + +static void +error_handler(struct png_struct_def *, const char *error) { + throw error; +} + +// in FreeImage warnings disabled + +static void +warning_handler(struct png_struct_def *, const char *warning) { +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "PNG"; +} + +static const char * DLL_CALLCONV +Description() { + return "Portable Network Graphics"; +} + +static const char * DLL_CALLCONV +Extension() { + return "png"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return "^.PNG\r"; +} + +static const char * DLL_CALLCONV +MimeType() { + return "image/png"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + BYTE signature[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + io.read_proc(&signature, 1, 8, handle); + + return (memcmp(png_signature, signature, 8) == 0); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + png_colorp png_palette; + int bpp, color_type, palette_entries; + + FIBITMAP *dib = NULL; + RGBQUAD *palette; // pointer to dib palette + png_bytepp row_pointers = NULL; + int i; + + s_io = &io; + s_handle = handle; + + if (handle) { + try { + // check to see if the file is in fact a PNG file + + unsigned char png_check[PNG_BYTES_TO_CHECK]; + + io.read_proc(png_check, 1, PNG_BYTES_TO_CHECK, handle); + + if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) + return NULL; // Bad signature + + // create the chunk manage structure + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)error_handler, error_handler, warning_handler); + + if (!png_ptr) + return NULL; + + // create the info structure + + info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return NULL; + } + + // init the IO + + png_set_read_fn(png_ptr, info_ptr, _ReadProc); + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + + // Because we have already read the signature... + + png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); + + // read the IHDR chunk + + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bpp, &color_type, NULL, NULL, NULL); + + // DIB's don't support >8 bits per sample + // => tell libpng to strip 16 bit/color files down to 8 bits/color + + if (bpp == 16) { + png_set_strip_16(png_ptr); + bpp = 8; + } + + // Set some additional flags + + switch(color_type) { + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + // Flip the RGB pixels to BGR (or RGBA to BGRA) + + png_set_bgr(png_ptr); + break; + + case PNG_COLOR_TYPE_PALETTE: + // Expand palette images to the full 8 bits from 2 or 4 bits/pixel + + if ((bpp == 2) || (bpp == 4)) { + png_set_packing(png_ptr); + bpp = 8; + } + + break; + + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + // Expand grayscale images to the full 8 bits from 2 or 4 bits/pixel + + if ((bpp == 2) || (bpp == 4)) { + png_set_expand(png_ptr); + bpp = 8; + } + + break; + + default: + throw "PNG format not supported"; + } + + // Set the background color to draw transparent and alpha images over. + // It is possible to set the red, green, and blue components directly + // for paletted images instead of supplying a palette index. Note that + // even if the PNG file supplies a background, you are not required to + // use it - you should use the (solid) application background if it has one. + + if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) { + png_color_16 my_background= { 0, 255, 255, 255, 0 }; + png_color_16 *image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + + // if this image has transparency, store the trns values + + png_bytep trans = NULL; + int num_trans = 0; + png_color_16p trans_values = NULL; + png_uint_32 transparent_value = png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); + + // unlike the example in the libpng documentation, we have *no* idea where + // this file may have come from--so if it doesn't have a file gamma, don't + // do any correction ("do no harm") + + double gamma = 0; + double screen_gamma = 2.2; + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + + // All transformations have been registered; now update info_ptr data + + png_read_update_info(png_ptr, info_ptr); + + // Create a DIB and write the bitmap header + // set up the DIB palette, if needed + + switch (color_type) { + case PNG_COLOR_TYPE_RGB: + png_set_invert_alpha(png_ptr); + + dib = freeimage.allocate_proc(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + break; + + case PNG_COLOR_TYPE_RGB_ALPHA : + dib = freeimage.allocate_proc(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + break; + + case PNG_COLOR_TYPE_PALETTE : + dib = freeimage.allocate_proc(width, height, bpp); + + png_get_PLTE(png_ptr,info_ptr, &png_palette,&palette_entries); + + palette = freeimage.get_palette_proc(dib); + + // store the palette + + for (i = 0; i < palette_entries; i++) { + palette[i].rgbRed = png_palette[i].red; + palette[i].rgbGreen = png_palette[i].green; + palette[i].rgbBlue = png_palette[i].blue; + } + + // store the transparency table + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + freeimage.set_transparency_table_proc(dib, (BYTE *)trans, num_trans); + + break; + + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + dib = freeimage.allocate_proc(width, height, bpp); + + palette = freeimage.get_palette_proc(dib); + palette_entries = 1 << bpp; + + for (i = 0; i < palette_entries; i++) { + palette[i].rgbRed = + palette[i].rgbGreen = + palette[i].rgbBlue = (i * 255) / (palette_entries - 1); + } + + // store the transparency table + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + freeimage.set_transparency_table_proc(dib, (BYTE *)trans, num_trans); + + break; + } + + // DIBs *do* support physical resolution + + if (png_get_valid(png_ptr,info_ptr,PNG_INFO_pHYs)) { + png_uint_32 res_x, res_y; + + // We'll overload this var and use 0 to mean no phys data, + // since if it's not in meters we can't use it anyway + + int res_unit_type = 0; + + png_get_pHYs(png_ptr,info_ptr,&res_x,&res_y,&res_unit_type); + + if (res_unit_type == 1) { + BITMAPINFOHEADER *bih = freeimage.get_info_header_proc(dib); + + bih->biXPelsPerMeter = res_x; + bih->biYPelsPerMeter = res_y; + } + } + + // set the individual row_pointers to point at the correct offsets + + row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); + + if (!row_pointers) { + if (palette) + png_free(png_ptr, palette); + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + freeimage.free_proc(dib); + free(row_pointers); + return NULL; + } + + // read in the bitmap bits via the pointer table + + for (png_uint_32 k = 0; k < height; k++) + row_pointers[height - 1 - k] = freeimage.get_scanline_proc(dib, k); + + png_read_image(png_ptr, row_pointers); + + // check if the bitmap contains transparency, if so enable it in the header + + if (freeimage.get_bpp_proc(dib) == 32) + if (freeimage.get_color_type_proc(dib) == FIC_RGBALPHA) + freeimage.set_transparent_proc(dib, TRUE); + else + freeimage.set_transparent_proc(dib, FALSE); + + // cleanup + + if (row_pointers) + free(row_pointers); + + png_read_end(png_ptr, info_ptr); + + if (png_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + return dib; + } catch (const char *text) { + if (png_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + if (row_pointers) + free(row_pointers); + + if (dib) + freeimage.free_proc(dib); + + freeimage.output_message_proc(s_format_id, text); + + return NULL; + } + } + + return NULL; +} + +static BOOL DLL_CALLCONV +Save(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette = NULL; + png_uint_32 width, height, bpp; + BOOL has_alpha_channel = FALSE; + + RGBQUAD *pal; // pointer to dib palette + int bit_depth; + int palette_entries; + int interlace_type; + + s_io = &io; + s_handle = handle; + + if ((dib) && (handle)) { + try { + // create the chunk manage structure + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)error_handler, error_handler, warning_handler); + + if (!png_ptr) { + return FALSE; + } + + // Allocate/initialize the image information data. + + info_ptr = png_create_info_struct(png_ptr); + + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return FALSE; + } + + // Set error handling. REQUIRED if you aren't supplying your own + // error handling functions in the png_create_write_struct() call. + + if (setjmp(png_jmpbuf(png_ptr))) { + // If we get here, we had a problem reading the file + + png_destroy_write_struct(&png_ptr, &info_ptr); + + return FALSE; + } + + // init the IO + + png_set_write_fn(png_ptr, info_ptr, _WriteProc, _FlushProc); + + // DIBs *do* support physical resolution + + BITMAPINFOHEADER *bih = freeimage.get_info_header_proc(dib); + png_uint_32 res_x = bih->biXPelsPerMeter; + png_uint_32 res_y = bih->biYPelsPerMeter; + + if ((res_x > 0) && (res_y > 0)) { + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, 1); + } + + // Set the image information here. Width and height are up to 2^31, + // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + + width = freeimage.get_width_proc(dib); + height = freeimage.get_height_proc(dib); + bpp = bit_depth = freeimage.get_bpp_proc(dib); + + if (bit_depth == 16) { + png_destroy_write_struct(&png_ptr, &info_ptr); + + throw "Format not supported"; // Note: this could be enhanced here... + } + + bit_depth = (bit_depth > 8) ? 8 : bit_depth; + + interlace_type = PNG_INTERLACE_NONE; // Default value + + switch (freeimage.get_color_type_proc(dib)) { + case FIC_MINISWHITE: + // Invert monochrome files to have 0 as black and 1 as white + // (no break here) + png_set_invert_mono(png_ptr); + + case FIC_MINISBLACK: + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + PNG_COLOR_TYPE_GRAY, interlace_type, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + break; + + case FIC_PALETTE: + { + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + PNG_COLOR_TYPE_PALETTE, interlace_type, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + // set the palette + + palette_entries = 1 << bit_depth; + palette = (png_colorp)png_malloc(png_ptr, palette_entries * sizeof (png_color)); + pal = freeimage.get_palette_proc(dib); + + for (int i = 0; i < palette_entries; i++) { + palette[i].red = pal[i].rgbRed; + palette[i].green = pal[i].rgbGreen; + palette[i].blue = pal[i].rgbBlue; + } + + png_set_PLTE(png_ptr, info_ptr, palette, palette_entries); + + // You must not free palette here, because png_set_PLTE only makes a link to + // the palette that you malloced. Wait until you are about to destroy + // the png structure. + + break; + } + + case FIC_RGBALPHA : + if (freeimage.is_transparent_proc(dib)) { + has_alpha_channel = TRUE; + + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + PNG_COLOR_TYPE_RGBA, interlace_type, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_bgr(png_ptr); // flip BGR pixels to RGB + break; + } + + // intentionally no break here... + + case FIC_RGB: + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + PNG_COLOR_TYPE_RGB, interlace_type, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_bgr(png_ptr); // flip BGR pixels to RGB + break; + } + + // Optional gamma chunk is strongly suggested if you have any guess + // as to the correct gamma of the image. + // png_set_gAMA(png_ptr, info_ptr, gamma); + + if ((freeimage.get_bpp_proc(dib) == 8) && (freeimage.is_transparent_proc(dib)) && (freeimage.get_transparency_count_proc(dib) > 0)) + png_set_tRNS(png_ptr, info_ptr, freeimage.get_transparency_table_proc(dib), freeimage.get_transparency_count_proc(dib), NULL); + + // Write the file header information. + + png_write_info(png_ptr, info_ptr); + + // write out the image data + + if ((bpp == 32) && (!has_alpha_channel)) { + BYTE *buffer = (BYTE *)malloc(width * 3); + + for (png_uint_32 k = 0; k < height; k++) { + freeimage.convert_line_32to24_proc(buffer, freeimage.get_scanline_proc(dib, height - k - 1), width); + + png_write_row(png_ptr, buffer); + } + + free(buffer); + } else { + for (png_uint_32 k = 0; k < height; k++) { + png_write_row(png_ptr, freeimage.get_scanline_proc(dib, height - k - 1)); + } + } + + // It is REQUIRED to call this to finish writing the rest of the file + // Bug with png_flush + + png_write_end(png_ptr, info_ptr); + + // clean up after the write, and free any memory allocated + + png_destroy_write_struct(&png_ptr, &info_ptr); + + if (palette) + png_free(png_ptr, palette); + + return TRUE; + } catch (const char *text) { + freeimage.output_message_proc(s_format_id, text); + } + } + + return FALSE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitPNG(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.pagecount_proc = NULL; + plugin.pagecapability_proc = NULL; + plugin.load_proc = Load; + plugin.save_proc = 0; //Save; + plugin.validate_proc = Validate; + plugin.mime_proc = MimeType; +} diff --git a/freeimage241/Source/FreeImage/PluginPNM.cpp b/freeimage241/Source/FreeImage/PluginPNM.cpp new file mode 100644 index 0000000..87e02af --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginPNM.cpp @@ -0,0 +1,599 @@ +// ========================================================== +// PNM (PPM, PGM, PBM) Loader and Writer +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@infonie.fr) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include // for sprintf() +#include + +#include "FreeImage.h" +#include "Utilities.h" + +// ========================================================== +// Internal functions +// ========================================================== + +static int +GetInt(FreeImageIO &io, fi_handle handle) { + // get an integer value from the actual position pointed by handle + + char c = 0; + BOOL firstchar; + + // skip forward to start of next number + + io.read_proc(&c, 1, 1, handle); + + while (1) { + // eat comments + + if (c == '#') { + // if we're at a comment, read to end of line + + firstchar = TRUE; + + while (1) { + io.read_proc(&c, 1, 1, handle); + + if (firstchar && c == ' ') { + // loop off 1 sp after # + + firstchar = FALSE; + } else if(c == '\n') { + break; + } + } + } + + if (c >= '0' && c <='9') { + // we've found what we were looking for + + break; + } + + io.read_proc(&c, 1, 1, handle); + } + + // we're at the start of a number, continue until we hit a non-number + + int i = 0; + + while (1) { + i = (i*10) + (c - '0'); + + io.read_proc(&c, 1, 1, handle); + + if (c < '0' || c > '9') + break; + } + + return i; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "PNM"; +} + +static const char * DLL_CALLCONV +Description() { + return "Portable Network Media"; +} + +static const char * DLL_CALLCONV +Extension() { + return "pbm,pgm,ppm"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE pbm_id1[] = { 0x50, 0x31 }; + BYTE pbm_id2[] = { 0x50, 0x34 }; + BYTE pgm_id1[] = { 0x50, 0x32 }; + BYTE pgm_id2[] = { 0x50, 0x35 }; + BYTE ppm_id1[] = { 0x50, 0x33 }; + BYTE ppm_id2[] = { 0x50, 0x36 }; + BYTE signature[2] = { 0, 0 }; + + io.read_proc(signature, 1, sizeof(pbm_id1), handle); + + if (memcmp(pbm_id1, signature, sizeof(pbm_id1)) == 0) + return TRUE; + + if (memcmp(pbm_id1, signature, sizeof(pbm_id2)) == 0) + return TRUE; + + if (memcmp(pbm_id1, signature, sizeof(pgm_id1)) == 0) + return TRUE; + + if (memcmp(pbm_id1, signature, sizeof(pgm_id2)) == 0) + return TRUE; + + if (memcmp(pbm_id1, signature, sizeof(ppm_id1)) == 0) + return TRUE; + + if (memcmp(pbm_id1, signature, sizeof(ppm_id2)) == 0) + return TRUE; + + return FALSE; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + char id_one, id_two; + WORD x, y; + FIBITMAP *dib; + BYTE *bits; // pointer to dib data + RGBQUAD *pal; // pointer to dib palette + int i, max, level; + + if (!handle) + return NULL; + + try { + // Read the first two bytes of the file to determine the file format + // "P1" = ascii bitmap, "P2" = ascii greymap, "P3" = ascii pixmap, + // "P4" = raw bitmap, "P5" = raw greymap, "P6" = raw pixmap + + io.read_proc(&id_one, 1, 1, handle); + io.read_proc(&id_two, 1, 1, handle); + + if (id_one != 'P' || id_two < '1' || id_two > '6') { + throw "Invalid magic number"; + } + + // Read the header information + + int width = GetInt(io, handle); + int height = GetInt(io, handle); + + // Create a new DIB + + switch (id_two) { + case '1': + case '4': + dib = freeimage.allocate_proc(width, height, 1); + break; + + case '2': + case '5': + dib = freeimage.allocate_proc(width, height, 8); + break; + + case '3': + case '6': + dib = freeimage.allocate_proc(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + break; + } + + if (dib == NULL) + throw "DIB allocation failed"; + + // Read the image... + + int pitch = freeimage.get_pitch_proc(dib); + + switch(id_two) { + case '1': + case '4': + // write the palette data + + pal = freeimage.get_palette_proc(dib); + pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; + pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; + + // write the bitmap data + + if (id_two == '1') { // ASCII bitmap + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < width; x++) { + if (GetInt(io, handle) == 0) + bits[x >> 3] |= (0x80 >> (x & 0x7)); + else + bits[x >> 3] &= (0xFF7F >> (x & 0x7)); + } + } + } else { // Raw bitmap + int line = CalculateLine(width, 1); + + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < line; x++) { + io.read_proc(&bits[x], 1, 1, handle); + + bits[x] = ~bits[x]; + } + } + } + + return dib; + + case '2': + case '5': + // Build a greyscale palette + + pal = freeimage.get_palette_proc(dib); + + for (i = 0; i < 256; i++) { + pal[i].rgbRed = + pal[i].rgbGreen = + pal[i].rgbBlue = i; + } + + max = GetInt(io, handle); // read the 'max' value + + // write the bitmap data + + if(id_two == '2') { // ASCII greymap + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + for (x = 0; x < width; x++) { + level = GetInt(io, handle); + bits[x] = (BYTE)((255 * level) / max); + } + } + } else { // Raw greymap + level = 0; + + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < width; x++) { + io.read_proc(&level, 1, 1, handle); + bits[x] = (BYTE)((255 * level) / max); + } + } + } + + return dib; + + case '3': + case '6': + max = GetInt(io, handle); // read the 'max' value + + // write the bitmap data + + if (id_two == '3') { // ASCII pixmap + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < width; x++) { + bits[2] = (BYTE)((255 * GetInt(io, handle)) / max); // R + bits[1] = (BYTE)((255 * GetInt(io, handle)) / max); // G + bits[0] = (BYTE)((255 * GetInt(io, handle)) / max); // B + + bits += 3; + } + } + } else { // Raw pixmap + level = 0; + + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < width; x++) { + io.read_proc(&level, 1, 1, handle); + bits[2] = (BYTE)((255 * level) / max); // R + + io.read_proc(&level, 1, 1, handle); + bits[1] = (BYTE)((255 * level) / max); // G + + io.read_proc(&level, 1, 1, handle); + bits[0] = (BYTE)((255 * level) / max); // B + + bits += 3; + } + } + } + + return dib; + } + + } catch(char *text) { + switch(id_two) { + case '1': + case '4': + freeimage.output_message_proc(s_format_id, text); + break; + case '2': + case '5': + freeimage.output_message_proc(s_format_id, text); + break; + case '3': + case '6': + freeimage.output_message_proc(s_format_id, text); + break; + } + + return NULL; + } + + return NULL; +} + +static BOOL DLL_CALLCONV +Save(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + // ---------------------------------------------------------- + // PNM Saving + // ---------------------------------------------------------- + // + // Output format : + // + // Bit depth flags file format + // ------------- -------------- ----------- + // 1-bit / pixel PNM_SAVE_ASCII PBM (P1) + // 1-bit / pixel PNM_SAVE_RAW PBM (P4) + // 8-bit / pixel PNM_SAVE_ASCII PGM (P2) + // 8-bit / pixel PNM_SAVE_RAW PGM (P5) + // 24-bit / pixel PNM_SAVE_ASCII PPM (P3) + // 24-bit / pixel PNM_SAVE_RAW PPM (P6) + // ---------------------------------------------------------- + + int magic, bpp; + WORD x, y, width, height; + BYTE *bits; // pointer to dib data + + if ((dib) && (handle)) { + bpp = freeimage.get_bpp_proc(dib); + width = freeimage.get_width_proc(dib); + height = freeimage.get_height_proc(dib); + + // Find the appropriate magic number for this file type + + magic = 0; + + switch (bpp) { + case 1 : + magic = 1; // PBM file (B & W) + break; + case 8 : + magic = 2; // PGM file (Greyscale) + break; + + case 24 : + magic = 3; // PPM file (RGB) + break; + + case 32 : + if (!freeimage.is_transparent_proc(dib)) + magic = 3; + else + throw "PNM does not support alpha channels"; + + break; + + default: + return FALSE; // Invalid bit depth + } + + if (flags == PNM_SAVE_RAW) + magic += 3; + + // Write the header info + + char buffer[20]; + sprintf(buffer, "P%d\n%d %d\n", magic, width, height); + io.write_proc(&buffer, strlen(buffer), 1, handle); + + if (bpp != 1) { + sprintf(buffer, "255\n"); + io.write_proc(&buffer, strlen(buffer), 1, handle); + } + + // Write the image data + /////////////////////// + + int pitch = (bpp == 32) ? CalculatePitch(CalculateLine(width, 24)) : freeimage.get_pitch_proc(dib); + + switch(bpp) { + case 32 : + case 24 : // 24-bit RGB, 3 bytes per pixel + { + if (flags == PNM_SAVE_RAW) { + BYTE *buffer = (BYTE *)malloc(pitch); + + for (y = 0; y < height; y++) { + // get a pointer to the (converted) scanline + + if (bpp == 32) + freeimage.convert_line_32to24_proc(buffer, freeimage.get_scanline_proc(dib, height - y - 1), width); + else + memcpy(buffer, freeimage.get_scanline_proc(dib, height - 1 - y), pitch); + + // write the scanline to disc + + BYTE *bits = buffer; + + for (x = 0; x < width; x++) { + io.write_proc(&bits[2], 1, 1, handle); // R + io.write_proc(&bits[1], 1, 1, handle); // G + io.write_proc(&bits[0], 1, 1, handle); // B + + bits += 3; + } + } + + free(buffer); + } else { + int length = 0; + + BYTE *buffer = (BYTE *)malloc(pitch); + + for (y = 0; y < height; y++) { + // get a pointer to the (converted) scanline + + if (bpp == 32) + freeimage.convert_line_32to24_proc(buffer, freeimage.get_scanline_proc(dib, height - 1 - y), width); + else + memcpy(buffer, freeimage.get_scanline_proc(dib, height - 1 - y), pitch); + + // write the scanline to disc + + BYTE *bits = buffer; + + for (x = 0; x < width; x++) { + char buffer[20]; + + sprintf(buffer, "%3d %3d %3d ", bits[2], bits[1], bits[0]); + + io.write_proc(&buffer, strlen(buffer), 1, handle); + + length += 12; + + if(length > 58) { + sprintf(buffer, "\n"); + + io.write_proc(&buffer, strlen(buffer), 1, handle); + + length = 0; + } + + bits += 3; + } + } + + free(buffer); + } + + break; + } + + case 8: // 8-bit greyscale + { + if (flags == PNM_SAVE_RAW) { + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < width; x++) { + io.write_proc(&bits[x], 1, 1, handle); + } + } + } else { + int length = 0; + + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < width; x++) { + sprintf(buffer, "%3d ", bits[x]); + + io.write_proc(&buffer, strlen(buffer), 1, handle); + + length += 4; + + if (length > 66) { + sprintf(buffer, "\n"); + + io.write_proc(&buffer, strlen(buffer), 1, handle); + + length = 0; + } + } + } + } + + break; + } + + case 1: // 1-bit B & W + { + RGBQUAD *pal = freeimage.get_palette_proc(dib); + int color; + + if (flags == PNM_SAVE_RAW) { + for(y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for(x = 0; x < freeimage.get_line_proc(dib); x++) + io.write_proc(&bits[x], 1, 1, handle); + } + } else { + int length = 0; + + for (y = 0; y < height; y++) { + bits = freeimage.get_bits_proc(dib) + (height - 1 - y) * pitch; + + for (x = 0; x < freeimage.get_line_proc(dib) * 8; x++) { + color = (bits[x>>3] & (0x80 >> (x & 0x07))) != 0; + + sprintf(buffer, "%c ", color ? '1':'0'); + + io.write_proc(&buffer, strlen(buffer), 1, handle); + + length += 2; + + if (length > 68) { + sprintf(buffer, "\n"); + + io.write_proc(&buffer, strlen(buffer), 1, handle); + + length = 0; + } + } + } + } + } + + break; + } + + return TRUE; + } + + return FALSE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitPNM(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.save_proc = Save; + plugin.validate_proc = Validate; +} + diff --git a/freeimage241/Source/FreeImage/PluginPSD.cpp b/freeimage241/Source/FreeImage/PluginPSD.cpp new file mode 100644 index 0000000..eaa55cb --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginPSD.cpp @@ -0,0 +1,389 @@ +// ========================================================== +// Photoshop Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// Based on public domain code created and +// published by Thatcher Ulrich (ulrich@world.std.com) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" + +// ========================================================== +// Bitmap pointer access macros +// ========================================================== + +#define BP_START(DIB, WIDTH, HEIGHT) \ + int scanline = 0; \ + unsigned *bits = (unsigned *)freeimage.get_scanline_proc(DIB, HEIGHT - 1 - scanline); \ + unsigned *p = bits; + +#define BP_NEXT(DIB, WIDTH, HEIGHT) \ + p++; \ + if (p - bits == width) { \ + scanline++; \ + bits = (unsigned *)freeimage.get_scanline_proc(DIB, HEIGHT - 1 - scanline); \ + p = bits; \ + } + +#define BP_SETVALUE(VALUE) \ + *p |= VALUE; + +// ========================================================== +// Internal functions +// ========================================================== + +static unsigned +Read8(FreeImageIO &io, fi_handle handle) { + unsigned i = 0; + io.read_proc(&i, 1, 1, handle); + return i; +} + +static unsigned +Read16(FreeImageIO &io, fi_handle handle) { + // reads a two-byte big-endian integer from the given file and returns its value. + // assumes unsigned. + + unsigned hi = Read8(io, handle); + unsigned lo = Read8(io, handle); + return lo + (hi << 8); +} + +static unsigned +Read32(FreeImageIO &io, fi_handle handle) { + // reads a four-byte big-endian integer from the given file and returns its value. + // assumes unsigned. + + unsigned b3 = Read8(io, handle); + unsigned b2 = Read8(io, handle); + unsigned b1 = Read8(io, handle); + unsigned b0 = Read8(io, handle); + return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0; +} + +// ---------------------------------------------------------- + +static void +ScanForResolution(float* hres, float* vres, FreeImageIO &io, fi_handle handle, int width, int height, int channel_count, int byte_count) { + // scans through the next byte_count bytes of the file, looking for an + // image resource block encoding the image's resolution. Returns the resolution(s), + // if found, in the pointed-to floats. Units are in pixels/meter. + + while (byte_count) { + // read the image resource block header. + + if (Read32(io, handle) != 0x3842494D /* "8BIM" */) + throw "image resource block has unknown signature"; + + int id = Read16(io, handle); + + // skip the name. + + int name_length = Read8(io, handle) | 1; // name_length must be odd, so that total including size byte is even. + + io.seek_proc(handle, name_length, SEEK_CUR); + + // get the size of the data block. + + int data_size = Read32(io, handle); + + if (data_size & 1 == 1) + data_size += 1; // block size must be even. + + // account for header size. + + byte_count -= 11 + name_length; + + // if this block is a resolution info structure, then get the resolution. + + if (id == 0x03ED) { + int junk; + + int hres_fixed = Read32(io, handle); + junk = Read16(io, handle); // display units of hres. + junk = Read16(io, handle); // display units of width. + + int vres_fixed = Read32(io, handle); + junk = Read16(io, handle); // display units of vres. + junk = Read16(io, handle); // display units of height. + + byte_count -= data_size; + data_size -= 16; + + // skip any extra bytes at the end of this block... + + if (data_size > 0) + io.seek_proc(handle, data_size, SEEK_CUR); + + // need to convert resolution figures from fixed point, pixels/inch + // to floating point, pixels/meter. + + *hres = hres_fixed * ((float)39.4 / (float)65536.0); + *vres = vres_fixed * ((float)39.4 / (float)65536.0); + } else { + // skip the rest of this block. + + io.seek_proc(handle, data_size, SEEK_CUR); + + byte_count -= data_size; + } + } +} + +// ---------------------------------------------------------- + +static FIBITMAP * +LoadPSDRGB(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int width, int height, int channel_count) { + // skip the mode data. (it's the palette for indexed color; other info for other modes.) + + int mode_data_count = Read32(io, handle); + + if (mode_data_count) + io.seek_proc(handle, mode_data_count, SEEK_CUR); + + // skip the image resources. (resolution, pen tool paths, alpha channel names, etc) + + int resource_data_count = Read32(io, handle); + + if (resource_data_count) + io.seek_proc(handle, resource_data_count, SEEK_CUR); + + // skip the reserved data + + int reserved_data_count = Read32(io, handle); + + if (reserved_data_count) + io.seek_proc(handle, reserved_data_count, SEEK_CUR); + + // find out if the data is compressed + // 0: no compressiod + // 1: RLE compressed + + unsigned compression = Read16(io, handle); + + if ((compression > 1) || (compression < 0)) + return NULL; + + // some formatting information about the channels + + const struct ChannelInfo { + int shift, mask, deflt; + } Channel[4] = { + { 16, 0x00FF0000, 0 }, // red + { 8, 0x0000FF00, 0 }, // green + { 0, 0x000000FF, 0 }, // blue + { 24, 0xFF000000, 255 } // alpha + }; + + // Create the destination bitmap + + FIBITMAP *dib = freeimage.allocate_proc(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + + // finally, read the image data. + + if (compression) { + // the RLE-compressed data is preceeded by a 2-byte data count for each row in the data + + io.seek_proc(handle, height * channel_count * 2, SEEK_CUR); + + // read the RLE data by channel + + for (int channel = 0; channel < (channel_count > 4 ? 4 : channel_count); channel++) { + const ChannelInfo &c = Channel[channel]; + + BP_START(dib, width, height) + + if (channel >= channel_count) { + // fill this channel with default data. + + unsigned def = (c.deflt << c.shift) & c.mask; + + for (int i = 0; i < width * height; i++) { + BP_SETVALUE(def); + BP_NEXT(dib, width, height) + } + } else { + // read the RLE data. + + int count = 0; + + while (count < width * height) { + int len = Read8(io, handle); + + if (len == 128) { + // nop + } else if (len < 128) { + // copy next len + 1 bytes literally. + + len++; + count += len; + + while (len) { + BP_SETVALUE(((Read8(io, handle) << c.shift) & c.mask)); + BP_NEXT(dib, width, height) + + len--; + } + } else if (len > 128) { + // next -len + 1 bytes in the dest are replicated from next source byte. + // (interpret len as a negative 8-bit int.) + + len ^= 0x0FF; + len += 2; + count += len; + + unsigned val = (Read8(io, handle) << c.shift) & c.mask; + + while (len) { + BP_SETVALUE(val); + BP_NEXT(dib, width, height) + + len--; + } + } + } + } + } + } else { + // we're at the raw image data. it's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + for (int channel = 0; channel < 4; channel++) { + const ChannelInfo &c = Channel[channel]; + + BP_START(dib, width, height) + + if (channel > channel_count) { + // fill this channel with default data. + + unsigned def = (c.deflt << c.shift) & c.mask; + + for (int i = 0; i < width * height; i++) { + BP_SETVALUE(def); + BP_NEXT(dib, width, height) + } + } else { + // read the data + + for (int i = 0; i < width * height; i++) { + BP_SETVALUE((Read8(io, handle) << c.shift) & c.mask); + BP_NEXT(dib, width, height) + } + } + } + } + + return dib; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "PSD"; +} + +static const char * DLL_CALLCONV +Description() { + return "Adobe Photoshop"; +} + +static const char * DLL_CALLCONV +Extension() { + return "psd"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + return (Read32(io, handle) == 0x38425053); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + try { + if (Read32(io, handle) == 0x38425053) { + if (Read16(io, handle) == 1) { + // 6 reserved bytes. + + Read32(io, handle); + Read16(io, handle); + + // Read the number of channels (R, G, B, A, etc). + + unsigned channel_count = Read16(io, handle); + + if (channel_count >= 0 && channel_count <= 16) { + unsigned height = Read32(io, handle); + unsigned width = Read32(io, handle); + + if (Read16(io, handle) == 8) { + unsigned mode = Read16(io, handle); + + // Valid options are: + // 0: Bitmap (not implemented) + // 1: Grayscale (not implemented) + // 2: Indexed color (not implemented) + // 3: RGB color + // 4: CMYK color (not implemented) + // 7: Multichannel (not implemented) + // 8: Duotone (not implemented) + // 9: Lab color (not implemented) + + switch (mode) { + case 3 : + return LoadPSDRGB(freeimage, io, handle, width, height, channel_count); + + default : + throw "color mode not supported"; + } + } + } + } + } + } catch(const char *message) { + freeimage.output_message_proc(s_format_id, message); + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitPSD(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.validate_proc = Validate; + plugin.load_proc = Load; +} diff --git a/freeimage241/Source/FreeImage/PluginRAS.cpp b/freeimage241/Source/FreeImage/PluginRAS.cpp new file mode 100644 index 0000000..a8bd01b --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginRAS.cpp @@ -0,0 +1,470 @@ +// ========================================================== +// Sun rasterfile Loader +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include +#include + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct { + DWORD magic; // Magic number + DWORD width; // Image width in pixels + DWORD height; // Image height in pixels + DWORD depth; // Depth (1, 8, 24 or 32 bits) of each pixel + DWORD length; // Image length (in bytes) + DWORD type; // Format of file (see RT_* below) + DWORD maptype; // Type of colormap (see RMT_* below) + DWORD maplength; // Length of colormap (in bytes) +} Sun_Header; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// ---------------------------------------------------------- + +// Following the header is the colormap, for maplength bytes (unless maplength is zero), +// then the image. Each row of the image is rounded to 2 bytes. + +#define RAS_MAGIC 0x59A66A95 // Magic number for Sun rasterfiles + +// Sun supported type's + +#define RT_OLD 0 // Old format (raw image in 68000 byte order) +#define RT_STANDARD 1 // Raw image in 68000 byte order +#define RT_BYTE_ENCODED 2 // Run-length encoding of bytes +#define RT_FORMAT_RGB 3 // XRGB or RGB instead of XBGR or BGR +#define RT_FORMAT_TIFF 4 // TIFF <-> standard rasterfile +#define RT_FORMAT_IFF 5 // IFF (TAAC format) <-> standard rasterfile + +#define RT_EXPERIMENTAL 0xffff // Reserved for testing + +// These are the possible colormap types. +// if it's in RGB format, the map is made up of three byte arrays +// (red, green, then blue) that are each 1/3 of the colormap length. + +#define RMT_NONE 0 // maplength is expected to be 0 +#define RMT_EQUAL_RGB 1 // red[maplength/3], green[maplength/3], blue[maplength/3] +#define RMT_RAW 2 // Raw colormap +#define RESC 128 // Run-length encoding escape character + +// ----- NOTES ----- +// Each line of the image is rounded out to a multiple of 16 bits. +// This corresponds to the rounding convention used by the memory pixrect +// package (/usr/include/pixrect/memvar.h) of the SunWindows system. +// The ras_encoding field (always set to 0 by Sun's supported software) +// was renamed to ras_length in release 2.0. As a result, rasterfiles +// of type 0 generated by the old software claim to have 0 length; for +// compatibility, code reading rasterfiles must be prepared to compute the +// TRUE length from the width, height, and depth fields. + +// ========================================================== +// Internal functions +// ========================================================== + +static void +SwapLong(DWORD *lp) { + // Byte Swapping Support + + register BYTE *cp = (BYTE*) lp; + + BYTE t; + + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; +} + +static void +ReadData(FreeImageIO &io, fi_handle handle, BYTE *buf, DWORD length, BOOL rle) { + // Read either Run-Length Encoded or normal image data + + static BYTE repchar, remaining= 0; + + if (rle) { + // Run-length encoded read + + while(length--) { + if (remaining) { + remaining--; + *(buf++)= repchar; + } else { + io.read_proc(&repchar, 1, 1, handle); + + if (repchar == RESC) { + io.read_proc(&remaining, 1, 1, handle); + + if (remaining == 0) { + *(buf++)= RESC; + } else { + io.read_proc(&repchar, 1, 1, handle); + + *(buf++)= repchar; + } + } else { + *(buf++)= repchar; + } + } + } + } else { + // Normal read + + io.read_proc(buf, length, 1, handle); + } +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "RAS"; +} + +static const char * DLL_CALLCONV +Description() { + return "Sun Raster Image"; +} + +static const char * DLL_CALLCONV +Extension() { + return "ras"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE ras_signature[] = { 0x59, 0xA6, 0x6A, 0x95 }; + BYTE signature[4] = { 0, 0, 0, 0 }; + + io.read_proc(signature, 1, sizeof(ras_signature), handle); + + return (memcmp(ras_signature, signature, sizeof(ras_signature)) == 0); +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + Sun_Header header; // Sun file header + WORD linelength; // Length of raster line in bytes + WORD fill; // Number of fill bytes per raster line + BOOL rle; // TRUE if RLE file + BOOL isRGB; // TRUE if file type is RT_FORMAT_RGB + BYTE fillchar; + + FIBITMAP *dib = NULL; + BYTE *bits; // Pointer to dib data + WORD x, y; + + if (handle) { + try { + // Read SUN raster header + + io.read_proc(&header, sizeof(Sun_Header), 1, handle); + + // SUN rasterfiles are big endian only + + SwapLong(&header.magic); + SwapLong(&header.width); + SwapLong(&header.height); + SwapLong(&header.depth); + SwapLong(&header.length); + SwapLong(&header.type); + SwapLong(&header.maptype); + SwapLong(&header.maplength); + + // Verify SUN identifier + + if (header.magic != RAS_MAGIC) + throw "Invalid magic number"; + + // Allocate a new DIB + + switch(header.depth) { + case 1: + case 8: + dib = freeimage.allocate_proc(header.width, header.height, header.depth); + break; + + case 24: + case 32: + dib = freeimage.allocate_proc(header.width, header.height, header.depth, 0xFF, 0xFF00, 0xFF0000); + break; + } + + if (dib == NULL) + throw "DIB allocation failed"; + + // Check the file format + + rle = FALSE; + isRGB = FALSE; + + switch(header.type) { + case RT_OLD: + case RT_STANDARD: + break; + + case RT_BYTE_ENCODED: + rle = TRUE; + break; + + case RT_FORMAT_RGB: + isRGB = TRUE; + break; + + case RT_FORMAT_TIFF: // I don't even know what these format are... + case RT_FORMAT_IFF: + + default: + throw "Unsupported Sun rasterfile"; + } + + // set up the colormap if needed + + switch(header.maptype) { + case RMT_NONE : + { + if (header.depth < 24) { + // Create linear color ramp + + RGBQUAD *pal = freeimage.get_palette_proc(dib); + + int numcolors = 1 << header.depth; + + for (int i = 0; i < numcolors; i++) { + pal[i].rgbRed = (255 * i) / (numcolors - 1); + pal[i].rgbGreen = (255 * i) / (numcolors - 1); + pal[i].rgbBlue = (255 * i) / (numcolors - 1); + } + } + + break; + } + + case RMT_EQUAL_RGB: + { + BYTE *r, *g, *b; + + // Read SUN raster colormap + + int numcolors = 1 << header.depth; + + r = (BYTE*)malloc(3 * numcolors * sizeof(BYTE)); + g = r + numcolors; + b = g + numcolors; + + RGBQUAD *pal = freeimage.get_palette_proc(dib); + + io.read_proc(r, 3 * numcolors, 1, handle); + + for (int i = 0; i < numcolors; i++) { + pal[i].rgbRed = r[i]; + pal[i].rgbGreen = g[i]; + pal[i].rgbBlue = b[i]; + } + + free(r); + break; + } + + case RMT_RAW: + { + BYTE *colormap; + + // Read (skip) SUN raster colormap. + + colormap = (BYTE *)malloc(header.maplength * sizeof(BYTE)); + + io.read_proc(colormap, header.maplength, 1, handle); + + free(colormap); + break; + } + } + + // Calculate the line + pitch + // Each row is multiple of 16 bits (2 bytes). + + if (header.depth == 1) + linelength = (WORD)((header.width / 8) + (header.width % 8 ? 1 : 0)); + else + linelength = (WORD)header.width; + + fill = (linelength % 2) ? 1 : 0; + + int pitch = freeimage.get_pitch_proc(dib); + + // Read the image data + + switch(header.depth) { + case 1: + case 8: + { + bits = freeimage.get_bits_proc(dib) + (header.height - 1) * pitch; + + for (y = 0; y < header.height; y++) { + ReadData(io, handle, bits, linelength, rle); + + bits -= pitch; + + if (fill) + ReadData(io, handle, &fillchar, fill, rle); + } + + break; + } + + case 24: + { + BYTE *buf, *bp; + + buf = (BYTE*)malloc(header.width * 3); + + for (y = 0; y < header.height; y++) { + bits = freeimage.get_bits_proc(dib) + (header.height - 1 - y) * pitch; + + ReadData(io, handle, buf, header.width * 3, rle); + + bp = buf; + + if (isRGB) { + for (x = 0; x < header.width; x++) { + bits[2] = *(bp++); // red + bits[1] = *(bp++); // green + bits[0] = *(bp++); // blue + + bits += 3; + } + } else { + for (x = 0; x < header.width; x++) { + bits[2] = *(bp + 2); // red + bits[1] = *(bp + 1); // green + bits[0] = *bp; // blue + + bits += 3; bp += 3; + } + } + + if (fill) + ReadData(io, handle, &fillchar, fill, rle); + } + + free(buf); + break; + } + + case 32: + { + BYTE *buf, *bp; + + buf = (BYTE*)malloc(header.width * 4); + + for (y = 0; y < header.height; y++) { + bits = freeimage.get_bits_proc(dib) + (header.height - 1 - y) * pitch; + + ReadData(io, handle, buf, header.width * 4, rle); + + bp = buf; + + if (isRGB) { + for (x = 0; x < header.width; x++) { + bp++; // skip byte + + bits[2] = *(bp++); // red + bits[1] = *(bp++); // green + bits[0] = *(bp++); // blue + + bits += 4; + } + } + else { + for (x = 0; x < header.width; x++) { + bits[2] = *(bp + 3); // red + bits[1] = *(bp + 2); // green + bits[0] = *(bp + 1); // blue + + bits += 4; + bp += 4; + } + } + + if (fill) + ReadData(io, handle, &fillchar, fill, rle); + } + + free(buf); + break; + } + } + + return dib; + + } catch (char *text) { + freeimage.output_message_proc(s_format_id, text); + + return NULL; + } + + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitRAS(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.validate_proc = Validate; +} diff --git a/freeimage241/Source/FreeImage/PluginTARGA.cpp b/freeimage241/Source/FreeImage/PluginTARGA.cpp new file mode 100644 index 0000000..7f6fd9b --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginTARGA.cpp @@ -0,0 +1,839 @@ +// ========================================================== +// TARGA Loader +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Jani Kajala (janik@remedy.fi) +// - Martin Weber (martweb@gmx.net) +// - Machiel ten Brinke (brinkem@uni-one.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Constants + headers +// ---------------------------------------------------------- + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct tagRGBTRIPLE { + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; +} RGBTRIPLE; + +typedef struct tagBGRAQUAD { + BYTE bgraBlue; + BYTE bgraGreen; + BYTE bgraRed; + BYTE bgraAlpha; +} BGRAQUAD; + +struct tagTGAHEADER { + BYTE id_length; + BYTE color_map_type; + BYTE image_type; + + WORD cm_first_entry; + WORD cm_length; + BYTE cm_size; + + WORD is_xorigin; + WORD is_yorigin; + WORD is_width; + WORD is_height; + BYTE is_pixel_depth; + BYTE is_image_descriptor; +}; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// ========================================================== +// Internal functions +// ========================================================== + +static BYTE * +Internal_GetScanLine(FreeImage &freeimage, FIBITMAP *dib, int scanline, int flipvert) { + //assert ((scanline >= 0) && (scanline < (int)freeimage.get_height_proc(dib))); + + if (flipvert) { + return freeimage.get_scanline_proc(dib, scanline); + } else { + return freeimage.get_scanline_proc(dib, freeimage.get_height_proc(dib) - scanline - 1); + } +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "TARGA"; +} + +static const char * DLL_CALLCONV +Description() { + return "Truevision Targa"; +} + +static const char * DLL_CALLCONV +Extension() { + return "tga,targa"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if (handle) { + try { + // remember the start offset + + long start_offset = io.tell_proc(handle); + + // read and process the bitmap's header + + FIBITMAP *dib = NULL; + tagTGAHEADER header; + + io.read_proc(&header, sizeof(tagTGAHEADER), 1, handle); + + int line = CalculateLine(header.is_width, header.is_pixel_depth); + int pitch = CalculatePitch(line); + int alphabits = header.is_image_descriptor & 0x0f; + int fliphoriz = (header.is_image_descriptor & 0x10) ? 0 : 1; + int flipvert = (header.is_image_descriptor & 0x20) ? 1 : 0; + + io.seek_proc(handle, header.id_length, SEEK_CUR); + switch (header.is_pixel_depth) { + case 8 : + { + dib = freeimage.allocate_proc(header.is_width, header.is_height, 8); + + if (dib == NULL) { + throw "DIB allocation failed"; + } + + // read the palette + + RGBQUAD *palette = freeimage.get_palette_proc(dib); + + if (header.color_map_type == 0) + for (unsigned i = 0; i < 256; i++) { + palette[i].rgbRed = i; + palette[i].rgbGreen = i; + palette[i].rgbBlue = i; + } + else if (alphabits) { + for (unsigned count = header.cm_first_entry; count < header.cm_length; count++) { + BGRAQUAD quad; + + io.read_proc(&quad, sizeof(RGBTRIPLE), 1, handle); + + palette[count].rgbBlue = quad.bgraBlue; + palette[count].rgbRed = quad.bgraRed; + palette[count].rgbGreen = quad.bgraGreen; + palette[count].rgbReserved = quad.bgraAlpha; + } + } + else { + for (unsigned count = header.cm_first_entry; count < header.cm_length; count++) { + RGBTRIPLE triple; + + io.read_proc(&triple, sizeof(RGBTRIPLE), 1, handle); + + palette[count].rgbRed = triple.rgbtRed; + palette[count].rgbGreen = triple.rgbtGreen; + palette[count].rgbBlue = triple.rgbtBlue; + } + } + + // read in the bitmap bits + switch (header.image_type) { + case 1 : + case 3 : + { + if (fliphoriz) { + for (unsigned count = header.is_height; count > 0; count--) + io.read_proc(Internal_GetScanLine(freeimage, dib, count - 1, flipvert), line, 1, handle); + + } + else { + for (unsigned count = 0; count < header.is_height; count++) + io.read_proc(Internal_GetScanLine(freeimage, dib, count, flipvert), line, 1, handle); + + } + + break; + } + + case 9 : + case 11: + { + int x = 0; + int y = 0; + BYTE *bits; + + if (fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height - y - 1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + + BYTE rle; + + while(1) { + io.read_proc(&rle,1, 1, handle); + + if (rle>127) { + rle -= 127; + + BYTE triple; + + io.read_proc(&triple, 1, 1, handle); + + for (int ix = 0; ix < rle; ix++) { + bits[x++] = triple; + + if (x >= line) { + x = 0; + + y++; + + if (y >= header.is_height) + goto done89; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } else { + rle++; + + for (int ix = 0; ix < rle; ix++) { + BYTE triple; + + io.read_proc(&triple, 1, 1, handle); + + bits[x++] = triple; + + if (x >= line) { + x = 0; + + y++; + + if (y >= header.is_height) + goto done89; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } + } + done89 : + break; + } + + default : + freeimage.free_proc(dib); + return NULL; + } + + break; + } + + case 15 : + case 16 : + { + int pixel_bits; + + // allocate the dib + + if (TARGA_LOAD_RGB888 & flags) { + pixel_bits = 24; + + dib = freeimage.allocate_proc(header.is_width, header.is_height, pixel_bits, 0xFF, 0xFF00, 0xFF0000); + } else { + pixel_bits = 16; + + dib = freeimage.allocate_proc(header.is_width, header.is_height, pixel_bits, 0x1F, 0x3E0, 0x7C00); + } + + if (dib == NULL) + throw "DIB allocation failed"; + + int line = CalculateLine(header.is_width, pixel_bits); + int pitch = CalculatePitch(line); + + const unsigned pixel_size = unsigned(pixel_bits) / 8; + + // note header.cm_size is a misleading name, it should be seen as header.cm_bits + // ignore current position in file and set filepointer explicitly from the beginning of the file + + int garblen = 0; + + if (header.color_map_type != 0) + garblen = (int)((header.cm_size + 7) / 8) * header.cm_length; /* should byte align */ + else + garblen = 0; + + io.seek_proc(handle, start_offset, SEEK_SET); + io.seek_proc(handle, sizeof(tagTGAHEADER) + header.id_length + garblen, SEEK_SET); + + // read in the bitmap bits + + WORD pixel; + + switch (header.image_type) { + case 2 : + { + for (int y = 0; y < header.is_height; y++) { + BYTE *bits; + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + + for (int x = 0; x < line; ) { + io.read_proc(&pixel, sizeof(WORD), 1, handle); + + if (TARGA_LOAD_RGB888 & flags) { + bits[x + 0] = ((pixel & 0x1F) * 0xFF) / 0x1F; + bits[x + 1] = (((pixel & 0x3E0) >> 5) * 0xFF) / 0x1F; + bits[x + 2] = (((pixel & 0x7C00) >> 10) * 0xFF) / 0x1F; + } else { + *reinterpret_cast(bits + x) = 0x7FFF & pixel; + } + + x += pixel_size; + } + } + + break; + } + + case 10 : + { + int x = 0; + int y = 0; + BYTE rle; + WORD pixel; + + while(1) { + BYTE *bits; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + + io.read_proc(&rle,1, 1, handle); + + // compressed block + + if (rle > 127) { + rle -= 127; + + io.read_proc(&pixel, sizeof(WORD), 1, handle); + + for (int ix = 0; ix < rle; ix++) { + if (TARGA_LOAD_RGB888 & flags) { + bits[x + 0] = ((pixel & 0x1F) * 0xFF) / 0x1F; + bits[x + 1] = (((pixel & 0x3E0) >> 5) * 0xFF) / 0x1F; + bits[x + 2] = (((pixel & 0x7C00) >> 10) * 0xFF) / 0x1F; + } else { + *reinterpret_cast(bits + x) = 0x7FFF & pixel; + } + + x += pixel_size; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done2; + } + } + } else { + rle++; + + for (int ix = 0; ix < rle; ix++) { + io.read_proc(&pixel, sizeof(WORD), 1, handle); + + if (TARGA_LOAD_RGB888 & flags) { + bits[x + 0] = ((pixel & 0x1F) * 0xFF) / 0x1F; + bits[x + 1] = (((pixel & 0x3E0) >> 5) * 0xFF) / 0x1F; + bits[x + 2] = (((pixel & 0x7C00) >> 10) * 0xFF) / 0x1F; + } else { + *reinterpret_cast(bits + x) = 0x7FFF & pixel; + } + + x += pixel_size; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done2; + } + } + } + } + + done2 : + break; + } + + default : + freeimage.free_proc(dib); + return NULL; + } + + break; + } + + case 24 : + { + dib = freeimage.allocate_proc(header.is_width, header.is_height, 24, 0xFF, 0xFF00, 0xFF0000); + + if (dib == 0) + throw "DIB allocation failed"; + + // read in the bitmap bits + + switch (header.image_type) { + case 2 : + { + if (fliphoriz) + for (unsigned count = header.is_height; count > 0; count--) { + BYTE *bits = bits = Internal_GetScanLine(freeimage, dib, count-1, flipvert); + + io.read_proc(bits, line, 1, handle); + + bits += pitch; + } + else + for (unsigned count = 0; count < header.is_height; count++) { + BYTE *bits = bits = Internal_GetScanLine(freeimage, dib, count, flipvert); + + io.read_proc(bits, line, 1, handle); + + bits += pitch; + } + + break; + } + + case 10 : + { + int x = 0; + int y = 0; + BYTE rle; + BYTE *bits; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + + if (alphabits) { + while(1) { + io.read_proc(&rle,1, 1, handle); + + if (rle>127) { + rle -= 127; + + BGRAQUAD quad; + + io.read_proc(&quad, sizeof(BGRAQUAD), 1, handle); + + for (int ix = 0; ix < rle; ix++) { + bits[x++] = quad.bgraBlue; + bits[x++] = quad.bgraGreen; + bits[x++] = quad.bgraRed; + bits[x++] = quad.bgraAlpha; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done243; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } else { + rle++; + + for (int ix = 0; ix < rle; ix++) { + BGRAQUAD quad; + + io.read_proc(&quad, sizeof(BGRAQUAD), 1, handle); + + bits[x++] = quad.bgraBlue; + bits[x++] = quad.bgraGreen; + bits[x++] = quad.bgraRed; + bits[x++] = quad.bgraAlpha; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done243; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } + } + } else { + while (1) { + io.read_proc(&rle,1, 1, handle); + + if (rle>127) { + rle -= 127; + + RGBTRIPLE triple; + + io.read_proc(&triple, sizeof(RGBTRIPLE), 1, handle); + + for (int ix = 0; ix < rle; ix++) { + bits[x++] = triple.rgbtBlue; + bits[x++] = triple.rgbtGreen; + bits[x++] = triple.rgbtRed; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done243; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } else { + rle++; + + for (int ix = 0; ix < rle; ix++) { + RGBTRIPLE triple; + + io.read_proc(&triple, sizeof(RGBTRIPLE), 1, handle); + + bits[x++] = triple.rgbtBlue; + bits[x++] = triple.rgbtGreen; + bits[x++] = triple.rgbtRed; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done243; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } + } + } + done243 : + break; + } + + default : + freeimage.free_proc(dib); + return NULL; + } + + break; + } + + case 32 : + { + int pixel_bits; + + if (TARGA_LOAD_RGB888 & flags) { + pixel_bits = 24; + + line = CalculateLine(header.is_width, pixel_bits); + pitch = CalculatePitch(line); + } else { + pixel_bits = 32; + } + + const unsigned pixel_size = unsigned (pixel_bits) / 8; + + // Allocate the DIB + + dib = freeimage.allocate_proc(header.is_width, header.is_height, pixel_bits, 0xFF, 0xFF00, 0xFF0000); + + if (dib == 0) + throw "DIB allocation failed"; + + // read in the bitmap bits + + switch (header.image_type) { + case 2 : + { + // uncompressed + + if (alphabits) { + if (fliphoriz) + for (unsigned count = header.is_height; count > 0; count--) { + BYTE *bits = bits = Internal_GetScanLine(freeimage, dib, count-1, flipvert); + + for (unsigned cols = 0; cols < header.is_width; cols++) { + RGBQUAD rgb; + + io.read_proc(&rgb, sizeof(RGBQUAD), 1, handle); + + bits[0] = rgb.rgbBlue; + bits[1] = rgb.rgbGreen; + bits[2] = rgb.rgbRed; + + if ((TARGA_LOAD_RGB888 & flags) != TARGA_LOAD_RGB888) + bits[3] = rgb.rgbReserved; + + bits += pixel_size; + } + } + else + for (unsigned count = 0; count < header.is_height; count++) { + BYTE *bits = Internal_GetScanLine(freeimage, dib, count, flipvert); + + for (unsigned cols = 0; cols < header.is_width; cols++) { + RGBQUAD rgb; + + io.read_proc(&rgb, sizeof(RGBQUAD), 1, handle); + + bits[0] = rgb.rgbBlue; + bits[1] = rgb.rgbGreen; + bits[2] = rgb.rgbRed; + + if ((TARGA_LOAD_RGB888 & flags) != TARGA_LOAD_RGB888) + bits[3] = rgb.rgbReserved; + + bits += pixel_size; + } + } + + } else { + if (fliphoriz) + for (unsigned count = header.is_height; count > 0; count--) { + BYTE *bits; + + if (fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-count, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, count-1, flipvert); + + for (unsigned cols = 0; cols < header.is_width; cols++) { + RGBQUAD rgb; + + io.read_proc(&rgb, sizeof(RGBQUAD), 1, handle); + + bits[0] = rgb.rgbBlue; + bits[1] = rgb.rgbGreen; + bits[2] = rgb.rgbRed; + + if ((TARGA_LOAD_RGB888 & flags) != TARGA_LOAD_RGB888) + bits[3] = rgb.rgbReserved; + + bits += pixel_size; + } + } + else + for (unsigned count = 0; count < header.is_height; count++) { + BYTE *bits; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-count-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, count, flipvert); + + for (unsigned cols = 0; cols < header.is_width; cols++) { + RGBQUAD rgb; + + io.read_proc(&rgb, sizeof(RGBQUAD), 1, handle); + + bits[0] = rgb.rgbBlue; + bits[1] = rgb.rgbGreen; + bits[2] = rgb.rgbRed; + + if ((TARGA_LOAD_RGB888 & flags) != TARGA_LOAD_RGB888) + bits[3] = rgb.rgbReserved; + + bits += pixel_size; + } + } + } + + break; + } + case 10: + { + int x = 0; + int y = 0; + BYTE rle; + BYTE *bits; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + + while(1) { + io.read_proc(&rle,1, 1, handle); + + if (rle>127) { + rle -= 127; + + BGRAQUAD quad; + + io.read_proc(&quad, sizeof(BGRAQUAD), 1, handle); + + for (int ix = 0; ix < rle; ix++) { + bits[x++] = quad.bgraBlue; + bits[x++] = quad.bgraGreen; + bits[x++] = quad.bgraRed; + bits[x++] = quad.bgraAlpha; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done3210; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } else { + rle++; + + for (int ix = 0; ix < rle; ix++) { + BGRAQUAD quad; + + io.read_proc(&quad, sizeof(BGRAQUAD), 1, handle); + + bits[x++] = quad.bgraBlue; + bits[x++] = quad.bgraGreen; + bits[x++] = quad.bgraRed; + bits[x++] = quad.bgraAlpha; + + if (x >= line) { + x = 0; + y++; + + if (y >= header.is_height) + goto done3210; + + if(fliphoriz) + bits = Internal_GetScanLine(freeimage, dib, header.is_height-y-1, flipvert); + else + bits = Internal_GetScanLine(freeimage, dib, y, flipvert); + } + } + } + } + + done3210 : + break; + } + + default : + freeimage.free_proc(dib); + return NULL; + } + + break; + } + } + + return (FIBITMAP *)dib; + + } catch(char *message) { + freeimage.output_message_proc(s_format_id, message); + + return NULL; + } + } + + return NULL; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitTARGA(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; +} diff --git a/freeimage241/Source/FreeImage/PluginTIFF.cpp b/freeimage241/Source/FreeImage/PluginTIFF.cpp new file mode 100644 index 0000000..f6d8736 --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginTIFF.cpp @@ -0,0 +1,789 @@ +// ========================================================== +// TIFF Loader and Writer +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Markus Loibl (markus.loibl@epost.de) +// - Luca Piergentili (l.pierge@terra.es) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifdef unix +#undef unix +#endif +#ifdef __unix +#undef __unix +#endif + +#include "../LibTIFF/tiffiop.h" + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- + +static FreeImageIO *g_io = NULL; + +// ---------------------------------------------------------- +// libtiff interface +// ---------------------------------------------------------- + +static tsize_t +_tiffReadProc(thandle_t file, tdata_t buf, tsize_t size) { + return g_io->read_proc(buf, size, 1, (fi_handle)file) * size; +} + +static tsize_t +_tiffWriteProc(thandle_t file, tdata_t buf, tsize_t size) { + return g_io->write_proc(buf, size, 1, (fi_handle)file) * size; +} + +static toff_t +_tiffSeekProc(thandle_t file, toff_t off, int whence) { + g_io->seek_proc((fi_handle)file, off, whence); + return g_io->tell_proc((fi_handle)file); +} + +static int +_tiffCloseProc(thandle_t fd) { + return 0; +} + +#include + +static toff_t +_tiffSizeProc(thandle_t file) { + struct stat sb; + return (fstat((int) file, &sb) < 0 ? 0 : sb.st_size); +} + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) { + return 0; +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) { +} + +// ---------------------------------------------------------- +// Open a TIFF file descriptor for read/writing. +// ---------------------------------------------------------- + +TIFF * +TIFFFdOpen(thandle_t handle, const char *name, const char *mode) { + TIFF *tif; + + tif = TIFFClientOpen(name, mode, handle, + _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, + _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); + + if (tif) + tif->tif_fd = (int)handle; + + return tif; +} + +// ---------------------------------------------------------- +// Open a TIFF file for read/writing. +// ---------------------------------------------------------- + +TIFF* +TIFFOpen(const char* name, const char* mode) { + return 0; +} + +tdata_t +_TIFFmalloc(tsize_t s) { + return malloc(s); +} + +void +_TIFFfree(tdata_t p) { + free(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) { + return realloc(p, s); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) { + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) { + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) { + return (memcmp(p1, p2, (size_t) c)); +} + +// ---------------------------------------------------------- +// in FreeImage warnings and errors are disabled +// ---------------------------------------------------------- + +static void +msdosWarningHandler(const char* module, const char* fmt, va_list ap) { +} + +TIFFErrorHandler _TIFFwarningHandler = msdosWarningHandler; + +static void +msdosErrorHandler(const char* module, const char* fmt, va_list ap) { +} + +TIFFErrorHandler _TIFFerrorHandler = msdosErrorHandler; + +// ---------------------------------------------------------- + +#define CVT(x) (((x) * 255L) / ((1L<<16)-1)) +#define SCALE(x) (((x)*((1L<<16)-1))/255) + +// ========================================================== +// Internal functions +// ========================================================== + +static uint16 +CheckColormap(int n, uint16* r, uint16* g, uint16* b) { + while (n-- > 0) { + if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) { + return 16; + } + } + + return 8; +} + +static uint16 +CheckPhotometric(FreeImage &freeimage, FIBITMAP *dib, uint16 bitspersample) { + RGBQUAD *rgb; + uint16 i; + + switch(bitspersample) { + case 1: + { + rgb = freeimage.get_palette_proc(dib); + + if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { + rgb++; + + if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) + return PHOTOMETRIC_MINISBLACK; + } + + if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { + rgb++; + + if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) + return PHOTOMETRIC_MINISWHITE; + } + + return PHOTOMETRIC_PALETTE; + } + + case 4: // Check if the DIB has a color or a greyscale palette + case 8: + rgb = freeimage.get_palette_proc(dib); + + for (i = 0; i < freeimage.get_colors_used_proc(dib); i++) { + if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) + return PHOTOMETRIC_PALETTE; + + // The DIB has a color palette if the greyscale isn't a linear ramp + + if (rgb->rgbRed != i) + return PHOTOMETRIC_PALETTE; + + rgb++; + } + + return PHOTOMETRIC_MINISBLACK; + + case 24: + return PHOTOMETRIC_RGB; + } + + return PHOTOMETRIC_MINISBLACK; +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "TIFF"; +} + +static const char * DLL_CALLCONV +Description() { + return "Tagged Image File Format"; +} + +static const char * DLL_CALLCONV +Extension() { + return "tif,tiff"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return "^[MI][MI][\\x01*][\\x01*]"; +} + +static const char * DLL_CALLCONV +MimeType() { + return "image/tiff"; +} + +static BOOL DLL_CALLCONV +Validate(FreeImageIO &io, fi_handle handle) { + BYTE tiff_id1[] = { 0x49, 0x49 }; + BYTE tiff_id2[] = { 0x4D, 0x4D }; + BYTE signature[2] = { 0, 0 }; + + io.read_proc(signature, 1, sizeof(tiff_id1), handle); + + if (memcmp(tiff_id1, signature, sizeof(tiff_id1)) == 0) + return TRUE; + + if (memcmp(tiff_id2, signature, sizeof(tiff_id1)) == 0) + return TRUE; + + return FALSE; +} + +// ---------------------------------------------------------- + +static void * DLL_CALLCONV +Open(FreeImageIO &io, fi_handle handle, BOOL read) { + g_io = &io; + + if (read) + return TIFFFdOpen((thandle_t)handle, "", "r"); + else + return TIFFFdOpen((thandle_t)handle, "", "w"); +} + +static void DLL_CALLCONV +Close(FreeImageIO &io, fi_handle handle, void *data) { + TIFFClose((TIFF *)data); + + g_io = NULL; +} + +// ---------------------------------------------------------- + +static int DLL_CALLCONV +PageCount(FreeImageIO &io, fi_handle handle, void *data) { + int nr_ifd = 0; + + TIFF *tif = (TIFF *)data; + + do { + nr_ifd++; + } while (TIFFReadDirectory(tif)); + + return nr_ifd; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data) { + if ((handle != NULL) && (data != NULL)) { + TIFF *tif; + uint32 height; + uint32 width; + uint16 bitspersample; + uint16 samplesperpixel; + uint32 rowsperstrip; + uint16 photometric; + uint16 compression; + uint32 x, y; + BOOL isRGB; + + int32 nrow; + BYTE *buf; + FIBITMAP *dib; + BYTE *bits; // pointer to dib data + RGBQUAD *pal; // pointer to dib palette + + if (handle) { + try { + tif = (TIFF *)data; + + if (page != -1) + if (!tif || !TIFFSetDirectory(tif, page)) + throw "Error encountered while opening TIFF file"; + + TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression); + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); + TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric); + + if (compression == COMPRESSION_LZW) + throw "LZW compression is no longer supported due to Unisys patent enforcement"; + + // Convert to 24 or 32 bits RGB if the image is full color + + isRGB = (bitspersample >= 8) && + (photometric == PHOTOMETRIC_RGB) || + (photometric == PHOTOMETRIC_YCBCR) || + (photometric == PHOTOMETRIC_SEPARATED) || + (photometric == PHOTOMETRIC_LOGLUV); + + if (isRGB) { + // Read the whole image into one big RGBA buffer and then + // convert it to a DIB. This is using the traditional + // TIFFReadRGBAImage() API that we trust. + + uint32* raster; // retrieve RGBA image + uint32 *row; + + raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); + + if (raster == NULL) { + throw "No space for raster buffer"; + } + + // Read the image in one chunk into an RGBA array + + if(!TIFFReadRGBAImage(tif, width, height, raster, 0)) { + _TIFFfree(raster); + return NULL; + } + + // create a new DIB + + if (samplesperpixel == 4) + dib = freeimage.allocate_proc(width, height, 32, 0xFF, 0xFF00, 0xFF0000); + else + dib = freeimage.allocate_proc(width, height, 24, 0xFF, 0xFF00, 0xFF0000); + + if (dib == NULL) { + _TIFFfree(raster); + + throw "DIB allocation failed"; + } + + // fill in the metrics (english or universal) + + float fResX, fResY; + uint16 resUnit; + TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resUnit); + TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fResX); + TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fResY); + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + + if (resUnit == RESUNIT_INCH) { + pInfoHeader->biXPelsPerMeter = (int) (fResX/0.0254000 + 0.5); + pInfoHeader->biYPelsPerMeter = (int) (fResY/0.0254000 + 0.5); + } else if(resUnit == RESUNIT_CENTIMETER) { + pInfoHeader->biXPelsPerMeter = (int) (fResX*100.0 + 0.5); + pInfoHeader->biYPelsPerMeter = (int) (fResY*100.0 + 0.5); + } + + // read the raster lines and save them in the DIB + // with RGB mode, we have to change the order of the 3 samples RGB + // We use macros for extracting components from the packed ABGR + // form returned by TIFFReadRGBAImage. + + BOOL has_alpha = FALSE; + row = &raster[0]; + + for (y = 0; y < height; y++) { + bits = freeimage.get_scanline_proc(dib, y); + + for (x = 0; x < width; x++) { + bits[0] = (BYTE)TIFFGetB(row[x]); + bits[1] = (BYTE)TIFFGetG(row[x]); + bits[2] = (BYTE)TIFFGetR(row[x]); + + if (samplesperpixel == 4) { + bits[3] = (BYTE)TIFFGetA(row[x]); + + if (bits[3] != 0) { + has_alpha = TRUE; + } + + bits += 4; + } else { + bits += 3; + } + } + + row += width; + } + + freeimage.set_transparent_proc(dib, has_alpha); + + _TIFFfree(raster); + + return (FIBITMAP *)dib; + } else { + // calculate the line + pitch + + int line = CalculateLine(width, bitspersample * samplesperpixel); + int pitch = CalculatePitch(line); + + // create a new DIB + + dib = freeimage.allocate_proc(width, height, bitspersample * samplesperpixel); + + if (dib == NULL) { + throw "No space for DIB image"; + } + + float fResX, fResY; + uint16 resUnit; + TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resUnit); + TIFFGetField(tif, TIFFTAG_XRESOLUTION, &fResX); + TIFFGetField(tif, TIFFTAG_YRESOLUTION, &fResY); + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + + if (resUnit == RESUNIT_INCH) { + /* english */ + + pInfoHeader->biXPelsPerMeter = (int) (fResX/0.0254000 + 0.5); + pInfoHeader->biYPelsPerMeter = (int) (fResY/0.0254000 + 0.5); + } else if (resUnit== RESUNIT_CENTIMETER) { + /* metric */ + + pInfoHeader->biXPelsPerMeter = (int) (fResX*100.0 + 0.5); + pInfoHeader->biYPelsPerMeter = (int) (fResY*100.0 + 0.5); + } + + // In the tiff file the lines are save from up to down + // In a DIB the lines must be save from down to up + + bits = freeimage.get_bits_proc(dib) + height * pitch; + + // now lpBits pointe on the bottom line + + // set up the colormap based on photometric + + pal = freeimage.get_palette_proc(dib); + + switch(photometric) { + case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types + case PHOTOMETRIC_MINISWHITE: + // Monochrome image + + if (bitspersample == 1) { + if (photometric == PHOTOMETRIC_MINISBLACK) { + pal[0].rgbRed = 0; + pal[0].rgbGreen = 0; + pal[0].rgbBlue = 0; + pal[1].rgbRed = 255; + pal[1].rgbGreen = 255; + pal[1].rgbBlue = 255; + } else { + pal[0].rgbRed = 255; + pal[0].rgbGreen = 255; + pal[0].rgbBlue = 255; + pal[1].rgbRed = 0; + pal[1].rgbGreen = 0; + pal[1].rgbBlue = 0; + } + } else { + // need to build the scale for greyscale images + + if (photometric == PHOTOMETRIC_MINISBLACK) { + for (int i = 0; i < 256; i++) { + pal[i].rgbRed = + pal[i].rgbGreen = + pal[i].rgbBlue = i; + } + } else { + for (int i = 0; i < 256; i++) { + pal[i].rgbRed = + pal[i].rgbGreen = + pal[i].rgbBlue = 255 - i; + } + } + } + + break; + + case PHOTOMETRIC_PALETTE: // color map indexed + uint16 *red; + uint16 *green; + uint16 *blue; + BOOL Palette16Bits; + + TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); + + // Is the palette 16 or 8 bits ? + + if (CheckColormap(1<= 0; i--) { + if (Palette16Bits) { + pal[i].rgbRed =(BYTE) CVT(red[i]); + pal[i].rgbGreen = (BYTE) CVT(green[i]); + pal[i].rgbBlue = (BYTE) CVT(blue[i]); + } else { + pal[i].rgbRed = (BYTE) red[i]; + pal[i].rgbGreen = (BYTE) green[i]; + pal[i].rgbBlue = (BYTE) blue[i]; + } + } + + break; + + } + + // read the tiff lines and save them in the DIB + + buf = new BYTE[TIFFStripSize(tif)]; + + for (y = 0; y < height; y += rowsperstrip) { + nrow = (y + rowsperstrip > height ? height - y : rowsperstrip); + + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, nrow * line) == -1) { + delete [] buf; + + return NULL; + } else { + for (int l = 0; l < nrow; l++) { + bits -= pitch; + + memcpy(bits, buf + l * line, line); + } + } + } + + delete [] buf; + + return (FIBITMAP *)dib; + + } + } catch (char *message) { + freeimage.output_message_proc(s_format_id, message); + + return NULL; + } + } + } + + return NULL; +} + +static BOOL DLL_CALLCONV +Save(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + if (dib != NULL) { + TIFF *out = (TIFF *)data; + + uint32 height; + uint32 width; + uint32 rowsperstrip = (uint32) -1; + uint16 bitspersample; + uint16 samplesperpixel; + uint16 photometric; + uint16 compression; + uint16 pitch; + + uint32 x, y; + + width = freeimage.get_width_proc(dib); + height = freeimage.get_height_proc(dib); + bitspersample = freeimage.get_bpp_proc(dib); + samplesperpixel = ((bitspersample == 24) || (bitspersample == 32)) ? 3 : 1; + photometric = CheckPhotometric(freeimage, dib, (bitspersample == 32) ? 24 : bitspersample); + + // don't accept ALPHA at this moment + + if ((bitspersample == 32) && (freeimage.is_transparent_proc(dib))) + throw "alpha channels are currently unsupported"; + + // handle standard width/height/bpp stuff + + TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(out, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, ((bitspersample == 32) ? 24 : bitspersample) / samplesperpixel); + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); + TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // single image plane + TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, rowsperstrip)); + + // handle metrics + + BITMAPINFOHEADER *pInfoHeader = freeimage.get_info_header_proc(dib); + TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); + TIFFSetField(out, TIFFTAG_XRESOLUTION, 0.0254*((float)pInfoHeader->biXPelsPerMeter)); + TIFFSetField(out, TIFFTAG_YRESOLUTION, 0.0254*((float)pInfoHeader->biYPelsPerMeter)); + + // multi-paging + + if (page >= 0) { + char page_number[20]; + sprintf(page_number, "Page %d", page); + + TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + TIFFSetField(out, TIFFTAG_PAGENUMBER, page); + TIFFSetField(out, TIFFTAG_PAGENAME, page_number); + } else { + TIFFSetField(out, TIFFTAG_SUBFILETYPE, 0); + } + + // palettes (image colormaps are automatically scaled to 16-bits) + + if (photometric == PHOTOMETRIC_PALETTE) { + uint16 *r, *g, *b; + uint16 nColors = freeimage.get_colors_used_proc(dib); + RGBQUAD *pal = freeimage.get_palette_proc(dib); + + r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * nColors); + g = r + nColors; + b = g + nColors; + + for (int i = nColors - 1; i >= 0; i--) { + r[i] = SCALE((uint16)pal[i].rgbRed); + g[i] = SCALE((uint16)pal[i].rgbGreen); + b[i] = SCALE((uint16)pal[i].rgbBlue); + } + + TIFFSetField(out, TIFFTAG_COLORMAP, r, g, b); + + _TIFFfree(r); + } + + // compression + + switch(bitspersample) { + case 1 : + compression = COMPRESSION_CCITTFAX4; + break; + + case 8 : + case 24 : + case 32 : + compression = COMPRESSION_PACKBITS; + break; + + default : + compression = COMPRESSION_NONE; + break; + } + + TIFFSetField(out, TIFFTAG_COMPRESSION, compression); + + // read the DIB lines from bottom to top + // and save them in the TIF + // ------------------------------------- + + pitch = freeimage.get_pitch_proc(dib); + + switch(bitspersample) { + case 1 : + case 4 : + case 8 : + { + for (y = 0; y < height; y++) { + BYTE *bits = freeimage.get_bits_row_col_proc(dib, 0, y); + + TIFFWriteScanline(out,bits, y, 0); + } + + break; + } + + case 24: + case 32 : + { + BYTE *buffer = (BYTE *)malloc(CalculatePitch(CalculateLine(width, 24))); + + for (y = 0; y < height; y++) { + // get a pointer to the (converted) scanline + + if (bitspersample == 32) + freeimage.convert_line_32to24_proc(buffer, freeimage.get_scanline_proc(dib, height - y - 1), width); + else + memcpy(buffer, freeimage.get_scanline_proc(dib, height - y - 1), pitch); + + // TIFFs store color data RGB instead of BGR + + BYTE *pBuf = buffer; + + for (x = 0; x < width; x++) { + BYTE tmp = pBuf[0]; + pBuf[0] = pBuf[2]; + pBuf[2] = tmp; + + pBuf += 3; + } + + // write the scanline to disc + + TIFFWriteScanline(out, buffer, y, 0); + } + + free(buffer); + + break; + } + } + + return TRUE; + } + + return FALSE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitTIFF(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.open_proc = Open; + plugin.close_proc = Close; + plugin.pagecount_proc = PageCount; + plugin.load_proc = Load; + plugin.save_proc = Save; + plugin.validate_proc = Validate; + plugin.mime_proc = MimeType; +} diff --git a/freeimage241/Source/FreeImage/PluginWBMP.cpp b/freeimage241/Source/FreeImage/PluginWBMP.cpp new file mode 100644 index 0000000..b46bc1d --- /dev/null +++ b/freeimage241/Source/FreeImage/PluginWBMP.cpp @@ -0,0 +1,356 @@ +// ========================================================== +// Wireless Bitmap Format Loader and Writer +// +// Design and implementation by +// - Hervé Drolon +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" + +// ---------------------------------------------------------- +// Wireless Bitmap Format +// ---------------------- +// The WBMP format enables graphical information to be sent to a variety of handsets. +// The WBMP format is terminal independent and describes only graphical information. + +// IMPLEMENTATION NOTES: +// ------------------------ +// The WBMP format is configured according to a type field value (TypeField below), +// which maps to all relevant image encoding information, such as: +// · Pixel organisation and encoding +// · Palette organisation and encoding +// · Compression characteristics +// · Animation encoding +// For each TypeField value, all relevant image characteristics are +// fully specified as part of the WAP documentation. +// Currently, a simple compact, monochrome image format is defined +// within the WBMP type space : +// +// Image Type Identifier, multi-byte integer 0 +// Image Format description 0 B/W, no compression +// ------------------------------------------------------------------------------- + +// WBMP Header + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +typedef struct { + WORD TypeField; // Image type identifier of multi-byte length + BYTE FixHeaderField; // Octet of general header information + BYTE ExtHeaderFields; // Zero or more extension header fields + WORD Width; // Multi-byte width field + WORD Height; // Multi-byte height field +} WBMPHEADER; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// The extension headers may be of type binary 00 through binary 11, defined as follows. + +// - Type 00 indicates a multi-byte bitfield used to specify additional header information. +// The first bit is set if a type 00, extension header is set if more data follows. +// The other bits are reserved for future use. +// - Type 01 - reserved for future use. +// - Type 10 - reserved for future use. +// - Type 11 indicates a sequence of parameter/value pairs. These can be used for +// optimisations and special purpose extensions, eg, animation image formats. +// The parameter size tells the length (1-8 bytes) of the following parameter name. +// The value size gives the length (1-16 bytes) of the following parameter value. +// The concatenation flag indicates whether another parameter/value pair will follow +// after reading the specified bytes of data. + +// ========================================================== +// Internal functions +// ========================================================== + +static DWORD +multiByteRead(FreeImageIO &io, fi_handle handle) { + // Multi-byte encoding / decoding + // ------------------------------- + // A multi-byte integer consists of a series of octets, where the most significant bit + // is the continuation flag, and the remaining seven bits are a scalar value. + // The continuation flag is used to indicate that an octet is not the end of the multi-byte + // sequence. + + DWORD Out = 0; + BYTE In = 0; + + while (io.read_proc(&In, 1, 1, handle)) { + Out += (In & 0x7F); + + if ((In & 0x80) == 0x00) { + // Last byte to read + + break; + } + + Out <<= 7; + } + + return Out; +} + +static void +multiByteWrite(FreeImageIO &io, fi_handle handle, DWORD In) { + BYTE Out, k = 1; + + while(In & (0x7F << 7*k)) + k++; + + while(k > 1) { + k--; + Out = (BYTE)(0x80 | (In >> 7*k) & 0xFF); + io.write_proc(&Out, 1, 1, handle); + } + + // Last byte to write + + Out = (BYTE)(In & 0x7F); + + io.write_proc(&Out, 1, 1, handle); +} + +static void +readExtHeader(FreeImageIO &io, fi_handle handle, BYTE b) { + // Extension header fields + // ------------------------ + // Read the extension header fields + // (since we don't use them for the moment, we skip them). + + switch(b & 0x60) { + // Type 00: read multi-byte bitfield + + case 0x00: + { + DWORD info = multiByteRead(io, handle); + } + break; + + // Type 11: read a sequence of parameter/value pairs. + + case 0x60: + { + BYTE sizeParamIdent = (b & 0x70) >> 4; // Size of Parameter Identifier (in bytes) + BYTE sizeParamValue = (b & 0x0F); // Size of Parameter Value (in bytes) + + BYTE *Ident = (BYTE*)malloc(sizeParamIdent * sizeof(BYTE)); + BYTE *Value = (BYTE*)malloc(sizeParamValue * sizeof(BYTE)); + + io.read_proc(Ident, sizeParamIdent, 1, handle); + io.read_proc(Value, sizeParamValue, 1, handle); + + free(Ident); + free(Value); + } + + break; + + // reserved for future use + case 0x20: // Type 01 + case 0x40: // Type 10 + break; + } +} + +// ========================================================== +// Plugin Interface +// ========================================================== + +static int s_format_id; + +// ========================================================== +// Plugin Implementation +// ========================================================== + +static const char * DLL_CALLCONV +Format() { + return "WBMP"; +} + +static const char * DLL_CALLCONV +Description() { + return "Wireless Bitmap"; +} + +static const char * DLL_CALLCONV +Extension() { + return "wbmp,wap"; +} + +static const char * DLL_CALLCONV +RegExpr() { + return NULL; +} + +static const char * DLL_CALLCONV +MimeType() { + return "image/vnd.wap.wbmp"; +} + +// ---------------------------------------------------------- + +static FIBITMAP * DLL_CALLCONV +Load(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *dataa) { + WORD x, y, width, height; + FIBITMAP *dib; + BYTE *bits; // pointer to dib data + RGBQUAD *pal; // pointer to dib palette + + WBMPHEADER header; + + if(handle) { + try { + // Read header information + // ----------------------- + + // Type + + header.TypeField = (WORD)multiByteRead(io, handle); + + if (header.TypeField != 0) + throw "Unsupported WBMP type"; + + // FixHeaderField + + io.read_proc(&header.FixHeaderField, 1, 1, handle); + + // ExtHeaderFields + // 1 = More will follow, 0 = Last octet + + if (header.FixHeaderField & 0x80) { + header.ExtHeaderFields = 0x80; + + while(header.ExtHeaderFields & 0x80) { + io.read_proc(&header.ExtHeaderFields, 1, 1, handle); + + readExtHeader(io, handle, header.ExtHeaderFields); + } + } + + // Width & Height + + width = (WORD)multiByteRead(io, handle); + height = (WORD)multiByteRead(io, handle); + + // Allocate a new dib + + dib = freeimage.allocate_proc(width, height, 1); + + if (!dib) { + throw "DIB allocation failed"; + } + + // write the palette data + + pal = freeimage.get_palette_proc(dib); + pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; + pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; + + // read the bitmap data + + int pitch = freeimage.get_pitch_proc(dib); + int line = freeimage.get_line_proc(dib); + + for (y = 0; y < height; y++) { + bits = freeimage.get_scanline_proc(dib, height - 1 - y); + + for (x = 0; x < line; x++) { + io.read_proc(&bits[x], 1, 1, handle); + } + } + + return dib; + + } catch(char *text) { + freeimage.output_message_proc(s_format_id, text); + + return NULL; + } + + } + + return NULL; +} + +static BOOL DLL_CALLCONV +Save(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { + BYTE *bits; // pointer to dib data + + if ((dib) && (handle)) { + try { + if (freeimage.get_bpp_proc(dib) != 1) + throw "Only 1-bit depth bitmaps can be saved as WBMP"; + + // Write the header + + WBMPHEADER header; + header.TypeField = 0; // Type 0: B/W, no compression + header.FixHeaderField = 0; // No ExtHeaderField + header.Width = freeimage.get_width_proc(dib); // Image width + header.Height = freeimage.get_height_proc(dib); // Image height + + multiByteWrite(io, handle, header.TypeField); + + io.write_proc(&header.FixHeaderField, 1, 1, handle); + + multiByteWrite(io, handle, header.Width); + multiByteWrite(io, handle, header.Height); + + // write the bitmap data + + WORD linelength = freeimage.get_line_proc(dib); + + for (WORD y = 0; y < header.Height; y++) { + bits = freeimage.get_scanline_proc(dib, header.Height - 1 - y); + + io.write_proc(&bits[0], linelength, 1, handle); + } + + return TRUE; + + } catch (char* text) { + freeimage.output_message_proc(s_format_id, text); + } + } + + return FALSE; +} + +// ========================================================== +// Init +// ========================================================== + +void DLL_CALLCONV +InitWBMP(Plugin &plugin, int format_id) { + s_format_id = format_id; + + plugin.format_proc = Format; + plugin.description_proc = Description; + plugin.extension_proc = Extension; + plugin.regexpr_proc = RegExpr; + plugin.load_proc = Load; + plugin.save_proc = Save; + plugin.mime_proc = MimeType; +} diff --git a/freeimage241/Source/FreeImage/WuQuantizer.cpp b/freeimage241/Source/FreeImage/WuQuantizer.cpp new file mode 100644 index 0000000..74cf1d0 --- /dev/null +++ b/freeimage241/Source/FreeImage/WuQuantizer.cpp @@ -0,0 +1,530 @@ +/////////////////////////////////////////////////////////////////////// +// C Implementation of Wu's Color Quantizer (v. 2) +// (see Graphics Gems vol. II, pp. 126-133) +// +// Author: Xiaolin Wu +// Dept. of Computer Science +// Univ. of Western Ontario +// London, Ontario N6A 5B7 +// wu@csd.uwo.ca +// +// Algorithm: Greedy orthogonal bipartition of RGB space for variance +// minimization aided by inclusion-exclusion tricks. +// For speed no nearest neighbor search is done. Slightly +// better performance can be expected by more sophisticated +// but more expensive versions. +// +// The author thanks Tom Lane at Tom_Lane@G.GP.CS.CMU.EDU for much of +// additional documentation and a cure to a previous bug. +// +// Free to distribute, comments and suggestions are appreciated. +/////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////// +// History +// ------- +// July 2000: C++ Implementation of Wu's Color Quantizer +// and adaptation for the FreeImage 2 Library +// Author: Hervé Drolon (drolon@iut.univ-lehavre.fr) +/////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "Quantizers.h" +#include "FreeImage.h" + +/////////////////////////////////////////////////////////////////////// + +// 3D array indexation + +#define INDEX(r, g, b) ((r << 10) + (r << 6) + r + (g << 5) + g + b) + +#define MAXCOLOR 256 +#define RED 2 +#define GREEN 1 +#define BLUE 0 + + +// Constructor / Destructor + +WuQuantizer::WuQuantizer(FIBITMAP *dib) +{ + width = FreeImage_GetWidth(dib); + height = FreeImage_GetHeight(dib); + pitch = FreeImage_GetPitch(dib); + m_dib = dib; + + gm2 = NULL; + wt = mr = mg = mb = NULL; + Qadd = NULL; + + // Allocate 3D arrays + gm2 = (float*)malloc(33 * 33 * 33 * sizeof(float)); + wt = (int32*)malloc(33 * 33 * 33 * sizeof(int32)); + mr = (int32*)malloc(33 * 33 * 33 * sizeof(int32)); + mg = (int32*)malloc(33 * 33 * 33 * sizeof(int32)); + mb = (int32*)malloc(33 * 33 * 33 * sizeof(int32)); + + // Allocate Qadd + Qadd = (uint16 *)malloc(sizeof(uint16) * width * height); + + if(!gm2 || !wt || !mr || !mg || !mb || !Qadd) + { + if(gm2) free(gm2); + if(wt) free(wt); + if(mr) free(mr); + if(mg) free(mg); + if(mb) free(mb); + if(Qadd) free(Qadd); + throw "Not enough memory"; + } + memset(gm2, 0, 35937 * sizeof(float)); + memset(wt, 0, 35937 * sizeof(int32)); + memset(mr, 0, 35937 * sizeof(int32)); + memset(mg, 0, 35937 * sizeof(int32)); + memset(mb, 0, 35937 * sizeof(int32)); + memset(Qadd, 0, sizeof(uint16) * width * height); +} + +WuQuantizer::~WuQuantizer() +{ + if(gm2) free(gm2); + if(wt) free(wt); + if(mr) free(mr); + if(mg) free(mg); + if(mb) free(mb); + if(Qadd) free(Qadd); +} + + +// Histogram is in elements 1..HISTSIZE along each axis, +// element 0 is for base or marginal value +// NB: these must start out 0! + +// Build 3-D color histogram of counts, r/g/b, c^2 +void WuQuantizer::Hist3D(int32 *vwt, int32 *vmr, int32 *vmg, int32 *vmb, float *m2) +{ + int ind; + int inr, ing, inb, table[256]; + int i; + uint16 y, x; + + for(i = 0; i < 256; i++) + table[i] = i * i; + + for(y = 0; y < height; y++) + { + uint8 *bits = FreeImage_GetBits(m_dib) + (y * pitch); + for(x = 0; x < width; x++) + { + inr = (bits[2] >> 3) + 1; + ing = (bits[1] >> 3) + 1; + inb = (bits[0] >> 3) + 1; + Qadd[y*width + x] = ind = INDEX(inr, ing, inb); + // [inr][ing][inb] + vwt[ind]++; + vmr[ind] += bits[2]; + vmg[ind] += bits[1]; + vmb[ind] += bits[0]; + m2[ind] += (float)(table[bits[2]] + table[bits[1]] + table[bits[0]]); + bits += 3; + } + } +} + + +// At conclusion of the histogram step, we can interpret +// wt[r][g][b] = sum over voxel of P(c) +// mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb +// m2[r][g][b] = sum over voxel of c^2*P(c) +// Actually each of these should be divided by 'ImageSize' to give the usual +// interpretation of P() as ranging from 0 to 1, but we needn't do that here. + + +// We now convert histogram into moments so that we can rapidly calculate +// the sums of the above quantities over any desired box. + +// Compute cumulative moments +void WuQuantizer::M3D(int32 *vwt, int32 *vmr, int32 *vmg, int32 *vmb, float *m2) +{ + uint16 ind1, ind2; + uint8 i, r, g, b; + int32 line, line_r, line_g, line_b; + int32 area[33], area_r[33], area_g[33], area_b[33]; + float line2, area2[33]; + + for(r = 1; r <= 32; r++) + { + for(i = 0; i <= 32; i++) + { + area2[i] = 0; + area[i] = area_r[i] = area_g[i] = area_b[i] = 0; + } + for(g = 1; g <= 32; g++) + { + line2 = 0; + line = line_r = line_g = line_b = 0; + for(b = 1; b <= 32; b++) + { + ind1 = INDEX(r, g, b); // [r][g][b] + line += vwt[ind1]; + line_r += vmr[ind1]; + line_g += vmg[ind1]; + line_b += vmb[ind1]; + line2 += m2[ind1]; + area[b] += line; + area_r[b] += line_r; + area_g[b] += line_g; + area_b[b] += line_b; + area2[b] += line2; + ind2 = ind1 - 1089; // [r-1][g][b] + vwt[ind1] = vwt[ind2] + area[b]; + vmr[ind1] = vmr[ind2] + area_r[b]; + vmg[ind1] = vmg[ind2] + area_g[b]; + vmb[ind1] = vmb[ind2] + area_b[b]; + m2[ind1] = m2[ind2] + area2[b]; + } + } + } +} + +// Compute sum over a box of any given statistic +int32 WuQuantizer::Vol( Box *cube, int32 *mmt ) +{ + return( mmt[INDEX(cube->r1, cube->g1, cube->b1)] + - mmt[INDEX(cube->r1, cube->g1, cube->b0)] + - mmt[INDEX(cube->r1, cube->g0, cube->b1)] + + mmt[INDEX(cube->r1, cube->g0, cube->b0)] + - mmt[INDEX(cube->r0, cube->g1, cube->b1)] + + mmt[INDEX(cube->r0, cube->g1, cube->b0)] + + mmt[INDEX(cube->r0, cube->g0, cube->b1)] + - mmt[INDEX(cube->r0, cube->g0, cube->b0)] ); +} + +// The next two routines allow a slightly more efficient calculation +// of Vol() for a proposed subbox of a given box. The sum of Top() +// and Bottom() is the Vol() of a subbox split in the given direction +// and with the specified new upper bound. + + +// Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1 +// (depending on dir) + +int32 WuQuantizer::Bottom(Box *cube, uint8 dir, int32 *mmt) +{ + switch(dir) + { + case RED: + return( - mmt[INDEX(cube->r0, cube->g1, cube->b1)] + + mmt[INDEX(cube->r0, cube->g1, cube->b0)] + + mmt[INDEX(cube->r0, cube->g0, cube->b1)] + - mmt[INDEX(cube->r0, cube->g0, cube->b0)] ); + break; + case GREEN: + return( - mmt[INDEX(cube->r1, cube->g0, cube->b1)] + + mmt[INDEX(cube->r1, cube->g0, cube->b0)] + + mmt[INDEX(cube->r0, cube->g0, cube->b1)] + - mmt[INDEX(cube->r0, cube->g0, cube->b0)] ); + break; + case BLUE: + return( - mmt[INDEX(cube->r1, cube->g1, cube->b0)] + + mmt[INDEX(cube->r1, cube->g0, cube->b0)] + + mmt[INDEX(cube->r0, cube->g1, cube->b0)] + - mmt[INDEX(cube->r0, cube->g0, cube->b0)] ); + break; + } + + return 0; +} + + +// Compute remainder of Vol(cube, mmt), substituting pos for +// r1, g1, or b1 (depending on dir) + +int32 WuQuantizer::Top(Box *cube, uint8 dir, int pos, int32 *mmt) +{ + switch(dir) + { + case RED: + return( mmt[INDEX(pos, cube->g1, cube->b1)] + -mmt[INDEX(pos, cube->g1, cube->b0)] + -mmt[INDEX(pos, cube->g0, cube->b1)] + +mmt[INDEX(pos, cube->g0, cube->b0)] ); + break; + case GREEN: + return( mmt[INDEX(cube->r1, pos, cube->b1)] + -mmt[INDEX(cube->r1, pos, cube->b0)] + -mmt[INDEX(cube->r0, pos, cube->b1)] + +mmt[INDEX(cube->r0, pos, cube->b0)] ); + break; + case BLUE: + return( mmt[INDEX(cube->r1, cube->g1, pos)] + -mmt[INDEX(cube->r1, cube->g0, pos)] + -mmt[INDEX(cube->r0, cube->g1, pos)] + +mmt[INDEX(cube->r0, cube->g0, pos)] ); + break; + } + + return 0; +} + +// Compute the weighted variance of a box +// NB: as with the raw statistics, this is really the variance * ImageSize + +float +WuQuantizer::Var(Box *cube) { + float dr = (float) Vol(cube, mr); + float dg = (float) Vol(cube, mg); + float db = (float) Vol(cube, mb); + float xx = gm2[INDEX(cube->r1, cube->g1, cube->b1)] + -gm2[INDEX(cube->r1, cube->g1, cube->b0)] + -gm2[INDEX(cube->r1, cube->g0, cube->b1)] + +gm2[INDEX(cube->r1, cube->g0, cube->b0)] + -gm2[INDEX(cube->r0, cube->g1, cube->b1)] + +gm2[INDEX(cube->r0, cube->g1, cube->b0)] + +gm2[INDEX(cube->r0, cube->g0, cube->b1)] + -gm2[INDEX(cube->r0, cube->g0, cube->b0)]; + + return (xx - (dr*dr+dg*dg+db*db)/(float)Vol(cube,wt)); +} + +// We want to minimize the sum of the variances of two subboxes. +// The sum(c^2) terms can be ignored since their sum over both subboxes +// is the same (the sum for the whole box) no matter where we split. +// The remaining terms have a minus sign in the variance formula, +// so we drop the minus sign and MAXIMIZE the sum of the two terms. + +float +WuQuantizer::Maximize(Box *cube, uint8 dir, int first, int last , int *cut, int32 whole_r, int32 whole_g, int32 whole_b, int32 whole_w) { + int32 half_r, half_g, half_b, half_w; + int i; + float temp; + + int32 base_r = Bottom(cube, dir, mr); + int32 base_g = Bottom(cube, dir, mg); + int32 base_b = Bottom(cube, dir, mb); + int32 base_w = Bottom(cube, dir, wt); + + float max = 0.0; + + *cut = -1; + + for (i = first; i < last; i++) { + half_r = base_r + Top(cube, dir, i, mr); + half_g = base_g + Top(cube, dir, i, mg); + half_b = base_b + Top(cube, dir, i, mb); + half_w = base_w + Top(cube, dir, i, wt); + + // now half_x is sum over lower half of box, if split at i + + if (half_w == 0) { // subbox could be empty of pixels! + continue; // never split into an empty box + } else { + temp = ((float)half_r*half_r + (float)half_g*half_g + (float)half_b*half_b)/half_w; + } + + half_r = whole_r - half_r; + half_g = whole_g - half_g; + half_b = whole_b - half_b; + half_w = whole_w - half_w; + + if (half_w == 0) { // subbox could be empty of pixels! + continue; // never split into an empty box + } else { + temp += ((float)half_r*half_r + (float)half_g*half_g + (float)half_b*half_b)/half_w; + } + + if (temp > max) { + max=temp; + *cut=i; + } + } + + return max; +} + +bool +WuQuantizer::Cut(Box *set1, Box *set2) { + uint8 dir; + int cutr, cutg, cutb; + + int32 whole_r = Vol(set1, mr); + int32 whole_g = Vol(set1, mg); + int32 whole_b = Vol(set1, mb); + int32 whole_w = Vol(set1, wt); + + float maxr = Maximize(set1, RED, set1->r0+1, set1->r1, &cutr, whole_r, whole_g, whole_b, whole_w); + float maxg = Maximize(set1, GREEN, set1->g0+1, set1->g1, &cutg, whole_r, whole_g, whole_b, whole_w); + float maxb = Maximize(set1, BLUE, set1->b0+1, set1->b1, &cutb, whole_r, whole_g, whole_b, whole_w); + + if ((maxr >= maxg) && (maxr >= maxb)) { + dir = RED; + + if (cutr < 0) { + return false; // can't split the box + } + } else if ((maxg >= maxr) && (maxg>=maxb)) { + dir = GREEN; + } else { + dir = BLUE; + } + + set2->r1 = set1->r1; + set2->g1 = set1->g1; + set2->b1 = set1->b1; + + switch (dir) { + case RED: + set2->r0 = set1->r1 = cutr; + set2->g0 = set1->g0; + set2->b0 = set1->b0; + break; + + case GREEN: + set2->g0 = set1->g1 = cutg; + set2->r0 = set1->r0; + set2->b0 = set1->b0; + break; + + case BLUE: + set2->b0 = set1->b1 = cutb; + set2->r0 = set1->r0; + set2->g0 = set1->g0; + break; + } + + set1->vol = (set1->r1-set1->r0)*(set1->g1-set1->g0)*(set1->b1-set1->b0); + set2->vol = (set2->r1-set2->r0)*(set2->g1-set2->g0)*(set2->b1-set2->b0); + + return true; +} + + +void +WuQuantizer::Mark(Box *cube, int label, uint8 *tag) { + for (int r = cube->r0 + 1; r <= cube->r1; r++) { + for (int g = cube->g0 + 1; g <= cube->g1; g++) { + for (int b = cube->b0 + 1; b <= cube->b1; b++) { + tag[INDEX(r, g, b)] = label; + } + } + } +} + +// Wu Quantization algorithm + +FIBITMAP * +WuQuantizer::Quantize() { + uint8 *tag = NULL; + + try { + int PalSize = 256; // Color look-up table size + Box cube[MAXCOLOR]; + int next; + int32 i, weight; + int k; + float vv[MAXCOLOR], temp; + + // Compute 3D histogram + + Hist3D(wt, mr, mg, mb, gm2); + + // Compute moments + + M3D(wt, mr, mg, mb, gm2); + + cube[0].r0 = cube[0].g0 = cube[0].b0 = 0; + cube[0].r1 = cube[0].g1 = cube[0].b1 = 32; + next = 0; + + for (i = 1; i < PalSize; i++) { + if(Cut(&cube[next], &cube[i])) { + // volume test ensures we won't try to cut one-cell box + vv[next] = (cube[next].vol > 1) ? Var(&cube[next]) : 0; + vv[i] = (cube[i].vol > 1) ? Var(&cube[i]) : 0; + } else { + vv[next] = 0.0; // don't try to split this box again + i--; // didn't create box i + } + + next = 0; temp = vv[0]; + + for (k = 1; k <= i; k++) { + if (vv[k] > temp) { + temp = vv[k]; next = k; + } + } + + if (temp <= 0.0) { + PalSize = i + 1; + + // Error: "Only got 'PalSize' boxes" + + break; + } + } + + // Partition done + + // the space for array gm2 can be freed now + + free(gm2); + + gm2 = NULL; + + // Allocate a new dib + + FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8); + + if (new_dib == NULL) { + throw "Not enough memory"; + } + + // create an optimized palette + + RGBQUAD *new_pal = FreeImage_GetPalette(new_dib); + + tag = (uint8*) malloc(33 * 33 * 33 * sizeof(uint8)); + + if (tag == NULL) { + throw "Not enough memory"; + } + + for (k = 0; k < PalSize; k++) { + Mark(&cube[k], k, tag); + weight = Vol(&cube[k], wt); + + if (weight) { + new_pal[k].rgbRed = (uint8)(Vol(&cube[k], mr) / weight); + new_pal[k].rgbGreen = (uint8)(Vol(&cube[k], mg) / weight); + new_pal[k].rgbBlue = (uint8)(Vol(&cube[k], mb) / weight); + } else { + // Error: bogus box 'k' + + new_pal[k].rgbRed = new_pal[k].rgbGreen = new_pal[k].rgbBlue = 0; + } + } + + int npitch = FreeImage_GetPitch(new_dib); + + for (uint16 y = 0; y < height; y++) { + uint8 *new_bits = FreeImage_GetBits(new_dib) + (y * npitch); + + for (uint16 x = 0; x < width; x++) { + new_bits[x] = tag[Qadd[y*width + x]]; + } + } + + // output 'new_pal' as color look-up table contents, + // 'new_bits' as the quantized image (array of table addresses). + + free(tag); + + return (FIBITMAP*) new_dib; + } catch(...) { + free(tag); + } + + return NULL; +} diff --git a/freeimage241/Source/FreeImageIO.h b/freeimage241/Source/FreeImageIO.h new file mode 100644 index 0000000..b157427 --- /dev/null +++ b/freeimage241/Source/FreeImageIO.h @@ -0,0 +1,33 @@ +// ========================================================== +// Input/Output functions +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef FREEIMAGEIO_H +#define FREEIMAGEIO_H + +#ifndef FREEIMAGE_H +#include "FreeImage.h" +#endif + +// ---------------------------------------------------------- + +void SetDefaultIO(FreeImageIO *io); + +#endif // !FREEIMAGEIO_H diff --git a/freeimage241/Source/FreeImageLib/FreeImageLib.dsp b/freeimage241/Source/FreeImageLib/FreeImageLib.dsp new file mode 100644 index 0000000..28fccb8 --- /dev/null +++ b/freeimage241/Source/FreeImageLib/FreeImageLib.dsp @@ -0,0 +1,240 @@ +# Microsoft Developer Studio Project File - Name="FreeImageLib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=FreeImageLib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "FreeImageLib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "FreeImageLib.mak" CFG="FreeImageLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "FreeImageLib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "FreeImageLib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "FreeImageLib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "..\\" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Release\FreeImage.lib" + +!ELSEIF "$(CFG)" == "FreeImageLib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\\" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\FreeImaged.lib" + +!ENDIF + +# Begin Target + +# Name "FreeImageLib - Win32 Release" +# Name "FreeImageLib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "Quantizers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\FreeImage\NNQuantizer.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\WuQuantizer.cpp +# End Source File +# End Group +# Begin Group "Conversion" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\FreeImage\Conversion.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\Conversion16_555.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\Conversion16_565.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\Conversion24.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\Conversion32.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\Conversion8.cpp +# End Source File +# End Group +# Begin Group "Plugins" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\FreeImage\Plugin.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginBMP.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginICO.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginIFF.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginJPEG.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginKOALA.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginMNG.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginPCD.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginPCX.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginPNG.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginPNM.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginPSD.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginRAS.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginTARGA.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginTIFF.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\PluginWBMP.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\FreeImage\BitmapAccess.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\FreeImage.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\FreeImageIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\GetType.cpp +# End Source File +# Begin Source File + +SOURCE=..\FreeImage\LoadFunctions.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\FreeImage.h +# End Source File +# Begin Source File + +SOURCE=..\FreeImageIO.h +# End Source File +# Begin Source File + +SOURCE=..\Plugin.h +# End Source File +# Begin Source File + +SOURCE=..\Quantizers.h +# End Source File +# Begin Source File + +SOURCE=..\Utilities.h +# End Source File +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/FreeImageQt/FreeImageQt.cpp b/freeimage241/Source/FreeImageQt/FreeImageQt.cpp new file mode 100644 index 0000000..2e66206 --- /dev/null +++ b/freeimage241/Source/FreeImageQt/FreeImageQt.cpp @@ -0,0 +1,714 @@ +// ========================================================== +// FreeImage Qt +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// Based on tiffIO code written by Markus L. Noga +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#pragma warning(disable : 4541) + +#include + +#include +#include +#include +#include +#include + +#include "FreeImageQt.h" + +// ========================================================== + +#define DLL_CALLCONV __stdcall + +// For C compatility ---------------------------------------- + +#ifdef __cplusplus +#define FI_DEFAULT(x) = x +#define FI_ENUM(x) enum x +#define FI_STRUCT(x) struct x +#else +#define FI_DEFAULT(x) +#define FI_ENUM(x) typedef int x; enum x +#define FI_STRUCT(x) typedef struct x x; struct x +#endif + +// File IO routines ----------------------------------------- + +#ifndef FREEIMAGE_IO +#define FREEIMAGE_IO + +#define fi_handle void* + +typedef unsigned (*FI_ReadProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef unsigned (*FI_WriteProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef int (*FI_SeekProc) (fi_handle handle, long offset, int origin); +typedef long (*FI_TellProc) (fi_handle handle); + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +struct FreeImageIO { + FI_ReadProc read_proc; //! pointer to the function used to read data + FI_WriteProc write_proc; //! pointer to the function used to write data + FI_SeekProc seek_proc; //! pointer to the function used to seek + FI_TellProc tell_proc; //! pointer to the function used to aquire the current position +}; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +#endif //!FREEIMAGE_IO + +// ---------------------------------------------------------- +// WINDOWS STUFF FOR DLL HANDLING +// ---------------------------------------------------------- + +static HMODULE s_library_handle; +static bool s_library_loaded = false; + +// ---------------------------------------------------------- +// DLL FUNCTION DECLARATIONS +// ---------------------------------------------------------- + +typedef void (DLL_CALLCONV *FreeImage_SetOutputMessageProc)(FreeImage_OutputMessageFunction omf); +typedef FIBITMAP *(DLL_CALLCONV *FreeImage_AllocateProc)(int width, int height, int bpp, int red_mask = 0, int green_mask = 0, int blue_mask = 0); +typedef void (DLL_CALLCONV *FreeImage_UnloadProc)(FIBITMAP *dib); +typedef int (DLL_CALLCONV *FreeImage_GetFIFCountProc)(); +typedef FREE_IMAGE_FORMAT (DLL_CALLCONV *FreeImage_GetFIFFromFormatProc)(const char *format); +typedef const char * (DLL_CALLCONV *FreeImage_GetFormatFromFIFProc)(int id); +typedef const char * (DLL_CALLCONV *FreeImage_GetFIFDescriptionProc)(int id); +typedef const char * (DLL_CALLCONV *FreeImage_GetFIFRegExprProc)(int id); +typedef const char * (DLL_CALLCONV *FreeImage_GetFIFExtensionListProc)(int id); +typedef FREE_IMAGE_FORMAT (DLL_CALLCONV *FreeImage_GetFIFFromFilenameProc)(const char *filename); +typedef BOOL (DLL_CALLCONV *FreeImage_FIFSupportsReadingProc)(FREE_IMAGE_FORMAT id); +typedef BOOL (DLL_CALLCONV *FreeImage_FIFSupportsWritingProc)(FREE_IMAGE_FORMAT id); +typedef FIBITMAP * (DLL_CALLCONV *FreeImage_LoadFromHandleProc)(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags = 0); +typedef BOOL (DLL_CALLCONV *FreeImage_SaveToHandleProc)(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags = 0); +typedef unsigned (DLL_CALLCONV *FreeImage_GetHeightProc) (FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetWidthProc) (FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetBPPProc) (FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetDotsPerMeterXProc) (FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetDotsPerMeterYProc) (FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetTransparencyCountProc) (FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetColorsUsedProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetPitchProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetRedMaskProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetGreenMaskProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FreeImage_GetBlueMaskProc)(FIBITMAP *dib); +typedef const char *(DLL_CALLCONV *FreeImage_GetVersionProc)(); +typedef const char *(DLL_CALLCONV *FreeImage_GetCopyrightMessageProc)(); +typedef FREE_IMAGE_FORMAT (DLL_CALLCONV *FreeImage_GetFileTypeFromHandleProc)(FreeImageIO *io, fi_handle handle, int size); +typedef void (DLL_CALLCONV *FreeImage_SetTransparentProc) (FIBITMAP *dib, BOOL enable); +typedef BOOL (DLL_CALLCONV *FreeImage_IsTransparentProc) (FIBITMAP *dib); +typedef BYTE *(DLL_CALLCONV *FreeImage_GetScanLineProc) (FIBITMAP *dib, int scanline); +typedef BYTE *(DLL_CALLCONV *FreeImage_GetTransparencyTableProc) (FIBITMAP *dib); +typedef RGBQUAD *(DLL_CALLCONV *FreeImage_GetPaletteProc)(FIBITMAP *dib); +typedef BITMAPINFOHEADER *(DLL_CALLCONV *FreeImage_GetInfoHeaderProc) (FIBITMAP *dib); +typedef void (DLL_CALLCONV *FreeImage_ConvertLine16To32_555Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FreeImage_ConvertLine16To32_565Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FreeImage_ConvertLine4To8Proc) (BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FreeImage_ConvertLine24To32Proc) (BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FreeImage_ConvertLine32To24Proc) (BYTE *target, BYTE *source, int width_in_pixels); + +// ---------------------------------------------------------- +// DLL FUNCTION ÍNSTANTIATONS +// ---------------------------------------------------------- + +FreeImage_SetOutputMessageProc FI_SetOutputMessageProc; +FreeImage_AllocateProc FI_AllocateProc; +FreeImage_UnloadProc FI_UnloadProc; +FreeImage_GetFIFCountProc FI_GetFIFCountProc; +FreeImage_GetFIFFromFormatProc FI_GetFIFFromFormatProc; +FreeImage_GetFormatFromFIFProc FI_GetFormatFromFIFProc; +FreeImage_GetFIFDescriptionProc FI_GetFIFDescriptionProc; +FreeImage_GetFIFRegExprProc FI_GetFIFRegExprProc; +FreeImage_GetFIFExtensionListProc FI_GetFIFExtensionListProc; +FreeImage_GetFIFFromFilenameProc FI_GetFIFFromFilenameProc; +FreeImage_FIFSupportsReadingProc FI_FIFSupportsReadingProc; +FreeImage_FIFSupportsWritingProc FI_FIFSupportsWritingProc; +FreeImage_LoadFromHandleProc FI_LoadFromHandleProc; +FreeImage_SaveToHandleProc FI_SaveToHandleProc; +FreeImage_GetHeightProc FI_GetHeightProc; +FreeImage_GetWidthProc FI_GetWidthProc; +FreeImage_GetBPPProc FI_GetBPPProc; +FreeImage_GetDotsPerMeterXProc FI_GetDotsPerMeterXProc; +FreeImage_GetDotsPerMeterYProc FI_GetDotsPerMeterYProc; +FreeImage_SetTransparentProc FI_SetTransparentProc; +FreeImage_IsTransparentProc FI_IsTransparentProc; +FreeImage_GetTransparencyCountProc FI_GetTransparencyCountProc; +FreeImage_GetColorsUsedProc FI_GetColorsUsedProc; +FreeImage_GetPitchProc FI_GetPitchProc; +FreeImage_GetRedMaskProc FI_GetRedMaskProc; +FreeImage_GetGreenMaskProc FI_GetGreenMaskProc; +FreeImage_GetBlueMaskProc FI_GetBlueMaskProc; +FreeImage_GetVersionProc FI_GetVersionProc; +FreeImage_GetCopyrightMessageProc FI_GetCopyrightMessageProc; +FreeImage_GetFileTypeFromHandleProc FI_GetFileTypeFromHandleProc; +FreeImage_GetScanLineProc FI_GetScanLineProc; +FreeImage_GetTransparencyTableProc FI_GetTransparencyTableProc; +FreeImage_GetPaletteProc FI_GetPaletteProc; +FreeImage_GetInfoHeaderProc FI_GetInfoHeaderProc; +FreeImage_ConvertLine4To8Proc FI_ConvertLine4To8Proc; +FreeImage_ConvertLine16To32_555Proc FI_ConvertLine16To32_555Proc; +FreeImage_ConvertLine16To32_565Proc FI_ConvertLine16To32_565Proc; +FreeImage_ConvertLine24To32Proc FI_ConvertLine24To32Proc; +FreeImage_ConvertLine32To24Proc FI_ConvertLine32To24Proc; + +// ---------------------------------------------------------- +// INTERNAL QT BITMAP HANDLING FUNCTIONS +// ---------------------------------------------------------- + +BOOL +FormatSupportedByQt(QStrList &list, const char *format) { + for (const char *qtformat = list.first(); qtformat != 0; qtformat = list.next()) { + if (stricmp(format, qtformat) == 0) + return TRUE; + } + + return FALSE; +} + +unsigned +GetDotsPerMeterX(FIBITMAP *dib) { + return (FI_GetDotsPerMeterXProc != NULL) ? FI_GetDotsPerMeterXProc(dib) : 0; +} + +unsigned +GetDotsPerMeterY(FIBITMAP *dib) { + return (FI_GetDotsPerMeterYProc != NULL) ? FI_GetDotsPerMeterYProc(dib) : 0; +} + +// ---------------------------------------------------------- +// FREEIMAGEIO FUNCTIONS SUITABLE FOR USE WITH QIODEVICE +// ---------------------------------------------------------- + +inline unsigned +_ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + char *b = static_cast(buffer); + + for (unsigned c = 0; c < count; c++) { + QIODevice *iod = static_cast(handle); + + iod->readBlock(b, size); + + b += size; + } + + return count; +} + +inline unsigned +_WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) { + char *b = static_cast(buffer); + + for (unsigned c = 0; c < count; c++) { + QIODevice *iod = static_cast(handle); + + iod->writeBlock(b, size); + + b += size; + } + + return count; +} + +inline int +_SeekProc(fi_handle handle, long offset, int origin) { + QIODevice *iod = static_cast(handle); + + switch(origin) { + case SEEK_SET : + iod->at(offset); + break; + + case SEEK_CUR : + iod->at(iod->at() + offset); + break; + + default : + return 1; + } + + return 0; +} + +inline long +_TellProc(fi_handle handle) { + QIODevice *iod = static_cast(handle); + + return iod->at(); +} + +// ---------------------------------------------------------- +// PLUGIN INTERFACE +// ---------------------------------------------------------- + +int +FIQT_GetFIFCount() { + return (FI_GetFIFCountProc != NULL) ? FI_GetFIFCountProc() : 0; +} + +FREE_IMAGE_FORMAT +FIQT_GetFIFFromFormat(const char *format) { + return (FI_GetFIFFromFormatProc != NULL) ? FI_GetFIFFromFormatProc(format) : FIF_UNKNOWN; +} + +const char * +FIQT_GetFormatFromFIF(FREE_IMAGE_FORMAT id) { + return (FI_GetFormatFromFIFProc != NULL) ? FI_GetFormatFromFIFProc(id) : NULL; +} + +const char * +FIQT_GetFIFDescription(FREE_IMAGE_FORMAT id) { + return (FI_GetFIFDescriptionProc != NULL) ? FI_GetFIFDescriptionProc(id) : NULL; +} + +const char * +FIQT_GetFIFExtensionList(FREE_IMAGE_FORMAT id) { + return (FI_GetFIFExtensionListProc != NULL) ? FI_GetFIFExtensionListProc(id) : NULL; +} + +bool +FIQT_FIFSupportsReading(FREE_IMAGE_FORMAT id) { + return (FI_FIFSupportsReadingProc != NULL) ? FI_FIFSupportsReadingProc(id) : false; +} + +bool +FIQT_FIFSupportsWriting(FREE_IMAGE_FORMAT id) { + return (FI_FIFSupportsWritingProc != NULL) ? FI_FIFSupportsWritingProc(id) : false; +} + +FREE_IMAGE_FORMAT +FIQT_GetFIFFromFilename(const char *filename) { + return (FI_GetFIFFromFilenameProc != NULL) ? FI_GetFIFFromFilenameProc(filename) : FIF_UNKNOWN; +} + +const char * +FIQT_GetFileTypeFromFormat(FREE_IMAGE_FORMAT fif) { + return FIQT_GetFormatFromFIF(fif); +} + +const char * +FIQT_GetFileTypeFromExtension(const char *format) { + FREE_IMAGE_FORMAT fif = FIQT_GetFIFFromFilename(format); + + return (fif != FIF_UNKNOWN) ? FIQT_GetFormatFromFIF(fif) : NULL; +} + +FREE_IMAGE_FORMAT +FIQT_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size) { + return (FI_GetFileTypeFromHandleProc != NULL) ? FI_GetFileTypeFromHandleProc(io, handle, size) : FIF_UNKNOWN; +} + +// ---------------------------------------------------------- +// LOAD/SAVE FUNCTIONS +// ---------------------------------------------------------- + +static void +FIQT_Load(QImageIO *iio) { + FreeImageIO io; + + io.read_proc = _ReadProc; + io.seek_proc = _SeekProc; + io.tell_proc = _TellProc; + io.write_proc = _WriteProc; + + // because we don't always receive the format string here, we need to do some of our own investigation... + // first try to identify the image by looking at the filename/extension + + FREE_IMAGE_FORMAT fif = FIQT_GetFIFFromFilename(iio->format()); + + if (fif == FIF_UNKNOWN) { + // format id based image lookup failed... try to identify the bitmap by looking at the header + + fif = FIQT_GetFileTypeFromHandle(&io, (fi_handle)iio->ioDevice(), 16); + + if (fif == FIF_UNKNOWN) { + // failed again... look at the complete filename as a last resort + + if (!iio->fileName().isEmpty()) { + fif = FIQT_GetFIFFromFilename(iio->fileName()); + + if (fif == FIF_UNKNOWN) { + iio->setStatus(-1); + return; + } + } else { + iio->setStatus(-1); + return; + } + } + } + + assert(fif != FIF_UNKNOWN); + + // if we come here, we have a valid FIF id + + if (FI_FIFSupportsReadingProc(fif)) { + FIBITMAP *bitmap = FI_LoadFromHandleProc(fif, &io, (fi_handle)iio->ioDevice(), 0); + + if (bitmap != NULL) { + QImage image; + + switch(FI_GetBPPProc(bitmap)) { + case 1 : + image.create(FI_GetWidthProc(bitmap), FI_GetHeightProc(bitmap), 1, FI_GetColorsUsedProc(bitmap), QImage::BigEndian); + break; + + case 4 : + image.create(FI_GetWidthProc(bitmap), FI_GetHeightProc(bitmap), 8, 256); + break; + + case 16 : + case 24 : + image.create(FI_GetWidthProc(bitmap), FI_GetHeightProc(bitmap), 32, 0); + break; + + default : + image.create(FI_GetWidthProc(bitmap), FI_GetHeightProc(bitmap), FI_GetBPPProc(bitmap), FI_GetColorsUsedProc(bitmap)); + break; + } + + // set metrics data + + image.setDotsPerMeterX(GetDotsPerMeterX(bitmap)); + image.setDotsPerMeterY(GetDotsPerMeterY(bitmap)); + + // if there is a palette, copy it + + if (FI_IsTransparentProc(bitmap)) { + image.setAlphaBuffer(TRUE); + + if (FI_GetBPPProc(bitmap) < 16) { + RGBQUAD *palette = FI_GetPaletteProc(bitmap); + BYTE *trans_table = FI_GetTransparencyTableProc(bitmap); + + unsigned i; + + for (i = 0; i < FI_GetTransparencyCountProc(bitmap); ++i) { + image.setColor(i, qRgba(palette[i].rgbRed, palette[i].rgbGreen, palette[i].rgbBlue, trans_table[i])); + } + + for (; i < FI_GetColorsUsedProc(bitmap); ++i) { + image.setColor(i, qRgba(palette[i].rgbRed, palette[i].rgbGreen, palette[i].rgbBlue, 0xff)); + } + } + } else { + image.setAlphaBuffer(FALSE); + + if (FI_GetBPPProc(bitmap) < 16) { + RGBQUAD *palette = FI_GetPaletteProc(bitmap); + + for (unsigned i = 0; i < FI_GetColorsUsedProc(bitmap); ++i) { + image.setColor(i, qRgb(palette[i].rgbRed, palette[i].rgbGreen, palette[i].rgbBlue)); + } + } + } + + // copy the bitmap data and convert if neccesary + + for (unsigned y = 0; y < FI_GetHeightProc(bitmap); y++) { + if (FI_GetBPPProc(bitmap) == 4) { + FI_ConvertLine4To8Proc(image.scanLine(FI_GetHeightProc(bitmap) - 1 - y), FI_GetScanLineProc(bitmap, y), FI_GetWidthProc(bitmap)); + } else if (FI_GetBPPProc(bitmap) == 16) { + if ((FI_GetRedMaskProc(bitmap) == 0x1F) && (FI_GetGreenMaskProc(bitmap) == 0x3E0) && (FI_GetBlueMaskProc(bitmap) == 0x7C00)) { + FI_ConvertLine16To32_555Proc(image.scanLine(FI_GetHeightProc(bitmap) - 1 - y), FI_GetScanLineProc(bitmap, y), FI_GetWidthProc(bitmap)); + } else { + FI_ConvertLine16To32_565Proc(image.scanLine(FI_GetHeightProc(bitmap) - 1 - y), FI_GetScanLineProc(bitmap, y), FI_GetWidthProc(bitmap)); + } + } else if (FI_GetBPPProc(bitmap) == 24) { + FI_ConvertLine24To32Proc(image.scanLine(FI_GetHeightProc(bitmap) - 1 - y), FI_GetScanLineProc(bitmap, y), FI_GetWidthProc(bitmap)); + } else { + memcpy(image.scanLine(FI_GetHeightProc(bitmap) - y - 1), FI_GetScanLineProc(bitmap, y), FI_GetPitchProc(bitmap)); + } + } + + iio->setImage(image); + iio->setStatus(0); + + FI_UnloadProc(bitmap); + + return; + } + } + + iio->setStatus(-1); +} + +static void +FIQT_Save(QImageIO *iio) { + FreeImageIO io; + + io.read_proc = _ReadProc; + io.seek_proc = _SeekProc; + io.tell_proc = _TellProc; + io.write_proc = _WriteProc; + + // get the save pointer for the needed bitmap format + + FREE_IMAGE_FORMAT fif = FIQT_GetFIFFromFilename(iio->format()); + + if (fif != FIF_UNKNOWN) { + if (FIQT_FIFSupportsWriting(fif)) { + FIBITMAP *bitmap; + + switch(fif) { + case FIF_BMP : + if ((!iio->image().hasAlphaBuffer()) && (iio->image().depth() == 32)) { + bitmap = FI_AllocateProc(iio->image().width(), iio->image().height(), 24); + } else { + bitmap = FI_AllocateProc(iio->image().width(), iio->image().height(), iio->image().depth()); + } + + break; + + case FIF_JPEG : + if (iio->image().depth() == 32) { + bitmap = FI_AllocateProc(iio->image().width(), iio->image().height(), 24); + } else { + bitmap = FI_AllocateProc(iio->image().width(), iio->image().height(), iio->image().depth()); + } + + break; + + default : + bitmap = FI_AllocateProc(iio->image().width(), iio->image().height(), iio->image().depth()); + break; + }; + + // enable alpha channels in the DIB when we must + + if (iio->image().hasAlphaBuffer()) { + FI_SetTransparentProc(bitmap, TRUE); + } else { + FI_SetTransparentProc(bitmap, FALSE); + } + + // copy the palette + + RGBQUAD *palette = FI_GetPaletteProc(bitmap); + QRgb *colorTable = iio->image().colorTable(); + + for (int i = 0; i < iio->image().numColors(); ++i) { + palette[i].rgbBlue = qBlue(colorTable[i]); + palette[i].rgbGreen = qGreen(colorTable[i]); + palette[i].rgbRed = qRed(colorTable[i]); + } + + // copy the metrics data + + BITMAPINFOHEADER *header = FI_GetInfoHeaderProc(bitmap); + header->biXPelsPerMeter = iio->image().dotsPerMeterX(); + header->biYPelsPerMeter = iio->image().dotsPerMeterY(); + + // copy the bits + + for (unsigned y = 0; y < FI_GetHeightProc(bitmap); y++) { + switch(fif) { + case FIF_BMP : + if ((!iio->image().hasAlphaBuffer()) && (iio->image().depth() == 32)) { + FI_ConvertLine32To24Proc(FI_GetScanLineProc(bitmap, y), iio->image().scanLine(FI_GetHeightProc(bitmap) - 1 - y), iio->image().width()); + } else { + memcpy(FI_GetScanLineProc(bitmap, y), iio->image().scanLine(FI_GetHeightProc(bitmap) - 1 - y), FI_GetPitchProc(bitmap)); + } + + break; + + case FIF_JPEG : + if (iio->image().depth() == 32) { + FI_ConvertLine32To24Proc(FI_GetScanLineProc(bitmap, y), iio->image().scanLine(FI_GetHeightProc(bitmap) - 1 - y), iio->image().width()); + } else { + memcpy(FI_GetScanLineProc(bitmap, y), iio->image().scanLine(FI_GetHeightProc(bitmap) - 1 - y), FI_GetPitchProc(bitmap)); + } + + break; + + default : + memcpy(FI_GetScanLineProc(bitmap, y), iio->image().scanLine(FI_GetHeightProc(bitmap) - 1 - y), FI_GetPitchProc(bitmap)); + break; + }; + } + + // save the bitmap + + if (FI_SaveToHandleProc(fif, bitmap, &io, (fi_handle)iio->ioDevice())) { + iio->setStatus(0); // status 0 == SUCCESS + } else { + iio->setStatus(-1); // status -1 == FAILURE + } + + FI_UnloadProc(bitmap); + + return; + } + } + + iio->setStatus(-1); +} + +// ---------------------------------------------------------- +// OUTPUT MESSAGE FUNCTIONS +// ---------------------------------------------------------- + +void +FIQT_SetOutputMessage(FreeImage_OutputMessageFunction omf) { + if (FI_SetOutputMessageProc != NULL) { + FI_SetOutputMessageProc(omf); + } +} + +// ---------------------------------------------------------- +// VERSION HANDLING / COPYRIGHT +// ---------------------------------------------------------- + +const char * +FIQT_GetVersion() { + return (FI_GetVersionProc != NULL) ? FI_GetVersionProc() : NULL; +} + +const char * +FIQT_GetCopyrightMessage() { + return (FI_GetCopyrightMessageProc != NULL) ? FI_GetCopyrightMessageProc() : NULL; +} + +// ---------------------------------------------------------- +// REGISTRATION OF FREEIMAGE IN THE QT MECHANISM +// ---------------------------------------------------------- + +bool +FIQT_Register(bool new_formats_only) { + if (!s_library_loaded) { +#ifdef _DEBUG + if ((s_library_handle = LoadLibrary("freeimaged.dll")) != NULL) { +#else + if ((s_library_handle = LoadLibrary("freeimage.dll")) != NULL) { +#endif + // extract the functions from the FreeImage library + + FI_SetOutputMessageProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_SetOutputMessage@4")); + FI_AllocateProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_Allocate@24")); + FI_UnloadProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_Unload@4")); + FI_GetFIFCountProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFIFCount@0")); + FI_GetFIFFromFormatProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFIFFromFormat@4")); + FI_GetFormatFromFIFProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFormatFromFIF@4")); + FI_GetFIFDescriptionProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFIFDescription@4")); + FI_GetFIFRegExprProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFIFRegExpr@4")); + FI_GetFIFExtensionListProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFIFExtensionList@4")); + FI_GetFIFFromFilenameProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFIFFromFilename@4")); + FI_FIFSupportsReadingProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_FIFSupportsReading@4")); + FI_FIFSupportsWritingProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_FIFSupportsWriting@4")); + FI_LoadFromHandleProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_LoadFromHandle@16")); + FI_SaveToHandleProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_SaveToHandle@20")); + FI_GetHeightProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetHeight@4")); + FI_GetWidthProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetWidth@4")); + FI_GetBPPProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetBPP@4")); + FI_GetDotsPerMeterXProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetDotsPerMeterX@4")); + FI_GetDotsPerMeterYProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetDotsPerMeterY@4")); + FI_SetTransparentProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_SetTransparent@8")); + FI_IsTransparentProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_IsTransparent@4")); + FI_GetTransparencyCountProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetTransparencyCount@4")); + FI_GetTransparencyTableProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetTransparencyTable@4")); + FI_GetColorsUsedProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetColorsUsed@4")); + FI_GetPaletteProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetPalette@4")); + FI_GetPitchProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetPitch@4")); + FI_GetVersionProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetVersion@0")); + FI_GetRedMaskProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetRedMask@4")); + FI_GetGreenMaskProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetGreenMask@4")); + FI_GetBlueMaskProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetBlueMask@4")); + FI_GetCopyrightMessageProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetCopyrightMessage@4")); + FI_GetFileTypeFromHandleProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetFileTypeFromHandle@12")); + FI_GetScanLineProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetScanLine@8")); + FI_GetInfoHeaderProc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_GetInfoHeader@4")); + FI_ConvertLine4To8Proc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_ConvertLine4To8@12")); + FI_ConvertLine16To32_555Proc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_ConvertLine16To32_555@12")); + FI_ConvertLine16To32_565Proc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_ConvertLine16To32_565@12")); + FI_ConvertLine24To32Proc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_ConvertLine24To32@12")); + FI_ConvertLine32To24Proc = reinterpret_cast(GetProcAddress(s_library_handle, "_FreeImage_ConvertLine32To24@12")); + + if ((FI_GetVersionProc != 0) && + (FI_AllocateProc != 0) && + (FI_UnloadProc != 0) && + (FI_LoadFromHandleProc != 0) && + (FI_SaveToHandleProc != 0) && + (FI_GetHeightProc != 0) && + (FI_GetWidthProc != 0) && + (FI_GetBPPProc != 0) && + (FI_GetScanLineProc != 0) && + (FI_GetTransparencyCountProc != 0) && + (FI_GetTransparencyTableProc != 0) && + (FI_IsTransparentProc != 0) && + (FI_GetColorsUsedProc != 0) && + (FI_GetPaletteProc != 0) && + (FI_GetPitchProc != 0) && + (FI_GetRedMaskProc != 0) && + (FI_GetGreenMaskProc != 0) && + (FI_GetBlueMaskProc != 0) && + (FI_GetInfoHeaderProc != 0) && + (FI_ConvertLine4To8Proc != 0) && + (FI_ConvertLine16To32_555Proc != 0) && + (FI_ConvertLine16To32_565Proc != 0) && + (FI_ConvertLine24To32Proc != 0), + (FI_ConvertLine32To24Proc != 0), + (FI_GetFIFRegExprProc != 0)) { + + QStrList format_list; + format_list = QImageIO::inputFormats(); + + for (int i = 0; i < FIQT_GetFIFCount(); ++i) { + if (!FormatSupportedByQt(format_list, FIQT_GetFormatFromFIF((FREE_IMAGE_FORMAT)i)) || !new_formats_only) { + QImageIO::defineIOHandler(FIQT_GetFormatFromFIF((FREE_IMAGE_FORMAT)i), FI_GetFIFRegExprProc(i), 0, FIQT_FIFSupportsReading((FREE_IMAGE_FORMAT)i) ? FIQT_Load : NULL, FIQT_FIFSupportsWriting((FREE_IMAGE_FORMAT)i) ? FIQT_Save : NULL); + } + } + + s_library_loaded = true; + + atexit(FIQT_Unregister); // when the application stops, automatically unregister + + return s_library_loaded; + } + } + + s_library_loaded = false; + + return s_library_loaded; + } + + return s_library_loaded; +} + +bool +FIQT_IsLoaded() { + return s_library_loaded; +} + +void +FIQT_Unregister() { + if (s_library_loaded) { + FreeLibrary(s_library_handle); + + s_library_loaded = FALSE; + } +} diff --git a/freeimage241/Source/FreeImageQt/FreeImageQt.dsp b/freeimage241/Source/FreeImageQt/FreeImageQt.dsp new file mode 100644 index 0000000..e7d6a61 --- /dev/null +++ b/freeimage241/Source/FreeImageQt/FreeImageQt.dsp @@ -0,0 +1,108 @@ +# Microsoft Developer Studio Project File - Name="FreeImageQt" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=FreeImageQt - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "FreeImageQt.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "FreeImageQt.mak" CFG="FreeImageQt - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "FreeImageQt - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "FreeImageQt - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "FreeImageQt - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "../../Dist" /I "..\zlib" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy Release\FreeImageQt.lib ..\..\Dist copy FreeImageQt.h ..\..\Dist +# End Special Build Tool + +!ELSEIF "$(CFG)" == "FreeImageQt - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../Dist" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\FreeImageQtd.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy Debug\FreeImageQtd.lib ..\..\Dist copy FreeImageQt.h ..\..\Dist +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "FreeImageQt - Win32 Release" +# Name "FreeImageQt - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\FreeImageQt.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\FreeImageQt.h +# End Source File +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/FreeImageQt/FreeImageQt.h b/freeimage241/Source/FreeImageQt/FreeImageQt.h new file mode 100644 index 0000000..7779a2e --- /dev/null +++ b/freeimage241/Source/FreeImageQt/FreeImageQt.h @@ -0,0 +1,88 @@ +// ========================================================== +// FreeImage Qt +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// Based on tiffIO code written by Markus L. Noga +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef FREEIMAGEQT_H +#define FREEIMAGEQT_H + +// ---------------------------------------------------------- + +class QString; + +// Bitmap types ------------------------------------------------------------- + +struct FIBITMAP { void *data; }; + +// FreeImage type FI_ENUM (------------------------------------------------------ + +enum FREE_IMAGE_FORMAT { + FIF_UNKNOWN = -1, + FIF_BMP = 0, + FIF_ICO, + FIF_JPEG, + FIF_JNG, + FIF_KOALA, + FIF_LBM, + FIF_MNG, + FIF_PBM, + FIF_PBMRAW, + FIF_PCD, + FIF_PCX, + FIF_PGM, + FIF_PGMRAW, + FIF_PNG, + FIF_PPM, + FIF_PPMRAW, + FIF_RAS, + FIF_TARGA, + FIF_TIFF, + FIF_WBMP, +}; + +// ---------------------------------------------------------- + +typedef void (*FreeImage_OutputMessageFunction)(FREE_IMAGE_FORMAT fif, const char *msg); +void FIQT_SetOutputMessage(FreeImage_OutputMessageFunction omf); + +// ---------------------------------------------------------- + +bool FIQT_Register(bool new_formats_only = false); +bool FIQT_IsLoaded(); +void FIQT_Unregister(); +const char *FIQT_GetVersion(); +const char *FIQT_GetCopyrightMessage(); + +// ---------------------------------------------------------- + +int FIQT_GetFIFCount(); +FREE_IMAGE_FORMAT FIQT_GetFIFFromFormat(const char *format); +const char *FIQT_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); +const char *FIQT_GetFIFDescription(FREE_IMAGE_FORMAT fif); +const char *FIQT_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); +bool FIQT_FIFSupportsReading(FREE_IMAGE_FORMAT fif); +bool FIQT_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); +FREE_IMAGE_FORMAT FIQT_GetFIFFromFilename(const char *filename); +const char *FIQT_GetFileTypeFromExtension(const char *format); +const char *FIQT_GetFileTypeFromFormat(FREE_IMAGE_FORMAT fif); // this function is deprecated + + +#endif //!FREEIMAGEQT_H diff --git a/freeimage241/Source/LibJPEG/LibJPEG.dsp b/freeimage241/Source/LibJPEG/LibJPEG.dsp new file mode 100644 index 0000000..2c220de --- /dev/null +++ b/freeimage241/Source/LibJPEG/LibJPEG.dsp @@ -0,0 +1,320 @@ +# Microsoft Developer Studio Project File - Name="LibJPEG" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=LibJPEG - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LibJPEG.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LibJPEG.mak" CFG="LibJPEG - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LibJPEG - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "LibJPEG - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/FreeImage/LibJPEG", IHAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LibJPEG - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "..\zlib" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "LibJPEG - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "LibJPEG - Win32 Release" +# Name "LibJPEG - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\jcapimin.c +# End Source File +# Begin Source File + +SOURCE=.\jcapistd.c +# End Source File +# Begin Source File + +SOURCE=.\jccoefct.c +# End Source File +# Begin Source File + +SOURCE=.\jccolor.c +# End Source File +# Begin Source File + +SOURCE=.\jcdctmgr.c +# End Source File +# Begin Source File + +SOURCE=.\jchuff.c +# End Source File +# Begin Source File + +SOURCE=.\jcinit.c +# End Source File +# Begin Source File + +SOURCE=.\jcmainct.c +# End Source File +# Begin Source File + +SOURCE=.\jcmarker.c +# End Source File +# Begin Source File + +SOURCE=.\jcmaster.c +# End Source File +# Begin Source File + +SOURCE=.\jcomapi.c +# End Source File +# Begin Source File + +SOURCE=.\jcparam.c +# End Source File +# Begin Source File + +SOURCE=.\jcphuff.c +# End Source File +# Begin Source File + +SOURCE=.\jcprepct.c +# End Source File +# Begin Source File + +SOURCE=.\jcsample.c +# End Source File +# Begin Source File + +SOURCE=.\jctrans.c +# End Source File +# Begin Source File + +SOURCE=.\jdapimin.c +# End Source File +# Begin Source File + +SOURCE=.\jdapistd.c +# End Source File +# Begin Source File + +SOURCE=.\jdatadst.c +# End Source File +# Begin Source File + +SOURCE=.\jdatasrc.c +# End Source File +# Begin Source File + +SOURCE=.\jdcoefct.c +# End Source File +# Begin Source File + +SOURCE=.\jdcolor.c +# End Source File +# Begin Source File + +SOURCE=.\jddctmgr.c +# End Source File +# Begin Source File + +SOURCE=.\jdhuff.c +# End Source File +# Begin Source File + +SOURCE=.\jdinput.c +# End Source File +# Begin Source File + +SOURCE=.\jdmainct.c +# End Source File +# Begin Source File + +SOURCE=.\jdmarker.c +# End Source File +# Begin Source File + +SOURCE=.\jdmaster.c +# End Source File +# Begin Source File + +SOURCE=.\jdmerge.c +# End Source File +# Begin Source File + +SOURCE=.\jdphuff.c +# End Source File +# Begin Source File + +SOURCE=.\jdpostct.c +# End Source File +# Begin Source File + +SOURCE=.\jdsample.c +# End Source File +# Begin Source File + +SOURCE=.\jdtrans.c +# End Source File +# Begin Source File + +SOURCE=.\jerror.c +# End Source File +# Begin Source File + +SOURCE=.\jfdctflt.c +# End Source File +# Begin Source File + +SOURCE=.\jfdctfst.c +# End Source File +# Begin Source File + +SOURCE=.\jfdctint.c +# End Source File +# Begin Source File + +SOURCE=.\jidctflt.c +# End Source File +# Begin Source File + +SOURCE=.\jidctfst.c +# End Source File +# Begin Source File + +SOURCE=.\jidctint.c +# End Source File +# Begin Source File + +SOURCE=.\jidctred.c +# End Source File +# Begin Source File + +SOURCE=.\jmemmgr.c +# End Source File +# Begin Source File + +SOURCE=.\jmemnobs.c +# End Source File +# Begin Source File + +SOURCE=.\jquant1.c +# End Source File +# Begin Source File + +SOURCE=.\jquant2.c +# End Source File +# Begin Source File + +SOURCE=.\jutils.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\jchuff.h +# End Source File +# Begin Source File + +SOURCE=.\jconfig.h +# End Source File +# Begin Source File + +SOURCE=.\jdct.h +# End Source File +# Begin Source File + +SOURCE=.\jdhuff.h +# End Source File +# Begin Source File + +SOURCE=.\jerror.h +# End Source File +# Begin Source File + +SOURCE=.\jinclude.h +# End Source File +# Begin Source File + +SOURCE=.\jmemsys.h +# End Source File +# Begin Source File + +SOURCE=.\jmorecfg.h +# End Source File +# Begin Source File + +SOURCE=.\jpegint.h +# End Source File +# Begin Source File + +SOURCE=.\jpeglib.h +# End Source File +# Begin Source File + +SOURCE=.\jversion.h +# End Source File +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/LibJPEG/ansi2knr.c b/freeimage241/Source/LibJPEG/ansi2knr.c new file mode 100644 index 0000000..4e05fc2 --- /dev/null +++ b/freeimage241/Source/LibJPEG/ansi2knr.c @@ -0,0 +1,693 @@ +/* ansi2knr.c */ +/* Convert ANSI C function definitions to K&R ("traditional C") syntax */ + +/* +ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone for the +consequences of using it or for whether it serves any particular purpose or +works at all, unless he says so in writing. Refer to the GNU General Public +License (the "GPL") for full details. + +Everyone is granted permission to copy, modify and redistribute ansi2knr, +but only under the conditions described in the GPL. A copy of this license +is supposed to have been given to you along with ansi2knr so you can know +your rights and responsibilities. It should be in a file named COPYLEFT. +[In the IJG distribution, the GPL appears below, not in a separate file.] +Among other things, the copyright notice and this notice must be preserved +on all copies. + +We explicitly state here what we believe is already implied by the GPL: if +the ansi2knr program is distributed as a separate set of sources and a +separate executable file which are aggregated on a storage medium together +with another program, this in itself does not bring the other program under +the GPL, nor does the mere fact that such a program or the procedures for +constructing it invoke the ansi2knr executable bring any other part of the +program under the GPL. +*/ + +/* +---------- Here is the GNU GPL file COPYLEFT, referred to above ---------- +----- These terms do NOT apply to the JPEG software itself; see README ------ + + GHOSTSCRIPT GENERAL PUBLIC LICENSE + (Clarified 11 Feb 1988) + + Copyright (C) 1988 Richard M. Stallman + Everyone is permitted to copy and distribute verbatim copies of this + license, but changing it is not allowed. You can also use this wording + to make the terms for other programs. + + The license agreements of most software companies keep you at the +mercy of those companies. By contrast, our general public license is +intended to give everyone the right to share Ghostscript. To make sure +that you get the rights we want you to have, we need to make +restrictions that forbid anyone to deny you these rights or to ask you +to surrender the rights. Hence this license agreement. + + Specifically, we want to make sure that you have the right to give +away copies of Ghostscript, that you receive source code or else can get +it if you want it, that you can change Ghostscript or use pieces of it +in new free programs, and that you know you can do these things. + + To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of Ghostscript, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + Also, for our own protection, we must make certain that everyone finds +out that there is no warranty for Ghostscript. If Ghostscript is +modified by someone else and passed on, we want its recipients to know +that what they have is not what we distributed, so that any problems +introduced by others will not reflect on our reputation. + + Therefore we (Richard M. Stallman and the Free Software Foundation, +Inc.) make the following terms which say what you must do to be allowed +to distribute or change Ghostscript. + + + COPYING POLICIES + + 1. You may copy and distribute verbatim copies of Ghostscript source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy a valid copyright and license +notice "Copyright (C) 1989 Aladdin Enterprises. All rights reserved. +Distributed by Free Software Foundation, Inc." (or with whatever year is +appropriate); keep intact the notices on all files that refer to this +License Agreement and to the absence of any warranty; and give any other +recipients of the Ghostscript program a copy of this License Agreement +along with the program. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of Ghostscript or any portion of +it, and copy and distribute such modifications under the terms of +Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of Ghostscript + or any part thereof, to be licensed at no charge to all third + parties on terms identical to those contained in this License + Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute Ghostscript (or a portion or derivative +of it, under Paragraph 2) in object code or executable form under the +terms of Paragraphs 1 and 2 above provided that you also do one of the +following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + shipping charge) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +For an executable file, complete source code means all the source code for +all modules it contains; but, as a special exception, it need not include +source code for modules which are standard libraries that accompany the +operating system on which the executable file runs. + + 4. You may not copy, sublicense, distribute or transfer Ghostscript +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer Ghostscript is +void and your rights to use the program under this License agreement +shall be automatically terminated. However, parties who have received +computer software programs from you with this License Agreement will not +have their licenses terminated so long as such parties remain in full +compliance. + + 5. If you wish to incorporate parts of Ghostscript into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not +yet worked out a simple rule that can be stated here, but we will often +permit this. We will be guided by the two goals of preserving the free +status of all derivatives of our free software and of promoting the +sharing and reuse of software. + +Your comments and suggestions about our licensing policies and our +software are welcome! Please contact the Free Software Foundation, +Inc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296. + + NO WARRANTY + + BECAUSE GHOSTSCRIPT IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD +M. STALLMAN, ALADDIN ENTERPRISES, L. PETER DEUTSCH, AND/OR OTHER PARTIES +PROVIDE GHOSTSCRIPT "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF GHOSTSCRIPT IS WITH +YOU. SHOULD GHOSTSCRIPT PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., L. PETER DEUTSCH, ALADDIN +ENTERPRISES, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE +GHOSTSCRIPT AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING +ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE +PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GHOSTSCRIPT, EVEN IF YOU +HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM +BY ANY OTHER PARTY. + +-------------------- End of file COPYLEFT ------------------------------ +*/ + +/* + * Usage: + ansi2knr input_file [output_file] + * If no output_file is supplied, output goes to stdout. + * There are no error messages. + * + * ansi2knr recognizes function definitions by seeing a non-keyword + * identifier at the left margin, followed by a left parenthesis, + * with a right parenthesis as the last character on the line, + * and with a left brace as the first token on the following line + * (ignoring possible intervening comments). + * It will recognize a multi-line header provided that no intervening + * line ends with a left or right brace or a semicolon. + * These algorithms ignore whitespace and comments, except that + * the function name must be the first thing on the line. + * The following constructs will confuse it: + * - Any other construct that starts at the left margin and + * follows the above syntax (such as a macro or function call). + * - Some macros that tinker with the syntax of the function header. + */ + +/* + * The original and principal author of ansi2knr is L. Peter Deutsch + * . Other authors are noted in the change history + * that follows (in reverse chronological order): + lpd 96-01-21 added code to cope with not HAVE_CONFIG_H and with + compilers that don't understand void, as suggested by + Tom Lane + lpd 96-01-15 changed to require that the first non-comment token + on the line following a function header be a left brace, + to reduce sensitivity to macros, as suggested by Tom Lane + + lpd 95-06-22 removed #ifndefs whose sole purpose was to define + undefined preprocessor symbols as 0; changed all #ifdefs + for configuration symbols to #ifs + lpd 95-04-05 changed copyright notice to make it clear that + including ansi2knr in a program does not bring the entire + program under the GPL + lpd 94-12-18 added conditionals for systems where ctype macros + don't handle 8-bit characters properly, suggested by + Francois Pinard ; + removed --varargs switch (this is now the default) + lpd 94-10-10 removed CONFIG_BROKETS conditional + lpd 94-07-16 added some conditionals to help GNU `configure', + suggested by Francois Pinard ; + properly erase prototype args in function parameters, + contributed by Jim Avera ; + correct error in writeblanks (it shouldn't erase EOLs) + lpd 89-xx-xx original version + */ + +/* Most of the conditionals here are to make ansi2knr work with */ +/* or without the GNU configure machinery. */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include + +#if HAVE_CONFIG_H + +/* + For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h). + This will define HAVE_CONFIG_H and so, activate the following lines. + */ + +# if STDC_HEADERS || HAVE_STRING_H +# include +# else +# include +# endif + +#else /* not HAVE_CONFIG_H */ + +/* Otherwise do it the hard way */ + +# ifdef BSD +# include +# else +# ifdef VMS + extern int strlen(), strncmp(); +# else +# include +# endif +# endif + +#endif /* not HAVE_CONFIG_H */ + +#if STDC_HEADERS +# include +#else +/* + malloc and free should be declared in stdlib.h, + but if you've got a K&R compiler, they probably aren't. + */ +# ifdef MSDOS +# include +# else +# ifdef VMS + extern char *malloc(); + extern void free(); +# else + extern char *malloc(); + extern int free(); +# endif +# endif + +#endif + +/* + * The ctype macros don't always handle 8-bit characters correctly. + * Compensate for this here. + */ +#ifdef isascii +# undef HAVE_ISASCII /* just in case */ +# define HAVE_ISASCII 1 +#else +#endif +#if STDC_HEADERS || !HAVE_ISASCII +# define is_ascii(c) 1 +#else +# define is_ascii(c) isascii(c) +#endif + +#define is_space(c) (is_ascii(c) && isspace(c)) +#define is_alpha(c) (is_ascii(c) && isalpha(c)) +#define is_alnum(c) (is_ascii(c) && isalnum(c)) + +/* Scanning macros */ +#define isidchar(ch) (is_alnum(ch) || (ch) == '_') +#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_') + +/* Forward references */ +char *skipspace(); +int writeblanks(); +int test1(); +int convert1(); + +/* The main program */ +int +main(argc, argv) + int argc; + char *argv[]; +{ FILE *in, *out; +#define bufsize 5000 /* arbitrary size */ + char *buf; + char *line; + char *more; + /* + * In previous versions, ansi2knr recognized a --varargs switch. + * If this switch was supplied, ansi2knr would attempt to convert + * a ... argument to va_alist and va_dcl; if this switch was not + * supplied, ansi2knr would simply drop any such arguments. + * Now, ansi2knr always does this conversion, and we only + * check for this switch for backward compatibility. + */ + int convert_varargs = 1; + + if ( argc > 1 && argv[1][0] == '-' ) + { if ( !strcmp(argv[1], "--varargs") ) + { convert_varargs = 1; + argc--; + argv++; + } + else + { fprintf(stderr, "Unrecognized switch: %s\n", argv[1]); + exit(1); + } + } + switch ( argc ) + { + default: + printf("Usage: ansi2knr input_file [output_file]\n"); + exit(0); + case 2: + out = stdout; + break; + case 3: + out = fopen(argv[2], "w"); + if ( out == NULL ) + { fprintf(stderr, "Cannot open output file %s\n", argv[2]); + exit(1); + } + } + in = fopen(argv[1], "r"); + if ( in == NULL ) + { fprintf(stderr, "Cannot open input file %s\n", argv[1]); + exit(1); + } + fprintf(out, "#line 1 \"%s\"\n", argv[1]); + buf = malloc(bufsize); + line = buf; + while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL ) + { +test: line += strlen(line); + switch ( test1(buf) ) + { + case 2: /* a function header */ + convert1(buf, out, 1, convert_varargs); + break; + case 1: /* a function */ + /* Check for a { at the start of the next line. */ + more = ++line; +f: if ( line >= buf + (bufsize - 1) ) /* overflow check */ + goto wl; + if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL ) + goto wl; + switch ( *skipspace(more, 1) ) + { + case '{': + /* Definitely a function header. */ + convert1(buf, out, 0, convert_varargs); + fputs(more, out); + break; + case 0: + /* The next line was blank or a comment: */ + /* keep scanning for a non-comment. */ + line += strlen(line); + goto f; + default: + /* buf isn't a function header, but */ + /* more might be. */ + fputs(buf, out); + strcpy(buf, more); + line = buf; + goto test; + } + break; + case -1: /* maybe the start of a function */ + if ( line != buf + (bufsize - 1) ) /* overflow check */ + continue; + /* falls through */ + default: /* not a function */ +wl: fputs(buf, out); + break; + } + line = buf; + } + if ( line != buf ) + fputs(buf, out); + free(buf); + fclose(out); + fclose(in); + return 0; +} + +/* Skip over space and comments, in either direction. */ +char * +skipspace(p, dir) + register char *p; + register int dir; /* 1 for forward, -1 for backward */ +{ for ( ; ; ) + { while ( is_space(*p) ) + p += dir; + if ( !(*p == '/' && p[dir] == '*') ) + break; + p += dir; p += dir; + while ( !(*p == '*' && p[dir] == '/') ) + { if ( *p == 0 ) + return p; /* multi-line comment?? */ + p += dir; + } + p += dir; p += dir; + } + return p; +} + +/* + * Write blanks over part of a string. + * Don't overwrite end-of-line characters. + */ +int +writeblanks(start, end) + char *start; + char *end; +{ char *p; + for ( p = start; p < end; p++ ) + if ( *p != '\r' && *p != '\n' ) + *p = ' '; + return 0; +} + +/* + * Test whether the string in buf is a function definition. + * The string may contain and/or end with a newline. + * Return as follows: + * 0 - definitely not a function definition; + * 1 - definitely a function definition; + * 2 - definitely a function prototype (NOT USED); + * -1 - may be the beginning of a function definition, + * append another line and look again. + * The reason we don't attempt to convert function prototypes is that + * Ghostscript's declaration-generating macros look too much like + * prototypes, and confuse the algorithms. + */ +int +test1(buf) + char *buf; +{ register char *p = buf; + char *bend; + char *endfn; + int contin; + + if ( !isidfirstchar(*p) ) + return 0; /* no name at left margin */ + bend = skipspace(buf + strlen(buf) - 1, -1); + switch ( *bend ) + { + case ';': contin = 0 /*2*/; break; + case ')': contin = 1; break; + case '{': return 0; /* not a function */ + case '}': return 0; /* not a function */ + default: contin = -1; + } + while ( isidchar(*p) ) + p++; + endfn = p; + p = skipspace(p, 1); + if ( *p++ != '(' ) + return 0; /* not a function */ + p = skipspace(p, 1); + if ( *p == ')' ) + return 0; /* no parameters */ + /* Check that the apparent function name isn't a keyword. */ + /* We only need to check for keywords that could be followed */ + /* by a left parenthesis (which, unfortunately, is most of them). */ + { static char *words[] = + { "asm", "auto", "case", "char", "const", "double", + "extern", "float", "for", "if", "int", "long", + "register", "return", "short", "signed", "sizeof", + "static", "switch", "typedef", "unsigned", + "void", "volatile", "while", 0 + }; + char **key = words; + char *kp; + int len = endfn - buf; + + while ( (kp = *key) != 0 ) + { if ( strlen(kp) == len && !strncmp(kp, buf, len) ) + return 0; /* name is a keyword */ + key++; + } + } + return contin; +} + +/* Convert a recognized function definition or header to K&R syntax. */ +int +convert1(buf, out, header, convert_varargs) + char *buf; + FILE *out; + int header; /* Boolean */ + int convert_varargs; /* Boolean */ +{ char *endfn; + register char *p; + char **breaks; + unsigned num_breaks = 2; /* for testing */ + char **btop; + char **bp; + char **ap; + char *vararg = 0; + + /* Pre-ANSI implementations don't agree on whether strchr */ + /* is called strchr or index, so we open-code it here. */ + for ( endfn = buf; *(endfn++) != '('; ) + ; +top: p = endfn; + breaks = (char **)malloc(sizeof(char *) * num_breaks * 2); + if ( breaks == 0 ) + { /* Couldn't allocate break table, give up */ + fprintf(stderr, "Unable to allocate break table!\n"); + fputs(buf, out); + return -1; + } + btop = breaks + num_breaks * 2 - 2; + bp = breaks; + /* Parse the argument list */ + do + { int level = 0; + char *lp = NULL; + char *rp; + char *end = NULL; + + if ( bp >= btop ) + { /* Filled up break table. */ + /* Allocate a bigger one and start over. */ + free((char *)breaks); + num_breaks <<= 1; + goto top; + } + *bp++ = p; + /* Find the end of the argument */ + for ( ; end == NULL; p++ ) + { switch(*p) + { + case ',': + if ( !level ) end = p; + break; + case '(': + if ( !level ) lp = p; + level++; + break; + case ')': + if ( --level < 0 ) end = p; + else rp = p; + break; + case '/': + p = skipspace(p, 1) - 1; + break; + default: + ; + } + } + /* Erase any embedded prototype parameters. */ + if ( lp ) + writeblanks(lp + 1, rp); + p--; /* back up over terminator */ + /* Find the name being declared. */ + /* This is complicated because of procedure and */ + /* array modifiers. */ + for ( ; ; ) + { p = skipspace(p - 1, -1); + switch ( *p ) + { + case ']': /* skip array dimension(s) */ + case ')': /* skip procedure args OR name */ + { int level = 1; + while ( level ) + switch ( *--p ) + { + case ']': case ')': level++; break; + case '[': case '(': level--; break; + case '/': p = skipspace(p, -1) + 1; break; + default: ; + } + } + if ( *p == '(' && *skipspace(p + 1, 1) == '*' ) + { /* We found the name being declared */ + while ( !isidfirstchar(*p) ) + p = skipspace(p, 1) + 1; + goto found; + } + break; + default: + goto found; + } + } +found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' ) + { if ( convert_varargs ) + { *bp++ = "va_alist"; + vararg = p-2; + } + else + { p++; + if ( bp == breaks + 1 ) /* sole argument */ + writeblanks(breaks[0], p); + else + writeblanks(bp[-1] - 1, p); + bp--; + } + } + else + { while ( isidchar(*p) ) p--; + *bp++ = p+1; + } + p = end; + } + while ( *p++ == ',' ); + *bp = p; + /* Make a special check for 'void' arglist */ + if ( bp == breaks+2 ) + { p = skipspace(breaks[0], 1); + if ( !strncmp(p, "void", 4) ) + { p = skipspace(p+4, 1); + if ( p == breaks[2] - 1 ) + { bp = breaks; /* yup, pretend arglist is empty */ + writeblanks(breaks[0], p + 1); + } + } + } + /* Put out the function name and left parenthesis. */ + p = buf; + while ( p != endfn ) putc(*p, out), p++; + /* Put out the declaration. */ + if ( header ) + { fputs(");", out); + for ( p = breaks[0]; *p; p++ ) + if ( *p == '\r' || *p == '\n' ) + putc(*p, out); + } + else + { for ( ap = breaks+1; ap < bp; ap += 2 ) + { p = *ap; + while ( isidchar(*p) ) + putc(*p, out), p++; + if ( ap < bp - 1 ) + fputs(", ", out); + } + fputs(") ", out); + /* Put out the argument declarations */ + for ( ap = breaks+2; ap <= bp; ap += 2 ) + (*ap)[-1] = ';'; + if ( vararg != 0 ) + { *vararg = 0; + fputs(breaks[0], out); /* any prior args */ + fputs("va_dcl", out); /* the final arg */ + fputs(bp[0], out); + } + else + fputs(breaks[0], out); + } + free((char *)breaks); + return 0; +} diff --git a/freeimage241/Source/LibJPEG/cderror.h b/freeimage241/Source/LibJPEG/cderror.h new file mode 100644 index 0000000..70435e1 --- /dev/null +++ b/freeimage241/Source/LibJPEG/cderror.h @@ -0,0 +1,132 @@ +/* + * cderror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the cjpeg/djpeg + * applications. These strings are not needed as part of the JPEG library + * proper. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef CDERROR_H +#define CDERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* CDERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */ + +#ifdef BMP_SUPPORTED +JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format") +JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported") +JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length") +JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1") +JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB") +JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported") +JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM") +JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image") +JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image") +JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image") +JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image") +#endif /* BMP_SUPPORTED */ + +#ifdef GIF_SUPPORTED +JMESSAGE(JERR_GIF_BUG, "GIF output got confused") +JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d") +JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB") +JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file") +JMESSAGE(JERR_GIF_NOT, "Not a GIF file") +JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image") +JMESSAGE(JTRC_GIF_BADVERSION, + "Warning: unexpected GIF version number '%c%c%c'") +JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x") +JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input") +JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file") +JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring") +JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image") +JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits") +#endif /* GIF_SUPPORTED */ + +#ifdef PPM_SUPPORTED +JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB") +JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file") +JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file") +JMESSAGE(JTRC_PGM, "%ux%u PGM image") +JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image") +JMESSAGE(JTRC_PPM, "%ux%u PPM image") +JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image") +#endif /* PPM_SUPPORTED */ + +#ifdef RLE_SUPPORTED +JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library") +JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB") +JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE") +JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file") +JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header") +JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header") +JMESSAGE(JERR_RLE_NOT, "Not an RLE file") +JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE") +JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup") +JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file") +JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d") +JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file") +JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d") +JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d") +#endif /* RLE_SUPPORTED */ + +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format") +JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file") +JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB") +JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image") +JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image") +JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image") +#else +JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled") +#endif /* TARGA_SUPPORTED */ + +JMESSAGE(JERR_BAD_CMAP_FILE, + "Color map file is invalid or of unsupported format") +JMESSAGE(JERR_TOO_MANY_COLORS, + "Output file format cannot handle %d colormap entries") +JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed") +#ifdef TARGA_SUPPORTED +JMESSAGE(JERR_UNKNOWN_FORMAT, + "Unrecognized input file format --- perhaps you need -targa") +#else +JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format") +#endif +JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTADDONCODE +} ADDON_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE diff --git a/freeimage241/Source/LibJPEG/cdjpeg.c b/freeimage241/Source/LibJPEG/cdjpeg.c new file mode 100644 index 0000000..b6250ff --- /dev/null +++ b/freeimage241/Source/LibJPEG/cdjpeg.c @@ -0,0 +1,181 @@ +/* + * cdjpeg.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common support routines used by the IJG application + * programs (cjpeg, djpeg, jpegtran). + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include /* to declare isupper(), tolower() */ +#ifdef NEED_SIGNAL_CATCHER +#include /* to declare signal() */ +#endif +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + + +/* + * Signal catcher to ensure that temporary files are removed before aborting. + * NB: for Amiga Manx C this is actually a global routine named _abort(); + * we put "#define signal_catcher _abort" in jconfig.h. Talk about bogus... + */ + +#ifdef NEED_SIGNAL_CATCHER + +static j_common_ptr sig_cinfo; + +void /* must be global for Manx C */ +signal_catcher (int signum) +{ + if (sig_cinfo != NULL) { + if (sig_cinfo->err != NULL) /* turn off trace output */ + sig_cinfo->err->trace_level = 0; + jpeg_destroy(sig_cinfo); /* clean up memory allocation & temp files */ + } + exit(EXIT_FAILURE); +} + + +GLOBAL(void) +enable_signal_catcher (j_common_ptr cinfo) +{ + sig_cinfo = cinfo; +#ifdef SIGINT /* not all systems have SIGINT */ + signal(SIGINT, signal_catcher); +#endif +#ifdef SIGTERM /* not all systems have SIGTERM */ + signal(SIGTERM, signal_catcher); +#endif +} + +#endif + + +/* + * Optional progress monitor: display a percent-done figure on stderr. + */ + +#ifdef PROGRESS_REPORT + +METHODDEF(void) +progress_monitor (j_common_ptr cinfo) +{ + cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress; + int total_passes = prog->pub.total_passes + prog->total_extra_passes; + int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit); + + if (percent_done != prog->percent_done) { + prog->percent_done = percent_done; + if (total_passes > 1) { + fprintf(stderr, "\rPass %d/%d: %3d%% ", + prog->pub.completed_passes + prog->completed_extra_passes + 1, + total_passes, percent_done); + } else { + fprintf(stderr, "\r %3d%% ", percent_done); + } + fflush(stderr); + } +} + + +GLOBAL(void) +start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress) +{ + /* Enable progress display, unless trace output is on */ + if (cinfo->err->trace_level == 0) { + progress->pub.progress_monitor = progress_monitor; + progress->completed_extra_passes = 0; + progress->total_extra_passes = 0; + progress->percent_done = -1; + cinfo->progress = &progress->pub; + } +} + + +GLOBAL(void) +end_progress_monitor (j_common_ptr cinfo) +{ + /* Clear away progress display */ + if (cinfo->err->trace_level == 0) { + fprintf(stderr, "\r \r"); + fflush(stderr); + } +} + +#endif + + +/* + * Case-insensitive matching of possibly-abbreviated keyword switches. + * keyword is the constant keyword (must be lower case already), + * minchars is length of minimum legal abbreviation. + */ + +GLOBAL(boolean) +keymatch (char * arg, const char * keyword, int minchars) +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return FALSE; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return FALSE; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return FALSE; + return TRUE; /* A-OK */ +} + + +/* + * Routines to establish binary I/O mode for stdin and stdout. + * Non-Unix systems often require some hacking to get out of text mode. + */ + +GLOBAL(FILE *) +read_stdin (void) +{ + FILE * input_file = stdin; + +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "Cannot reopen stdin\n"); + exit(EXIT_FAILURE); + } +#endif + return input_file; +} + + +GLOBAL(FILE *) +write_stdout (void) +{ + FILE * output_file = stdout; + +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdout), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { + fprintf(stderr, "Cannot reopen stdout\n"); + exit(EXIT_FAILURE); + } +#endif + return output_file; +} diff --git a/freeimage241/Source/LibJPEG/cdjpeg.h b/freeimage241/Source/LibJPEG/cdjpeg.h new file mode 100644 index 0000000..2b387b6 --- /dev/null +++ b/freeimage241/Source/LibJPEG/cdjpeg.h @@ -0,0 +1,184 @@ +/* + * cdjpeg.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains common declarations for the sample applications + * cjpeg and djpeg. It is NOT used by the core JPEG library. + */ + +#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */ +#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" /* get library error codes too */ +#include "cderror.h" /* get application-specific error codes */ + + +/* + * Object interface for cjpeg's source file decoding modules + */ + +typedef struct cjpeg_source_struct * cjpeg_source_ptr; + +struct cjpeg_source_struct { + JMETHOD(void, start_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + JMETHOD(void, finish_input, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); + + FILE *input_file; + + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * Object interface for djpeg's output file encoding modules + */ + +typedef struct djpeg_dest_struct * djpeg_dest_ptr; + +struct djpeg_dest_struct { + /* start_output is called after jpeg_start_decompress finishes. + * The color map will be ready at this time, if one is needed. + */ + JMETHOD(void, start_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + /* Emit the specified number of pixel rows from the buffer. */ + JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + /* Finish up at the end of the image. */ + JMETHOD(void, finish_output, (j_decompress_ptr cinfo, + djpeg_dest_ptr dinfo)); + + /* Target file spec; filled in by djpeg.c after object is created. */ + FILE * output_file; + + /* Output pixel-row buffer. Created by module init or start_output. + * Width is cinfo->output_width * cinfo->output_components; + * height is buffer_height. + */ + JSAMPARRAY buffer; + JDIMENSION buffer_height; +}; + + +/* + * cjpeg/djpeg may need to perform extra passes to convert to or from + * the source/destination file format. The JPEG library does not know + * about these passes, but we'd like them to be counted by the progress + * monitor. We use an expanded progress monitor object to hold the + * additional pass count. + */ + +struct cdjpeg_progress_mgr { + struct jpeg_progress_mgr pub; /* fields known to JPEG library */ + int completed_extra_passes; /* extra passes completed */ + int total_extra_passes; /* total extra */ + /* last printed percentage stored here to avoid multiple printouts */ + int percent_done; +}; + +typedef struct cdjpeg_progress_mgr * cd_progress_ptr; + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_read_bmp jIRdBMP +#define jinit_write_bmp jIWrBMP +#define jinit_read_gif jIRdGIF +#define jinit_write_gif jIWrGIF +#define jinit_read_ppm jIRdPPM +#define jinit_write_ppm jIWrPPM +#define jinit_read_rle jIRdRLE +#define jinit_write_rle jIWrRLE +#define jinit_read_targa jIRdTarga +#define jinit_write_targa jIWrTarga +#define read_quant_tables RdQTables +#define read_scan_script RdScnScript +#define set_quant_slots SetQSlots +#define set_sample_factors SetSFacts +#define read_color_map RdCMap +#define enable_signal_catcher EnSigCatcher +#define start_progress_monitor StProgMon +#define end_progress_monitor EnProgMon +#define read_stdin RdStdin +#define write_stdout WrStdout +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Module selection routines for I/O modules. */ + +EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo, + boolean is_os2)); +EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo)); +EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo)); +EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo)); + +/* cjpeg support routines (in rdswitch.c) */ + +EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename, + int scale_factor, boolean force_baseline)); +EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename)); +EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg)); +EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg)); + +/* djpeg support routines (in rdcolmap.c) */ + +EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* common support routines (in cdjpeg.c) */ + +EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo)); +EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo, + cd_progress_ptr progress)); +EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo)); +EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars)); +EXTERN(FILE *) read_stdin JPP((void)); +EXTERN(FILE *) write_stdout JPP((void)); + +/* miscellaneous useful macros */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif +#ifndef EXIT_WARNING +#ifdef VMS +#define EXIT_WARNING 1 /* VMS is very nonstandard */ +#else +#define EXIT_WARNING 2 +#endif +#endif diff --git a/freeimage241/Source/LibJPEG/change.log b/freeimage241/Source/LibJPEG/change.log new file mode 100644 index 0000000..74102c0 --- /dev/null +++ b/freeimage241/Source/LibJPEG/change.log @@ -0,0 +1,217 @@ +CHANGE LOG for Independent JPEG Group's JPEG software + + +Version 6b 27-Mar-1998 +----------------------- + +jpegtran has new features for lossless image transformations (rotation +and flipping) as well as "lossless" reduction to grayscale. + +jpegtran now copies comments by default; it has a -copy switch to enable +copying all APPn blocks as well, or to suppress comments. (Formerly it +always suppressed comments and APPn blocks.) jpegtran now also preserves +JFIF version and resolution information. + +New decompressor library feature: COM and APPn markers found in the input +file can be saved in memory for later use by the application. (Before, +you had to code this up yourself with a custom marker processor.) + +There is an unused field "void * client_data" now in compress and decompress +parameter structs; this may be useful in some applications. + +JFIF version number information is now saved by the decoder and accepted by +the encoder. jpegtran uses this to copy the source file's version number, +to ensure "jpegtran -copy all" won't create bogus files that contain JFXX +extensions but claim to be version 1.01. Applications that generate their +own JFXX extension markers also (finally) have a supported way to cause the +encoder to emit JFIF version number 1.02. + +djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather +than as unknown APP0 markers. + +In -verbose mode, djpeg and rdjpgcom will try to print the contents of +APP12 markers as text. Some digital cameras store useful text information +in APP12 markers. + +Handling of truncated data streams is more robust: blocks beyond the one in +which the error occurs will be output as uniform gray, or left unchanged +if decoding a progressive JPEG. The appearance no longer depends on the +Huffman tables being used. + +Huffman tables are checked for validity much more carefully than before. + +To avoid the Unisys LZW patent, djpeg's GIF output capability has been +changed to produce "uncompressed GIFs", and cjpeg's GIF input capability +has been removed altogether. We're not happy about it either, but there +seems to be no good alternative. + +The configure script now supports building libjpeg as a shared library +on many flavors of Unix (all the ones that GNU libtool knows how to +build shared libraries for). Use "./configure --enable-shared" to +try this out. + +New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio. +Also, a jconfig file and a build script for Metrowerks CodeWarrior +on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there +are miscellaneous other minor improvements in the makefiles. + +jmemmac.c now knows how to create temporary files following Mac System 7 +conventions. + +djpeg's -map switch is now able to read raw-format PPM files reliably. + +cjpeg -progressive -restart no longer generates any unnecessary DRI markers. + +Multiple calls to jpeg_simple_progression for a single JPEG object +no longer leak memory. + + +Version 6a 7-Feb-96 +-------------------- + +Library initialization sequence modified to detect version mismatches +and struct field packing mismatches between library and calling application. +This change requires applications to be recompiled, but does not require +any application source code change. + +All routine declarations changed to the style "GLOBAL(type) name ...", +that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the +routine's return type as an argument. This makes it possible to add +Microsoft-style linkage keywords to all the routines by changing just +these macros. Note that any application code that was using these macros +will have to be changed. + +DCT coefficient quantization tables are now stored in normal array order +rather than zigzag order. Application code that calls jpeg_add_quant_table, +or otherwise manipulates quantization tables directly, will need to be +changed. If you need to make such code work with either older or newer +versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is +recommended. + +djpeg's trace capability now dumps DQT tables in natural order, not zigzag +order. This allows the trace output to be made into a "-qtables" file +more easily. + +New system-dependent memory manager module for use on Apple Macintosh. + +Fix bug in cjpeg's -smooth option: last one or two scanlines would be +duplicates of the prior line unless the image height mod 16 was 1 or 2. + +Repair minor problems in VMS, BCC, MC6 makefiles. + +New configure script based on latest GNU Autoconf. + +Correct the list of include files needed by MetroWerks C for ccommand(). + +Numerous small documentation updates. + + +Version 6 2-Aug-95 +------------------- + +Progressive JPEG support: library can read and write full progressive JPEG +files. A "buffered image" mode supports incremental decoding for on-the-fly +display of progressive images. Simply recompiling an existing IJG-v5-based +decoder with v6 should allow it to read progressive files, though of course +without any special progressive display. + +New "jpegtran" application performs lossless transcoding between different +JPEG formats; primarily, it can be used to convert baseline to progressive +JPEG and vice versa. In support of jpegtran, the library now allows lossless +reading and writing of JPEG files as DCT coefficient arrays. This ability +may be of use in other applications. + +Notes for programmers: +* We changed jpeg_start_decompress() to be able to suspend; this makes all +decoding modes available to suspending-input applications. However, +existing applications that use suspending input will need to be changed +to check the return value from jpeg_start_decompress(). You don't need to +do anything if you don't use a suspending data source. +* We changed the interface to the virtual array routines: access_virt_array +routines now take a count of the number of rows to access this time. The +last parameter to request_virt_array routines is now interpreted as the +maximum number of rows that may be accessed at once, but not necessarily +the height of every access. + + +Version 5b 15-Mar-95 +--------------------- + +Correct bugs with grayscale images having v_samp_factor > 1. + +jpeg_write_raw_data() now supports output suspension. + +Correct bugs in "configure" script for case of compiling in +a directory other than the one containing the source files. + +Repair bug in jquant1.c: sometimes didn't use as many colors as it could. + +Borland C makefile and jconfig file work under either MS-DOS or OS/2. + +Miscellaneous improvements to documentation. + + +Version 5a 7-Dec-94 +-------------------- + +Changed color conversion roundoff behavior so that grayscale values are +represented exactly. (This causes test image files to change.) + +Make ordered dither use 16x16 instead of 4x4 pattern for a small quality +improvement. + +New configure script based on latest GNU Autoconf. +Fix configure script to handle CFLAGS correctly. +Rename *.auto files to *.cfg, so that configure script still works if +file names have been truncated for DOS. + +Fix bug in rdbmp.c: didn't allow for extra data between header and image. + +Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data. + +Fix several bugs in rdrle.c. + +NEED_SHORT_EXTERNAL_NAMES option was broken. + +Revise jerror.h/jerror.c for more flexibility in message table. + +Repair oversight in jmemname.c NO_MKTEMP case: file could be there +but unreadable. + + +Version 5 24-Sep-94 +-------------------- + +Version 5 represents a nearly complete redesign and rewrite of the IJG +software. Major user-visible changes include: + * Automatic configuration simplifies installation for most Unix systems. + * A range of speed vs. image quality tradeoffs are supported. + This includes resizing of an image during decompression: scaling down + by a factor of 1/2, 1/4, or 1/8 is handled very efficiently. + * New programs rdjpgcom and wrjpgcom allow insertion and extraction + of text comments in a JPEG file. + +The application programmer's interface to the library has changed completely. +Notable improvements include: + * We have eliminated the use of callback routines for handling the + uncompressed image data. The application now sees the library as a + set of routines that it calls to read or write image data on a + scanline-by-scanline basis. + * The application image data is represented in a conventional interleaved- + pixel format, rather than as a separate array for each color channel. + This can save a copying step in many programs. + * The handling of compressed data has been cleaned up: the application can + supply routines to source or sink the compressed data. It is possible to + suspend processing on source/sink buffer overrun, although this is not + supported in all operating modes. + * All static state has been eliminated from the library, so that multiple + instances of compression or decompression can be active concurrently. + * JPEG abbreviated datastream formats are supported, ie, quantization and + Huffman tables can be stored separately from the image data. + * And not only that, but the documentation of the library has improved + considerably! + + +The last widely used release before the version 5 rewrite was version 4A of +18-Feb-93. Change logs before that point have been discarded, since they +are not of much interest after the rewrite. diff --git a/freeimage241/Source/LibJPEG/cjpeg.c b/freeimage241/Source/LibJPEG/cjpeg.c new file mode 100644 index 0000000..f2a929f --- /dev/null +++ b/freeimage241/Source/LibJPEG/cjpeg.c @@ -0,0 +1,606 @@ +/* + * cjpeg.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a command-line user interface for the JPEG compressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * cjpeg [options] inputfile outputfile + * cjpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + * To simplify script writing, the "-outfile" switch is provided. The syntax + * cjpeg [options] -outfile outputfile inputfile + * works regardless of which command line style is used. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "jversion.h" /* for version message */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + + +/* Create the add-on message string table. */ + +#define JMESSAGE(code,string) string , + +static const char * const cdjpeg_message_table[] = { +#include "cderror.h" + NULL +}; + + +/* + * This routine determines what format the input file is, + * and selects the appropriate input-reading module. + * + * To determine which family of input formats the file belongs to, + * we may look only at the first byte of the file, since C does not + * guarantee that more than one character can be pushed back with ungetc. + * Looking at additional bytes would require one of these approaches: + * 1) assume we can fseek() the input file (fails for piped input); + * 2) assume we can push back more than one character (works in + * some C implementations, but unportable); + * 3) provide our own buffering (breaks input readers that want to use + * stdio directly, such as the RLE library); + * or 4) don't put back the data, and modify the input_init methods to assume + * they start reading after the start of file (also breaks RLE library). + * #1 is attractive for MS-DOS but is untenable on Unix. + * + * The most portable solution for file types that can't be identified by their + * first byte is to make the user tell us what they are. This is also the + * only approach for "raw" file types that contain only arbitrary values. + * We presently apply this method for Targa files. Most of the time Targa + * files start with 0x00, so we recognize that case. Potentially, however, + * a Targa file could start with any byte value (byte 0 is the length of the + * seldom-used ID field), so we provide a switch to force Targa input mode. + */ + +static boolean is_targa; /* records user -targa switch */ + + +LOCAL(cjpeg_source_ptr) +select_file_type (j_compress_ptr cinfo, FILE * infile) +{ + int c; + + if (is_targa) { +#ifdef TARGA_SUPPORTED + return jinit_read_targa(cinfo); +#else + ERREXIT(cinfo, JERR_TGA_NOTCOMP); +#endif + } + + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_INPUT_EMPTY); + if (ungetc(c, infile) == EOF) + ERREXIT(cinfo, JERR_UNGETC_FAILED); + + switch (c) { +#ifdef BMP_SUPPORTED + case 'B': + return jinit_read_bmp(cinfo); +#endif +#ifdef GIF_SUPPORTED + case 'G': + return jinit_read_gif(cinfo); +#endif +#ifdef PPM_SUPPORTED + case 'P': + return jinit_read_ppm(cinfo); +#endif +#ifdef RLE_SUPPORTED + case 'R': + return jinit_read_rle(cinfo); +#endif +#ifdef TARGA_SUPPORTED + case 0x00: + return jinit_read_targa(cinfo); +#endif + default: + ERREXIT(cinfo, JERR_UNKNOWN_FORMAT); + break; + } + + return NULL; /* suppress compiler warnings */ +} + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + * The main program in this file doesn't actually use this capability... + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -quality N Compression quality (0..100; 5-95 is useful range)\n"); + fprintf(stderr, " -grayscale Create monochrome JPEG file\n"); +#ifdef ENTROPY_OPT_SUPPORTED + fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); +#endif +#ifdef C_PROGRESSIVE_SUPPORTED + fprintf(stderr, " -progressive Create progressive JPEG file\n"); +#endif +#ifdef TARGA_SUPPORTED + fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n"); +#endif + fprintf(stderr, "Switches for advanced users:\n"); +#ifdef DCT_ISLOW_SUPPORTED + fprintf(stderr, " -dct int Use integer DCT method%s\n", + (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); +#endif +#ifdef DCT_IFAST_SUPPORTED + fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n", + (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : "")); +#endif +#ifdef DCT_FLOAT_SUPPORTED + fprintf(stderr, " -dct float Use floating-point DCT method%s\n", + (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : "")); +#endif + fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); +#ifdef INPUT_SMOOTHING_SUPPORTED + fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n"); +#endif + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + fprintf(stderr, "Switches for wizards:\n"); +#ifdef C_ARITH_CODING_SUPPORTED + fprintf(stderr, " -arithmetic Use arithmetic coding\n"); +#endif + fprintf(stderr, " -baseline Force baseline quantization tables\n"); + fprintf(stderr, " -qtables file Use quantization tables given in file\n"); + fprintf(stderr, " -qslots N[,...] Set component quantization tables\n"); + fprintf(stderr, " -sample HxV[,...] Set component sampling factors\n"); +#ifdef C_MULTISCAN_FILES_SUPPORTED + fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n"); +#endif + exit(EXIT_FAILURE); +} + + +LOCAL(int) +parse_switches (j_compress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + int quality; /* -quality parameter */ + int q_scale_factor; /* scaling percentage for -qtables */ + boolean force_baseline; + boolean simple_progressive; + char * qtablefile = NULL; /* saves -qtables filename if any */ + char * qslotsarg = NULL; /* saves -qslots parm if any */ + char * samplearg = NULL; /* saves -sample parm if any */ + char * scansarg = NULL; /* saves -scans parm if any */ + + /* Set up default JPEG parameters. */ + /* Note that default -quality level need not, and does not, + * match the default scaling for an explicit -qtables argument. + */ + quality = 75; /* default -quality value */ + q_scale_factor = 100; /* default to no scaling for -qtables */ + force_baseline = FALSE; /* by default, allow 16-bit quantizers */ + simple_progressive = FALSE; + is_targa = FALSE; + outfilename = NULL; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "arithmetic", 1)) { + /* Use arithmetic coding. */ +#ifdef C_ARITH_CODING_SUPPORTED + cinfo->arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "baseline", 1)) { + /* Force baseline-compatible output (8-bit quantizer values). */ + force_baseline = TRUE; + + } else if (keymatch(arg, "dct", 2)) { + /* Select DCT algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "int", 1)) { + cinfo->dct_method = JDCT_ISLOW; + } else if (keymatch(argv[argn], "fast", 2)) { + cinfo->dct_method = JDCT_IFAST; + } else if (keymatch(argv[argn], "float", 2)) { + cinfo->dct_method = JDCT_FLOAT; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { + /* Force a monochrome JPEG file to be generated. */ + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { + /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "progressive", 1)) { + /* Select simple progressive mode. */ +#ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; + /* We must postpone execution until num_components is known. */ +#else + fprintf(stderr, "%s: sorry, progressive output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "quality", 1)) { + /* Quality factor (quantization table scaling factor). */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &quality) != 1) + usage(); + /* Change scale factor in case -qtables is present. */ + q_scale_factor = jpeg_quality_scaling(quality); + + } else if (keymatch(arg, "qslots", 2)) { + /* Quantization table slot numbers. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + qslotsarg = argv[argn]; + /* Must delay setting qslots until after we have processed any + * colorspace-determining switches, since jpeg_set_colorspace sets + * default quant table numbers. + */ + + } else if (keymatch(arg, "qtables", 2)) { + /* Quantization tables fetched from file. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + qtablefile = argv[argn]; + /* We postpone actually reading the file in case -quality comes later. */ + + } else if (keymatch(arg, "restart", 1)) { + /* Restart interval in MCU rows (or in MCUs with 'b'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (lval < 0 || lval > 65535L) + usage(); + if (ch == 'b' || ch == 'B') { + cinfo->restart_interval = (unsigned int) lval; + cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ + } else { + cinfo->restart_in_rows = (int) lval; + /* restart_interval will be computed during startup */ + } + + } else if (keymatch(arg, "sample", 2)) { + /* Set sampling factors. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + samplearg = argv[argn]; + /* Must delay setting sample factors until after we have processed any + * colorspace-determining switches, since jpeg_set_colorspace sets + * default sampling factors. + */ + + } else if (keymatch(arg, "scans", 2)) { + /* Set scan script. */ +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (++argn >= argc) /* advance to next argument */ + usage(); + scansarg = argv[argn]; + /* We must postpone reading the file in case -progressive appears. */ +#else + fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "smooth", 2)) { + /* Set input smoothing factor. */ + int val; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &val) != 1) + usage(); + if (val < 0 || val > 100) + usage(); + cinfo->smoothing_factor = val; + + } else if (keymatch(arg, "targa", 1)) { + /* Input file is Targa format. */ + is_targa = TRUE; + + } else { + usage(); /* bogus switch */ + } + } + + /* Post-switch-scanning cleanup */ + + if (for_real) { + + /* Set quantization tables for selected quality. */ + /* Some or all may be overridden if -qtables is present. */ + jpeg_set_quality(cinfo, quality, force_baseline); + + if (qtablefile != NULL) /* process -qtables if it was present */ + if (! read_quant_tables(cinfo, qtablefile, + q_scale_factor, force_baseline)) + usage(); + + if (qslotsarg != NULL) /* process -qslots if it was present */ + if (! set_quant_slots(cinfo, qslotsarg)) + usage(); + + if (samplearg != NULL) /* process -sample if it was present */ + if (! set_sample_factors(cinfo, samplearg)) + usage(); + +#ifdef C_PROGRESSIVE_SUPPORTED + if (simple_progressive) /* process -progressive; -scans can override */ + jpeg_simple_progression(cinfo); +#endif + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (scansarg != NULL) /* process -scans if it was present */ + if (! read_scan_script(cinfo, scansarg)) + usage(); +#endif + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + int file_index; + cjpeg_source_ptr src_mgr; + FILE * input_file; + FILE * output_file; + JDIMENSION num_scanlines; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "cjpeg"; /* in case C library doesn't provide it */ + + /* Initialize the JPEG compression object with default error handling. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + /* Add some application-specific error messages (from cderror.h) */ + jerr.addon_message_table = cdjpeg_message_table; + jerr.first_addon_message = JMSG_FIRSTADDONCODE; + jerr.last_addon_message = JMSG_LASTADDONCODE; + + /* Now safe to enable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &cinfo); +#endif + + /* Initialize JPEG parameters. + * Much of this may be overridden later. + * In particular, we don't yet know the input file's color space, + * but we need to provide some value for jpeg_set_defaults() to work. + */ + + cinfo.in_color_space = JCS_RGB; /* arbitrary guess */ + jpeg_set_defaults(&cinfo); + + /* Scan command line to find file names. + * It is convenient to use just one switch-parsing routine, but the switch + * values read here are ignored; we will rescan the switches after opening + * the input file. + */ + + file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); + +#ifdef TWO_FILE_COMMANDLINE + /* Must have either -outfile switch or explicit output file name */ + if (outfilename == NULL) { + if (file_index != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + outfilename = argv[file_index+1]; + } else { + if (file_index != argc-1) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + } +#else + /* Unix style: expect zero or one file name */ + if (file_index < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } +#endif /* TWO_FILE_COMMANDLINE */ + + /* Open the input file. */ + if (file_index < argc) { + if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ + input_file = read_stdin(); + } + + /* Open the output file. */ + if (outfilename != NULL) { + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, outfilename); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + output_file = write_stdout(); + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &cinfo, &progress); +#endif + + /* Figure out the input file format, and set up to read it. */ + src_mgr = select_file_type(&cinfo, input_file); + src_mgr->input_file = input_file; + + /* Read the input file header to obtain file size & colorspace. */ + (*src_mgr->start_input) (&cinfo, src_mgr); + + /* Now that we know input colorspace, fix colorspace-dependent defaults */ + jpeg_default_colorspace(&cinfo); + + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); + + /* Specify data destination for compression */ + jpeg_stdio_dest(&cinfo, output_file); + + /* Start compressor */ + jpeg_start_compress(&cinfo, TRUE); + + /* Process data */ + while (cinfo.next_scanline < cinfo.image_height) { + num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); + (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines); + } + + /* Finish compression and release memory */ + (*src_mgr->finish_input) (&cinfo, src_mgr); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + /* Close files, if we opened them */ + if (input_file != stdin) + fclose(input_file); + if (output_file != stdout) + fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &cinfo); +#endif + + /* All done. */ + exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/freeimage241/Source/LibJPEG/ckconfig.c b/freeimage241/Source/LibJPEG/ckconfig.c new file mode 100644 index 0000000..34baf79 --- /dev/null +++ b/freeimage241/Source/LibJPEG/ckconfig.c @@ -0,0 +1,402 @@ +/* + * ckconfig.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + */ + +/* + * This program is intended to help you determine how to configure the JPEG + * software for installation on a particular system. The idea is to try to + * compile and execute this program. If your compiler fails to compile the + * program, make changes as indicated in the comments below. Once you can + * compile the program, run it, and it will produce a "jconfig.h" file for + * your system. + * + * As a general rule, each time you try to compile this program, + * pay attention only to the *first* error message you get from the compiler. + * Many C compilers will issue lots of spurious error messages once they + * have gotten confused. Go to the line indicated in the first error message, + * and read the comments preceding that line to see what to change. + * + * Almost all of the edits you may need to make to this program consist of + * changing a line that reads "#define SOME_SYMBOL" to "#undef SOME_SYMBOL", + * or vice versa. This is called defining or undefining that symbol. + */ + + +/* First we must see if your system has the include files we need. + * We start out with the assumption that your system has all the ANSI-standard + * include files. If you get any error trying to include one of these files, + * undefine the corresponding HAVE_xxx symbol. + */ + +#define HAVE_STDDEF_H /* replace 'define' by 'undef' if error here */ +#ifdef HAVE_STDDEF_H /* next line will be skipped if you undef... */ +#include +#endif + +#define HAVE_STDLIB_H /* same thing for stdlib.h */ +#ifdef HAVE_STDLIB_H +#include +#endif + +#include /* If you ain't got this, you ain't got C. */ + +/* We have to see if your string functions are defined by + * strings.h (old BSD convention) or string.h (everybody else). + * We try the non-BSD convention first; define NEED_BSD_STRINGS + * if the compiler says it can't find string.h. + */ + +#undef NEED_BSD_STRINGS + +#ifdef NEED_BSD_STRINGS +#include +#else +#include +#endif + +/* On some systems (especially older Unix machines), type size_t is + * defined only in the include file . If you get a failure + * on the size_t test below, try defining NEED_SYS_TYPES_H. + */ + +#undef NEED_SYS_TYPES_H /* start by assuming we don't need it */ +#ifdef NEED_SYS_TYPES_H +#include +#endif + + +/* Usually type size_t is defined in one of the include files we've included + * above. If not, you'll get an error on the "typedef size_t my_size_t;" line. + * In that case, first try defining NEED_SYS_TYPES_H just above. + * If that doesn't work, you'll have to search through your system library + * to figure out which include file defines "size_t". Look for a line that + * says "typedef something-or-other size_t;". Then, change the line below + * that says "#include " to instead include the file + * you found size_t in, and define NEED_SPECIAL_INCLUDE. If you can't find + * type size_t anywhere, try replacing "#include " with + * "typedef unsigned int size_t;". + */ + +#undef NEED_SPECIAL_INCLUDE /* assume we DON'T need it, for starters */ + +#ifdef NEED_SPECIAL_INCLUDE +#include +#endif + +typedef size_t my_size_t; /* The payoff: do we have size_t now? */ + + +/* The next question is whether your compiler supports ANSI-style function + * prototypes. You need to know this in order to choose between using + * makefile.ansi and using makefile.unix. + * The #define line below is set to assume you have ANSI function prototypes. + * If you get an error in this group of lines, undefine HAVE_PROTOTYPES. + */ + +#define HAVE_PROTOTYPES + +#ifdef HAVE_PROTOTYPES +int testfunction (int arg1, int * arg2); /* check prototypes */ + +struct methods_struct { /* check method-pointer declarations */ + int (*error_exit) (char *msgtext); + int (*trace_message) (char *msgtext); + int (*another_method) (void); +}; + +int testfunction (int arg1, int * arg2) /* check definitions */ +{ + return arg2[arg1]; +} + +int test2function (void) /* check void arg list */ +{ + return 0; +} +#endif + + +/* Now we want to find out if your compiler knows what "unsigned char" means. + * If you get an error on the "unsigned char un_char;" line, + * then undefine HAVE_UNSIGNED_CHAR. + */ + +#define HAVE_UNSIGNED_CHAR + +#ifdef HAVE_UNSIGNED_CHAR +unsigned char un_char; +#endif + + +/* Now we want to find out if your compiler knows what "unsigned short" means. + * If you get an error on the "unsigned short un_short;" line, + * then undefine HAVE_UNSIGNED_SHORT. + */ + +#define HAVE_UNSIGNED_SHORT + +#ifdef HAVE_UNSIGNED_SHORT +unsigned short un_short; +#endif + + +/* Now we want to find out if your compiler understands type "void". + * If you get an error anywhere in here, undefine HAVE_VOID. + */ + +#define HAVE_VOID + +#ifdef HAVE_VOID +/* Caution: a C++ compiler will insist on complete prototypes */ +typedef void * void_ptr; /* check void * */ +#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */ +typedef void (*void_func) (int a, int b); +#else +typedef void (*void_func) (); +#endif + +#ifdef HAVE_PROTOTYPES /* check void function result */ +void test3function (void_ptr arg1, void_func arg2) +#else +void test3function (arg1, arg2) + void_ptr arg1; + void_func arg2; +#endif +{ + char * locptr = (char *) arg1; /* check casting to and from void * */ + arg1 = (void *) locptr; + (*arg2) (1, 2); /* check call of fcn returning void */ +} +#endif + + +/* Now we want to find out if your compiler knows what "const" means. + * If you get an error here, undefine HAVE_CONST. + */ + +#define HAVE_CONST + +#ifdef HAVE_CONST +static const int carray[3] = {1, 2, 3}; + +#ifdef HAVE_PROTOTYPES +int test4function (const int arg1) +#else +int test4function (arg1) + const int arg1; +#endif +{ + return carray[arg1]; +} +#endif + + +/* If you get an error or warning about this structure definition, + * define INCOMPLETE_TYPES_BROKEN. + */ + +#undef INCOMPLETE_TYPES_BROKEN + +#ifndef INCOMPLETE_TYPES_BROKEN +typedef struct undefined_structure * undef_struct_ptr; +#endif + + +/* If you get an error about duplicate names, + * define NEED_SHORT_EXTERNAL_NAMES. + */ + +#undef NEED_SHORT_EXTERNAL_NAMES + +#ifndef NEED_SHORT_EXTERNAL_NAMES + +int possibly_duplicate_function () +{ + return 0; +} + +int possibly_dupli_function () +{ + return 1; +} + +#endif + + + +/************************************************************************ + * OK, that's it. You should not have to change anything beyond this + * point in order to compile and execute this program. (You might get + * some warnings, but you can ignore them.) + * When you run the program, it will make a couple more tests that it + * can do automatically, and then it will create jconfig.h and print out + * any additional suggestions it has. + ************************************************************************ + */ + + +#ifdef HAVE_PROTOTYPES +int is_char_signed (int arg) +#else +int is_char_signed (arg) + int arg; +#endif +{ + if (arg == 189) { /* expected result for unsigned char */ + return 0; /* type char is unsigned */ + } + else if (arg != -67) { /* expected result for signed char */ + printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n"); + printf("I fear the JPEG software will not work at all.\n\n"); + } + return 1; /* assume char is signed otherwise */ +} + + +#ifdef HAVE_PROTOTYPES +int is_shifting_signed (long arg) +#else +int is_shifting_signed (arg) + long arg; +#endif +/* See whether right-shift on a long is signed or not. */ +{ + long res = arg >> 4; + + if (res == -0x7F7E80CL) { /* expected result for signed shift */ + return 1; /* right shift is signed */ + } + /* see if unsigned-shift hack will fix it. */ + /* we can't just test exact value since it depends on width of long... */ + res |= (~0L) << (32-4); + if (res == -0x7F7E80CL) { /* expected result now? */ + return 0; /* right shift is unsigned */ + } + printf("Right shift isn't acting as I expect it to.\n"); + printf("I fear the JPEG software will not work at all.\n\n"); + return 0; /* try it with unsigned anyway */ +} + + +#ifdef HAVE_PROTOTYPES +int main (int argc, char ** argv) +#else +int main (argc, argv) + int argc; + char ** argv; +#endif +{ + char signed_char_check = (char) (-67); + FILE *outfile; + + /* Attempt to write jconfig.h */ + if ((outfile = fopen("jconfig.h", "w")) == NULL) { + printf("Failed to write jconfig.h\n"); + return 1; + } + + /* Write out all the info */ + fprintf(outfile, "/* jconfig.h --- generated by ckconfig.c */\n"); + fprintf(outfile, "/* see jconfig.doc for explanations */\n\n"); +#ifdef HAVE_PROTOTYPES + fprintf(outfile, "#define HAVE_PROTOTYPES\n"); +#else + fprintf(outfile, "#undef HAVE_PROTOTYPES\n"); +#endif +#ifdef HAVE_UNSIGNED_CHAR + fprintf(outfile, "#define HAVE_UNSIGNED_CHAR\n"); +#else + fprintf(outfile, "#undef HAVE_UNSIGNED_CHAR\n"); +#endif +#ifdef HAVE_UNSIGNED_SHORT + fprintf(outfile, "#define HAVE_UNSIGNED_SHORT\n"); +#else + fprintf(outfile, "#undef HAVE_UNSIGNED_SHORT\n"); +#endif +#ifdef HAVE_VOID + fprintf(outfile, "/* #define void char */\n"); +#else + fprintf(outfile, "#define void char\n"); +#endif +#ifdef HAVE_CONST + fprintf(outfile, "/* #define const */\n"); +#else + fprintf(outfile, "#define const\n"); +#endif + if (is_char_signed((int) signed_char_check)) + fprintf(outfile, "#undef CHAR_IS_UNSIGNED\n"); + else + fprintf(outfile, "#define CHAR_IS_UNSIGNED\n"); +#ifdef HAVE_STDDEF_H + fprintf(outfile, "#define HAVE_STDDEF_H\n"); +#else + fprintf(outfile, "#undef HAVE_STDDEF_H\n"); +#endif +#ifdef HAVE_STDLIB_H + fprintf(outfile, "#define HAVE_STDLIB_H\n"); +#else + fprintf(outfile, "#undef HAVE_STDLIB_H\n"); +#endif +#ifdef NEED_BSD_STRINGS + fprintf(outfile, "#define NEED_BSD_STRINGS\n"); +#else + fprintf(outfile, "#undef NEED_BSD_STRINGS\n"); +#endif +#ifdef NEED_SYS_TYPES_H + fprintf(outfile, "#define NEED_SYS_TYPES_H\n"); +#else + fprintf(outfile, "#undef NEED_SYS_TYPES_H\n"); +#endif + fprintf(outfile, "#undef NEED_FAR_POINTERS\n"); +#ifdef NEED_SHORT_EXTERNAL_NAMES + fprintf(outfile, "#define NEED_SHORT_EXTERNAL_NAMES\n"); +#else + fprintf(outfile, "#undef NEED_SHORT_EXTERNAL_NAMES\n"); +#endif +#ifdef INCOMPLETE_TYPES_BROKEN + fprintf(outfile, "#define INCOMPLETE_TYPES_BROKEN\n"); +#else + fprintf(outfile, "#undef INCOMPLETE_TYPES_BROKEN\n"); +#endif + fprintf(outfile, "\n#ifdef JPEG_INTERNALS\n\n"); + if (is_shifting_signed(-0x7F7E80B1L)) + fprintf(outfile, "#undef RIGHT_SHIFT_IS_UNSIGNED\n"); + else + fprintf(outfile, "#define RIGHT_SHIFT_IS_UNSIGNED\n"); + fprintf(outfile, "\n#endif /* JPEG_INTERNALS */\n"); + fprintf(outfile, "\n#ifdef JPEG_CJPEG_DJPEG\n\n"); + fprintf(outfile, "#define BMP_SUPPORTED /* BMP image file format */\n"); + fprintf(outfile, "#define GIF_SUPPORTED /* GIF image file format */\n"); + fprintf(outfile, "#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */\n"); + fprintf(outfile, "#undef RLE_SUPPORTED /* Utah RLE image file format */\n"); + fprintf(outfile, "#define TARGA_SUPPORTED /* Targa image file format */\n\n"); + fprintf(outfile, "#undef TWO_FILE_COMMANDLINE /* You may need this on non-Unix systems */\n"); + fprintf(outfile, "#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */\n"); + fprintf(outfile, "#undef DONT_USE_B_MODE\n"); + fprintf(outfile, "/* #define PROGRESS_REPORT */ /* optional */\n"); + fprintf(outfile, "\n#endif /* JPEG_CJPEG_DJPEG */\n"); + + /* Close the jconfig.h file */ + fclose(outfile); + + /* User report */ + printf("Configuration check for Independent JPEG Group's software done.\n"); + printf("\nI have written the jconfig.h file for you.\n\n"); +#ifdef HAVE_PROTOTYPES + printf("You should use makefile.ansi as the starting point for your Makefile.\n"); +#else + printf("You should use makefile.unix as the starting point for your Makefile.\n"); +#endif + +#ifdef NEED_SPECIAL_INCLUDE + printf("\nYou'll need to change jconfig.h to include the system include file\n"); + printf("that you found type size_t in, or add a direct definition of type\n"); + printf("size_t if that's what you used. Just add it to the end.\n"); +#endif + + return 0; +} diff --git a/freeimage241/Source/LibJPEG/djpeg.c b/freeimage241/Source/LibJPEG/djpeg.c new file mode 100644 index 0000000..e099e90 --- /dev/null +++ b/freeimage241/Source/LibJPEG/djpeg.c @@ -0,0 +1,616 @@ +/* + * djpeg.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a command-line user interface for the JPEG decompressor. + * It should work on any system with Unix- or MS-DOS-style command lines. + * + * Two different command line styles are permitted, depending on the + * compile-time switch TWO_FILE_COMMANDLINE: + * djpeg [options] inputfile outputfile + * djpeg [options] [inputfile] + * In the second style, output is always to standard output, which you'd + * normally redirect to a file or pipe to some other program. Input is + * either from a named file or from standard input (typically redirected). + * The second style is convenient on Unix but is unhelpful on systems that + * don't support pipes. Also, you MUST use the first style if your system + * doesn't do binary I/O to stdin/stdout. + * To simplify script writing, the "-outfile" switch is provided. The syntax + * djpeg [options] -outfile outputfile inputfile + * works regardless of which command line style is used. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "jversion.h" /* for version message */ + +#include /* to declare isprint() */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + + +/* Create the add-on message string table. */ + +#define JMESSAGE(code,string) string , + +static const char * const cdjpeg_message_table[] = { +#include "cderror.h" + NULL +}; + + +/* + * This list defines the known output image formats + * (not all of which need be supported by a given version). + * You can change the default output format by defining DEFAULT_FMT; + * indeed, you had better do so if you undefine PPM_SUPPORTED. + */ + +typedef enum { + FMT_BMP, /* BMP format (Windows flavor) */ + FMT_GIF, /* GIF format */ + FMT_OS2, /* BMP format (OS/2 flavor) */ + FMT_PPM, /* PPM/PGM (PBMPLUS formats) */ + FMT_RLE, /* RLE format */ + FMT_TARGA, /* Targa format */ + FMT_TIFF /* TIFF format */ +} IMAGE_FORMATS; + +#ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */ +#define DEFAULT_FMT FMT_PPM +#endif + +static IMAGE_FORMATS requested_fmt; + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + * The main program in this file doesn't actually use this capability... + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -colors N Reduce image to no more than N colors\n"); + fprintf(stderr, " -fast Fast, low-quality processing\n"); + fprintf(stderr, " -grayscale Force grayscale output\n"); +#ifdef IDCT_SCALING_SUPPORTED + fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n"); +#endif +#ifdef BMP_SUPPORTED + fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n", + (DEFAULT_FMT == FMT_BMP ? " (default)" : "")); +#endif +#ifdef GIF_SUPPORTED + fprintf(stderr, " -gif Select GIF output format%s\n", + (DEFAULT_FMT == FMT_GIF ? " (default)" : "")); +#endif +#ifdef BMP_SUPPORTED + fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n", + (DEFAULT_FMT == FMT_OS2 ? " (default)" : "")); +#endif +#ifdef PPM_SUPPORTED + fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n", + (DEFAULT_FMT == FMT_PPM ? " (default)" : "")); +#endif +#ifdef RLE_SUPPORTED + fprintf(stderr, " -rle Select Utah RLE output format%s\n", + (DEFAULT_FMT == FMT_RLE ? " (default)" : "")); +#endif +#ifdef TARGA_SUPPORTED + fprintf(stderr, " -targa Select Targa output format%s\n", + (DEFAULT_FMT == FMT_TARGA ? " (default)" : "")); +#endif + fprintf(stderr, "Switches for advanced users:\n"); +#ifdef DCT_ISLOW_SUPPORTED + fprintf(stderr, " -dct int Use integer DCT method%s\n", + (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : "")); +#endif +#ifdef DCT_IFAST_SUPPORTED + fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n", + (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : "")); +#endif +#ifdef DCT_FLOAT_SUPPORTED + fprintf(stderr, " -dct float Use floating-point DCT method%s\n", + (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : "")); +#endif + fprintf(stderr, " -dither fs Use F-S dithering (default)\n"); + fprintf(stderr, " -dither none Don't use dithering in quantization\n"); + fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n"); +#ifdef QUANT_2PASS_SUPPORTED + fprintf(stderr, " -map FILE Map to colors used in named image file\n"); +#endif + fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n"); +#ifdef QUANT_1PASS_SUPPORTED + fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n"); +#endif + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + exit(EXIT_FAILURE); +} + + +LOCAL(int) +parse_switches (j_decompress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + + /* Set up default JPEG parameters. */ + requested_fmt = DEFAULT_FMT; /* set default output file format */ + outfilename = NULL; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "bmp", 1)) { + /* BMP output format. */ + requested_fmt = FMT_BMP; + + } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) || + keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) { + /* Do color quantization. */ + int val; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d", &val) != 1) + usage(); + cinfo->desired_number_of_colors = val; + cinfo->quantize_colors = TRUE; + + } else if (keymatch(arg, "dct", 2)) { + /* Select IDCT algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "int", 1)) { + cinfo->dct_method = JDCT_ISLOW; + } else if (keymatch(argv[argn], "fast", 2)) { + cinfo->dct_method = JDCT_IFAST; + } else if (keymatch(argv[argn], "float", 2)) { + cinfo->dct_method = JDCT_FLOAT; + } else + usage(); + + } else if (keymatch(arg, "dither", 2)) { + /* Select dithering algorithm. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "fs", 2)) { + cinfo->dither_mode = JDITHER_FS; + } else if (keymatch(argv[argn], "none", 2)) { + cinfo->dither_mode = JDITHER_NONE; + } else if (keymatch(argv[argn], "ordered", 2)) { + cinfo->dither_mode = JDITHER_ORDERED; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "fast", 1)) { + /* Select recommended processing options for quick-and-dirty output. */ + cinfo->two_pass_quantize = FALSE; + cinfo->dither_mode = JDITHER_ORDERED; + if (! cinfo->quantize_colors) /* don't override an earlier -colors */ + cinfo->desired_number_of_colors = 216; + cinfo->dct_method = JDCT_FASTEST; + cinfo->do_fancy_upsampling = FALSE; + + } else if (keymatch(arg, "gif", 1)) { + /* GIF output format. */ + requested_fmt = FMT_GIF; + + } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) { + /* Force monochrome output. */ + cinfo->out_color_space = JCS_GRAYSCALE; + + } else if (keymatch(arg, "map", 3)) { + /* Quantize to a color map taken from an input file. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (for_real) { /* too expensive to do twice! */ +#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */ + FILE * mapfile; + + if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + read_color_map(cinfo, mapfile); + fclose(mapfile); + cinfo->quantize_colors = TRUE; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "nosmooth", 3)) { + /* Suppress fancy upsampling */ + cinfo->do_fancy_upsampling = FALSE; + + } else if (keymatch(arg, "onepass", 3)) { + /* Use fast one-pass quantization. */ + cinfo->two_pass_quantize = FALSE; + + } else if (keymatch(arg, "os2", 3)) { + /* BMP output format (OS/2 flavor). */ + requested_fmt = FMT_OS2; + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) { + /* PPM/PGM output format. */ + requested_fmt = FMT_PPM; + + } else if (keymatch(arg, "rle", 1)) { + /* RLE output format. */ + requested_fmt = FMT_RLE; + + } else if (keymatch(arg, "scale", 1)) { + /* Scale the output image by a fraction M/N. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%d/%d", + &cinfo->scale_num, &cinfo->scale_denom) != 2) + usage(); + + } else if (keymatch(arg, "targa", 1)) { + /* Targa output format. */ + requested_fmt = FMT_TARGA; + + } else { + usage(); /* bogus switch */ + } + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * Marker processor for COM and interesting APPn markers. + * This replaces the library's built-in processor, which just skips the marker. + * We want to print out the marker as text, to the extent possible. + * Note this code relies on a non-suspending data source. + */ + +LOCAL(unsigned int) +jpeg_getc (j_decompress_ptr cinfo) +/* Read next byte */ +{ + struct jpeg_source_mgr * datasrc = cinfo->src; + + if (datasrc->bytes_in_buffer == 0) { + if (! (*datasrc->fill_input_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + datasrc->bytes_in_buffer--; + return GETJOCTET(*datasrc->next_input_byte++); +} + + +METHODDEF(boolean) +print_text_marker (j_decompress_ptr cinfo) +{ + boolean traceit = (cinfo->err->trace_level >= 1); + INT32 length; + unsigned int ch; + unsigned int lastch = 0; + + length = jpeg_getc(cinfo) << 8; + length += jpeg_getc(cinfo); + length -= 2; /* discount the length word itself */ + + if (traceit) { + if (cinfo->unread_marker == JPEG_COM) + fprintf(stderr, "Comment, length %ld:\n", (long) length); + else /* assume it is an APPn otherwise */ + fprintf(stderr, "APP%d, length %ld:\n", + cinfo->unread_marker - JPEG_APP0, (long) length); + } + + while (--length >= 0) { + ch = jpeg_getc(cinfo); + if (traceit) { + /* Emit the character in a readable form. + * Nonprintables are converted to \nnn form, + * while \ is converted to \\. + * Newlines in CR, CR/LF, or LF form will be printed as one newline. + */ + if (ch == '\r') { + fprintf(stderr, "\n"); + } else if (ch == '\n') { + if (lastch != '\r') + fprintf(stderr, "\n"); + } else if (ch == '\\') { + fprintf(stderr, "\\\\"); + } else if (isprint(ch)) { + putc(ch, stderr); + } else { + fprintf(stderr, "\\%03o", ch); + } + lastch = ch; + } + } + + if (traceit) + fprintf(stderr, "\n"); + + return TRUE; +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + int file_index; + djpeg_dest_ptr dest_mgr = NULL; + FILE * input_file; + FILE * output_file; + JDIMENSION num_scanlines; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "djpeg"; /* in case C library doesn't provide it */ + + /* Initialize the JPEG decompression object with default error handling. */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + /* Add some application-specific error messages (from cderror.h) */ + jerr.addon_message_table = cdjpeg_message_table; + jerr.first_addon_message = JMSG_FIRSTADDONCODE; + jerr.last_addon_message = JMSG_LASTADDONCODE; + + /* Insert custom marker processor for COM and APP12. + * APP12 is used by some digital camera makers for textual info, + * so we provide the ability to display it as text. + * If you like, additional APPn marker types can be selected for display, + * but don't try to override APP0 or APP14 this way (see libjpeg.doc). + */ + jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); + jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker); + + /* Now safe to enable signal catcher. */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &cinfo); +#endif + + /* Scan command line to find file names. */ + /* It is convenient to use just one switch-parsing routine, but the switch + * values read here are ignored; we will rescan the switches after opening + * the input file. + * (Exception: tracing level set here controls verbosity for COM markers + * found during jpeg_read_header...) + */ + + file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); + +#ifdef TWO_FILE_COMMANDLINE + /* Must have either -outfile switch or explicit output file name */ + if (outfilename == NULL) { + if (file_index != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + outfilename = argv[file_index+1]; + } else { + if (file_index != argc-1) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + } +#else + /* Unix style: expect zero or one file name */ + if (file_index < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } +#endif /* TWO_FILE_COMMANDLINE */ + + /* Open the input file. */ + if (file_index < argc) { + if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ + input_file = read_stdin(); + } + + /* Open the output file. */ + if (outfilename != NULL) { + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, outfilename); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + output_file = write_stdout(); + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &cinfo, &progress); +#endif + + /* Specify data source for decompression */ + jpeg_stdio_src(&cinfo, input_file); + + /* Read file header, set default decompression parameters */ + (void) jpeg_read_header(&cinfo, TRUE); + + /* Adjust default decompression parameters by re-parsing the options */ + file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); + + /* Initialize the output module now to let it override any crucial + * option settings (for instance, GIF wants to force color quantization). + */ + switch (requested_fmt) { +#ifdef BMP_SUPPORTED + case FMT_BMP: + dest_mgr = jinit_write_bmp(&cinfo, FALSE); + break; + case FMT_OS2: + dest_mgr = jinit_write_bmp(&cinfo, TRUE); + break; +#endif +#ifdef GIF_SUPPORTED + case FMT_GIF: + dest_mgr = jinit_write_gif(&cinfo); + break; +#endif +#ifdef PPM_SUPPORTED + case FMT_PPM: + dest_mgr = jinit_write_ppm(&cinfo); + break; +#endif +#ifdef RLE_SUPPORTED + case FMT_RLE: + dest_mgr = jinit_write_rle(&cinfo); + break; +#endif +#ifdef TARGA_SUPPORTED + case FMT_TARGA: + dest_mgr = jinit_write_targa(&cinfo); + break; +#endif + default: + ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); + break; + } + dest_mgr->output_file = output_file; + + /* Start decompressor */ + (void) jpeg_start_decompress(&cinfo); + + /* Write output file header */ + (*dest_mgr->start_output) (&cinfo, dest_mgr); + + /* Process data */ + while (cinfo.output_scanline < cinfo.output_height) { + num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, + dest_mgr->buffer_height); + (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); + } + +#ifdef PROGRESS_REPORT + /* Hack: count final pass as done in case finish_output does an extra pass. + * The library won't have updated completed_passes. + */ + progress.pub.completed_passes = progress.pub.total_passes; +#endif + + /* Finish decompression and release memory. + * I must do it in this order because output module has allocated memory + * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. + */ + (*dest_mgr->finish_output) (&cinfo, dest_mgr); + (void) jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + /* Close files, if we opened them */ + if (input_file != stdin) + fclose(input_file); + if (output_file != stdout) + fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &cinfo); +#endif + + /* All done. */ + exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/freeimage241/Source/LibJPEG/example.c b/freeimage241/Source/LibJPEG/example.c new file mode 100644 index 0000000..7fc354f --- /dev/null +++ b/freeimage241/Source/LibJPEG/example.c @@ -0,0 +1,433 @@ +/* + * example.c + * + * This file illustrates how to use the IJG code as a subroutine library + * to read or write JPEG image files. You should look at this code in + * conjunction with the documentation file libjpeg.doc. + * + * This code will not do anything useful as-is, but it may be helpful as a + * skeleton for constructing routines that call the JPEG library. + * + * We present these routines in the same coding style used in the JPEG code + * (ANSI function definitions, etc); but you are of course free to code your + * routines in a different style if you prefer. + */ + +#include + +/* + * Include file for users of JPEG library. + * You will need to have included system headers that define at least + * the typedefs FILE and size_t before you can include jpeglib.h. + * (stdio.h is sufficient on ANSI-conforming systems.) + * You may also wish to include "jerror.h". + */ + +#include "jpeglib.h" + +/* + * is used for the optional error recovery mechanism shown in + * the second part of the example. + */ + +#include + + + +/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to feed data into the JPEG compressor. + * We present a minimal version that does not worry about refinements such + * as error recovery (the JPEG code will just exit() if it gets an error). + */ + + +/* + * IMAGE DATA FORMATS: + * + * The standard input image format is a rectangular array of pixels, with + * each pixel having the same number of "component" values (color channels). + * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars). + * If you are working with color data, then the color values for each pixel + * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit + * RGB color. + * + * For this example, we'll assume that this data structure matches the way + * our application has stored the image in memory, so we can just pass a + * pointer to our image buffer. In particular, let's say that the image is + * RGB color and is described by: + */ + +extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */ +extern int image_height; /* Number of rows in image */ +extern int image_width; /* Number of columns in image */ + + +/* + * Sample routine for JPEG compression. We assume that the target file name + * and a compression quality factor are passed in. + */ + +GLOBAL(void) +write_JPEG_file (char * filename, int quality) +{ + /* This struct contains the JPEG compression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + * It is possible to have several such structures, representing multiple + * compression/decompression processes, in existence at once. We refer + * to any one struct (and its associated working data) as a "JPEG object". + */ + struct jpeg_compress_struct cinfo; + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct jpeg_error_mgr jerr; + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + + /* Here we use the library-supplied code to send compressed data to a + * stdio stream. You can also write your own code to do something else. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to write binary files. + */ + if ((outfile = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + exit(1); + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + + /* First we supply a description of the input image. + * Four fields of the cinfo struct must be filled in: + */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + /* Now use the library's routine to set default compression parameters. + * (You must set at least cinfo.in_color_space before calling this, + * since the defaults depend on the source color space.) + */ + jpeg_set_defaults(&cinfo); + /* Now you can set any non-default parameters you wish to. + * Here we just illustrate the use of quality (quantization table) scaling: + */ + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + + /* TRUE ensures that we will write a complete interchange-JPEG file. + * Pass TRUE unless you are very sure of what you're doing. + */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + /* jpeg_write_scanlines(...); */ + + /* Here we use the library's state variable cinfo.next_scanline as the + * loop counter, so that we don't have to keep track ourselves. + * To keep things simple, we pass one scanline per call; you can pass + * more if you wish, though. + */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + + while (cinfo.next_scanline < cinfo.image_height) { + /* jpeg_write_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could pass + * more than one scanline at a time if that's more convenient. + */ + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ +} + + +/* + * SOME FINE POINTS: + * + * In the above loop, we ignored the return value of jpeg_write_scanlines, + * which is the number of scanlines actually written. We could get away + * with this because we were only relying on the value of cinfo.next_scanline, + * which will be incremented correctly. If you maintain additional loop + * variables then you should be careful to increment them properly. + * Actually, for output to a stdio stream you needn't worry, because + * then jpeg_write_scanlines will write all the lines passed (or else exit + * with a fatal error). Partial writes can only occur if you use a data + * destination module that can demand suspension of the compressor. + * (If you don't know what that's for, you don't need it.) + * + * If the compressor requires full-image buffers (for entropy-coding + * optimization or a multi-scan JPEG file), it will create temporary + * files for anything that doesn't fit within the maximum-memory setting. + * (Note that temp files are NOT needed if you use the default parameters.) + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + * + * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG + * files to be compatible with everyone else's. If you cannot readily read + * your data in that order, you'll need an intermediate array to hold the + * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top + * source data using the JPEG code's internal virtual-array mechanisms. + */ + + + +/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/ + +/* This half of the example shows how to read data from the JPEG decompressor. + * It's a bit more refined than the above, in that we show: + * (a) how to modify the JPEG library's standard error-reporting behavior; + * (b) how to allocate workspace using the library's memory manager. + * + * Just to make this example a little different from the first one, we'll + * assume that we do not intend to put the whole image into an in-memory + * buffer, but to send it line-by-line someplace else. We need a one- + * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG + * memory manager allocate it for us. This approach is actually quite useful + * because we don't need to remember to deallocate the buffer separately: it + * will go away automatically when the JPEG object is cleaned up. + */ + + +/* + * ERROR HANDLING: + * + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * Our example here shows how to override the "error_exit" method so that + * control is returned to the library's caller when a fatal error occurs, + * rather than calling exit() as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + + +/* + * Sample routine for JPEG decompression. We assume that the source file name + * is passed in. We want to return 1 on success, 0 on error. + */ + + +GLOBAL(int) +read_JPEG_file (char * filename) +{ + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; + /* More stuff */ + FILE * infile; /* source file */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + + /* In this example we want to open the input file before doing anything else, + * so that the setjmp() error recovery below can assume the file is open. + * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + * requires it in order to read binary files. + */ + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", filename); + return 0; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return 0; + } + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, infile); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + /* Make a one-row-high sample array that will go away when done with image */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + /* Assume put_scanline_someplace wants a pointer and sample count. */ + put_scanline_someplace(buffer[0], row_stride); + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + fclose(infile); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return 1; +} + + +/* + * SOME FINE POINTS: + * + * In the above code, we ignored the return value of jpeg_read_scanlines, + * which is the number of scanlines actually read. We could get away with + * this because we asked for only one line at a time and we weren't using + * a suspending data source. See libjpeg.doc for more info. + * + * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); + * we should have done it beforehand to ensure that the space would be + * counted against the JPEG max_memory setting. In some systems the above + * code would risk an out-of-memory error. However, in general we don't + * know the output image dimensions before jpeg_start_decompress(), unless we + * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. + * + * Scanlines are returned in the same order as they appear in the JPEG file, + * which is standardly top-to-bottom. If you must emit data bottom-to-top, + * you can use one of the virtual arrays provided by the JPEG memory manager + * to invert the data. See wrbmp.c for an example. + * + * As with compression, some operating modes may require temporary files. + * On some systems you may need to set up a signal handler to ensure that + * temporary files are deleted if the program is interrupted. See libjpeg.doc. + */ diff --git a/freeimage241/Source/LibJPEG/jcapimin.c b/freeimage241/Source/LibJPEG/jcapimin.c new file mode 100644 index 0000000..54fb8c5 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcapimin.c @@ -0,0 +1,280 @@ +/* + * jcapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-compression case or the transcoding-only + * case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jcapistd.c. But also see jcparam.c for + * parameter-setup helper routines, jcomapi.c for routines shared by + * compression and decompression, and jctrans.c for the transcoding case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG compression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_compress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_compress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = FALSE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->dest = NULL; + + cinfo->comp_info = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + cinfo->script_space = NULL; + + cinfo->input_gamma = 1.0; /* in case application forgets */ + + /* OK, I'm ready */ + cinfo->global_state = CSTATE_START; +} + + +/* + * Destruction of a JPEG compression object + */ + +GLOBAL(void) +jpeg_destroy_compress (j_compress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG compression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_compress (j_compress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Forcibly suppress or un-suppress all quantization and Huffman tables. + * Marks all currently defined tables as already written (if suppress) + * or not written (if !suppress). This will control whether they get emitted + * by a subsequent jpeg_start_compress call. + * + * This routine is exported for use by applications that want to produce + * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but + * since it is called by jpeg_start_compress, we put it here --- otherwise + * jcparam.o would be linked whether the application used it or not. + */ + +GLOBAL(void) +jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress) +{ + int i; + JQUANT_TBL * qtbl; + JHUFF_TBL * htbl; + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL) + qtbl->sent_table = suppress; + } + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL) + htbl->sent_table = suppress; + } +} + + +/* + * Finish JPEG compression. + * + * If a multipass operating mode was selected, this may do a great deal of + * work including most of the actual output. + */ + +GLOBAL(void) +jpeg_finish_compress (j_compress_ptr cinfo) +{ + JDIMENSION iMCU_row; + + if (cinfo->global_state == CSTATE_SCANNING || + cinfo->global_state == CSTATE_RAW_OK) { + /* Terminate first pass */ + if (cinfo->next_scanline < cinfo->image_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_pass) (cinfo); + } else if (cinfo->global_state != CSTATE_WRCOEFS) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any remaining passes */ + while (! cinfo->master->is_last_pass) { + (*cinfo->master->prepare_for_pass) (cinfo); + for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) { + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) iMCU_row; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* We bypass the main controller and invoke coef controller directly; + * all work is being done from the coefficient buffer. + */ + if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } + (*cinfo->master->finish_pass) (cinfo); + } + /* Write EOI, do final cleanup */ + (*cinfo->marker->write_file_trailer) (cinfo); + (*cinfo->dest->term_destination) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); +} + + +/* + * Write a special marker. + * This is only recommended for writing COM or APPn markers. + * Must be called after jpeg_start_compress() and before + * first call to jpeg_write_scanlines() or jpeg_write_raw_data(). + */ + +GLOBAL(void) +jpeg_write_marker (j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen) +{ + JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val)); + + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); + write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */ + while (datalen--) { + (*write_marker_byte) (cinfo, *dataptr); + dataptr++; + } +} + +/* Same, but piecemeal. */ + +GLOBAL(void) +jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +{ + if (cinfo->next_scanline != 0 || + (cinfo->global_state != CSTATE_SCANNING && + cinfo->global_state != CSTATE_RAW_OK && + cinfo->global_state != CSTATE_WRCOEFS)) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + (*cinfo->marker->write_marker_header) (cinfo, marker, datalen); +} + +GLOBAL(void) +jpeg_write_m_byte (j_compress_ptr cinfo, int val) +{ + (*cinfo->marker->write_marker_byte) (cinfo, val); +} + + +/* + * Alternate compression function: just write an abbreviated table file. + * Before calling this, all parameters and a data destination must be set up. + * + * To produce a pair of files containing abbreviated tables and abbreviated + * image data, one would proceed as follows: + * + * initialize JPEG object + * set JPEG parameters + * set destination to table file + * jpeg_write_tables(cinfo); + * set destination to image file + * jpeg_start_compress(cinfo, FALSE); + * write data... + * jpeg_finish_compress(cinfo); + * + * jpeg_write_tables has the side effect of marking all tables written + * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress + * will not re-emit the tables unless it is passed write_all_tables=TRUE. + */ + +GLOBAL(void) +jpeg_write_tables (j_compress_ptr cinfo) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Initialize the marker writer ... bit of a crock to do it here. */ + jinit_marker_writer(cinfo); + /* Write them tables! */ + (*cinfo->marker->write_tables_only) (cinfo); + /* And clean up. */ + (*cinfo->dest->term_destination) (cinfo); + /* + * In library releases up through v6a, we called jpeg_abort() here to free + * any working memory allocated by the destination manager and marker + * writer. Some applications had a problem with that: they allocated space + * of their own from the library memory manager, and didn't want it to go + * away during write_tables. So now we do nothing. This will cause a + * memory leak if an app calls write_tables repeatedly without doing a full + * compression cycle or otherwise resetting the JPEG object. However, that + * seems less bad than unexpectedly freeing memory in the normal case. + * An app that prefers the old behavior can call jpeg_abort for itself after + * each call to jpeg_write_tables(). + */ +} diff --git a/freeimage241/Source/LibJPEG/jcapistd.c b/freeimage241/Source/LibJPEG/jcapistd.c new file mode 100644 index 0000000..c0320b1 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcapistd.c @@ -0,0 +1,161 @@ +/* + * jcapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the compression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-compression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_compress, it will end up linking in the entire compressor. + * We thus must separate this file from jcapimin.c to avoid linking the + * whole compression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Compression initialization. + * Before calling this, all parameters and a data destination must be set up. + * + * We require a write_all_tables parameter as a failsafe check when writing + * multiple datastreams from the same compression object. Since prior runs + * will have left all the tables marked sent_table=TRUE, a subsequent run + * would emit an abbreviated stream (no tables) by default. This may be what + * is wanted, but for safety's sake it should not be the default behavior: + * programmers should have to make a deliberate choice to emit abbreviated + * images. Therefore the documentation and examples should encourage people + * to pass write_all_tables=TRUE; then it will take active thought to do the + * wrong thing. + */ + +GLOBAL(void) +jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (write_all_tables) + jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */ + + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + jinit_compress_master(cinfo); + /* Set up for the first pass */ + (*cinfo->master->prepare_for_pass) (cinfo); + /* Ready for application to drive first pass through jpeg_write_scanlines + * or jpeg_write_raw_data. + */ + cinfo->next_scanline = 0; + cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); +} + + +/* + * Write some scanlines of data to the JPEG compressor. + * + * The return value will be the number of lines actually written. + * This should be less than the supplied num_lines only in case that + * the data destination module has requested suspension of the compressor, + * or if more than image_height scanlines are passed in. + * + * Note: we warn about excess calls to jpeg_write_scanlines() since + * this likely signals an application programmer error. However, + * excess scanlines passed in the last valid call are *silently* ignored, + * so that the application need not adjust num_lines for end-of-image + * when using a multiple-scanline buffer. + */ + +GLOBAL(JDIMENSION) +jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION num_lines) +{ + JDIMENSION row_ctr, rows_left; + + if (cinfo->global_state != CSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_scanlines. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_scanlines. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Ignore any extra scanlines at bottom of image. */ + rows_left = cinfo->image_height - cinfo->next_scanline; + if (num_lines > rows_left) + num_lines = rows_left; + + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines); + cinfo->next_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to write raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION num_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != CSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->next_scanline >= cinfo->image_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->next_scanline; + cinfo->progress->pass_limit = (long) cinfo->image_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Give master control module another chance if this is first call to + * jpeg_write_raw_data. This lets output of the frame/scan headers be + * delayed so that application can write COM, etc, markers between + * jpeg_start_compress and jpeg_write_raw_data. + */ + if (cinfo->master->call_pass_startup) + (*cinfo->master->pass_startup) (cinfo); + + /* Verify that at least one iMCU row has been passed. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE; + if (num_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Directly compress the row. */ + if (! (*cinfo->coef->compress_data) (cinfo, data)) { + /* If compressor did not consume the whole row, suspend processing. */ + return 0; + } + + /* OK, we processed one iMCU row. */ + cinfo->next_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} diff --git a/freeimage241/Source/LibJPEG/jccoefct.c b/freeimage241/Source/LibJPEG/jccoefct.c new file mode 100644 index 0000000..1963ddb --- /dev/null +++ b/freeimage241/Source/LibJPEG/jccoefct.c @@ -0,0 +1,449 @@ +/* + * jccoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for compression. + * This controller is the top level of the JPEG compressor proper. + * The coefficient buffer lies between forward-DCT and entropy encoding steps. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* We use a full-image coefficient buffer when doing Huffman optimization, + * and also for writing multiple-scan JPEG files. In all cases, the DCT + * step is run during the first pass, and subsequent passes need only read + * the buffered coefficients. + */ +#ifdef ENTROPY_OPT_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#else +#ifdef C_MULTISCAN_FILES_SUPPORTED +#define FULL_COEF_BUFFER_SUPPORTED +#endif +#endif + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* For single-pass compression, it's sufficient to buffer just one MCU + * (although this may prove a bit slow in practice). We allocate a + * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each + * MCU constructed and sent. (On 80x86, the workspace is FAR even though + * it's not really very big; this is to keep the module interfaces unchanged + * when a large coefficient buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays. + */ + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +/* Forward declarations */ +METHODDEF(boolean) compress_data + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#ifdef FULL_COEF_BUFFER_SUPPORTED +METHODDEF(boolean) compress_first_pass + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +METHODDEF(boolean) compress_output + JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (coef->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_data; + break; +#ifdef FULL_COEF_BUFFER_SUPPORTED + case JBUF_SAVE_AND_PASS: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_first_pass; + break; + case JBUF_CRANK_DEST: + if (coef->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + coef->pub.compress_data = compress_output; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data in the single-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(boolean) +compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, bi, ci, yindex, yoffset, blockcnt; + JDIMENSION ypos, xpos; + jpeg_component_info *compptr; + + /* Loop to write as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Determine where data comes from in input_buf and do the DCT thing. + * Each call on forward_DCT processes a horizontal row of DCT blocks + * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks + * sequentially. Dummy blocks at the right or bottom edge are filled in + * specially. The data in them does not matter for image reconstruction, + * so we fill them with values that will encode to the smallest amount of + * data, viz: all zeroes in the AC entries, DC entries equal to previous + * block's DC value. (Thanks to Thomas Kinsman for this idea.) + */ + blkn = 0; + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + xpos = MCU_col_num * compptr->MCU_sample_width; + ypos = yoffset * DCTSIZE; /* ypos == (yoffset+yindex) * DCTSIZE */ + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + (*cinfo->fdct->forward_DCT) (cinfo, compptr, + input_buf[compptr->component_index], + coef->MCU_buffer[blkn], + ypos, xpos, (JDIMENSION) blockcnt); + if (blockcnt < compptr->MCU_width) { + /* Create some dummy blocks at the right edge of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn + blockcnt], + (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK)); + for (bi = blockcnt; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0]; + } + } + } else { + /* Create a row of dummy blocks at the bottom of the image. */ + jzero_far((void FAR *) coef->MCU_buffer[blkn], + compptr->MCU_width * SIZEOF(JBLOCK)); + for (bi = 0; bi < compptr->MCU_width; bi++) { + coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0]; + } + } + blkn += compptr->MCU_width; + ypos += DCTSIZE; + } + } + /* Try to write the MCU. In event of a suspension failure, we will + * re-DCT the MCU on restart (a bit inefficient, could be fixed...) + */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +#ifdef FULL_COEF_BUFFER_SUPPORTED + +/* + * Process some data in the first pass of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the image. + * This amount of data is read from the source buffer, DCT'd and quantized, + * and saved into the virtual arrays. We also generate suitable dummy blocks + * as needed at the right and lower edges. (The dummy blocks are constructed + * in the virtual arrays, which have been padded appropriately.) This makes + * it possible for subsequent passes not to worry about real vs. dummy blocks. + * + * We must also emit the data to the entropy encoder. This is conveniently + * done by calling compress_output() after we've loaded the current strip + * of the virtual arrays. + * + * NB: input_buf contains a plane for each component in image. All + * components are DCT'd and loaded into the virtual arrays in this pass. + * However, it may be that only a subset of the components are emitted to + * the entropy encoder during this first pass; be careful about looking + * at the scan-dependent variables (MCU dimensions, etc). + */ + +METHODDEF(boolean) +compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION blocks_across, MCUs_across, MCUindex; + int bi, ci, h_samp_factor, block_row, block_rows, ndummy; + JCOEF lastDC; + jpeg_component_info *compptr; + JBLOCKARRAY buffer; + JBLOCKROW thisblockrow, lastblockrow; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (coef->iMCU_row_num < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here, since may not be set! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + blocks_across = compptr->width_in_blocks; + h_samp_factor = compptr->h_samp_factor; + /* Count number of dummy blocks to be added at the right margin. */ + ndummy = (int) (blocks_across % h_samp_factor); + if (ndummy > 0) + ndummy = h_samp_factor - ndummy; + /* Perform DCT for all non-dummy blocks in this iMCU row. Each call + * on forward_DCT processes a complete horizontal row of DCT blocks. + */ + for (block_row = 0; block_row < block_rows; block_row++) { + thisblockrow = buffer[block_row]; + (*cinfo->fdct->forward_DCT) (cinfo, compptr, + input_buf[ci], thisblockrow, + (JDIMENSION) (block_row * DCTSIZE), + (JDIMENSION) 0, blocks_across); + if (ndummy > 0) { + /* Create dummy blocks at the right edge of the image. */ + thisblockrow += blocks_across; /* => first dummy block */ + jzero_far((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK)); + lastDC = thisblockrow[-1][0]; + for (bi = 0; bi < ndummy; bi++) { + thisblockrow[bi][0] = lastDC; + } + } + } + /* If at end of image, create dummy block rows as needed. + * The tricky part here is that within each MCU, we want the DC values + * of the dummy blocks to match the last real block's DC value. + * This squeezes a few more bytes out of the resulting file... + */ + if (coef->iMCU_row_num == last_iMCU_row) { + blocks_across += ndummy; /* include lower right corner */ + MCUs_across = blocks_across / h_samp_factor; + for (block_row = block_rows; block_row < compptr->v_samp_factor; + block_row++) { + thisblockrow = buffer[block_row]; + lastblockrow = buffer[block_row-1]; + jzero_far((void FAR *) thisblockrow, + (size_t) (blocks_across * SIZEOF(JBLOCK))); + for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) { + lastDC = lastblockrow[h_samp_factor-1][0]; + for (bi = 0; bi < h_samp_factor; bi++) { + thisblockrow[bi][0] = lastDC; + } + thisblockrow += h_samp_factor; /* advance to next MCU in row */ + lastblockrow += h_samp_factor; + } + } + } + } + /* NB: compress_output will increment iMCU_row_num if successful. + * A suspension return will result in redoing all the work above next time. + */ + + /* Emit data to the entropy encoder, sharing code with subsequent passes */ + return compress_output(cinfo, input_buf); +} + + +/* + * Process some data in subsequent passes of a multi-pass case. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. + * NB: during first pass, this is safe only because the buffers will + * already be aligned properly, so jmemmgr.c won't need to do any I/O. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + +#endif /* FULL_COEF_BUFFER_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef FULL_COEF_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + int ci; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->whole_image[0] = NULL; /* flag for no virtual arrays */ + } +} diff --git a/freeimage241/Source/LibJPEG/jccolor.c b/freeimage241/Source/LibJPEG/jccolor.c new file mode 100644 index 0000000..0a8a4b5 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jccolor.c @@ -0,0 +1,459 @@ +/* + * jccolor.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_converter pub; /* public fields */ + + /* Private state for RGB->YCC conversion */ + INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */ +} my_color_converter; + +typedef my_color_converter * my_cconvert_ptr; + + +/**************** RGB -> YCbCr conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B + * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE + * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, + * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and + * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) + * were not represented exactly. Now we sacrifice exact representation of + * maximum red and maximum blue in order to get exact grayscales. + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times R,G,B for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included + * in the tables to save adding them separately in the inner loop. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS) +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L< Y section */ +#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */ +#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */ +#define R_CB_OFF (3*(MAXJSAMPLE+1)) +#define G_CB_OFF (4*(MAXJSAMPLE+1)) +#define B_CB_OFF (5*(MAXJSAMPLE+1)) +#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */ +#define G_CR_OFF (6*(MAXJSAMPLE+1)) +#define B_CR_OFF (7*(MAXJSAMPLE+1)) +#define TABLE_SIZE (8*(MAXJSAMPLE+1)) + + +/* + * Initialize for RGB->YCC colorspace conversion. + */ + +METHODDEF(void) +rgb_ycc_start (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + INT32 * rgb_ycc_tab; + INT32 i; + + /* Allocate and fill in the conversion tables. */ + cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (TABLE_SIZE * SIZEOF(INT32))); + + for (i = 0; i <= MAXJSAMPLE; i++) { + rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i; + rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i; + rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF; + rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i; + rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i; + /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. + * This ensures that the maximum output will round to MAXJSAMPLE + * not MAXJSAMPLE+1, and thus that we don't have to range-limit. + */ + rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +/* B=>Cb and R=>Cr tables are the same + rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1; +*/ + rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i; + rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i; + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * + * Note that we change from the application's interleaved-pixel format + * to our internal noninterleaved, one-plane-per-component format. + * The input buffer is therefore three times as wide as the output buffer. + * + * A starting row offset is provided only for the output buffer. The caller + * can easily adjust the passed input_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +rgb_ycc_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/**************** Cases other than RGB -> YCbCr **************/ + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles RGB->grayscale conversion, which is the same + * as the RGB->Y portion of RGB->YCbCr. + * We assume rgb_ycc_start has been called (we only use the Y tables). + */ + +METHODDEF(void) +rgb_gray_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = GETJSAMPLE(inptr[RGB_RED]); + g = GETJSAMPLE(inptr[RGB_GREEN]); + b = GETJSAMPLE(inptr[RGB_BLUE]); + inptr += RGB_PIXELSIZE; + /* Y */ + outptr[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles Adobe-style CMYK->YCCK conversion, + * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same + * conversion as above, while passing K (black) unchanged. + * We assume rgb_ycc_start has been called. + */ + +METHODDEF(void) +cmyk_ycck_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int r, g, b; + register INT32 * ctab = cconvert->rgb_ycc_tab; + register JSAMPROW inptr; + register JSAMPROW outptr0, outptr1, outptr2, outptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + r = MAXJSAMPLE - GETJSAMPLE(inptr[0]); + g = MAXJSAMPLE - GETJSAMPLE(inptr[1]); + b = MAXJSAMPLE - GETJSAMPLE(inptr[2]); + /* K passes through as-is */ + outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */ + inptr += 4; + /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations + * must be too; we do not need an explicit range-limiting operation. + * Hence the value being shifted is never negative, and we don't + * need the general RIGHT_SHIFT macro. + */ + /* Y */ + outptr0[col] = (JSAMPLE) + ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) + >> SCALEBITS); + /* Cb */ + outptr1[col] = (JSAMPLE) + ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF]) + >> SCALEBITS); + /* Cr */ + outptr2[col] = (JSAMPLE) + ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF]) + >> SCALEBITS); + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles grayscale output with no conversion. + * The source can be either plain grayscale or YCbCr (since Y == gray). + */ + +METHODDEF(void) +grayscale_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->image_width; + int instride = cinfo->input_components; + + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr = output_buf[0][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */ + inptr += instride; + } + } +} + + +/* + * Convert some rows of samples to the JPEG colorspace. + * This version handles multi-component colorspaces without conversion. + * We assume input_components == num_components. + */ + +METHODDEF(void) +null_convert (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows) +{ + register JSAMPROW inptr; + register JSAMPROW outptr; + register JDIMENSION col; + register int ci; + int nc = cinfo->num_components; + JDIMENSION num_cols = cinfo->image_width; + + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < nc; ci++) { + inptr = *input_buf; + outptr = output_buf[ci][output_row]; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ + inptr += nc; + } + } + input_buf++; + output_row++; + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +null_method (j_compress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for input colorspace conversion. + */ + +GLOBAL(void) +jinit_color_converter (j_compress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_converter)); + cinfo->cconvert = (struct jpeg_color_converter *) cconvert; + /* set start_pass to null method until we find out differently */ + cconvert->pub.start_pass = null_method; + + /* Make sure input_components agrees with in_color_space */ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + if (cinfo->input_components != 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + if (cinfo->input_components != RGB_PIXELSIZE) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; +#endif /* else share code with YCbCr */ + + case JCS_YCbCr: + if (cinfo->input_components != 3) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->input_components != 4) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->input_components < 1) + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + break; + } + + /* Check num_components, set conversion method based on requested space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_GRAYSCALE) + cconvert->pub.color_convert = grayscale_convert; + else if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_gray_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = grayscale_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_RGB) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = rgb_ycc_convert; + } else if (cinfo->in_color_space == JCS_YCbCr) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + if (cinfo->in_color_space == JCS_CMYK) { + cconvert->pub.start_pass = rgb_ycc_start; + cconvert->pub.color_convert = cmyk_ycck_convert; + } else if (cinfo->in_color_space == JCS_YCCK) + cconvert->pub.color_convert = null_convert; + else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: /* allow null conversion of JCS_UNKNOWN */ + if (cinfo->jpeg_color_space != cinfo->in_color_space || + cinfo->num_components != cinfo->input_components) + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + cconvert->pub.color_convert = null_convert; + break; + } +} diff --git a/freeimage241/Source/LibJPEG/jcdctmgr.c b/freeimage241/Source/LibJPEG/jcdctmgr.c new file mode 100644 index 0000000..61fa79b --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcdctmgr.c @@ -0,0 +1,387 @@ +/* + * jcdctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the forward-DCT management logic. + * This code selects a particular DCT implementation to be used, + * and it performs related housekeeping chores including coefficient + * quantization. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_forward_dct pub; /* public fields */ + + /* Pointer to the DCT routine actually in use */ + forward_DCT_method_ptr do_dct; + + /* The actual post-DCT divisors --- not identical to the quant table + * entries, because of scaling (especially for an unnormalized DCT). + * Each table is given in normal array order. + */ + DCTELEM * divisors[NUM_QUANT_TBLS]; + +#ifdef DCT_FLOAT_SUPPORTED + /* Same as above for the floating-point case. */ + float_DCT_method_ptr do_float_dct; + FAST_FLOAT * float_divisors[NUM_QUANT_TBLS]; +#endif +} my_fdct_controller; + +typedef my_fdct_controller * my_fdct_ptr; + + +/* + * Initialize for a processing pass. + * Verify that all referenced Q-tables are present, and set up + * the divisor table for each one. + * In the current implementation, DCT of all components is done during + * the first pass, even if only some components will be output in the + * first scan. Hence all components should be examined here. + */ + +METHODDEF(void) +start_pass_fdctmgr (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + int ci, qtblno, i; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + DCTELEM * dtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + qtblno = compptr->quant_tbl_no; + /* Make sure specified quantization table is present */ + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + qtbl = cinfo->quant_tbl_ptrs[qtblno]; + /* Compute divisors for this quant table */ + /* We may do this more than once for same table, but it's not a big deal */ + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + /* For LL&M IDCT method, divisors are equal to raw quantization + * coefficients multiplied by 8 (to counteract scaling). + */ + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3; + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + */ +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + if (fdct->divisors[qtblno] == NULL) { + fdct->divisors[qtblno] = (DCTELEM *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(DCTELEM)); + } + dtbl = fdct->divisors[qtblno]; + for (i = 0; i < DCTSIZE2; i++) { + dtbl[i] = (DCTELEM) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-3); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, divisors are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * We apply a further scale factor of 8. + * What's actually stored is 1/divisor so that the inner loop can + * use a multiplication rather than a division. + */ + FAST_FLOAT * fdtbl; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + if (fdct->float_divisors[qtblno] == NULL) { + fdct->float_divisors[qtblno] = (FAST_FLOAT *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + DCTSIZE2 * SIZEOF(FAST_FLOAT)); + } + fdtbl = fdct->float_divisors[qtblno]; + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fdtbl[i] = (FAST_FLOAT) + (1.0 / (((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col] * 8.0))); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Perform forward DCT on one or more blocks of a component. + * + * The input samples are taken from the sample_data[] array starting at + * position start_row/start_col, and moving to the right for any additional + * blocks. The quantized coefficients are returned in coef_blocks[]. + */ + +METHODDEF(void) +forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for integer DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + forward_DCT_method_ptr do_dct = fdct->do_dct; + DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no]; + DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register DCTELEM *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = GETJSAMPLE(*elemptr++) - CENTERJSAMPLE; + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register DCTELEM temp, qval; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + qval = divisors[i]; + temp = workspace[i]; + /* Divide the coefficient value by qval, ensuring proper rounding. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * + * In most files, at least half of the output values will be zero + * (at default quantization settings, more like three-quarters...) + * so we should ensure that this case is fast. On many machines, + * a comparison is enough cheaper than a divide to make a special test + * a win. Since both inputs will be nonnegative, we need only test + * for a < b to discover whether a/b is 0. + * If your machine's division is fast enough, define FAST_DIVIDE. + */ +#ifdef FAST_DIVIDE +#define DIVIDE_BY(a,b) a /= b +#else +#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0 +#endif + if (temp < 0) { + temp = -temp; + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + temp = -temp; + } else { + temp += qval>>1; /* for rounding */ + DIVIDE_BY(temp, qval); + } + output_ptr[i] = (JCOEF) temp; + } + } + } +} + + +#ifdef DCT_FLOAT_SUPPORTED + +METHODDEF(void) +forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks) +/* This version is used for floating-point DCT implementations. */ +{ + /* This routine is heavily used, so it's worth coding it tightly. */ + my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct; + float_DCT_method_ptr do_dct = fdct->do_float_dct; + FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no]; + FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */ + JDIMENSION bi; + + sample_data += start_row; /* fold in the vertical offset once */ + + for (bi = 0; bi < num_blocks; bi++, start_col += DCTSIZE) { + /* Load data into workspace, applying unsigned->signed conversion */ + { register FAST_FLOAT *workspaceptr; + register JSAMPROW elemptr; + register int elemr; + + workspaceptr = workspace; + for (elemr = 0; elemr < DCTSIZE; elemr++) { + elemptr = sample_data[elemr] + start_col; +#if DCTSIZE == 8 /* unroll the inner loop */ + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + *workspaceptr++ = (FAST_FLOAT)(GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); +#else + { register int elemc; + for (elemc = DCTSIZE; elemc > 0; elemc--) { + *workspaceptr++ = (FAST_FLOAT) + (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE); + } + } +#endif + } + } + + /* Perform the DCT */ + (*do_dct) (workspace); + + /* Quantize/descale the coefficients, and store into coef_blocks[] */ + { register FAST_FLOAT temp; + register int i; + register JCOEFPTR output_ptr = coef_blocks[bi]; + + for (i = 0; i < DCTSIZE2; i++) { + /* Apply the quantization and scaling factor */ + temp = workspace[i] * divisors[i]; + /* Round to nearest integer. + * Since C does not specify the direction of rounding for negative + * quotients, we have to force the dividend positive for portability. + * The maximum coefficient size is +-16K (for 12-bit data), so this + * code should work for either 16-bit or 32-bit ints. + */ + output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384); + } + } + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ + + +/* + * Initialize FDCT manager. + */ + +GLOBAL(void) +jinit_forward_dct (j_compress_ptr cinfo) +{ + my_fdct_ptr fdct; + int i; + + fdct = (my_fdct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_fdct_controller)); + cinfo->fdct = (struct jpeg_forward_dct *) fdct; + fdct->pub.start_pass = start_pass_fdctmgr; + + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + fdct->pub.forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_islow; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + fdct->pub.forward_DCT = forward_DCT; + fdct->do_dct = jpeg_fdct_ifast; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + fdct->pub.forward_DCT = forward_DCT_float; + fdct->do_float_dct = jpeg_fdct_float; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + + /* Mark divisor tables unallocated */ + for (i = 0; i < NUM_QUANT_TBLS; i++) { + fdct->divisors[i] = NULL; +#ifdef DCT_FLOAT_SUPPORTED + fdct->float_divisors[i] = NULL; +#endif + } +} diff --git a/freeimage241/Source/LibJPEG/jchuff.c b/freeimage241/Source/LibJPEG/jchuff.c new file mode 100644 index 0000000..f235250 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jchuff.c @@ -0,0 +1,909 @@ +/* + * jchuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines. + * + * Much of the complexity here has to do with supporting output suspension. + * If the data destination module demands suspension, we want to be able to + * back up to the start of the current MCU. To do this, we copy state + * variables into local working storage, and update them back to the + * permanent JPEG objects only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jcphuff.c */ + + +/* Expanded entropy encoder object for Huffman encoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).put_buffer = (src).put_buffer, \ + (dest).put_bits = (src).put_bits, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + savable_state saved; /* Bit buffer & DC state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + +#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */ + long * dc_count_ptrs[NUM_HUFF_TBLS]; + long * ac_count_ptrs[NUM_HUFF_TBLS]; +#endif +} huff_entropy_encoder; + +typedef huff_entropy_encoder * huff_entropy_ptr; + +/* Working state while writing an MCU. + * This struct contains all the fields that are needed by subroutines. + */ + +typedef struct { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + savable_state cur; /* Current bit buffer & DC state */ + j_compress_ptr cinfo; /* dump_buffer needs access to this */ +} working_state; + + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_huff JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_huff JPP((j_compress_ptr cinfo)); +#ifdef ENTROPY_OPT_SUPPORTED +METHODDEF(boolean) encode_mcu_gather JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_gather JPP((j_compress_ptr cinfo)); +#endif + + +/* + * Initialize for a Huffman-compressed scan. + * If gather_statistics is TRUE, we do not output anything during the scan, + * just count the Huffman symbols used and generate Huffman code tables. + */ + +METHODDEF(void) +start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + entropy->pub.encode_mcu = encode_mcu_gather; + entropy->pub.finish_pass = finish_pass_gather; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + entropy->pub.encode_mcu = encode_mcu_huff; + entropy->pub.finish_pass = finish_pass_huff; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (gather_statistics) { +#ifdef ENTROPY_OPT_SUPPORTED + /* Check for invalid table indexes */ + /* (make_c_derived_tbl does this in the other path) */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + if (actbl < 0 || actbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->dc_count_ptrs[dctbl] == NULL) + entropy->dc_count_ptrs[dctbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * SIZEOF(long)); + if (entropy->ac_count_ptrs[actbl] == NULL) + entropy->ac_count_ptrs[actbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->ac_count_ptrs[actbl], 257 * SIZEOF(long)); +#endif + } else { + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_c_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bit buffer to empty */ + entropy->saved.put_buffer = 0; + entropy->saved.put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + * + * Note this is also used by jcphuff.c. + */ + +GLOBAL(void) +jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + c_derived_tbl *dtbl; + int p, i, l, lastp, si, maxsymbol; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (c_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(c_derived_tbl)); + dtbl = *pdtbl; + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + lastp = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure C.3: generate encoding tables */ + /* These are code and size indexed by symbol value */ + + /* Set all codeless symbols to have code length 0; + * this lets us detect duplicate VAL entries here, and later + * allows emit_bits to detect any attempt to emit such symbols. + */ + MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi)); + + /* This is also a convenient place to check for out-of-range + * and duplicated VAL entries. We allow 0..255 for AC symbols + * but only 0..15 for DC. (We could constrain them further + * based on data depth and mode, but this seems enough.) + */ + maxsymbol = isDC ? 15 : 255; + + for (p = 0; p < lastp; p++) { + i = htbl->huffval[p]; + if (i < 0 || i > maxsymbol || dtbl->ehufsi[i]) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + dtbl->ehufco[i] = huffcode[p]; + dtbl->ehufsi[i] = huffsize[p]; + } +} + + +/* Outputting bytes to the file */ + +/* Emit a byte, taking 'action' if must suspend. */ +#define emit_byte(state,val,action) \ + { *(state)->next_output_byte++ = (JOCTET) (val); \ + if (--(state)->free_in_buffer == 0) \ + if (! dump_buffer(state)) \ + { action; } } + + +LOCAL(boolean) +dump_buffer (working_state * state) +/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */ +{ + struct jpeg_destination_mgr * dest = state->cinfo->dest; + + if (! (*dest->empty_output_buffer) (state->cinfo)) + return FALSE; + /* After a successful buffer dump, must reset buffer pointers */ + state->next_output_byte = dest->next_output_byte; + state->free_in_buffer = dest->free_in_buffer; + return TRUE; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(boolean) +emit_bits (working_state * state, unsigned int code, int size) +/* Emit some bits; return TRUE if successful, FALSE if must suspend */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = state->cur.put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE); + + put_buffer &= (((INT32) 1)<cur.put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(state, c, return FALSE); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(state, 0, return FALSE); + } + put_buffer <<= 8; + put_bits -= 8; + } + + state->cur.put_buffer = put_buffer; /* update state variables */ + state->cur.put_bits = put_bits; + + return TRUE; +} + + +LOCAL(boolean) +flush_bits (working_state * state) +{ + if (! emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */ + return FALSE; + state->cur.put_buffer = 0; /* and reset bit-buffer to empty */ + state->cur.put_bits = 0; + return TRUE; +} + + +/* Encode a single block's worth of coefficients */ + +LOCAL(boolean) +encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, + c_derived_tbl *dctbl, c_derived_tbl *actbl) +{ + register int temp, temp2; + register int nbits; + register int k, r, i; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = temp2 = block[0] - last_dc_val; + + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit the Huffman-coded symbol for the number of bits */ + if (! emit_bits(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + if (! emit_bits(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0])) + return FALSE; + r -= 16; + } + + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); + + /* Emit Huffman symbol for run length / number of bits */ + i = (r << 4) + nbits; + if (! emit_bits(state, actbl->ehufco[i], actbl->ehufsi[i])) + return FALSE; + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (! emit_bits(state, (unsigned int) temp2, nbits)) + return FALSE; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + if (! emit_bits(state, actbl->ehufco[0], actbl->ehufsi[0])) + return FALSE; + + return TRUE; +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(boolean) +emit_restart (working_state * state, int restart_num) +{ + int ci; + + if (! flush_bits(state)) + return FALSE; + + emit_byte(state, 0xFF, return FALSE); + emit_byte(state, JPEG_RST0 + restart_num, return FALSE); + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < state->cinfo->comps_in_scan; ci++) + state->cur.last_dc_val[ci] = 0; + + /* The restart counter is not updated until we successfully write the MCU. */ + + return TRUE; +} + + +/* + * Encode and output one MCU's worth of Huffman-compressed coefficients. + */ + +METHODDEF(boolean) +encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + int blkn, ci; + jpeg_component_info * compptr; + + /* Load up working state */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! emit_restart(&state, entropy->next_restart_num)) + return FALSE; + } + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + if (! encode_one_block(&state, + MCU_data[blkn][0], state.cur.last_dc_val[ci], + entropy->dc_derived_tbls[compptr->dc_tbl_no], + entropy->ac_derived_tbls[compptr->ac_tbl_no])) + return FALSE; + /* Update last_dc_val */ + state.cur.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + /* Completed MCU, so update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed scan. + */ + +METHODDEF(void) +finish_pass_huff (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + working_state state; + + /* Load up working state ... flush_bits needs it */ + state.next_output_byte = cinfo->dest->next_output_byte; + state.free_in_buffer = cinfo->dest->free_in_buffer; + ASSIGN_STATE(state.cur, entropy->saved); + state.cinfo = cinfo; + + /* Flush out the last data */ + if (! flush_bits(&state)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + + /* Update state */ + cinfo->dest->next_output_byte = state.next_output_byte; + cinfo->dest->free_in_buffer = state.free_in_buffer; + ASSIGN_STATE(entropy->saved, state.cur); +} + + +/* + * Huffman coding optimization. + * + * We first scan the supplied data and count the number of uses of each symbol + * that is to be Huffman-coded. (This process MUST agree with the code above.) + * Then we build a Huffman coding tree for the observed counts. + * Symbols which are not needed at all for the particular image are not + * assigned any code, which saves space in the DHT marker as well as in + * the compressed data. + */ + +#ifdef ENTROPY_OPT_SUPPORTED + + +/* Process a single block's worth of coefficients */ + +LOCAL(void) +htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val, + long dc_counts[], long ac_counts[]) +{ + register int temp; + register int nbits; + register int k, r; + + /* Encode the DC coefficient difference per section F.1.2.1 */ + + temp = block[0] - last_dc_val; + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count the Huffman symbol for the number of bits */ + dc_counts[nbits]++; + + /* Encode the AC coefficients per section F.1.2.2 */ + + r = 0; /* r = run length of zeros */ + + for (k = 1; k < DCTSIZE2; k++) { + if ((temp = block[jpeg_natural_order[k]]) == 0) { + r++; + } else { + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + ac_counts[0xF0]++; + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + if (temp < 0) + temp = -temp; + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count Huffman symbol for run length / number of bits */ + ac_counts[(r << 4) + nbits]++; + + r = 0; + } + } + + /* If the last coef(s) were zero, emit an end-of-block code */ + if (r > 0) + ac_counts[0]++; +} + + +/* + * Trial-encode one MCU's worth of Huffman-compressed coefficients. + * No data is actually output, so no suspension return is possible. + */ + +METHODDEF(boolean) +encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn, ci; + jpeg_component_info * compptr; + + /* Take care of restart intervals if needed */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Update restart state */ + entropy->restarts_to_go = cinfo->restart_interval; + } + entropy->restarts_to_go--; + } + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci], + entropy->dc_count_ptrs[compptr->dc_tbl_no], + entropy->ac_count_ptrs[compptr->ac_tbl_no]); + entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0]; + } + + return TRUE; +} + + +/* + * Generate the best Huffman code table for the given counts, fill htbl. + * Note this is also used by jcphuff.c. + * + * The JPEG standard requires that no symbol be assigned a codeword of all + * one bits (so that padding bits added at the end of a compressed segment + * can't look like a valid code). Because of the canonical ordering of + * codewords, this just means that there must be an unused slot in the + * longest codeword length category. Section K.2 of the JPEG spec suggests + * reserving such a slot by pretending that symbol 256 is a valid symbol + * with count 1. In theory that's not optimal; giving it count zero but + * including it in the symbol set anyway should give a better Huffman code. + * But the theoretically better code actually seems to come out worse in + * practice, because it produces more all-ones bytes (which incur stuffed + * zero bytes in the final file). In any case the difference is tiny. + * + * The JPEG standard requires Huffman codes to be no more than 16 bits long. + * If some symbols have a very small but nonzero probability, the Huffman tree + * must be adjusted to meet the code length restriction. We currently use + * the adjustment method suggested in JPEG section K.2. This method is *not* + * optimal; it may not choose the best possible limited-length code. But + * typically only very-low-frequency symbols will be given less-than-optimal + * lengths, so the code is almost optimal. Experimental comparisons against + * an optimal limited-length-code algorithm indicate that the difference is + * microscopic --- usually less than a hundredth of a percent of total size. + * So the extra complexity of an optimal algorithm doesn't seem worthwhile. + */ + +GLOBAL(void) +jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]) +{ +#define MAX_CLEN 32 /* assumed maximum initial code length */ + UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */ + int codesize[257]; /* codesize[k] = code length of symbol k */ + int others[257]; /* next symbol in current branch of tree */ + int c1, c2; + int p, i, j; + long v; + + /* This algorithm is explained in section K.2 of the JPEG standard */ + + MEMZERO(bits, SIZEOF(bits)); + MEMZERO(codesize, SIZEOF(codesize)); + for (i = 0; i < 257; i++) + others[i] = -1; /* init links to empty */ + + freq[256] = 1; /* make sure 256 has a nonzero count */ + /* Including the pseudo-symbol 256 in the Huffman procedure guarantees + * that no real symbol is given code-value of all ones, because 256 + * will be placed last in the largest codeword category. + */ + + /* Huffman's basic algorithm to assign optimal code lengths to symbols */ + + for (;;) { + /* Find the smallest nonzero frequency, set c1 = its symbol */ + /* In case of ties, take the larger symbol number */ + c1 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v) { + v = freq[i]; + c1 = i; + } + } + + /* Find the next smallest nonzero frequency, set c2 = its symbol */ + /* In case of ties, take the larger symbol number */ + c2 = -1; + v = 1000000000L; + for (i = 0; i <= 256; i++) { + if (freq[i] && freq[i] <= v && i != c1) { + v = freq[i]; + c2 = i; + } + } + + /* Done if we've merged everything into one frequency */ + if (c2 < 0) + break; + + /* Else merge the two counts/trees */ + freq[c1] += freq[c2]; + freq[c2] = 0; + + /* Increment the codesize of everything in c1's tree branch */ + codesize[c1]++; + while (others[c1] >= 0) { + c1 = others[c1]; + codesize[c1]++; + } + + others[c1] = c2; /* chain c2 onto c1's tree branch */ + + /* Increment the codesize of everything in c2's tree branch */ + codesize[c2]++; + while (others[c2] >= 0) { + c2 = others[c2]; + codesize[c2]++; + } + } + + /* Now count the number of symbols of each code length */ + for (i = 0; i <= 256; i++) { + if (codesize[i]) { + /* The JPEG standard seems to think that this can't happen, */ + /* but I'm paranoid... */ + if (codesize[i] > MAX_CLEN) + ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW); + + bits[codesize[i]]++; + } + } + + /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure + * Huffman procedure assigned any such lengths, we must adjust the coding. + * Here is what the JPEG spec says about how this next bit works: + * Since symbols are paired for the longest Huffman code, the symbols are + * removed from this length category two at a time. The prefix for the pair + * (which is one bit shorter) is allocated to one of the pair; then, + * skipping the BITS entry for that prefix length, a code word from the next + * shortest nonzero BITS entry is converted into a prefix for two code words + * one bit longer. + */ + + for (i = MAX_CLEN; i > 16; i--) { + while (bits[i] > 0) { + j = i - 2; /* find length of new prefix to be used */ + while (bits[j] == 0) + j--; + + bits[i] -= 2; /* remove two symbols */ + bits[i-1]++; /* one goes in this length */ + bits[j+1] += 2; /* two new symbols in this length */ + bits[j]--; /* symbol of this length is now a prefix */ + } + } + + /* Remove the count for the pseudo-symbol 256 from the largest codelength */ + while (bits[i] == 0) /* find largest codelength still in use */ + i--; + bits[i]--; + + /* Return final symbol counts (only for lengths 0..16) */ + MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits)); + + /* Return a list of the symbols sorted by code length */ + /* It's not real clear to me why we don't need to consider the codelength + * changes made above, but the JPEG spec seems to think this works. + */ + p = 0; + for (i = 1; i <= MAX_CLEN; i++) { + for (j = 0; j <= 255; j++) { + if (codesize[j] == i) { + htbl->huffval[p] = (UINT8) j; + p++; + } + } + } + + /* Set sent_table FALSE so updated table will be written to JPEG file. */ + htbl->sent_table = FALSE; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did_dc[NUM_HUFF_TBLS]; + boolean did_ac[NUM_HUFF_TBLS]; + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did_dc, SIZEOF(did_dc)); + MEMZERO(did_ac, SIZEOF(did_ac)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + if (! did_dc[dctbl]) { + htblptr = & cinfo->dc_huff_tbl_ptrs[dctbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[dctbl]); + did_dc[dctbl] = TRUE; + } + if (! did_ac[actbl]) { + htblptr = & cinfo->ac_huff_tbl_ptrs[actbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[actbl]); + did_ac[actbl] = TRUE; + } + } +} + + +#endif /* ENTROPY_OPT_SUPPORTED */ + + +/* + * Module initialization routine for Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_huff_encoder (j_compress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass_huff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; +#ifdef ENTROPY_OPT_SUPPORTED + entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL; +#endif + } +} diff --git a/freeimage241/Source/LibJPEG/jchuff.h b/freeimage241/Source/LibJPEG/jchuff.h new file mode 100644 index 0000000..a9599fc --- /dev/null +++ b/freeimage241/Source/LibJPEG/jchuff.h @@ -0,0 +1,47 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, boolean isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/freeimage241/Source/LibJPEG/jcinit.c b/freeimage241/Source/LibJPEG/jcinit.c new file mode 100644 index 0000000..5efffe3 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcinit.c @@ -0,0 +1,72 @@ +/* + * jcinit.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains initialization logic for the JPEG compressor. + * This routine is in charge of selecting the modules to be executed and + * making an initialization call to each one. + * + * Logically, this code belongs in jcmaster.c. It's split out because + * linking this routine implies linking the entire compression library. + * For a transcoding-only application, we want to be able to use jcmaster.c + * without linking in the whole library. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Master selection of compression modules. + * This is done once at the start of processing an image. We determine + * which modules will be used and give them appropriate initialization calls. + */ + +GLOBAL(void) +jinit_compress_master (j_compress_ptr cinfo) +{ + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, FALSE /* full compression */); + + /* Preprocessing */ + if (! cinfo->raw_data_in) { + jinit_color_converter(cinfo); + jinit_downsampler(cinfo); + jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + } + /* Forward DCT */ + jinit_forward_dct(cinfo); + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_encoder(cinfo); + } + + /* Need a full-image coefficient buffer in any multi-pass mode. */ + jinit_c_coef_controller(cinfo, + (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding)); + jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} diff --git a/freeimage241/Source/LibJPEG/jcmainct.c b/freeimage241/Source/LibJPEG/jcmainct.c new file mode 100644 index 0000000..e0279a7 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcmainct.c @@ -0,0 +1,293 @@ +/* + * jcmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for compression. + * The main buffer lies between the pre-processor and the JPEG + * compressor proper; it holds downsampled data in the JPEG colorspace. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Note: currently, there is no operating mode in which a full-image buffer + * is needed at this step. If there were, that mode could not be used with + * "raw data" input, since this module is bypassed in that case. However, + * we've left the code here for possible use in special applications. + */ +#undef FULL_MAIN_BUFFER_SUPPORTED + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_main_controller pub; /* public fields */ + + JDIMENSION cur_iMCU_row; /* number of current iMCU row */ + JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */ + boolean suspended; /* remember if we suspended output */ + J_BUF_MODE pass_mode; /* current operating mode */ + + /* If using just a strip buffer, this points to the entire set of buffers + * (we allocate one for each component). In the full-image case, this + * points to the currently accessible strips of the virtual arrays. + */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* If using full-image storage, this array holds pointers to virtual-array + * control blocks for each component. Unused if not full-image storage. + */ + jvirt_sarray_ptr whole_image[MAX_COMPONENTS]; +#endif +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#ifdef FULL_MAIN_BUFFER_SUPPORTED +METHODDEF(void) process_data_buffer_main + JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + /* Do nothing in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + main->cur_iMCU_row = 0; /* initialize counters */ + main->rowgroup_ctr = 0; + main->suspended = FALSE; + main->pass_mode = pass_mode; /* save mode for use by process_data */ + + switch (pass_mode) { + case JBUF_PASS_THRU: +#ifdef FULL_MAIN_BUFFER_SUPPORTED + if (main->whole_image[0] != NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + main->pub.process_data = process_data_simple_main; + break; +#ifdef FULL_MAIN_BUFFER_SUPPORTED + case JBUF_SAVE_SOURCE: + case JBUF_CRANK_DEST: + case JBUF_SAVE_AND_PASS: + if (main->whole_image[0] == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + main->pub.process_data = process_data_buffer_main; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This routine handles the simple pass-through mode, + * where we have only a strip buffer. + */ + +METHODDEF(void) +process_data_simple_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Read input data if we haven't filled the main buffer yet */ + if (main->rowgroup_ctr < DCTSIZE) + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + main->buffer, &main->rowgroup_ctr, + (JDIMENSION) DCTSIZE); + + /* If we don't have a full iMCU row buffered, return to application for + * more data. Note that preprocessor will always pad to fill the iMCU row + * at the bottom of the image. + */ + if (main->rowgroup_ctr != DCTSIZE) + return; + + /* Send the completed row to the compressor */ + if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! main->suspended) { + (*in_row_ctr)--; + main->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (main->suspended) { + (*in_row_ctr)++; + main->suspended = FALSE; + } + main->rowgroup_ctr = 0; + main->cur_iMCU_row++; + } +} + + +#ifdef FULL_MAIN_BUFFER_SUPPORTED + +/* + * Process some data. + * This routine handles all of the modes that use a full-size buffer. + */ + +METHODDEF(void) +process_data_buffer_main (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci; + jpeg_component_info *compptr; + boolean writing = (main->pass_mode != JBUF_CRANK_DEST); + + while (main->cur_iMCU_row < cinfo->total_iMCU_rows) { + /* Realign the virtual buffers if at the start of an iMCU row. */ + if (main->rowgroup_ctr == 0) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->buffer[ci] = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, main->whole_image[ci], + main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE), + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing); + } + /* In a read pass, pretend we just read some source data. */ + if (! writing) { + *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE; + main->rowgroup_ctr = DCTSIZE; + } + } + + /* If a write pass, read input data until the current iMCU row is full. */ + /* Note: preprocessor will pad if necessary to fill the last iMCU row. */ + if (writing) { + (*cinfo->prep->pre_process_data) (cinfo, + input_buf, in_row_ctr, in_rows_avail, + main->buffer, &main->rowgroup_ctr, + (JDIMENSION) DCTSIZE); + /* Return to application if we need more data to fill the iMCU row. */ + if (main->rowgroup_ctr < DCTSIZE) + return; + } + + /* Emit data, unless this is a sink-only pass. */ + if (main->pass_mode != JBUF_SAVE_SOURCE) { + if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) { + /* If compressor did not consume the whole row, then we must need to + * suspend processing and return to the application. In this situation + * we pretend we didn't yet consume the last input row; otherwise, if + * it happened to be the last row of the image, the application would + * think we were done. + */ + if (! main->suspended) { + (*in_row_ctr)--; + main->suspended = TRUE; + } + return; + } + /* We did finish the row. Undo our little suspension hack if a previous + * call suspended; then mark the main buffer empty. + */ + if (main->suspended) { + (*in_row_ctr)++; + main->suspended = FALSE; + } + } + + /* If get here, we are done with this iMCU row. Mark buffer empty. */ + main->rowgroup_ctr = 0; + main->cur_iMCU_row++; + } +} + +#endif /* FULL_MAIN_BUFFER_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr main; + int ci; + jpeg_component_info *compptr; + + main = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_c_main_controller *) main; + main->pub.start_pass = start_pass_main; + + /* We don't need to create a buffer in raw-data mode. */ + if (cinfo->raw_data_in) + return; + + /* Create the buffer. It holds downsampled data, so each component + * may be of a different size. + */ + if (need_full_buffer) { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + /* Allocate a full-image virtual array for each component */ + /* Note we pad the bottom to a multiple of the iMCU height */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->whole_image[ci] = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor) * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); + } +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif + } else { +#ifdef FULL_MAIN_BUFFER_SUPPORTED + main->whole_image[0] = NULL; /* flag for no virtual arrays */ +#endif + /* Allocate a strip buffer for each component */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor * DCTSIZE)); + } + } +} diff --git a/freeimage241/Source/LibJPEG/jcmarker.c b/freeimage241/Source/LibJPEG/jcmarker.c new file mode 100644 index 0000000..3d1e6c6 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcmarker.c @@ -0,0 +1,664 @@ +/* + * jcmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write JPEG datastream markers. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_writer pub; /* public fields */ + + unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */ +} my_marker_writer; + +typedef my_marker_writer * my_marker_ptr; + + +/* + * Basic output routines. + * + * Note that we do not support suspension while writing a marker. + * Therefore, an application using suspension must ensure that there is + * enough buffer space for the initial markers (typ. 600-700 bytes) before + * calling jpeg_start_compress, and enough space to write the trailing EOI + * (a few bytes) before calling jpeg_finish_compress. Multipass compression + * modes are not supported at all with suspension, so those two are the only + * points where markers will be written. + */ + +LOCAL(void) +emit_byte (j_compress_ptr cinfo, int val) +/* Emit a byte */ +{ + struct jpeg_destination_mgr * dest = cinfo->dest; + + *(dest->next_output_byte)++ = (JOCTET) val; + if (--dest->free_in_buffer == 0) { + if (! (*dest->empty_output_buffer) (cinfo)) + ERREXIT(cinfo, JERR_CANT_SUSPEND); + } +} + + +LOCAL(void) +emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark) +/* Emit a marker code */ +{ + emit_byte(cinfo, 0xFF); + emit_byte(cinfo, (int) mark); +} + + +LOCAL(void) +emit_2bytes (j_compress_ptr cinfo, int value) +/* Emit a 2-byte integer; these are always MSB first in JPEG files */ +{ + emit_byte(cinfo, (value >> 8) & 0xFF); + emit_byte(cinfo, value & 0xFF); +} + + +/* + * Routines to write specific marker types. + */ + +LOCAL(int) +emit_dqt (j_compress_ptr cinfo, int index) +/* Emit a DQT marker */ +/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */ +{ + JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index]; + int prec; + int i; + + if (qtbl == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index); + + prec = 0; + for (i = 0; i < DCTSIZE2; i++) { + if (qtbl->quantval[i] > 255) + prec = 1; + } + + if (! qtbl->sent_table) { + emit_marker(cinfo, M_DQT); + + emit_2bytes(cinfo, prec ? DCTSIZE2*2 + 1 + 2 : DCTSIZE2 + 1 + 2); + + emit_byte(cinfo, index + (prec<<4)); + + for (i = 0; i < DCTSIZE2; i++) { + /* The table entries must be emitted in zigzag order. */ + unsigned int qval = qtbl->quantval[jpeg_natural_order[i]]; + if (prec) + emit_byte(cinfo, (int) (qval >> 8)); + emit_byte(cinfo, (int) (qval & 0xFF)); + } + + qtbl->sent_table = TRUE; + } + + return prec; +} + + +LOCAL(void) +emit_dht (j_compress_ptr cinfo, int index, boolean is_ac) +/* Emit a DHT marker */ +{ + JHUFF_TBL * htbl; + int length, i; + + if (is_ac) { + htbl = cinfo->ac_huff_tbl_ptrs[index]; + index += 0x10; /* output index has AC bit set */ + } else { + htbl = cinfo->dc_huff_tbl_ptrs[index]; + } + + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index); + + if (! htbl->sent_table) { + emit_marker(cinfo, M_DHT); + + length = 0; + for (i = 1; i <= 16; i++) + length += htbl->bits[i]; + + emit_2bytes(cinfo, length + 2 + 1 + 16); + emit_byte(cinfo, index); + + for (i = 1; i <= 16; i++) + emit_byte(cinfo, htbl->bits[i]); + + for (i = 0; i < length; i++) + emit_byte(cinfo, htbl->huffval[i]); + + htbl->sent_table = TRUE; + } +} + + +LOCAL(void) +emit_dac (j_compress_ptr cinfo) +/* Emit a DAC marker */ +/* Since the useful info is so small, we want to emit all the tables in */ +/* one DAC marker. Therefore this routine does its own scan of the table. */ +{ +#ifdef C_ARITH_CODING_SUPPORTED + char dc_in_use[NUM_ARITH_TBLS]; + char ac_in_use[NUM_ARITH_TBLS]; + int length, i; + jpeg_component_info *compptr; + + for (i = 0; i < NUM_ARITH_TBLS; i++) + dc_in_use[i] = ac_in_use[i] = 0; + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + dc_in_use[compptr->dc_tbl_no] = 1; + ac_in_use[compptr->ac_tbl_no] = 1; + } + + length = 0; + for (i = 0; i < NUM_ARITH_TBLS; i++) + length += dc_in_use[i] + ac_in_use[i]; + + emit_marker(cinfo, M_DAC); + + emit_2bytes(cinfo, length*2 + 2); + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + if (dc_in_use[i]) { + emit_byte(cinfo, i); + emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4)); + } + if (ac_in_use[i]) { + emit_byte(cinfo, i + 0x10); + emit_byte(cinfo, cinfo->arith_ac_K[i]); + } + } +#endif /* C_ARITH_CODING_SUPPORTED */ +} + + +LOCAL(void) +emit_dri (j_compress_ptr cinfo) +/* Emit a DRI marker */ +{ + emit_marker(cinfo, M_DRI); + + emit_2bytes(cinfo, 4); /* fixed length */ + + emit_2bytes(cinfo, (int) cinfo->restart_interval); +} + + +LOCAL(void) +emit_sof (j_compress_ptr cinfo, JPEG_MARKER code) +/* Emit a SOF marker */ +{ + int ci; + jpeg_component_info *compptr; + + emit_marker(cinfo, code); + + emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */ + + /* Make sure image isn't bigger than SOF field can handle */ + if ((long) cinfo->image_height > 65535L || + (long) cinfo->image_width > 65535L) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535); + + emit_byte(cinfo, cinfo->data_precision); + emit_2bytes(cinfo, (int) cinfo->image_height); + emit_2bytes(cinfo, (int) cinfo->image_width); + + emit_byte(cinfo, cinfo->num_components); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + emit_byte(cinfo, compptr->component_id); + emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor); + emit_byte(cinfo, compptr->quant_tbl_no); + } +} + + +LOCAL(void) +emit_sos (j_compress_ptr cinfo) +/* Emit a SOS marker */ +{ + int i, td, ta; + jpeg_component_info *compptr; + + emit_marker(cinfo, M_SOS); + + emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */ + + emit_byte(cinfo, cinfo->comps_in_scan); + + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + emit_byte(cinfo, compptr->component_id); + td = compptr->dc_tbl_no; + ta = compptr->ac_tbl_no; + if (cinfo->progressive_mode) { + /* Progressive mode: only DC or only AC tables are used in one scan; + * furthermore, Huffman coding of DC refinement uses no table at all. + * We emit 0 for unused field(s); this is recommended by the P&M text + * but does not seem to be specified in the standard. + */ + if (cinfo->Ss == 0) { + ta = 0; /* DC scan */ + if (cinfo->Ah != 0 && !cinfo->arith_code) + td = 0; /* no DC table either */ + } else { + td = 0; /* AC scan */ + } + } + emit_byte(cinfo, (td << 4) + ta); + } + + emit_byte(cinfo, cinfo->Ss); + emit_byte(cinfo, cinfo->Se); + emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al); +} + + +LOCAL(void) +emit_jfif_app0 (j_compress_ptr cinfo) +/* Emit a JFIF-compliant APP0 marker */ +{ + /* + * Length of APP0 block (2 bytes) + * Block ID (4 bytes - ASCII "JFIF") + * Zero byte (1 byte to terminate the ID string) + * Version Major, Minor (2 bytes - major first) + * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm) + * Xdpu (2 bytes - dots per unit horizontal) + * Ydpu (2 bytes - dots per unit vertical) + * Thumbnail X size (1 byte) + * Thumbnail Y size (1 byte) + */ + + emit_marker(cinfo, M_APP0); + + emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */ + + emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */ + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0x49); + emit_byte(cinfo, 0x46); + emit_byte(cinfo, 0); + emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */ + emit_byte(cinfo, cinfo->JFIF_minor_version); + emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */ + emit_2bytes(cinfo, (int) cinfo->X_density); + emit_2bytes(cinfo, (int) cinfo->Y_density); + emit_byte(cinfo, 0); /* No thumbnail image */ + emit_byte(cinfo, 0); +} + + +LOCAL(void) +emit_adobe_app14 (j_compress_ptr cinfo) +/* Emit an Adobe APP14 marker */ +{ + /* + * Length of APP14 block (2 bytes) + * Block ID (5 bytes - ASCII "Adobe") + * Version Number (2 bytes - currently 100) + * Flags0 (2 bytes - currently 0) + * Flags1 (2 bytes - currently 0) + * Color transform (1 byte) + * + * Although Adobe TN 5116 mentions Version = 101, all the Adobe files + * now in circulation seem to use Version = 100, so that's what we write. + * + * We write the color transform byte as 1 if the JPEG color space is + * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with + * whether the encoder performed a transformation, which is pretty useless. + */ + + emit_marker(cinfo, M_APP14); + + emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */ + + emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */ + emit_byte(cinfo, 0x64); + emit_byte(cinfo, 0x6F); + emit_byte(cinfo, 0x62); + emit_byte(cinfo, 0x65); + emit_2bytes(cinfo, 100); /* Version */ + emit_2bytes(cinfo, 0); /* Flags0 */ + emit_2bytes(cinfo, 0); /* Flags1 */ + switch (cinfo->jpeg_color_space) { + case JCS_YCbCr: + emit_byte(cinfo, 1); /* Color transform = 1 */ + break; + case JCS_YCCK: + emit_byte(cinfo, 2); /* Color transform = 2 */ + break; + default: + emit_byte(cinfo, 0); /* Color transform = 0 */ + break; + } +} + + +/* + * These routines allow writing an arbitrary marker with parameters. + * The only intended use is to emit COM or APPn markers after calling + * write_file_header and before calling write_frame_header. + * Other uses are not guaranteed to produce desirable results. + * Counting the parameter bytes properly is the caller's responsibility. + */ + +METHODDEF(void) +write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen) +/* Emit an arbitrary marker header */ +{ + if (datalen > (unsigned int) 65533) /* safety check */ + ERREXIT(cinfo, JERR_BAD_LENGTH); + + emit_marker(cinfo, (JPEG_MARKER) marker); + + emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */ +} + +METHODDEF(void) +write_marker_byte (j_compress_ptr cinfo, int val) +/* Emit one byte of marker parameters following write_marker_header */ +{ + emit_byte(cinfo, val); +} + + +/* + * Write datastream header. + * This consists of an SOI and optional APPn markers. + * We recommend use of the JFIF marker, but not the Adobe marker, + * when using YCbCr or grayscale data. The JFIF marker should NOT + * be used for any other JPEG colorspace. The Adobe marker is helpful + * to distinguish RGB, CMYK, and YCCK colorspaces. + * Note that an application can write additional header markers after + * jpeg_start_compress returns. + */ + +METHODDEF(void) +write_file_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + emit_marker(cinfo, M_SOI); /* first the SOI */ + + /* SOI is defined to reset restart interval to 0 */ + marker->last_restart_interval = 0; + + if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */ + emit_jfif_app0(cinfo); + if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */ + emit_adobe_app14(cinfo); +} + + +/* + * Write frame header. + * This consists of DQT and SOFn markers. + * Note that we do not emit the SOF until we have emitted the DQT(s). + * This avoids compatibility problems with incorrect implementations that + * try to error-check the quant table numbers as soon as they see the SOF. + */ + +METHODDEF(void) +write_frame_header (j_compress_ptr cinfo) +{ + int ci, prec; + boolean is_baseline; + jpeg_component_info *compptr; + + /* Emit DQT for each quantization table. + * Note that emit_dqt() suppresses any duplicate tables. + */ + prec = 0; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prec += emit_dqt(cinfo, compptr->quant_tbl_no); + } + /* now prec is nonzero iff there are any 16-bit quant tables. */ + + /* Check for a non-baseline specification. + * Note we assume that Huffman table numbers won't be changed later. + */ + if (cinfo->arith_code || cinfo->progressive_mode || + cinfo->data_precision != 8) { + is_baseline = FALSE; + } else { + is_baseline = TRUE; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1) + is_baseline = FALSE; + } + if (prec && is_baseline) { + is_baseline = FALSE; + /* If it's baseline except for quantizer size, warn the user */ + TRACEMS(cinfo, 0, JTRC_16BIT_TABLES); + } + } + + /* Emit the proper SOF marker */ + if (cinfo->arith_code) { + emit_sof(cinfo, M_SOF9); /* SOF code for arithmetic coding */ + } else { + if (cinfo->progressive_mode) + emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */ + else if (is_baseline) + emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */ + else + emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */ + } +} + + +/* + * Write scan header. + * This consists of DHT or DAC markers, optional DRI, and SOS. + * Compressed data will be written following the SOS. + */ + +METHODDEF(void) +write_scan_header (j_compress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + int i; + jpeg_component_info *compptr; + + if (cinfo->arith_code) { + /* Emit arith conditioning info. We may have some duplication + * if the file has multiple scans, but it's so small it's hardly + * worth worrying about. + */ + emit_dac(cinfo); + } else { + /* Emit Huffman tables. + * Note that emit_dht() suppresses any duplicate tables. + */ + for (i = 0; i < cinfo->comps_in_scan; i++) { + compptr = cinfo->cur_comp_info[i]; + if (cinfo->progressive_mode) { + /* Progressive mode: only DC or only AC tables are used in one scan */ + if (cinfo->Ss == 0) { + if (cinfo->Ah == 0) /* DC needs no table for refinement scan */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + } else { + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } else { + /* Sequential mode: need both DC and AC tables */ + emit_dht(cinfo, compptr->dc_tbl_no, FALSE); + emit_dht(cinfo, compptr->ac_tbl_no, TRUE); + } + } + } + + /* Emit DRI if required --- note that DRI value could change for each scan. + * We avoid wasting space with unnecessary DRIs, however. + */ + if (cinfo->restart_interval != marker->last_restart_interval) { + emit_dri(cinfo); + marker->last_restart_interval = cinfo->restart_interval; + } + + emit_sos(cinfo); +} + + +/* + * Write datastream trailer. + */ + +METHODDEF(void) +write_file_trailer (j_compress_ptr cinfo) +{ + emit_marker(cinfo, M_EOI); +} + + +/* + * Write an abbreviated table-specification datastream. + * This consists of SOI, DQT and DHT tables, and EOI. + * Any table that is defined and not marked sent_table = TRUE will be + * emitted. Note that all tables will be marked sent_table = TRUE at exit. + */ + +METHODDEF(void) +write_tables_only (j_compress_ptr cinfo) +{ + int i; + + emit_marker(cinfo, M_SOI); + + for (i = 0; i < NUM_QUANT_TBLS; i++) { + if (cinfo->quant_tbl_ptrs[i] != NULL) + (void) emit_dqt(cinfo, i); + } + + if (! cinfo->arith_code) { + for (i = 0; i < NUM_HUFF_TBLS; i++) { + if (cinfo->dc_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, FALSE); + if (cinfo->ac_huff_tbl_ptrs[i] != NULL) + emit_dht(cinfo, i, TRUE); + } + } + + emit_marker(cinfo, M_EOI); +} + + +/* + * Initialize the marker writer module. + */ + +GLOBAL(void) +jinit_marker_writer (j_compress_ptr cinfo) +{ + my_marker_ptr marker; + + /* Create the subobject */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_marker_writer)); + cinfo->marker = (struct jpeg_marker_writer *) marker; + /* Initialize method pointers */ + marker->pub.write_file_header = write_file_header; + marker->pub.write_frame_header = write_frame_header; + marker->pub.write_scan_header = write_scan_header; + marker->pub.write_file_trailer = write_file_trailer; + marker->pub.write_tables_only = write_tables_only; + marker->pub.write_marker_header = write_marker_header; + marker->pub.write_marker_byte = write_marker_byte; + /* Initialize private state */ + marker->last_restart_interval = 0; +} diff --git a/freeimage241/Source/LibJPEG/jcmaster.c b/freeimage241/Source/LibJPEG/jcmaster.c new file mode 100644 index 0000000..aab4020 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcmaster.c @@ -0,0 +1,590 @@ +/* + * jcmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG compressor. + * These routines are concerned with parameter validation, initial setup, + * and inter-pass control (determining the number of passes and the work + * to be done in each pass). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef enum { + main_pass, /* input data, also do first output step */ + huff_opt_pass, /* Huffman code optimization pass */ + output_pass /* data output pass */ +} c_pass_type; + +typedef struct { + struct jpeg_comp_master pub; /* public fields */ + + c_pass_type pass_type; /* the type of the current pass */ + + int pass_number; /* # of passes completed */ + int total_passes; /* total # of passes needed */ + + int scan_number; /* current index in scan_info[] */ +} my_comp_master; + +typedef my_comp_master * my_master_ptr; + + +/* + * Support routines that do various essential calculations. + */ + +LOCAL(void) +initial_setup (j_compress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ + int ci; + jpeg_component_info *compptr; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Sanity check on image dimensions */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0 || cinfo->input_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* Width of an input scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Fill in the correct component_index value; don't rely on application */ + compptr->component_index = ci; + /* For compression, we never do DCT scaling. */ + compptr->DCT_scaled_size = DCTSIZE; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed (this flag isn't actually used for compression) */ + compptr->component_needed = TRUE; + } + + /* Compute number of fully interleaved MCU rows (number of times that + * main controller will call coefficient controller). + */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL(void) +validate_script (j_compress_ptr cinfo) +/* Verify that the scan script in cinfo->scan_info[] is valid; also + * determine whether it uses progressive JPEG, and set cinfo->progressive_mode. + */ +{ + const jpeg_scan_info * scanptr; + int scanno, ncomps, ci, coefi, thisi; + int Ss, Se, Ah, Al; + boolean component_sent[MAX_COMPONENTS]; +#ifdef C_PROGRESSIVE_SUPPORTED + int * last_bitpos_ptr; + int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; + /* -1 until that coefficient has been seen; then last Al for it */ +#endif + + if (cinfo->num_scans <= 0) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0); + + /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; + * for progressive JPEG, no scan can have this. + */ + scanptr = cinfo->scan_info; + if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) { +#ifdef C_PROGRESSIVE_SUPPORTED + cinfo->progressive_mode = TRUE; + last_bitpos_ptr = & last_bitpos[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (coefi = 0; coefi < DCTSIZE2; coefi++) + *last_bitpos_ptr++ = -1; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + for (ci = 0; ci < cinfo->num_components; ci++) + component_sent[ci] = FALSE; + } + + for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) { + /* Validate component indexes */ + ncomps = scanptr->comps_in_scan; + if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (thisi < 0 || thisi >= cinfo->num_components) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + /* Components must appear in SOF order within each scan */ + if (ci > 0 && thisi <= scanptr->component_index[ci-1]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + } + /* Validate progression parameters */ + Ss = scanptr->Ss; + Se = scanptr->Se; + Ah = scanptr->Ah; + Al = scanptr->Al; + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that + * seems wrong: the upper bound ought to depend on data precision. + * Perhaps they really meant 0..N+1 for N-bit precision. + * Here we allow 0..10 for 8-bit data; Al larger than 10 results in + * out-of-range reconstructed DC values during the first DC scan, + * which might cause problems for some decoders. + */ +#if BITS_IN_JSAMPLE == 8 +#define MAX_AH_AL 10 +#else +#define MAX_AH_AL 13 +#endif + if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 || + Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + if (Ss == 0) { + if (Se != 0) /* DC and AC together not OK */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + if (ncomps != 1) /* AC scans must be for only one component */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + for (ci = 0; ci < ncomps; ci++) { + last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0]; + if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */ + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + for (coefi = Ss; coefi <= Se; coefi++) { + if (last_bitpos_ptr[coefi] < 0) { + /* first scan of this coefficient */ + if (Ah != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } else { + /* not first scan */ + if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + } + last_bitpos_ptr[coefi] = Al; + } + } +#endif + } else { + /* For sequential JPEG, all progression parameters must be these: */ + if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0) + ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno); + /* Make sure components are not sent twice */ + for (ci = 0; ci < ncomps; ci++) { + thisi = scanptr->component_index[ci]; + if (component_sent[thisi]) + ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno); + component_sent[thisi] = TRUE; + } + } + } + + /* Now verify that everything got sent. */ + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + /* For progressive mode, we only check that at least some DC data + * got sent for each component; the spec does not require that all bits + * of all coefficients be transmitted. Would it be wiser to enforce + * transmission of all coefficient bits?? + */ + for (ci = 0; ci < cinfo->num_components; ci++) { + if (last_bitpos[ci][0] < 0) + ERREXIT(cinfo, JERR_MISSING_DATA); + } +#endif + } else { + for (ci = 0; ci < cinfo->num_components; ci++) { + if (! component_sent[ci]) + ERREXIT(cinfo, JERR_MISSING_DATA); + } + } +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +LOCAL(void) +select_scan_parameters (j_compress_ptr cinfo) +/* Set up the scan parameters for the current scan */ +{ + int ci; + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (cinfo->scan_info != NULL) { + /* Prepare for current scan --- the script is already validated */ + my_master_ptr master = (my_master_ptr) cinfo->master; + const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number; + + cinfo->comps_in_scan = scanptr->comps_in_scan; + for (ci = 0; ci < scanptr->comps_in_scan; ci++) { + cinfo->cur_comp_info[ci] = + &cinfo->comp_info[scanptr->component_index[ci]]; + } + cinfo->Ss = scanptr->Ss; + cinfo->Se = scanptr->Se; + cinfo->Ah = scanptr->Ah; + cinfo->Al = scanptr->Al; + } + else +#endif + { + /* Prepare for single sequential-JPEG scan containing all components */ + if (cinfo->num_components > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPS_IN_SCAN); + cinfo->comps_in_scan = cinfo->num_components; + for (ci = 0; ci < cinfo->num_components; ci++) { + cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci]; + } + cinfo->Ss = 0; + cinfo->Se = DCTSIZE2-1; + cinfo->Ah = 0; + cinfo->Al = 0; + } +} + + +LOCAL(void) +per_scan_setup (j_compress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = DCTSIZE; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*DCTSIZE)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } + + /* Convert restart specified in rows to actual MCU count. */ + /* Note that count must fit in 16 bits, so we provide limiting. */ + if (cinfo->restart_in_rows > 0) { + long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row; + cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L); + } +} + + +/* + * Per-pass setup. + * This is called at the beginning of each pass. We determine which modules + * will be active during this pass and give them appropriate start_pass calls. + * We also set is_last_pass to indicate whether any more passes will be + * required. + */ + +METHODDEF(void) +prepare_for_pass (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + switch (master->pass_type) { + case main_pass: + /* Initial pass: will collect input data, and do either Huffman + * optimization or data output for the first scan. + */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (! cinfo->raw_data_in) { + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->downsample->start_pass) (cinfo); + (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU); + } + (*cinfo->fdct->start_pass) (cinfo); + (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding); + (*cinfo->coef->start_pass) (cinfo, + (master->total_passes > 1 ? + JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + if (cinfo->optimize_coding) { + /* No immediate data output; postpone writing frame/scan headers */ + master->pub.call_pass_startup = FALSE; + } else { + /* Will write frame/scan headers at first jpeg_write_scanlines call */ + master->pub.call_pass_startup = TRUE; + } + break; +#ifdef ENTROPY_OPT_SUPPORTED + case huff_opt_pass: + /* Do Huffman optimization for a scan after the first one. */ + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) { + (*cinfo->entropy->start_pass) (cinfo, TRUE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + master->pub.call_pass_startup = FALSE; + break; + } + /* Special case: Huffman DC refinement scans need no Huffman table + * and therefore we can skip the optimization pass for them. + */ + master->pass_type = output_pass; + master->pass_number++; + /*FALLTHROUGH*/ +#endif + case output_pass: + /* Do a data-output pass. */ + /* We need not repeat per-scan setup if prior optimization pass did it. */ + if (! cinfo->optimize_coding) { + select_scan_parameters(cinfo); + per_scan_setup(cinfo); + } + (*cinfo->entropy->start_pass) (cinfo, FALSE); + (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST); + /* We emit frame/scan headers now */ + if (master->scan_number == 0) + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); + master->pub.call_pass_startup = FALSE; + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + } + + master->pub.is_last_pass = (master->pass_number == master->total_passes-1); + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->total_passes; + } +} + + +/* + * Special start-of-pass hook. + * This is called by jpeg_write_scanlines if call_pass_startup is TRUE. + * In single-pass processing, we need this hook because we don't want to + * write frame/scan headers during jpeg_start_compress; we want to let the + * application write COM markers etc. between jpeg_start_compress and the + * jpeg_write_scanlines loop. + * In multi-pass processing, this routine is not used. + */ + +METHODDEF(void) +pass_startup (j_compress_ptr cinfo) +{ + cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */ + + (*cinfo->marker->write_frame_header) (cinfo); + (*cinfo->marker->write_scan_header) (cinfo); +} + + +/* + * Finish up at end of pass. + */ + +METHODDEF(void) +finish_pass_master (j_compress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* The entropy coder always needs an end-of-pass call, + * either to analyze statistics or to flush its output buffer. + */ + (*cinfo->entropy->finish_pass) (cinfo); + + /* Update state for next pass */ + switch (master->pass_type) { + case main_pass: + /* next pass is either output of scan 0 (after optimization) + * or output of scan 1 (if no optimization). + */ + master->pass_type = output_pass; + if (! cinfo->optimize_coding) + master->scan_number++; + break; + case huff_opt_pass: + /* next pass is always output of current scan */ + master->pass_type = output_pass; + break; + case output_pass: + /* next pass is either optimization or output of next scan */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + master->scan_number++; + break; + } + + master->pass_number++; +} + + +/* + * Initialize master compression control. + */ + +GLOBAL(void) +jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_comp_master)); + cinfo->master = (struct jpeg_comp_master *) master; + master->pub.prepare_for_pass = prepare_for_pass; + master->pub.pass_startup = pass_startup; + master->pub.finish_pass = finish_pass_master; + master->pub.is_last_pass = FALSE; + + /* Validate parameters, determine derived values */ + initial_setup(cinfo); + + if (cinfo->scan_info != NULL) { +#ifdef C_MULTISCAN_FILES_SUPPORTED + validate_script(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + cinfo->progressive_mode = FALSE; + cinfo->num_scans = 1; + } + + if (cinfo->progressive_mode) /* TEMPORARY HACK ??? */ + cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */ + + /* Initialize my private state */ + if (transcode_only) { + /* no main pass in transcoding */ + if (cinfo->optimize_coding) + master->pass_type = huff_opt_pass; + else + master->pass_type = output_pass; + } else { + /* for normal compression, first pass is always this type: */ + master->pass_type = main_pass; + } + master->scan_number = 0; + master->pass_number = 0; + if (cinfo->optimize_coding) + master->total_passes = cinfo->num_scans * 2; + else + master->total_passes = cinfo->num_scans; +} diff --git a/freeimage241/Source/LibJPEG/jcomapi.c b/freeimage241/Source/LibJPEG/jcomapi.c new file mode 100644 index 0000000..9b1fa75 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcomapi.c @@ -0,0 +1,106 @@ +/* + * jcomapi.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface routines that are used for both + * compression and decompression. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Abort processing of a JPEG compression or decompression operation, + * but don't destroy the object itself. + * + * For this, we merely clean up all the nonpermanent memory pools. + * Note that temp files (virtual arrays) are not allowed to belong to + * the permanent pool, so we will be able to close all temp files here. + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_abort (j_common_ptr cinfo) +{ + int pool; + + /* Do nothing if called on a not-initialized or destroyed JPEG object. */ + if (cinfo->mem == NULL) + return; + + /* Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + (*cinfo->mem->free_pool) (cinfo, pool); + } + + /* Reset overall state for possible reuse of object */ + if (cinfo->is_decompressor) { + cinfo->global_state = DSTATE_START; + /* Try to keep application from accessing now-deleted marker list. + * A bit kludgy to do it here, but this is the most central place. + */ + ((j_decompress_ptr) cinfo)->marker_list = NULL; + } else { + cinfo->global_state = CSTATE_START; + } +} + + +/* + * Destruction of a JPEG object. + * + * Everything gets deallocated except the master jpeg_compress_struct itself + * and the error manager struct. Both of these are supplied by the application + * and must be freed, if necessary, by the application. (Often they are on + * the stack and so don't need to be freed anyway.) + * Closing a data source or destination, if necessary, is the application's + * responsibility. + */ + +GLOBAL(void) +jpeg_destroy (j_common_ptr cinfo) +{ + /* We need only tell the memory manager to release everything. */ + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + if (cinfo->mem != NULL) + (*cinfo->mem->self_destruct) (cinfo); + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + cinfo->global_state = 0; /* mark it destroyed */ +} + + +/* + * Convenience routines for allocating quantization and Huffman tables. + * (Would jutils.c be a more reasonable place to put these?) + */ + +GLOBAL(JQUANT_TBL *) +jpeg_alloc_quant_table (j_common_ptr cinfo) +{ + JQUANT_TBL *tbl; + + tbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} + + +GLOBAL(JHUFF_TBL *) +jpeg_alloc_huff_table (j_common_ptr cinfo) +{ + JHUFF_TBL *tbl; + + tbl = (JHUFF_TBL *) + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + return tbl; +} diff --git a/freeimage241/Source/LibJPEG/jconfig.h b/freeimage241/Source/LibJPEG/jconfig.h new file mode 100644 index 0000000..7e291c7 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jconfig.h @@ -0,0 +1,45 @@ +/* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +/* #define void char */ +/* #define const */ +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS /* we presume a 32-bit flat memory model */ +#undef NEED_SHORT_EXTERNAL_NAMES +#undef INCOMPLETE_TYPES_BROKEN + +/* Define "boolean" as unsigned char, not int, per Windows custom */ +#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */ +typedef unsigned char boolean; +#endif +#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */ + + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#define TWO_FILE_COMMANDLINE /* optional */ +#define USE_SETMODE /* Microsoft has setmode() */ +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE +#undef PROGRESS_REPORT /* optional */ + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/freeimage241/Source/LibJPEG/jcparam.c b/freeimage241/Source/LibJPEG/jcparam.c new file mode 100644 index 0000000..6fc48f5 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcparam.c @@ -0,0 +1,610 @@ +/* + * jcparam.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains optional default-setting code for the JPEG compressor. + * Applications do not have to use this file, but those that don't use it + * must know a lot more about the innards of the JPEG code. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Quantization table setup routines + */ + +GLOBAL(void) +jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, boolean force_baseline) +/* Define a quantization table equal to the basic_table times + * a scale factor (given as a percentage). + * If force_baseline is TRUE, the computed quantization table entries + * are limited to 1..255 for JPEG baseline compatibility. + */ +{ + JQUANT_TBL ** qtblptr; + int i; + long temp; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl); + + qtblptr = & cinfo->quant_tbl_ptrs[which_tbl]; + + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo); + + for (i = 0; i < DCTSIZE2; i++) { + temp = ((long) basic_table[i] * scale_factor + 50L) / 100L; + /* limit the values to the valid range */ + if (temp <= 0L) temp = 1L; + if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */ + if (force_baseline && temp > 255L) + temp = 255L; /* limit to baseline range if requested */ + (*qtblptr)->quantval[i] = (UINT16) temp; + } + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*qtblptr)->sent_table = FALSE; +} + + +GLOBAL(void) +jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables + * and a straight percentage-scaling quality scale. In most cases it's better + * to use jpeg_set_quality (below); this entry point is provided for + * applications that insist on a linear percentage scaling. + */ +{ + /* These are the sample quantization tables given in JPEG spec section K.1. + * The spec says that the values given produce "good" quality, and + * when divided by 2, "very good" quality. + */ + static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 + }; + static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + }; + + /* Set up two quantization tables using the specified scaling */ + jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, + scale_factor, force_baseline); + jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, + scale_factor, force_baseline); +} + + +GLOBAL(int) +jpeg_quality_scaling (int quality) +/* Convert a user-specified quality rating to a percentage scaling factor + * for an underlying quantization table, using our recommended scaling curve. + * The input 'quality' factor should be 0 (terrible) to 100 (very good). + */ +{ + /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */ + if (quality <= 0) quality = 1; + if (quality > 100) quality = 100; + + /* The basic table is used as-is (scaling 100) for a quality of 50. + * Qualities 50..100 are converted to scaling percentage 200 - 2*Q; + * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table + * to make all the table entries 1 (hence, minimum quantization loss). + * Qualities 1..50 are converted to scaling percentage 5000/Q. + */ + if (quality < 50) + quality = 5000 / quality; + else + quality = 200 - quality*2; + + return quality; +} + + +GLOBAL(void) +jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline) +/* Set or change the 'quality' (quantization) setting, using default tables. + * This is the standard quality-adjusting entry point for typical user + * interfaces; only those who want detailed control over quantization tables + * would use the preceding three routines directly. + */ +{ + /* Convert user 0-100 rating to percentage scaling */ + quality = jpeg_quality_scaling(quality); + + /* Set up standard quality tables */ + jpeg_set_linear_quality(cinfo, quality, force_baseline); +} + + +/* + * Huffman table setup routines + */ + +LOCAL(void) +add_huff_table (j_compress_ptr cinfo, + JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) +/* Define a Huffman table */ +{ + int nsymbols, len; + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + /* Copy the number-of-symbols-of-each-code-length counts */ + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + + /* Validate the counts. We do this here mainly so we can copy the right + * number of symbols from the val[] array, without risking marching off + * the end of memory. jchuff.c will do a more thorough test later. + */ + nsymbols = 0; + for (len = 1; len <= 16; len++) + nsymbols += bits[len]; + if (nsymbols < 1 || nsymbols > 256) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8)); + + /* Initialize sent_table FALSE so table will be written to JPEG file. */ + (*htblptr)->sent_table = FALSE; +} + + +LOCAL(void) +std_huff_tables (j_compress_ptr cinfo) +/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ +/* IMPORTANT: these are only valid for 8-bit data precision! */ +{ + static const UINT8 bits_dc_luminance[17] = + { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_luminance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_dc_chrominance[17] = + { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + static const UINT8 val_dc_chrominance[] = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + static const UINT8 bits_ac_luminance[17] = + { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; + static const UINT8 val_ac_luminance[] = + { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + static const UINT8 bits_ac_chrominance[17] = + { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; + static const UINT8 val_ac_chrominance[] = + { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa }; + + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0], + bits_dc_luminance, val_dc_luminance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0], + bits_ac_luminance, val_ac_luminance); + add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1], + bits_dc_chrominance, val_dc_chrominance); + add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1], + bits_ac_chrominance, val_ac_chrominance); +} + + +/* + * Default parameter setup for compression. + * + * Applications that don't choose to use this routine must do their + * own setup of all these parameters. Alternately, you can call this + * to establish defaults and then alter parameters selectively. This + * is the recommended approach since, if we add any new parameters, + * your code will still work (they'll be set to reasonable defaults). + */ + +GLOBAL(void) +jpeg_set_defaults (j_compress_ptr cinfo) +{ + int i; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Allocate comp_info array large enough for maximum component count. + * Array is made permanent in case application wants to compress + * multiple images at same param settings. + */ + if (cinfo->comp_info == NULL) + cinfo->comp_info = (jpeg_component_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + MAX_COMPONENTS * SIZEOF(jpeg_component_info)); + + /* Initialize everything not dependent on the color space */ + + cinfo->data_precision = BITS_IN_JSAMPLE; + /* Set up two quantization tables using default quality of 75 */ + jpeg_set_quality(cinfo, 75, TRUE); + /* Set up two Huffman tables */ + std_huff_tables(cinfo); + + /* Initialize default arithmetic coding conditioning */ + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + + /* Default is no multiple-scan output */ + cinfo->scan_info = NULL; + cinfo->num_scans = 0; + + /* Expect normal source image, not raw downsampled data */ + cinfo->raw_data_in = FALSE; + + /* Use Huffman coding, not arithmetic coding, by default */ + cinfo->arith_code = FALSE; + + /* By default, don't do extra passes to optimize entropy coding */ + cinfo->optimize_coding = FALSE; + /* The standard Huffman tables are only valid for 8-bit data precision. + * If the precision is higher, force optimization on so that usable + * tables will be computed. This test can be removed if default tables + * are supplied that are valid for the desired precision. + */ + if (cinfo->data_precision > 8) + cinfo->optimize_coding = TRUE; + + /* By default, use the simpler non-cosited sampling alignment */ + cinfo->CCIR601_sampling = FALSE; + + /* No input smoothing */ + cinfo->smoothing_factor = 0; + + /* DCT algorithm preference */ + cinfo->dct_method = JDCT_DEFAULT; + + /* No restart markers */ + cinfo->restart_interval = 0; + cinfo->restart_in_rows = 0; + + /* Fill in default JFIF marker parameters. Note that whether the marker + * will actually be written is determined by jpeg_set_colorspace. + * + * By default, the library emits JFIF version code 1.01. + * An application that wants to emit JFIF 1.02 extension markers should set + * JFIF_minor_version to 2. We could probably get away with just defaulting + * to 1.02, but there may still be some decoders in use that will complain + * about that; saying 1.01 should minimize compatibility problems. + */ + cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; /* Pixel size is unknown by default */ + cinfo->X_density = 1; /* Pixel aspect ratio is square by default */ + cinfo->Y_density = 1; + + /* Choose JPEG colorspace based on input space, set defaults accordingly */ + + jpeg_default_colorspace(cinfo); +} + + +/* + * Select an appropriate JPEG colorspace for in_color_space. + */ + +GLOBAL(void) +jpeg_default_colorspace (j_compress_ptr cinfo) +{ + switch (cinfo->in_color_space) { + case JCS_GRAYSCALE: + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + break; + case JCS_RGB: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_YCbCr: + jpeg_set_colorspace(cinfo, JCS_YCbCr); + break; + case JCS_CMYK: + jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */ + break; + case JCS_YCCK: + jpeg_set_colorspace(cinfo, JCS_YCCK); + break; + case JCS_UNKNOWN: + jpeg_set_colorspace(cinfo, JCS_UNKNOWN); + break; + default: + ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE); + } +} + + +/* + * Set the JPEG colorspace, and choose colorspace-dependent default values. + */ + +GLOBAL(void) +jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace) +{ + jpeg_component_info * compptr; + int ci; + +#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \ + (compptr = &cinfo->comp_info[index], \ + compptr->component_id = (id), \ + compptr->h_samp_factor = (hsamp), \ + compptr->v_samp_factor = (vsamp), \ + compptr->quant_tbl_no = (quant), \ + compptr->dc_tbl_no = (dctbl), \ + compptr->ac_tbl_no = (actbl) ) + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* For all colorspaces, we use Q and Huff tables 0 for luminance components, + * tables 1 for chrominance components. + */ + + cinfo->jpeg_color_space = colorspace; + + cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */ + cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */ + + switch (colorspace) { + case JCS_GRAYSCALE: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 1; + /* JFIF specifies component ID 1 */ + SET_COMP(0, 1, 1,1, 0, 0,0); + break; + case JCS_RGB: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */ + cinfo->num_components = 3; + SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0); + SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0); + SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0); + break; + case JCS_YCbCr: + cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */ + cinfo->num_components = 3; + /* JFIF specifies component IDs 1,2,3 */ + /* We default to 2x2 subsamples of chrominance */ + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + break; + case JCS_CMYK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */ + cinfo->num_components = 4; + SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0); + SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0); + SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0); + SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0); + break; + case JCS_YCCK: + cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */ + cinfo->num_components = 4; + SET_COMP(0, 1, 2,2, 0, 0,0); + SET_COMP(1, 2, 1,1, 1, 1,1); + SET_COMP(2, 3, 1,1, 1, 1,1); + SET_COMP(3, 4, 2,2, 0, 0,0); + break; + case JCS_UNKNOWN: + cinfo->num_components = cinfo->input_components; + if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + for (ci = 0; ci < cinfo->num_components; ci++) { + SET_COMP(ci, ci, 1,1, 0, 0,0); + } + break; + default: + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + } +} + + +#ifdef C_PROGRESSIVE_SUPPORTED + +LOCAL(jpeg_scan_info *) +fill_a_scan (jpeg_scan_info * scanptr, int ci, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for specified component */ +{ + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_scans (jpeg_scan_info * scanptr, int ncomps, + int Ss, int Se, int Ah, int Al) +/* Support routine: generate one scan for each component */ +{ + int ci; + + for (ci = 0; ci < ncomps; ci++) { + scanptr->comps_in_scan = 1; + scanptr->component_index[0] = ci; + scanptr->Ss = Ss; + scanptr->Se = Se; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } + return scanptr; +} + +LOCAL(jpeg_scan_info *) +fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al) +/* Support routine: generate interleaved DC scan if possible, else N scans */ +{ + int ci; + + if (ncomps <= MAX_COMPS_IN_SCAN) { + /* Single interleaved DC scan */ + scanptr->comps_in_scan = ncomps; + for (ci = 0; ci < ncomps; ci++) + scanptr->component_index[ci] = ci; + scanptr->Ss = scanptr->Se = 0; + scanptr->Ah = Ah; + scanptr->Al = Al; + scanptr++; + } else { + /* Noninterleaved DC scan for each component */ + scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al); + } + return scanptr; +} + + +/* + * Create a recommended progressive-JPEG script. + * cinfo->num_components and cinfo->jpeg_color_space must be correct. + */ + +GLOBAL(void) +jpeg_simple_progression (j_compress_ptr cinfo) +{ + int ncomps = cinfo->num_components; + int nscans; + jpeg_scan_info * scanptr; + + /* Safety check to ensure start_compress not called yet. */ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Figure space needed for script. Calculation must match code below! */ + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + nscans = 10; + } else { + /* All-purpose script for other color spaces. */ + if (ncomps > MAX_COMPS_IN_SCAN) + nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */ + else + nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */ + } + + /* Allocate space for script. + * We need to put it in the permanent pool in case the application performs + * multiple compressions without changing the settings. To avoid a memory + * leak if jpeg_simple_progression is called repeatedly for the same JPEG + * object, we try to re-use previously allocated space, and we allocate + * enough space to handle YCbCr even if initially asked for grayscale. + */ + if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) { + cinfo->script_space_size = MAX(nscans, 10); + cinfo->script_space = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + cinfo->script_space_size * SIZEOF(jpeg_scan_info)); + } + scanptr = cinfo->script_space; + cinfo->scan_info = scanptr; + cinfo->num_scans = nscans; + + if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) { + /* Custom script for YCbCr color images. */ + /* Initial DC scan */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + /* Initial AC scan: get some luma data out in a hurry */ + scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2); + /* Chroma data is too small to be worth expending many scans on */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1); + /* Complete spectral selection for luma AC */ + scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2); + /* Refine next bit of luma AC */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1); + /* Finish DC successive approximation */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + /* Finish AC successive approximation */ + scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0); + scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0); + /* Luma bottom bit comes last since it's usually largest scan */ + scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0); + } else { + /* All-purpose script for other color spaces. */ + /* Successive approximation first pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 0, 1); + scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2); + scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2); + /* Successive approximation second pass */ + scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1); + /* Successive approximation final pass */ + scanptr = fill_dc_scans(scanptr, ncomps, 1, 0); + scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0); + } +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jcphuff.c b/freeimage241/Source/LibJPEG/jcphuff.c new file mode 100644 index 0000000..07f9178 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcphuff.c @@ -0,0 +1,833 @@ +/* + * jcphuff.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy encoding routines for progressive JPEG. + * + * We do not support output suspension in this module, since the library + * currently does not allow multiple-scan files to be written with output + * suspension. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jchuff.h" /* Declarations shared with jchuff.c */ + +#ifdef C_PROGRESSIVE_SUPPORTED + +/* Expanded entropy encoder object for progressive Huffman encoding. */ + +typedef struct { + struct jpeg_entropy_encoder pub; /* public fields */ + + /* Mode flag: TRUE for optimization, FALSE for actual data output */ + boolean gather_statistics; + + /* Bit-level coding status. + * next_output_byte/free_in_buffer are local copies of cinfo->dest fields. + */ + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + INT32 put_buffer; /* current bit-accumulation buffer */ + int put_bits; /* # of bits now in it */ + j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */ + + /* Coding status for DC components */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ + + /* Coding status for AC components */ + int ac_tbl_no; /* the table number of the single component */ + unsigned int EOBRUN; /* run length of EOBs */ + unsigned int BE; /* # of buffered correction bits before MCU */ + char * bit_buffer; /* buffer for correction bits (1 per char) */ + /* packing correction bits tightly would save some space but cost time... */ + + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + int next_restart_num; /* next restart number to write (0-7) */ + + /* Pointers to derived tables (these workspaces have image lifespan). + * Since any one scan codes only DC or only AC, we only need one set + * of tables, not one for DC and one for AC. + */ + c_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + /* Statistics tables for optimization; again, one set is enough */ + long * count_ptrs[NUM_HUFF_TBLS]; +} phuff_entropy_encoder; + +typedef phuff_entropy_encoder * phuff_entropy_ptr; + +/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit + * buffer can hold. Larger sizes may slightly improve compression, but + * 1000 is already well into the realm of overkill. + * The minimum safe size is 64 bits. + */ + +#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */ + +/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32. + * We assume that int right shift is unsigned if INT32 right shift is, + * which should be safe. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS int ishift_temp; +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +/* Forward declarations */ +METHODDEF(boolean) encode_mcu_DC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_first JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_DC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) encode_mcu_AC_refine JPP((j_compress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(void) finish_pass_phuff JPP((j_compress_ptr cinfo)); +METHODDEF(void) finish_pass_gather_phuff JPP((j_compress_ptr cinfo)); + + +/* + * Initialize for a Huffman-compressed scan using progressive JPEG. + */ + +METHODDEF(void) +start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + + entropy->cinfo = cinfo; + entropy->gather_statistics = gather_statistics; + + is_DC_band = (cinfo->Ss == 0); + + /* We assume jcmaster.c already validated the scan parameters. */ + + /* Select execution routines */ + if (cinfo->Ah == 0) { + if (is_DC_band) + entropy->pub.encode_mcu = encode_mcu_DC_first; + else + entropy->pub.encode_mcu = encode_mcu_AC_first; + } else { + if (is_DC_band) + entropy->pub.encode_mcu = encode_mcu_DC_refine; + else { + entropy->pub.encode_mcu = encode_mcu_AC_refine; + /* AC refinement needs a correction bit buffer */ + if (entropy->bit_buffer == NULL) + entropy->bit_buffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + MAX_CORR_BITS * SIZEOF(char)); + } + } + if (gather_statistics) + entropy->pub.finish_pass = finish_pass_gather_phuff; + else + entropy->pub.finish_pass = finish_pass_phuff; + + /* Only DC coefficients may be interleaved, so cinfo->comps_in_scan = 1 + * for AC coefficients. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Initialize DC predictions to 0 */ + entropy->last_dc_val[ci] = 0; + /* Get table index */ + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + entropy->ac_tbl_no = tbl = compptr->ac_tbl_no; + } + if (gather_statistics) { + /* Check for invalid table index */ + /* (make_c_derived_tbl does this in the other path) */ + if (tbl < 0 || tbl >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl); + /* Allocate and zero the statistics tables */ + /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */ + if (entropy->count_ptrs[tbl] == NULL) + entropy->count_ptrs[tbl] = (long *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 257 * SIZEOF(long)); + MEMZERO(entropy->count_ptrs[tbl], 257 * SIZEOF(long)); + } else { + /* Compute derived values for Huffman table */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl, + & entropy->derived_tbls[tbl]); + } + } + + /* Initialize AC stuff */ + entropy->EOBRUN = 0; + entropy->BE = 0; + + /* Initialize bit buffer to empty */ + entropy->put_buffer = 0; + entropy->put_bits = 0; + + /* Initialize restart stuff */ + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num = 0; +} + + +/* Outputting bytes to the file. + * NB: these must be called only when actually outputting, + * that is, entropy->gather_statistics == FALSE. + */ + +/* Emit a byte */ +#define emit_byte(entropy,val) \ + { *(entropy)->next_output_byte++ = (JOCTET) (val); \ + if (--(entropy)->free_in_buffer == 0) \ + dump_buffer(entropy); } + + +LOCAL(void) +dump_buffer (phuff_entropy_ptr entropy) +/* Empty the output buffer; we do not support suspension in this module. */ +{ + struct jpeg_destination_mgr * dest = entropy->cinfo->dest; + + if (! (*dest->empty_output_buffer) (entropy->cinfo)) + ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND); + /* After a successful buffer dump, must reset buffer pointers */ + entropy->next_output_byte = dest->next_output_byte; + entropy->free_in_buffer = dest->free_in_buffer; +} + + +/* Outputting bits to the file */ + +/* Only the right 24 bits of put_buffer are used; the valid bits are + * left-justified in this part. At most 16 bits can be passed to emit_bits + * in one call, and we never retain more than 7 bits in put_buffer + * between calls, so 24 bits are sufficient. + */ + +INLINE +LOCAL(void) +emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size) +/* Emit some bits, unless we are in gather mode */ +{ + /* This routine is heavily used, so it's worth coding tightly. */ + register INT32 put_buffer = (INT32) code; + register int put_bits = entropy->put_bits; + + /* if size is 0, caller used an invalid Huffman table entry */ + if (size == 0) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + if (entropy->gather_statistics) + return; /* do nothing if we're only getting stats */ + + put_buffer &= (((INT32) 1)<put_buffer; /* and merge with old buffer contents */ + + while (put_bits >= 8) { + int c = (int) ((put_buffer >> 16) & 0xFF); + + emit_byte(entropy, c); + if (c == 0xFF) { /* need to stuff a zero byte? */ + emit_byte(entropy, 0); + } + put_buffer <<= 8; + put_bits -= 8; + } + + entropy->put_buffer = put_buffer; /* update variables */ + entropy->put_bits = put_bits; +} + + +LOCAL(void) +flush_bits (phuff_entropy_ptr entropy) +{ + emit_bits(entropy, 0x7F, 7); /* fill any partial byte with ones */ + entropy->put_buffer = 0; /* and reset bit-buffer to empty */ + entropy->put_bits = 0; +} + + +/* + * Emit (or just count) a Huffman symbol. + */ + +INLINE +LOCAL(void) +emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol) +{ + if (entropy->gather_statistics) + entropy->count_ptrs[tbl_no][symbol]++; + else { + c_derived_tbl * tbl = entropy->derived_tbls[tbl_no]; + emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]); + } +} + + +/* + * Emit bits from a correction bit buffer. + */ + +LOCAL(void) +emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart, + unsigned int nbits) +{ + if (entropy->gather_statistics) + return; /* no real work */ + + while (nbits > 0) { + emit_bits(entropy, (unsigned int) (*bufstart), 1); + bufstart++; + nbits--; + } +} + + +/* + * Emit any pending EOBRUN symbol. + */ + +LOCAL(void) +emit_eobrun (phuff_entropy_ptr entropy) +{ + register int temp, nbits; + + if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */ + temp = entropy->EOBRUN; + nbits = 0; + while ((temp >>= 1)) + nbits++; + /* safety check: shouldn't happen given limited correction-bit buffer */ + if (nbits > 14) + ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE); + + emit_symbol(entropy, entropy->ac_tbl_no, nbits << 4); + if (nbits) + emit_bits(entropy, entropy->EOBRUN, nbits); + + entropy->EOBRUN = 0; + + /* Emit any buffered correction bits */ + emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE); + entropy->BE = 0; + } +} + + +/* + * Emit a restart marker & resynchronize predictions. + */ + +LOCAL(void) +emit_restart (phuff_entropy_ptr entropy, int restart_num) +{ + int ci; + + emit_eobrun(entropy); + + if (! entropy->gather_statistics) { + flush_bits(entropy); + emit_byte(entropy, 0xFF); + emit_byte(entropy, JPEG_RST0 + restart_num); + } + + if (entropy->cinfo->Ss == 0) { + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++) + entropy->last_dc_val[ci] = 0; + } else { + /* Re-initialize all AC-related fields to 0 */ + entropy->EOBRUN = 0; + entropy->BE = 0; + } +} + + +/* + * MCU encoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + int blkn, ci; + int Al = cinfo->Al; + JBLOCKROW block; + jpeg_component_info * compptr; + ISHIFT_TEMPS + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + + /* Compute the DC value after the required point transform by Al. + * This is simply an arithmetic right shift. + */ + temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al); + + /* DC differences are figured on the point-transformed values. */ + temp = temp2 - entropy->last_dc_val[ci]; + entropy->last_dc_val[ci] = temp2; + + /* Encode the DC coefficient difference per section G.1.2.1 */ + temp2 = temp; + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + /* For a negative input, want temp2 = bitwise complement of abs(input) */ + /* This code assumes we are on a two's complement machine */ + temp2--; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 0; + while (temp) { + nbits++; + temp >>= 1; + } + /* Check for out-of-range coefficient values. + * Since we're encoding a difference, the range limit is twice as much. + */ + if (nbits > MAX_COEF_BITS+1) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit the Huffman-coded symbol for the number of bits */ + emit_symbol(entropy, compptr->dc_tbl_no, nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + if (nbits) /* emit_bits rejects calls with size 0 */ + emit_bits(entropy, (unsigned int) temp2, nbits); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp, temp2; + register int nbits; + register int r, k; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */ + + r = 0; /* r = run length of zeros */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = (*block)[jpeg_natural_order[k]]) == 0) { + r++; + continue; + } + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value; so the code is + * interwoven with finding the abs value (temp) and output bits (temp2). + */ + if (temp < 0) { + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ + temp2 = ~temp; + } else { + temp >>= Al; /* apply the point transform */ + temp2 = temp; + } + /* Watch out for case that nonzero coef is zero after point transform */ + if (temp == 0) { + r++; + continue; + } + + /* Emit any pending EOBRUN */ + if (entropy->EOBRUN > 0) + emit_eobrun(entropy); + /* if run length > 15, must emit special run-length-16 codes (0xF0) */ + while (r > 15) { + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + } + + /* Find the number of bits needed for the magnitude of the coefficient */ + nbits = 1; /* there must be at least one 1 bit */ + while ((temp >>= 1)) + nbits++; + /* Check for out-of-range coefficient values */ + if (nbits > MAX_COEF_BITS) + ERREXIT(cinfo, JERR_BAD_DCT_COEF); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits); + + /* Emit that number of bits of the value, if positive, */ + /* or the complement of its magnitude, if negative. */ + emit_bits(entropy, (unsigned int) temp2, nbits); + + r = 0; /* reset zero run length */ + } + + if (r > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + if (entropy->EOBRUN == 0x7FFF) + emit_eobrun(entropy); /* force it out to avoid overflow */ + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp; + int blkn; + int Al = cinfo->Al; + JBLOCKROW block; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data blocks */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* We simply emit the Al'th bit of the DC coefficient value. */ + temp = (*block)[0]; + emit_bits(entropy, (unsigned int) (temp >> Al), 1); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * MCU encoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + register int temp; + register int r, k; + int EOB; + char *BR_buffer; + unsigned int BR; + int Se = cinfo->Se; + int Al = cinfo->Al; + JBLOCKROW block; + int absvalues[DCTSIZE2]; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Emit restart marker if needed */ + if (cinfo->restart_interval) + if (entropy->restarts_to_go == 0) + emit_restart(entropy, entropy->next_restart_num); + + /* Encode the MCU data block */ + block = MCU_data[0]; + + /* It is convenient to make a pre-pass to determine the transformed + * coefficients' absolute values and the EOB position. + */ + EOB = 0; + for (k = cinfo->Ss; k <= Se; k++) { + temp = (*block)[jpeg_natural_order[k]]; + /* We must apply the point transform by Al. For AC coefficients this + * is an integer division with rounding towards 0. To do this portably + * in C, we shift after obtaining the absolute value. + */ + if (temp < 0) + temp = -temp; /* temp is abs value of input */ + temp >>= Al; /* apply the point transform */ + absvalues[k] = temp; /* save abs value for main pass */ + if (temp == 1) + EOB = k; /* EOB = index of last newly-nonzero coef */ + } + + /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */ + + r = 0; /* r = run length of zeros */ + BR = 0; /* BR = count of buffered bits added now */ + BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */ + + for (k = cinfo->Ss; k <= Se; k++) { + if ((temp = absvalues[k]) == 0) { + r++; + continue; + } + + /* Emit any required ZRLs, but not if they can be folded into EOB */ + while (r > 15 && k <= EOB) { + /* emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + /* Emit ZRL */ + emit_symbol(entropy, entropy->ac_tbl_no, 0xF0); + r -= 16; + /* Emit buffered correction bits that must be associated with ZRL */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + } + + /* If the coef was previously nonzero, it only needs a correction bit. + * NOTE: a straight translation of the spec's figure G.7 would suggest + * that we also need to test r > 15. But if r > 15, we can only get here + * if k > EOB, which implies that this coefficient is not 1. + */ + if (temp > 1) { + /* The correction bit is the next bit of the absolute value. */ + BR_buffer[BR++] = (char) (temp & 1); + continue; + } + + /* Emit any pending EOBRUN and the BE correction bits */ + emit_eobrun(entropy); + + /* Count/emit Huffman symbol for run length / number of bits */ + emit_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1); + + /* Emit output bit for newly-nonzero coef */ + temp = ((*block)[jpeg_natural_order[k]] < 0) ? 0 : 1; + emit_bits(entropy, (unsigned int) temp, 1); + + /* Emit buffered correction bits that must be associated with this code */ + emit_buffered_bits(entropy, BR_buffer, BR); + BR_buffer = entropy->bit_buffer; /* BE bits are gone now */ + BR = 0; + r = 0; /* reset zero run length */ + } + + if (r > 0 || BR > 0) { /* If there are trailing zeroes, */ + entropy->EOBRUN++; /* count an EOB */ + entropy->BE += BR; /* concat my correction bits to older ones */ + /* We force out the EOB if we risk either: + * 1. overflow of the EOB counter; + * 2. overflow of the correction bit buffer during the next MCU. + */ + if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1)) + emit_eobrun(entropy); + } + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; + + /* Update restart-interval state too */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) { + entropy->restarts_to_go = cinfo->restart_interval; + entropy->next_restart_num++; + entropy->next_restart_num &= 7; + } + entropy->restarts_to_go--; + } + + return TRUE; +} + + +/* + * Finish up at the end of a Huffman-compressed progressive scan. + */ + +METHODDEF(void) +finish_pass_phuff (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + + entropy->next_output_byte = cinfo->dest->next_output_byte; + entropy->free_in_buffer = cinfo->dest->free_in_buffer; + + /* Flush out any buffered data */ + emit_eobrun(entropy); + flush_bits(entropy); + + cinfo->dest->next_output_byte = entropy->next_output_byte; + cinfo->dest->free_in_buffer = entropy->free_in_buffer; +} + + +/* + * Finish up a statistics-gathering pass and create the new Huffman tables. + */ + +METHODDEF(void) +finish_pass_gather_phuff (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band; + int ci, tbl; + jpeg_component_info * compptr; + JHUFF_TBL **htblptr; + boolean did[NUM_HUFF_TBLS]; + + /* Flush out buffered data (all we care about is counting the EOB symbol) */ + emit_eobrun(entropy); + + is_DC_band = (cinfo->Ss == 0); + + /* It's important not to apply jpeg_gen_optimal_table more than once + * per table, because it clobbers the input frequency counts! + */ + MEMZERO(did, SIZEOF(did)); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + if (is_DC_band) { + if (cinfo->Ah != 0) /* DC refinement needs no table */ + continue; + tbl = compptr->dc_tbl_no; + } else { + tbl = compptr->ac_tbl_no; + } + if (! did[tbl]) { + if (is_DC_band) + htblptr = & cinfo->dc_huff_tbl_ptrs[tbl]; + else + htblptr = & cinfo->ac_huff_tbl_ptrs[tbl]; + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[tbl]); + did[tbl] = TRUE; + } + } +} + + +/* + * Module initialization routine for progressive Huffman entropy encoding. + */ + +GLOBAL(void) +jinit_phuff_encoder (j_compress_ptr cinfo) +{ + phuff_entropy_ptr entropy; + int i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_encoder)); + cinfo->entropy = (struct jpeg_entropy_encoder *) entropy; + entropy->pub.start_pass = start_pass_phuff; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + entropy->count_ptrs[i] = NULL; + } + entropy->bit_buffer = NULL; /* needed only in AC refinement scan */ +} + +#endif /* C_PROGRESSIVE_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jcprepct.c b/freeimage241/Source/LibJPEG/jcprepct.c new file mode 100644 index 0000000..fa93333 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcprepct.c @@ -0,0 +1,354 @@ +/* + * jcprepct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the compression preprocessing controller. + * This controller manages the color conversion, downsampling, + * and edge expansion steps. + * + * Most of the complexity here is associated with buffering input rows + * as required by the downsampler. See the comments at the head of + * jcsample.c for the downsampler's needs. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* At present, jcsample.c can request context rows only for smoothing. + * In the future, we might also need context rows for CCIR601 sampling + * or other more-complex downsampling procedures. The code to support + * context rows should be compiled only if needed. + */ +#ifdef INPUT_SMOOTHING_SUPPORTED +#define CONTEXT_ROWS_SUPPORTED +#endif + + +/* + * For the simple (no-context-row) case, we just need to buffer one + * row group's worth of pixels for the downsampling step. At the bottom of + * the image, we pad to a full row group by replicating the last pixel row. + * The downsampler's last output row is then replicated if needed to pad + * out to a full iMCU row. + * + * When providing context rows, we must buffer three row groups' worth of + * pixels. Three row groups are physically allocated, but the row pointer + * arrays are made five row groups high, with the extra pointers above and + * below "wrapping around" to point to the last and first real row groups. + * This allows the downsampler to access the proper context rows. + * At the top and bottom of the image, we create dummy context rows by + * copying the first or last real pixel row. This copying could be avoided + * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the + * trouble on the compression side. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_prep_controller pub; /* public fields */ + + /* Downsampling input buffer. This buffer holds color-converted data + * until we have enough to do a downsample step. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + JDIMENSION rows_to_go; /* counts rows remaining in source image */ + int next_buf_row; /* index of next row to store in color_buf */ + +#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */ + int this_row_group; /* starting row index of group to process */ + int next_buf_stop; /* downsample when we reach this index */ +#endif +} my_prep_controller; + +typedef my_prep_controller * my_prep_ptr; + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + + if (pass_mode != JBUF_PASS_THRU) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Initialize total-height counter for detecting bottom of image */ + prep->rows_to_go = cinfo->image_height; + /* Mark the conversion buffer empty */ + prep->next_buf_row = 0; +#ifdef CONTEXT_ROWS_SUPPORTED + /* Preset additional state variables for context mode. + * These aren't used in non-context mode, so we needn't test which mode. + */ + prep->this_row_group = 0; + /* Set next_buf_stop to stop after two row groups have been read in. */ + prep->next_buf_stop = 2 * cinfo->max_v_samp_factor; +#endif +} + + +/* + * Expand an image vertically from height input_rows to height output_rows, + * by duplicating the bottom row. + */ + +LOCAL(void) +expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols, + int input_rows, int output_rows) +{ + register int row; + + for (row = input_rows; row < output_rows; row++) { + jcopy_sample_rows(image_data, input_rows-1, image_data, row, + 1, num_cols); + } +} + + +/* + * Process some data in the simple no-context case. + * + * Preprocessor output data is counted in "row groups". A row group + * is defined to be v_samp_factor sample rows of each component. + * Downsampling will produce this much data from each max_v_samp_factor + * input rows. + */ + +METHODDEF(void) +pre_process_data (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + JDIMENSION inrows; + jpeg_component_info * compptr; + + while (*in_row_ctr < in_rows_avail && + *out_row_group_ctr < out_row_groups_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = cinfo->max_v_samp_factor - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + /* If at bottom of image, pad to fill the conversion buffer. */ + if (prep->rows_to_go == 0 && + prep->next_buf_row < cinfo->max_v_samp_factor) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, cinfo->max_v_samp_factor); + } + prep->next_buf_row = cinfo->max_v_samp_factor; + } + /* If we've filled the conversion buffer, empty it. */ + if (prep->next_buf_row == cinfo->max_v_samp_factor) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, (JDIMENSION) 0, + output_buf, *out_row_group_ctr); + prep->next_buf_row = 0; + (*out_row_group_ctr)++; + } + /* If at bottom of image, pad the output to a full iMCU height. + * Note we assume the caller is providing a one-iMCU-height output buffer! + */ + if (prep->rows_to_go == 0 && + *out_row_group_ctr < out_row_groups_avail) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + expand_bottom_edge(output_buf[ci], + compptr->width_in_blocks * DCTSIZE, + (int) (*out_row_group_ctr * compptr->v_samp_factor), + (int) (out_row_groups_avail * compptr->v_samp_factor)); + } + *out_row_group_ctr = out_row_groups_avail; + break; /* can exit outer loop without test */ + } + } +} + + +#ifdef CONTEXT_ROWS_SUPPORTED + +/* + * Process some data in the context case. + */ + +METHODDEF(void) +pre_process_context (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int numrows, ci; + int buf_height = cinfo->max_v_samp_factor * 3; + JDIMENSION inrows; + + while (*out_row_group_ctr < out_row_groups_avail) { + if (*in_row_ctr < in_rows_avail) { + /* Do color conversion to fill the conversion buffer. */ + inrows = in_rows_avail - *in_row_ctr; + numrows = prep->next_buf_stop - prep->next_buf_row; + numrows = (int) MIN((JDIMENSION) numrows, inrows); + (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, + prep->color_buf, + (JDIMENSION) prep->next_buf_row, + numrows); + /* Pad at top of image, if first time through */ + if (prep->rows_to_go == cinfo->image_height) { + for (ci = 0; ci < cinfo->num_components; ci++) { + int row; + for (row = 1; row <= cinfo->max_v_samp_factor; row++) { + jcopy_sample_rows(prep->color_buf[ci], 0, + prep->color_buf[ci], -row, + 1, cinfo->image_width); + } + } + } + *in_row_ctr += numrows; + prep->next_buf_row += numrows; + prep->rows_to_go -= numrows; + } else { + /* Return for more data, unless we are at the bottom of the image. */ + if (prep->rows_to_go != 0) + break; + /* When at bottom of image, pad to fill the conversion buffer. */ + if (prep->next_buf_row < prep->next_buf_stop) { + for (ci = 0; ci < cinfo->num_components; ci++) { + expand_bottom_edge(prep->color_buf[ci], cinfo->image_width, + prep->next_buf_row, prep->next_buf_stop); + } + prep->next_buf_row = prep->next_buf_stop; + } + } + /* If we've gotten enough data, downsample a row group. */ + if (prep->next_buf_row == prep->next_buf_stop) { + (*cinfo->downsample->downsample) (cinfo, + prep->color_buf, + (JDIMENSION) prep->this_row_group, + output_buf, *out_row_group_ctr); + (*out_row_group_ctr)++; + /* Advance pointers with wraparound as necessary. */ + prep->this_row_group += cinfo->max_v_samp_factor; + if (prep->this_row_group >= buf_height) + prep->this_row_group = 0; + if (prep->next_buf_row >= buf_height) + prep->next_buf_row = 0; + prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor; + } + } +} + + +/* + * Create the wrapped-around downsampling input buffer needed for context mode. + */ + +LOCAL(void) +create_context_buffer (j_compress_ptr cinfo) +{ + my_prep_ptr prep = (my_prep_ptr) cinfo->prep; + int rgroup_height = cinfo->max_v_samp_factor; + int ci, i; + jpeg_component_info * compptr; + JSAMPARRAY true_buffer, fake_buffer; + + /* Grab enough space for fake row pointers for all the components; + * we need five row groups' worth of pointers for each component. + */ + fake_buffer = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (cinfo->num_components * 5 * rgroup_height) * + SIZEOF(JSAMPROW)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate the actual buffer space (3 row groups) for this component. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + true_buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) (3 * rgroup_height)); + /* Copy true buffer row pointers into the middle of the fake row array */ + MEMCOPY(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * SIZEOF(JSAMPROW)); + /* Fill in the above and below wraparound pointers */ + for (i = 0; i < rgroup_height; i++) { + fake_buffer[i] = true_buffer[2 * rgroup_height + i]; + fake_buffer[4 * rgroup_height + i] = true_buffer[i]; + } + prep->color_buf[ci] = fake_buffer + rgroup_height; + fake_buffer += 5 * rgroup_height; /* point to space for next component */ + } +} + +#endif /* CONTEXT_ROWS_SUPPORTED */ + + +/* + * Initialize preprocessing controller. + */ + +GLOBAL(void) +jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer) +{ + my_prep_ptr prep; + int ci; + jpeg_component_info * compptr; + + if (need_full_buffer) /* safety check */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + prep = (my_prep_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_prep_controller)); + cinfo->prep = (struct jpeg_c_prep_controller *) prep; + prep->pub.start_pass = start_pass_prep; + + /* Allocate the color conversion buffer. + * We make the buffer wide enough to allow the downsampler to edge-expand + * horizontally within the buffer, if it so chooses. + */ + if (cinfo->downsample->need_context_rows) { + /* Set up to provide context rows */ +#ifdef CONTEXT_ROWS_SUPPORTED + prep->pub.pre_process_data = pre_process_context; + create_context_buffer(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* No context, just make it tall enough for one row group */ + prep->pub.pre_process_data = pre_process_data; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + prep->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (((long) compptr->width_in_blocks * DCTSIZE * + cinfo->max_h_samp_factor) / compptr->h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/freeimage241/Source/LibJPEG/jcsample.c b/freeimage241/Source/LibJPEG/jcsample.c new file mode 100644 index 0000000..212ec87 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jcsample.c @@ -0,0 +1,519 @@ +/* + * jcsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains downsampling routines. + * + * Downsampling input data is counted in "row groups". A row group + * is defined to be max_v_samp_factor pixel rows of each component, + * from which the downsampler produces v_samp_factor sample rows. + * A single row group is processed in each call to the downsampler module. + * + * The downsampler is responsible for edge-expansion of its output data + * to fill an integral number of DCT blocks horizontally. The source buffer + * may be modified if it is helpful for this purpose (the source buffer is + * allocated wide enough to correspond to the desired output width). + * The caller (the prep controller) is responsible for vertical padding. + * + * The downsampler may request "context rows" by setting need_context_rows + * during startup. In this case, the input arrays will contain at least + * one row group's worth of pixels above and below the passed-in data; + * the caller will create dummy rows at image top and bottom by replicating + * the first or last real pixel row. + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + * + * The downsampling algorithm used here is a simple average of the source + * pixels covered by the output pixel. The hi-falutin sampling literature + * refers to this as a "box filter". In general the characteristics of a box + * filter are not very good, but for the specific cases we normally use (1:1 + * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not + * nearly so bad. If you intend to use other sampling ratios, you'd be well + * advised to improve this code. + * + * A simple input-smoothing capability is provided. This is mainly intended + * for cleaning up color-dithered GIF input files (if you find it inadequate, + * we suggest using an external filtering program such as pnmconvol). When + * enabled, each input pixel P is replaced by a weighted sum of itself and its + * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, + * where SF = (smoothing_factor / 1024). + * Currently, smoothing is only supported for 2h2v sampling factors. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to downsample a single component */ +typedef JMETHOD(void, downsample1_ptr, + (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data)); + +/* Private subobject */ + +typedef struct { + struct jpeg_downsampler pub; /* public fields */ + + /* Downsampling method pointers, one per component */ + downsample1_ptr methods[MAX_COMPONENTS]; +} my_downsampler; + +typedef my_downsampler * my_downsample_ptr; + + +/* + * Initialize for a downsampling pass. + */ + +METHODDEF(void) +start_pass_downsample (j_compress_ptr cinfo) +{ + /* no work for now */ +} + + +/* + * Expand a component horizontally from width input_cols to width output_cols, + * by duplicating the rightmost samples. + */ + +LOCAL(void) +expand_right_edge (JSAMPARRAY image_data, int num_rows, + JDIMENSION input_cols, JDIMENSION output_cols) +{ + register JSAMPROW ptr; + register JSAMPLE pixval; + register int count; + int row; + int numcols = (int) (output_cols - input_cols); + + if (numcols > 0) { + for (row = 0; row < num_rows; row++) { + ptr = image_data[row] + input_cols; + pixval = ptr[-1]; /* don't need GETJSAMPLE() here */ + for (count = numcols; count > 0; count--) + *ptr++ = pixval; + } + } +} + + +/* + * Do downsampling for a whole row group (all components). + * + * In this version we simply downsample each component independently. + */ + +METHODDEF(void) +sep_downsample (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, JDIMENSION out_row_group_index) +{ + my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample; + int ci; + jpeg_component_info * compptr; + JSAMPARRAY in_ptr, out_ptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + in_ptr = input_buf[ci] + in_row_index; + out_ptr = output_buf[ci] + (out_row_group_index * compptr->v_samp_factor); + (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr); + } +} + + +/* + * Downsample pixel values of a single component. + * One row group is processed per call. + * This version handles arbitrary integral sampling ratios, without smoothing. + * Note that this version is not actually used for customary sampling ratios. + */ + +METHODDEF(void) +int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v; + JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */ + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + JSAMPROW inptr, outptr; + INT32 outvalue; + + h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor; + v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor; + numpix = h_expand * v_expand; + numpix2 = numpix/2; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * h_expand); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + for (outcol = 0, outcol_h = 0; outcol < output_cols; + outcol++, outcol_h += h_expand) { + outvalue = 0; + for (v = 0; v < v_expand; v++) { + inptr = input_data[inrow+v] + outcol_h; + for (h = 0; h < h_expand; h++) { + outvalue += (INT32) GETJSAMPLE(*inptr++); + } + } + *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix); + } + inrow += v_expand; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * without smoothing. + */ + +METHODDEF(void) +fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + /* Copy the data */ + jcopy_sample_rows(input_data, 0, output_data, 0, + cinfo->max_v_samp_factor, cinfo->image_width); + /* Edge-expand */ + expand_right_edge(output_data, cinfo->max_v_samp_factor, + cinfo->image_width, compptr->width_in_blocks * DCTSIZE); +} + + +/* + * Downsample pixel values of a single component. + * This version handles the common case of 2:1 horizontal and 1:1 vertical, + * without smoothing. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + bias = 0; /* bias = 0,1,0,1,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1]) + + bias) >> 1); + bias ^= 1; /* 0=>1, 1=>0 */ + inptr += 2; + } + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * without smoothing. + */ + +METHODDEF(void) +h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION outcol; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr0, inptr1, outptr; + register int bias; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data, cinfo->max_v_samp_factor, + cinfo->image_width, output_cols * 2); + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + bias = 1; /* bias = 1,2,1,2,... for successive samples */ + for (outcol = 0; outcol < output_cols; outcol++) { + *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]) + + bias) >> 2); + bias ^= 3; /* 1=>2, 2=>1 */ + inptr0 += 2; inptr1 += 2; + } + inrow += 2; + } +} + + +#ifdef INPUT_SMOOTHING_SUPPORTED + +/* + * Downsample pixel values of a single component. + * This version handles the standard case of 2:1 horizontal and 2:1 vertical, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int inrow, outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols * 2); + + /* We don't bother to form the individual "smoothed" input pixel values; + * we can directly compute the output which is the average of the four + * smoothed values. Each of the four member pixels contributes a fraction + * (1-8*SF) to its own smoothed image and a fraction SF to each of the three + * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final + * output. The four corner-adjacent neighbor pixels contribute a fraction + * SF to just one smoothed pixel, or SF/4 to the final output; while the + * eight edge-adjacent neighbors contribute SF to each of two smoothed + * pixels, or SF/2 overall. In order to use integer arithmetic, these + * factors are scaled by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ + neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */ + + inrow = 0; + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr0 = input_data[inrow]; + inptr1 = input_data[inrow+1]; + above_ptr = input_data[inrow-1]; + below_ptr = input_data[inrow+2]; + + /* Special case for first column: pretend column -1 is same as column 0 */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]); + neighsum += neighsum; + neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + /* sum of pixels directly mapped to this output element */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + /* sum of edge-neighbor pixels */ + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]); + /* The edge-neighbors count twice as much as corner-neighbors */ + neighsum += neighsum; + /* Add in the corner-neighbors */ + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]); + /* form final output scaled up by 2^16 */ + membersum = membersum * memberscale + neighsum * neighscale; + /* round, descale and output it */ + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]); + neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) + + GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) + + GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]); + neighsum += neighsum; + neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) + + GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]); + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + inrow += 2; + } +} + + +/* + * Downsample pixel values of a single component. + * This version handles the special case of a full-size component, + * with smoothing. One row of context is required. + */ + +METHODDEF(void) +fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr, + JSAMPARRAY input_data, JSAMPARRAY output_data) +{ + int outrow; + JDIMENSION colctr; + JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE; + register JSAMPROW inptr, above_ptr, below_ptr, outptr; + INT32 membersum, neighsum, memberscale, neighscale; + int colsum, lastcolsum, nextcolsum; + + /* Expand input data enough to let all the output samples be generated + * by the standard loop. Special-casing padded output would be more + * efficient. + */ + expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, + cinfo->image_width, output_cols); + + /* Each of the eight neighbor pixels contributes a fraction SF to the + * smoothed pixel, while the main pixel contributes (1-8*SF). In order + * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. + * Also recall that SF = smoothing_factor / 1024. + */ + + memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ + neighscale = cinfo->smoothing_factor * 64; /* scaled SF */ + + for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) { + outptr = output_data[outrow]; + inptr = input_data[outrow]; + above_ptr = input_data[outrow-1]; + below_ptr = input_data[outrow+1]; + + /* Special case for first column */ + colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) + + GETJSAMPLE(*inptr); + membersum = GETJSAMPLE(*inptr++); + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = colsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + + for (colctr = output_cols - 2; colctr > 0; colctr--) { + membersum = GETJSAMPLE(*inptr++); + above_ptr++; below_ptr++; + nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) + + GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + nextcolsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16); + lastcolsum = colsum; colsum = nextcolsum; + } + + /* Special case for last column */ + membersum = GETJSAMPLE(*inptr); + neighsum = lastcolsum + (colsum - membersum) + colsum; + membersum = membersum * memberscale + neighsum * neighscale; + *outptr = (JSAMPLE) ((membersum + 32768) >> 16); + + } +} + +#endif /* INPUT_SMOOTHING_SUPPORTED */ + + +/* + * Module initialization routine for downsampling. + * Note that we must select a routine for each component. + */ + +GLOBAL(void) +jinit_downsampler (j_compress_ptr cinfo) +{ + my_downsample_ptr downsample; + int ci; + jpeg_component_info * compptr; + boolean smoothok = TRUE; + + downsample = (my_downsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_downsampler)); + cinfo->downsample = (struct jpeg_downsampler *) downsample; + downsample->pub.start_pass = start_pass_downsample; + downsample->pub.downsample = sep_downsample; + downsample->pub.need_context_rows = FALSE; + + if (cinfo->CCIR601_sampling) + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* Verify we can handle the sampling factors, and set up method pointers */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = fullsize_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = fullsize_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor == cinfo->max_v_samp_factor) { + smoothok = FALSE; + downsample->methods[ci] = h2v1_downsample; + } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && + compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor) { + downsample->methods[ci] = h2v2_smooth_downsample; + downsample->pub.need_context_rows = TRUE; + } else +#endif + downsample->methods[ci] = h2v2_downsample; + } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && + (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) { + smoothok = FALSE; + downsample->methods[ci] = int_downsample; + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + } + +#ifdef INPUT_SMOOTHING_SUPPORTED + if (cinfo->smoothing_factor && !smoothok) + TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL); +#endif +} diff --git a/freeimage241/Source/LibJPEG/jctrans.c b/freeimage241/Source/LibJPEG/jctrans.c new file mode 100644 index 0000000..0e6d707 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jctrans.c @@ -0,0 +1,388 @@ +/* + * jctrans.c + * + * Copyright (C) 1995-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding compression, + * that is, writing raw DCT coefficient arrays to an output JPEG file. + * The routines in jcapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transencode_master_selection + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); +LOCAL(void) transencode_coef_controller + JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)); + + +/* + * Compression initialization for writing raw-coefficient data. + * Before calling this, all parameters and a data destination must be set up. + * Call jpeg_finish_compress() to actually write the data. + * + * The number of passed virtual arrays must match cinfo->num_components. + * Note that the virtual arrays need not be filled or even realized at + * the time write_coefficients is called; indeed, if the virtual arrays + * were requested from this compression object's memory manager, they + * typically will be realized during this routine and filled afterwards. + */ + +GLOBAL(void) +jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays) +{ + if (cinfo->global_state != CSTATE_START) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Mark all tables to be written */ + jpeg_suppress_tables(cinfo, FALSE); + /* (Re)initialize error mgr and destination modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->dest->init_destination) (cinfo); + /* Perform master selection of active modules */ + transencode_master_selection(cinfo, coef_arrays); + /* Wait for jpeg_finish_compress() call */ + cinfo->next_scanline = 0; /* so jpeg_write_marker works */ + cinfo->global_state = CSTATE_WRCOEFS; +} + + +/* + * Initialize the compression object with default parameters, + * then copy from the source object all parameters needed for lossless + * transcoding. Parameters that can be varied without loss (such as + * scan script and Huffman optimization) are left in their default states. + */ + +GLOBAL(void) +jpeg_copy_critical_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo) +{ + JQUANT_TBL ** qtblptr; + jpeg_component_info *incomp, *outcomp; + JQUANT_TBL *c_quant, *slot_quant; + int tblno, ci, coefi; + + /* Safety check to ensure start_compress not called yet. */ + if (dstinfo->global_state != CSTATE_START) + ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state); + /* Copy fundamental image dimensions */ + dstinfo->image_width = srcinfo->image_width; + dstinfo->image_height = srcinfo->image_height; + dstinfo->input_components = srcinfo->num_components; + dstinfo->in_color_space = srcinfo->jpeg_color_space; + /* Initialize all parameters to default values */ + jpeg_set_defaults(dstinfo); + /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB. + * Fix it to get the right header markers for the image colorspace. + */ + jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space); + dstinfo->data_precision = srcinfo->data_precision; + dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; + /* Copy the source's quantization tables. */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + if (srcinfo->quant_tbl_ptrs[tblno] != NULL) { + qtblptr = & dstinfo->quant_tbl_ptrs[tblno]; + if (*qtblptr == NULL) + *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo); + MEMCOPY((*qtblptr)->quantval, + srcinfo->quant_tbl_ptrs[tblno]->quantval, + SIZEOF((*qtblptr)->quantval)); + (*qtblptr)->sent_table = FALSE; + } + } + /* Copy the source's per-component info. + * Note we assume jpeg_set_defaults has allocated the dest comp_info array. + */ + dstinfo->num_components = srcinfo->num_components; + if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS) + ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components, + MAX_COMPONENTS); + for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info; + ci < dstinfo->num_components; ci++, incomp++, outcomp++) { + outcomp->component_id = incomp->component_id; + outcomp->h_samp_factor = incomp->h_samp_factor; + outcomp->v_samp_factor = incomp->v_samp_factor; + outcomp->quant_tbl_no = incomp->quant_tbl_no; + /* Make sure saved quantization table for component matches the qtable + * slot. If not, the input file re-used this qtable slot. + * IJG encoder currently cannot duplicate this. + */ + tblno = outcomp->quant_tbl_no; + if (tblno < 0 || tblno >= NUM_QUANT_TBLS || + srcinfo->quant_tbl_ptrs[tblno] == NULL) + ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno); + slot_quant = srcinfo->quant_tbl_ptrs[tblno]; + c_quant = incomp->quant_table; + if (c_quant != NULL) { + for (coefi = 0; coefi < DCTSIZE2; coefi++) { + if (c_quant->quantval[coefi] != slot_quant->quantval[coefi]) + ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno); + } + } + /* Note: we do not copy the source's Huffman table assignments; + * instead we rely on jpeg_set_colorspace to have made a suitable choice. + */ + } + /* Also copy JFIF version and resolution information, if available. + * Strictly speaking this isn't "critical" info, but it's nearly + * always appropriate to copy it if available. In particular, + * if the application chooses to copy JFIF 1.02 extension markers from + * the source file, we need to copy the version to make sure we don't + * emit a file that has 1.02 extensions but a claimed version of 1.01. + * We will *not*, however, copy version info from mislabeled "2.01" files. + */ + if (srcinfo->saw_JFIF_marker) { + if (srcinfo->JFIF_major_version == 1) { + dstinfo->JFIF_major_version = srcinfo->JFIF_major_version; + dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version; + } + dstinfo->density_unit = srcinfo->density_unit; + dstinfo->X_density = srcinfo->X_density; + dstinfo->Y_density = srcinfo->Y_density; + } +} + + +/* + * Master selection of compression modules for transcoding. + * This substitutes for jcinit.c's initialization of the full compressor. + */ + +LOCAL(void) +transencode_master_selection (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + /* Although we don't actually use input_components for transcoding, + * jcmaster.c's initial_setup will complain if input_components is 0. + */ + cinfo->input_components = 1; + /* Initialize master control (includes parameter checking/processing) */ + jinit_c_master_control(cinfo, TRUE /* transcode only */); + + /* Entropy encoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef C_PROGRESSIVE_SUPPORTED + jinit_phuff_encoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_encoder(cinfo); + } + + /* We need a special coefficient buffer controller. */ + transencode_coef_controller(cinfo, coef_arrays); + + jinit_marker_writer(cinfo); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Write the datastream header (SOI, JFIF) immediately. + * Frame and scan headers are postponed till later. + * This lets application insert special markers after the SOI. + */ + (*cinfo->marker->write_file_header) (cinfo); +} + + +/* + * The rest of this file is a special implementation of the coefficient + * buffer controller. This is similar to jccoefct.c, but it handles only + * output from presupplied virtual arrays. Furthermore, we generate any + * dummy padding blocks on-the-fly rather than expecting them to be present + * in the arrays. + */ + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_c_coef_controller pub; /* public fields */ + + JDIMENSION iMCU_row_num; /* iMCU row # within image */ + JDIMENSION mcu_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* Virtual block array for each component. */ + jvirt_barray_ptr * whole_image; + + /* Workspace for constructing dummy blocks at right/bottom edges. */ + JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU]; +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + + +LOCAL(void) +start_iMCU_row (j_compress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->mcu_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + if (pass_mode != JBUF_CRANK_DEST) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + coef->iMCU_row_num = 0; + start_iMCU_row(cinfo); +} + + +/* + * Process some data. + * We process the equivalent of one fully interleaved MCU row ("iMCU" row) + * per call, ie, v_samp_factor block rows for each component in the scan. + * The data is obtained from the virtual arrays and fed to the entropy coder. + * Returns TRUE if the iMCU row is completed, FALSE if suspended. + * + * NB: input_buf is ignored; it is likely to be a NULL pointer. + */ + +METHODDEF(boolean) +compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, blockcnt; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + coef->iMCU_row_num * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (coef->iMCU_row_num < last_iMCU_row || + yindex+yoffset < compptr->last_row_height) { + /* Fill in pointers to real blocks in this row */ + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < blockcnt; xindex++) + MCU_buffer[blkn++] = buffer_ptr++; + } else { + /* At bottom of image, need a whole row of dummy blocks */ + xindex = 0; + } + /* Fill in any dummy blocks needed in this row. + * Dummy blocks are filled in the same way as in jccoefct.c: + * all zeroes in the AC entries, DC entries equal to previous + * block's DC value. The init routine has already zeroed the + * AC entries, so we need only set the DC entries correctly. + */ + for (; xindex < compptr->MCU_width; xindex++) { + MCU_buffer[blkn] = coef->dummy_buffer[blkn]; + MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0]; + blkn++; + } + } + } + /* Try to write the MCU. */ + if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->mcu_ctr = MCU_col_num; + return FALSE; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->mcu_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + coef->iMCU_row_num++; + start_iMCU_row(cinfo); + return TRUE; +} + + +/* + * Initialize coefficient buffer controller. + * + * Each passed coefficient array must be the right size for that + * coefficient: width_in_blocks wide and height_in_blocks high, + * with unitheight at least v_samp_factor. + */ + +LOCAL(void) +transencode_coef_controller (j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays) +{ + my_coef_ptr coef; + JBLOCKROW buffer; + int i; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_c_coef_controller *) coef; + coef->pub.start_pass = start_pass_coef; + coef->pub.compress_data = compress_output; + + /* Save pointer to virtual arrays */ + coef->whole_image = coef_arrays; + + /* Allocate and pre-zero space for dummy DCT blocks. */ + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + jzero_far((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) { + coef->dummy_buffer[i] = buffer + i; + } +} diff --git a/freeimage241/Source/LibJPEG/jdapimin.c b/freeimage241/Source/LibJPEG/jdapimin.c new file mode 100644 index 0000000..cadb59f --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdapimin.c @@ -0,0 +1,395 @@ +/* + * jdapimin.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "minimum" API routines that may be + * needed in either the normal full-decompression case or the + * transcoding-only case. + * + * Most of the routines intended to be called directly by an application + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + * shared by compression and decompression, and jdtrans.c for the transcoding + * case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * Initialization of a JPEG decompression object. + * The error manager must already be set up (in case memory manager fails). + */ + +GLOBAL(void) +jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize) +{ + int i; + + /* Guard against version mismatches between library and caller. */ + cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */ + if (version != JPEG_LIB_VERSION) + ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); + if (structsize != SIZEOF(struct jpeg_decompress_struct)) + ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, + (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize); + + /* For debugging purposes, we zero the whole master structure. + * But the application has already set the err pointer, and may have set + * client_data, so we have to save and restore those fields. + * Note: if application hasn't set client_data, tools like Purify may + * complain here. + */ + { + struct jpeg_error_mgr * err = cinfo->err; + void * client_data = cinfo->client_data; /* ignore Purify complaint here */ + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + cinfo->err = err; + cinfo->client_data = client_data; + } + cinfo->is_decompressor = TRUE; + + /* Initialize a memory manager instance for this object */ + jinit_memory_mgr((j_common_ptr) cinfo); + + /* Zero out pointers to permanent structures. */ + cinfo->progress = NULL; + cinfo->src = NULL; + + for (i = 0; i < NUM_QUANT_TBLS; i++) + cinfo->quant_tbl_ptrs[i] = NULL; + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + cinfo->dc_huff_tbl_ptrs[i] = NULL; + cinfo->ac_huff_tbl_ptrs[i] = NULL; + } + + /* Initialize marker processor so application can override methods + * for COM, APPn markers before calling jpeg_read_header. + */ + cinfo->marker_list = NULL; + jinit_marker_reader(cinfo); + + /* And initialize the overall input controller. */ + jinit_input_controller(cinfo); + + /* OK, I'm ready */ + cinfo->global_state = DSTATE_START; +} + + +/* + * Destruction of a JPEG decompression object + */ + +GLOBAL(void) +jpeg_destroy_decompress (j_decompress_ptr cinfo) +{ + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Abort processing of a JPEG decompression operation, + * but don't destroy the object itself. + */ + +GLOBAL(void) +jpeg_abort_decompress (j_decompress_ptr cinfo) +{ + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ +} + + +/* + * Set default decompression parameters. + */ + +LOCAL(void) +default_decompress_parms (j_decompress_ptr cinfo) +{ + /* Guess the input colorspace, and set output colorspace accordingly. */ + /* (Wish JPEG committee had provided a real way to specify this...) */ + /* Note application may override our guesses. */ + switch (cinfo->num_components) { + case 1: + cinfo->jpeg_color_space = JCS_GRAYSCALE; + cinfo->out_color_space = JCS_GRAYSCALE; + break; + + case 3: + if (cinfo->saw_JFIF_marker) { + cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ + } else if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_RGB; + break; + case 1: + cinfo->jpeg_color_space = JCS_YCbCr; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + break; + } + } else { + /* Saw no special markers, try to guess from the component IDs */ + int cid0 = cinfo->comp_info[0].component_id; + int cid1 = cinfo->comp_info[1].component_id; + int cid2 = cinfo->comp_info[2].component_id; + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ + else if (cid0 == 82 && cid1 == 71 && cid2 == 66) + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + else { + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + } + } + /* Always guess RGB is proper output colorspace. */ + cinfo->out_color_space = JCS_RGB; + break; + + case 4: + if (cinfo->saw_Adobe_marker) { + switch (cinfo->Adobe_transform) { + case 0: + cinfo->jpeg_color_space = JCS_CMYK; + break; + case 2: + cinfo->jpeg_color_space = JCS_YCCK; + break; + default: + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + break; + } + } else { + /* No special markers, assume straight CMYK. */ + cinfo->jpeg_color_space = JCS_CMYK; + } + cinfo->out_color_space = JCS_CMYK; + break; + + default: + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->out_color_space = JCS_UNKNOWN; + break; + } + + /* Set defaults for other decompression parameters. */ + cinfo->scale_num = 1; /* 1:1 scaling */ + cinfo->scale_denom = 1; + cinfo->output_gamma = 1.0; + cinfo->buffered_image = FALSE; + cinfo->raw_data_out = FALSE; + cinfo->dct_method = JDCT_DEFAULT; + cinfo->do_fancy_upsampling = TRUE; + cinfo->do_block_smoothing = TRUE; + cinfo->quantize_colors = FALSE; + /* We set these in case application only sets quantize_colors. */ + cinfo->dither_mode = JDITHER_FS; +#ifdef QUANT_2PASS_SUPPORTED + cinfo->two_pass_quantize = TRUE; +#else + cinfo->two_pass_quantize = FALSE; +#endif + cinfo->desired_number_of_colors = 256; + cinfo->colormap = NULL; + /* Initialize for no mode change in buffered-image mode. */ + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; +} + + +/* + * Decompression startup: read start of JPEG datastream to see what's there. + * Need only initialize JPEG object and supply a data source before calling. + * + * This routine will read as far as the first SOS marker (ie, actual start of + * compressed data), and will save all tables and parameters in the JPEG + * object. It will also initialize the decompression parameters to default + * values, and finally return JPEG_HEADER_OK. On return, the application may + * adjust the decompression parameters and then call jpeg_start_decompress. + * (Or, if the application only wanted to determine the image parameters, + * the data need not be decompressed. In that case, call jpeg_abort or + * jpeg_destroy to release any temporary space.) + * If an abbreviated (tables only) datastream is presented, the routine will + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + * re-use the JPEG object to read the abbreviated image datastream(s). + * It is unnecessary (but OK) to call jpeg_abort in this case. + * The JPEG_SUSPENDED return code only occurs if the data source module + * requests suspension of the decompressor. In this case the application + * should load more source data and then re-call jpeg_read_header to resume + * processing. + * If a non-suspending data source is used and require_image is TRUE, then the + * return code need not be inspected since only JPEG_HEADER_OK is possible. + * + * This routine is now just a front end to jpeg_consume_input, with some + * extra error checking. + */ + +GLOBAL(int) +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) +{ + int retcode; + + if (cinfo->global_state != DSTATE_START && + cinfo->global_state != DSTATE_INHEADER) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + retcode = jpeg_consume_input(cinfo); + + switch (retcode) { + case JPEG_REACHED_SOS: + retcode = JPEG_HEADER_OK; + break; + case JPEG_REACHED_EOI: + if (require_image) /* Complain if application wanted an image */ + ERREXIT(cinfo, JERR_NO_IMAGE); + /* Reset to start state; it would be safer to require the application to + * call jpeg_abort, but we can't change it now for compatibility reasons. + * A side effect is to free any temporary memory (there shouldn't be any). + */ + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + retcode = JPEG_HEADER_TABLES_ONLY; + break; + case JPEG_SUSPENDED: + /* no work */ + break; + } + + return retcode; +} + + +/* + * Consume data in advance of what the decompressor requires. + * This can be called at any time once the decompressor object has + * been created and a data source has been set up. + * + * This routine is essentially a state machine that handles a couple + * of critical state-transition actions, namely initial setup and + * transition from header scanning to ready-for-start_decompress. + * All the actual input is done via the input controller's consume_input + * method. + */ + +GLOBAL(int) +jpeg_consume_input (j_decompress_ptr cinfo) +{ + int retcode = JPEG_SUSPENDED; + + /* NB: every possible DSTATE value should be listed in this switch */ + switch (cinfo->global_state) { + case DSTATE_START: + /* Start-of-datastream actions: reset appropriate modules */ + (*cinfo->inputctl->reset_input_controller) (cinfo); + /* Initialize application's data source module */ + (*cinfo->src->init_source) (cinfo); + cinfo->global_state = DSTATE_INHEADER; + /*FALLTHROUGH*/ + case DSTATE_INHEADER: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + /* Set up default parameters based on header data */ + default_decompress_parms(cinfo); + /* Set global state: ready for start_decompress */ + cinfo->global_state = DSTATE_READY; + } + break; + case DSTATE_READY: + /* Can't advance past first SOS until start_decompress is called */ + retcode = JPEG_REACHED_SOS; + break; + case DSTATE_PRELOAD: + case DSTATE_PRESCAN: + case DSTATE_SCANNING: + case DSTATE_RAW_OK: + case DSTATE_BUFIMAGE: + case DSTATE_BUFPOST: + case DSTATE_STOPPING: + retcode = (*cinfo->inputctl->consume_input) (cinfo); + break; + default: + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + return retcode; +} + + +/* + * Have we finished reading the input file? + */ + +GLOBAL(boolean) +jpeg_input_complete (j_decompress_ptr cinfo) +{ + /* Check for valid jpeg object */ + if (cinfo->global_state < DSTATE_START || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->eoi_reached; +} + + +/* + * Is there more than one scan? + */ + +GLOBAL(boolean) +jpeg_has_multiple_scans (j_decompress_ptr cinfo) +{ + /* Only valid after jpeg_read_header completes */ + if (cinfo->global_state < DSTATE_READY || + cinfo->global_state > DSTATE_STOPPING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return cinfo->inputctl->has_multiple_scans; +} + + +/* + * Finish JPEG decompression. + * + * This will normally just verify the file trailer and release temp storage. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_decompress (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + /* Terminate final pass of non-buffered mode */ + if (cinfo->output_scanline < cinfo->output_height) + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + /* Finishing after a buffered-image operation */ + cinfo->global_state = DSTATE_STOPPING; + } else if (cinfo->global_state != DSTATE_STOPPING) { + /* STOPPING = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read until EOI */ + while (! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + /* Do final cleanup */ + (*cinfo->src->term_source) (cinfo); + /* We can use jpeg_abort to release memory and reset global_state */ + jpeg_abort((j_common_ptr) cinfo); + return TRUE; +} diff --git a/freeimage241/Source/LibJPEG/jdapistd.c b/freeimage241/Source/LibJPEG/jdapistd.c new file mode 100644 index 0000000..c8e3fa0 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdapistd.c @@ -0,0 +1,275 @@ +/* + * jdapistd.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains application interface code for the decompression half + * of the JPEG library. These are the "standard" API routines that are + * used in the normal full-decompression case. They are not used by a + * transcoding-only application. Note that if an application links in + * jpeg_start_decompress, it will end up linking in the entire decompressor. + * We thus must separate this file from jdapimin.c to avoid linking the + * whole decompression library into a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo)); + + +/* + * Decompression initialization. + * jpeg_read_header must be completed before calling this. + * + * If a multipass operating mode was selected, this will do all but the + * last pass, and thus may take a great deal of time. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_start_decompress (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize master control, select active modules */ + jinit_master_decompress(cinfo); + if (cinfo->buffered_image) { + /* No more work here; expecting jpeg_start_output next */ + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; + } + cinfo->global_state = DSTATE_PRELOAD; + } + if (cinfo->global_state == DSTATE_PRELOAD) { + /* If file has multiple scans, absorb them all into the coef buffer */ + if (cinfo->inputctl->has_multiple_scans) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return FALSE; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* jdmaster underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + } + cinfo->output_scan_number = cinfo->input_scan_number; + } else if (cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Perform any dummy output passes, and set up for the final pass */ + return output_pass_setup(cinfo); +} + + +/* + * Set up for an output pass, and perform any dummy pass(es) needed. + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + * Exit: If done, returns TRUE and sets global_state for proper output mode. + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + */ + +LOCAL(boolean) +output_pass_setup (j_decompress_ptr cinfo) +{ + if (cinfo->global_state != DSTATE_PRESCAN) { + /* First call: do pass setup */ + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; + cinfo->global_state = DSTATE_PRESCAN; + } + /* Loop over any required dummy passes */ + while (cinfo->master->is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Crank through the dummy pass */ + while (cinfo->output_scanline < cinfo->output_height) { + JDIMENSION last_scanline; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + /* Process some data */ + last_scanline = cinfo->output_scanline; + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + &cinfo->output_scanline, (JDIMENSION) 0); + if (cinfo->output_scanline == last_scanline) + return FALSE; /* No progress made, must suspend */ + } + /* Finish up dummy pass, and set up for another one */ + (*cinfo->master->finish_output_pass) (cinfo); + (*cinfo->master->prepare_for_output_pass) (cinfo); + cinfo->output_scanline = 0; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } + /* Ready for application to drive output pass through + * jpeg_read_scanlines or jpeg_read_raw_data. + */ + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + return TRUE; +} + + +/* + * Read some scanlines of data from the JPEG decompressor. + * + * The return value will be the number of lines actually read. + * This may be less than the number requested in several cases, + * including bottom of image, data source suspension, and operating + * modes that emit multiple scanlines at a time. + * + * Note: we warn about excess calls to jpeg_read_scanlines() since + * this likely signals an application programmer error. However, + * an oversize buffer (max_lines > scanlines remaining) is not an error. + */ + +GLOBAL(JDIMENSION) +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + JDIMENSION max_lines) +{ + JDIMENSION row_ctr; + + if (cinfo->global_state != DSTATE_SCANNING) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Process some data */ + row_ctr = 0; + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + cinfo->output_scanline += row_ctr; + return row_ctr; +} + + +/* + * Alternate entry point to read raw data. + * Processes exactly one iMCU row per call, unless suspended. + */ + +GLOBAL(JDIMENSION) +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + JDIMENSION max_lines) +{ + JDIMENSION lines_per_iMCU_row; + + if (cinfo->global_state != DSTATE_RAW_OK) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + if (cinfo->output_scanline >= cinfo->output_height) { + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + return 0; + } + + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) { + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + cinfo->progress->pass_limit = (long) cinfo->output_height; + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + } + + /* Verify that at least one iMCU row can be returned. */ + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size; + if (max_lines < lines_per_iMCU_row) + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + /* Decompress directly into user's buffer. */ + if (! (*cinfo->coef->decompress_data) (cinfo, data)) + return 0; /* suspension forced, can do nothing more */ + + /* OK, we processed one iMCU row. */ + cinfo->output_scanline += lines_per_iMCU_row; + return lines_per_iMCU_row; +} + + +/* Additional entry points for buffered-image mode. */ + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Initialize for an output pass in buffered-image mode. + */ + +GLOBAL(boolean) +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) +{ + if (cinfo->global_state != DSTATE_BUFIMAGE && + cinfo->global_state != DSTATE_PRESCAN) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + /* Limit scan number to valid range */ + if (scan_number <= 0) + scan_number = 1; + if (cinfo->inputctl->eoi_reached && + scan_number > cinfo->input_scan_number) + scan_number = cinfo->input_scan_number; + cinfo->output_scan_number = scan_number; + /* Perform any dummy output passes, and set up for the real pass */ + return output_pass_setup(cinfo); +} + + +/* + * Finish up after an output pass in buffered-image mode. + * + * Returns FALSE if suspended. The return value need be inspected only if + * a suspending data source is used. + */ + +GLOBAL(boolean) +jpeg_finish_output (j_decompress_ptr cinfo) +{ + if ((cinfo->global_state == DSTATE_SCANNING || + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + /* Terminate this pass. */ + /* We do not require the whole pass to have been completed. */ + (*cinfo->master->finish_output_pass) (cinfo); + cinfo->global_state = DSTATE_BUFPOST; + } else if (cinfo->global_state != DSTATE_BUFPOST) { + /* BUFPOST = repeat call after a suspension, anything else is error */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + } + /* Read markers looking for SOS or EOI */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + return FALSE; /* Suspend, come back later */ + } + cinfo->global_state = DSTATE_BUFIMAGE; + return TRUE; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jdatadst.c b/freeimage241/Source/LibJPEG/jdatadst.c new file mode 100644 index 0000000..a8f6fb0 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdatadst.c @@ -0,0 +1,151 @@ +/* + * jdatadst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains compression data destination routines for the case of + * emitting JPEG data to a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * destination manager. + * IMPORTANT: we assume that fwrite() will correctly transcribe an array of + * JOCTETs into 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data destination object for stdio output */ + +typedef struct { + struct jpeg_destination_mgr pub; /* public fields */ + + FILE * outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + + +/* + * Initialize destination --- called by jpeg_start_compress + * before any data is actually written. + */ + +METHODDEF(void) +init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * SIZEOF(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + + +/* + * Empty the output buffer --- called whenever buffer fills up. + * + * In typical applications, this should write the entire output buffer + * (ignoring the current state of next_output_byte & free_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been dumped. + * + * In applications that need to be able to suspend compression due to output + * overrun, a FALSE return indicates that the buffer cannot be emptied now. + * In this situation, the compressor will return to its caller (possibly with + * an indication that it has not accepted all the supplied scanlines). The + * application should resume compression after it has made more room in the + * output buffer. Note that there are substantial restrictions on the use of + * suspension --- see the documentation. + * + * When suspending, the compressor will back up to a convenient restart point + * (typically the start of the current MCU). next_output_byte & free_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point will be regenerated after resumption, so do not + * write it out when emptying the buffer externally. + */ + +METHODDEF(boolean) +empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + (size_t) OUTPUT_BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + + +/* + * Terminate destination --- called by jpeg_finish_compress + * after all data has been written. Usually needs to flush buffer. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } + fflush(dest->outfile); + /* Make sure we wrote the output file OK */ + if (ferror(dest->outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Prepare for output to a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing compression. + */ + +GLOBAL(void) +jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile) +{ + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} diff --git a/freeimage241/Source/LibJPEG/jdatasrc.c b/freeimage241/Source/LibJPEG/jdatasrc.c new file mode 100644 index 0000000..9a41b90 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdatasrc.c @@ -0,0 +1,213 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ + +#include "jinclude.h" +#include "jpeglib.h" +#include "jerror.h" + + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE *infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF(void) +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF(void) +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF(void) +term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL(void) +jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} diff --git a/freeimage241/Source/LibJPEG/jdcoefct.c b/freeimage241/Source/LibJPEG/jdcoefct.c new file mode 100644 index 0000000..4938d20 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdcoefct.c @@ -0,0 +1,736 @@ +/* + * jdcoefct.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the coefficient buffer controller for decompression. + * This controller is the top level of the JPEG decompressor proper. + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + * + * In buffered-image mode, this controller is the interface between + * input-oriented processing and output-oriented processing. + * Also, the input side (only) is used when reading a file for transcoding. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +/* Block smoothing is only applicable for progressive JPEG, so: */ +#ifndef D_PROGRESSIVE_SUPPORTED +#undef BLOCK_SMOOTHING_SUPPORTED +#endif + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_coef_controller pub; /* public fields */ + + /* These variables keep track of the current location of the input side. */ + /* cinfo->input_iMCU_row is also used for this. */ + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + /* In single-pass modes, it's sufficient to buffer just one MCU. + * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, + * and let the entropy decoder write into that workspace each time. + * (On 80x86, the workspace is FAR even though it's not really very big; + * this is to keep the module interfaces unchanged when a large coefficient + * buffer is necessary.) + * In multi-pass modes, this array points to the current MCU's blocks + * within the virtual arrays; it is used only by the input side. + */ + JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* In multi-pass modes, we need a virtual block array for each component. */ + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* When doing block smoothing, we latch coefficient Al values here */ + int * coef_bits_latch; +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ +#endif +} my_coef_controller; + +typedef my_coef_controller * my_coef_ptr; + +/* Forward declarations */ +METHODDEF(int) decompress_onepass + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#ifdef D_MULTISCAN_FILES_SUPPORTED +METHODDEF(int) decompress_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif +#ifdef BLOCK_SMOOTHING_SUPPORTED +LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo)); +METHODDEF(int) decompress_smooth_data + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); +#endif + + +LOCAL(void) +start_iMCU_row (j_decompress_ptr cinfo) +/* Reset within-iMCU-row counters for a new row (input side) */ +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + * But at the bottom of the image, process only what's left. + */ + if (cinfo->comps_in_scan > 1) { + coef->MCU_rows_per_iMCU_row = 1; + } else { + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + else + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + } + + coef->MCU_ctr = 0; + coef->MCU_vert_offset = 0; +} + + +/* + * Initialize for an input processing pass. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + cinfo->input_iMCU_row = 0; + start_iMCU_row(cinfo); +} + + +/* + * Initialize for an output processing pass. + */ + +METHODDEF(void) +start_output_pass (j_decompress_ptr cinfo) +{ +#ifdef BLOCK_SMOOTHING_SUPPORTED + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + /* If multipass, check to see whether to use block smoothing on this pass */ + if (coef->pub.coef_arrays != NULL) { + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + coef->pub.decompress_data = decompress_smooth_data; + else + coef->pub.decompress_data = decompress_data; + } +#endif + cinfo->output_iMCU_row = 0; +} + + +/* + * Decompress and return some data in the single-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Input and output must run in lockstep since we have only a one-MCU buffer. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image, + * which we index according to the component's SOF position. + */ + +METHODDEF(int) +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + int blkn, ci, xindex, yindex, yoffset, useful_width; + JSAMPARRAY output_ptr; + JDIMENSION start_col, output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Loop to process as much as one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + MCU_col_num++) { + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + jzero_far((void FAR *) coef->MCU_buffer[0], + (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + /* Determine where data should go in output_buf and do the IDCT thing. + * We skip dummy blocks at the right and bottom edges (but blkn gets + * incremented past them!). Note the inner loop relies on having + * allocated the MCU_buffer[] blocks sequentially. + */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) { + blkn += compptr->MCU_blocks; + continue; + } + inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + : compptr->last_col_width; + output_ptr = output_buf[compptr->component_index] + + yoffset * compptr->DCT_scaled_size; + start_col = MCU_col_num * compptr->MCU_sample_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + if (cinfo->input_iMCU_row < last_iMCU_row || + yoffset+yindex < compptr->last_row_height) { + output_col = start_col; + for (xindex = 0; xindex < useful_width; xindex++) { + (*inverse_DCT) (cinfo, compptr, + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + output_ptr, output_col); + output_col += compptr->DCT_scaled_size; + } + } + blkn += compptr->MCU_width; + output_ptr += compptr->DCT_scaled_size; + } + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + cinfo->output_iMCU_row++; + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Dummy consume-input routine for single-pass operation. + */ + +METHODDEF(int) +dummy_consume_data (j_decompress_ptr cinfo) +{ + return JPEG_SUSPENDED; /* Always indicate nothing was done */ +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Consume input data and store it in the full-image coefficient buffer. + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + * ie, v_samp_factor block rows for each component in the scan. + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + */ + +METHODDEF(int) +consume_data (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION MCU_col_num; /* index of current MCU within row */ + int blkn, ci, xindex, yindex, yoffset; + JDIMENSION start_col; + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + JBLOCKROW buffer_ptr; + jpeg_component_info *compptr; + + /* Align the virtual buffers for the components used in this scan. */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + buffer[ci] = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + cinfo->input_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, TRUE); + /* Note: entropy decoder expects buffer to be zeroed, + * but this is handled automatically by the memory manager + * because we requested a pre-zeroed array. + */ + } + + /* Loop to process one whole iMCU row */ + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + yoffset++) { + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + MCU_col_num++) { + /* Construct list of pointers to DCT blocks belonging to this MCU */ + blkn = 0; /* index of current DCT block within MCU */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + start_col = MCU_col_num * compptr->MCU_width; + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + coef->MCU_buffer[blkn++] = buffer_ptr++; + } + } + } + /* Try to fetch the MCU. */ + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + /* Suspension forced; update state counters and exit */ + coef->MCU_vert_offset = yoffset; + coef->MCU_ctr = MCU_col_num; + return JPEG_SUSPENDED; + } + } + /* Completed an MCU row, but perhaps not an iMCU row */ + coef->MCU_ctr = 0; + } + /* Completed the iMCU row, advance counters for next one */ + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + start_iMCU_row(cinfo); + return JPEG_ROW_COMPLETED; + } + /* Completed the scan */ + (*cinfo->inputctl->finish_input_pass) (cinfo); + return JPEG_SCAN_COMPLETED; +} + + +/* + * Decompress and return some data in the multi-pass case. + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + * + * NB: output_buf contains a plane for each component in image. + */ + +METHODDEF(int) +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num; + int ci, block_row, block_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number < cinfo->output_scan_number || + (cinfo->input_scan_number == cinfo->output_scan_number && + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Align the virtual buffer for this component. */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + cinfo->output_iMCU_row * compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) + block_rows = compptr->v_samp_factor; + else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + } + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + output_col = 0; + for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + output_ptr, output_col); + buffer_ptr++; + output_col += compptr->DCT_scaled_size; + } + output_ptr += compptr->DCT_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +/* + * This code applies interblock smoothing as described by section K.8 + * of the JPEG standard: the first 5 AC coefficients are estimated from + * the DC values of a DCT block and its 8 neighboring blocks. + * We apply smoothing only for progressive JPEG decoding, and only if + * the coefficients it can estimate are not yet known to full precision. + */ + +/* Natural-order array positions of the first 5 zigzag-order coefficients */ +#define Q01_POS 1 +#define Q10_POS 8 +#define Q20_POS 16 +#define Q11_POS 9 +#define Q02_POS 2 + +/* + * Determine whether block smoothing is applicable and safe. + * We also latch the current states of the coef_bits[] entries for the + * AC coefficients; otherwise, if the input side of the decompressor + * advances into a new scan, we might think the coefficients are known + * more accurately than they really are. + */ + +LOCAL(boolean) +smoothing_ok (j_decompress_ptr cinfo) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + boolean smoothing_useful = FALSE; + int ci, coefi; + jpeg_component_info *compptr; + JQUANT_TBL * qtable; + int * coef_bits; + int * coef_bits_latch; + + if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) + return FALSE; + + /* Allocate latch area if not already done */ + if (coef->coef_bits_latch == NULL) + coef->coef_bits_latch = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * + (SAVED_COEFS * SIZEOF(int))); + coef_bits_latch = coef->coef_bits_latch; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* All components' quantization values must already be latched. */ + if ((qtable = compptr->quant_table) == NULL) + return FALSE; + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + if (qtable->quantval[0] == 0 || + qtable->quantval[Q01_POS] == 0 || + qtable->quantval[Q10_POS] == 0 || + qtable->quantval[Q20_POS] == 0 || + qtable->quantval[Q11_POS] == 0 || + qtable->quantval[Q02_POS] == 0) + return FALSE; + /* DC values must be at least partly known for all components. */ + coef_bits = cinfo->coef_bits[ci]; + if (coef_bits[0] < 0) + return FALSE; + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + for (coefi = 1; coefi <= 5; coefi++) { + coef_bits_latch[coefi] = coef_bits[coefi]; + if (coef_bits[coefi] != 0) + smoothing_useful = TRUE; + } + coef_bits_latch += SAVED_COEFS; + } + + return smoothing_useful; +} + + +/* + * Variant of decompress_data for use when doing block smoothing. + */ + +METHODDEF(int) +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) +{ + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + JDIMENSION block_num, last_block_column; + int ci, block_row, block_rows, access_rows; + JBLOCKARRAY buffer; + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + JSAMPARRAY output_ptr; + JDIMENSION output_col; + jpeg_component_info *compptr; + inverse_DCT_method_ptr inverse_DCT; + boolean first_row, last_row; + JBLOCK workspace; + int *coef_bits; + JQUANT_TBL *quanttbl; + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + int Al, pred; + + /* Force some input to be done if we are getting ahead of the input. */ + while (cinfo->input_scan_number <= cinfo->output_scan_number && + ! cinfo->inputctl->eoi_reached) { + if (cinfo->input_scan_number == cinfo->output_scan_number) { + /* If input is working on current scan, we ordinarily want it to + * have completed the current row. But if input scan is DC, + * we want it to keep one row ahead so that next block row's DC + * values are up to date. + */ + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + break; + } + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + return JPEG_SUSPENDED; + } + + /* OK, output from the virtual arrays. */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Don't bother to IDCT an uninteresting component. */ + if (! compptr->component_needed) + continue; + /* Count non-dummy DCT block rows in this iMCU row. */ + if (cinfo->output_iMCU_row < last_iMCU_row) { + block_rows = compptr->v_samp_factor; + access_rows = block_rows * 2; /* this and next iMCU row */ + last_row = FALSE; + } else { + /* NB: can't use last_row_height here; it is input-side-dependent! */ + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (block_rows == 0) block_rows = compptr->v_samp_factor; + access_rows = block_rows; /* this iMCU row only */ + last_row = TRUE; + } + /* Align the virtual buffer for this component. */ + if (cinfo->output_iMCU_row > 0) { + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + (JDIMENSION) access_rows, FALSE); + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + first_row = FALSE; + } else { + buffer = (*cinfo->mem->access_virt_barray) + ((j_common_ptr) cinfo, coef->whole_image[ci], + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + first_row = TRUE; + } + /* Fetch component-dependent info */ + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + quanttbl = compptr->quant_table; + Q00 = quanttbl->quantval[0]; + Q01 = quanttbl->quantval[Q01_POS]; + Q10 = quanttbl->quantval[Q10_POS]; + Q20 = quanttbl->quantval[Q20_POS]; + Q11 = quanttbl->quantval[Q11_POS]; + Q02 = quanttbl->quantval[Q02_POS]; + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + output_ptr = output_buf[ci]; + /* Loop over all DCT blocks to be processed. */ + for (block_row = 0; block_row < block_rows; block_row++) { + buffer_ptr = buffer[block_row]; + if (first_row && block_row == 0) + prev_block_row = buffer_ptr; + else + prev_block_row = buffer[block_row-1]; + if (last_row && block_row == block_rows-1) + next_block_row = buffer_ptr; + else + next_block_row = buffer[block_row+1]; + /* We fetch the surrounding DC values using a sliding-register approach. + * Initialize all nine here so as to do the right thing on narrow pics. + */ + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + output_col = 0; + last_block_column = compptr->width_in_blocks - 1; + for (block_num = 0; block_num <= last_block_column; block_num++) { + /* Fetch current DCT block into workspace so we can modify it. */ + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + /* Update DC values */ + if (block_num < last_block_column) { + DC3 = (int) prev_block_row[1][0]; + DC6 = (int) buffer_ptr[1][0]; + DC9 = (int) next_block_row[1][0]; + } + /* Compute coefficient estimates per K.8. + * An estimate is applied only if coefficient is still zero, + * and is not known to be fully accurate. + */ + /* AC01 */ + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + num = 36 * Q00 * (DC4 - DC6); + if (num >= 0) { + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_scaled_size; + } + output_ptr += compptr->DCT_scaled_size; + } + } + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + return JPEG_ROW_COMPLETED; + return JPEG_SCAN_COMPLETED; +} + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + +/* + * Initialize coefficient buffer controller. + */ + +GLOBAL(void) +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_coef_ptr coef; + + coef = (my_coef_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_coef_controller)); + cinfo->coef = (struct jpeg_d_coef_controller *) coef; + coef->pub.start_input_pass = start_input_pass; + coef->pub.start_output_pass = start_output_pass; +#ifdef BLOCK_SMOOTHING_SUPPORTED + coef->coef_bits_latch = NULL; +#endif + + /* Create the coefficient buffer. */ + if (need_full_buffer) { +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* Allocate a full-image virtual array for each component, */ + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + /* Note we ask for a pre-zeroed array. */ + int ci, access_rows; + jpeg_component_info *compptr; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + access_rows = compptr->v_samp_factor; +#ifdef BLOCK_SMOOTHING_SUPPORTED + /* If block smoothing could be used, need a bigger window */ + if (cinfo->progressive_mode) + access_rows *= 3; +#endif + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) access_rows); + } + coef->pub.consume_data = consume_data; + coef->pub.decompress_data = decompress_data; + coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + /* We only need a single-MCU buffer. */ + JBLOCKROW buffer; + int i; + + buffer = (JBLOCKROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { + coef->MCU_buffer[i] = buffer + i; + } + coef->pub.consume_data = dummy_consume_data; + coef->pub.decompress_data = decompress_onepass; + coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ + } +} diff --git a/freeimage241/Source/LibJPEG/jdcolor.c b/freeimage241/Source/LibJPEG/jdcolor.c new file mode 100644 index 0000000..6c04dfe --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdcolor.c @@ -0,0 +1,396 @@ +/* + * jdcolor.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains output colorspace conversion routines. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private subobject */ + +typedef struct { + struct jpeg_color_deconverter pub; /* public fields */ + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ +} my_color_deconverter; + +typedef my_color_deconverter * my_cconvert_ptr; + + +/**************** YCbCr -> RGB conversion: most common case **************/ + +/* + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + * The conversion equations to be implemented are therefore + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + * + * To avoid floating-point arithmetic, we represent the fractional constants + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + * the products by 2^16, with appropriate rounding, to get the correct answer. + * Notice that Y, being an integral input, does not contribute any fraction + * so it need not participate in the rounding. + * + * For even more speed, we avoid doing any multiplications in the inner loop + * by precalculating the constants times Cb and Cr for all possible values. + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + * for 12-bit samples it is still acceptable. It's not very reasonable for + * 16-bit samples, but if you want lossless storage you shouldn't be changing + * colorspace anyway. + * The Cr=>R and Cb=>B values can be rounded to integers in advance; the + * values for the G calculation are left scaled up, since we must add them + * together before rounding. + */ + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + int i; + INT32 x; + SHIFT_TEMPS + + cconvert->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + cconvert->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + cconvert->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + cconvert->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + cconvert->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Convert some rows of samples to the output colorspace. + * + * Note that we change from noninterleaved, one-plane-per-component format + * to interleaved-pixel format. The output buffer is therefore three times + * as wide as the input buffer. + * A starting row offset is provided only for the input buffer. The caller + * can easily adjust the passed output_buf value to accommodate any row + * offset required on that side. + */ + +METHODDEF(void) +ycc_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + outptr[RGB_GREEN] = range_limit[y + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS))]; + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/**************** Cases other than YCbCr -> RGB **************/ + + +/* + * Color conversion for no colorspace change: just copy the data, + * converting from separate-planes to interleaved representation. + */ + +METHODDEF(void) +null_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION count; + register int num_components = cinfo->num_components; + JDIMENSION num_cols = cinfo->output_width; + int ci; + + while (--num_rows >= 0) { + for (ci = 0; ci < num_components; ci++) { + inptr = input_buf[ci][input_row]; + outptr = output_buf[0] + ci; + for (count = num_cols; count > 0; count--) { + *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ + outptr += num_components; + } + } + input_row++; + output_buf++; + } +} + + +/* + * Color conversion for grayscale: just copy the data. + * This also works for YCbCr -> grayscale conversion, in which + * we just copy the Y (luminance) component and ignore chrominance. + */ + +METHODDEF(void) +grayscale_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, + num_rows, cinfo->output_width); +} + + +/* + * Convert grayscale to RGB: just duplicate the graylevel three times. + * This is provided to support applications that don't want to cope + * with grayscale as a separate case. + */ + +METHODDEF(void) +gray_rgb_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + register JSAMPROW inptr, outptr; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + + while (--num_rows >= 0) { + inptr = input_buf[0][input_row++]; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + /* We can dispense with GETJSAMPLE() here */ + outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col]; + outptr += RGB_PIXELSIZE; + } + } +} + + +/* + * Adobe-style YCCK->CMYK conversion. + * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same + * conversion as above, while passing K (black) unchanged. + * We assume build_ycc_rgb_table has been called. + */ + +METHODDEF(void) +ycck_cmyk_convert (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows) +{ + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + register int y, cb, cr; + register JSAMPROW outptr; + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + register JDIMENSION col; + JDIMENSION num_cols = cinfo->output_width; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + register int * Crrtab = cconvert->Cr_r_tab; + register int * Cbbtab = cconvert->Cb_b_tab; + register INT32 * Crgtab = cconvert->Cr_g_tab; + register INT32 * Cbgtab = cconvert->Cb_g_tab; + SHIFT_TEMPS + + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + y = GETJSAMPLE(inptr0[col]); + cb = GETJSAMPLE(inptr1[col]); + cr = GETJSAMPLE(inptr2[col]); + /* Range-limiting is essential due to noise introduced by DCT losses. */ + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + SCALEBITS)))]; + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + /* K passes through unchanged */ + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + outptr += 4; + } + } +} + + +/* + * Empty method for start_pass. + */ + +METHODDEF(void) +start_pass_dcolor (j_decompress_ptr cinfo) +{ + /* no work needed */ +} + + +/* + * Module initialization routine for output colorspace conversion. + */ + +GLOBAL(void) +jinit_color_deconverter (j_decompress_ptr cinfo) +{ + my_cconvert_ptr cconvert; + int ci; + + cconvert = (my_cconvert_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_color_deconverter)); + cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; + cconvert->pub.start_pass = start_pass_dcolor; + + /* Make sure num_components agrees with jpeg_color_space */ + switch (cinfo->jpeg_color_space) { + case JCS_GRAYSCALE: + if (cinfo->num_components != 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_RGB: + case JCS_YCbCr: + if (cinfo->num_components != 3) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + case JCS_CMYK: + case JCS_YCCK: + if (cinfo->num_components != 4) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + + default: /* JCS_UNKNOWN can be anything */ + if (cinfo->num_components < 1) + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + break; + } + + /* Set out_color_components and conversion method based on requested space. + * Also clear the component_needed flags for any unused components, + * so that earlier pipeline stages can avoid useless computation. + */ + + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = grayscale_convert; + /* For color->grayscale conversion, only the Y (0) component is needed */ + for (ci = 1; ci < cinfo->num_components; ci++) + cinfo->comp_info[ci].component_needed = FALSE; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_RGB: + cinfo->out_color_components = RGB_PIXELSIZE; + if (cinfo->jpeg_color_space == JCS_YCbCr) { + cconvert->pub.color_convert = ycc_rgb_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { + cconvert->pub.color_convert = gray_rgb_convert; + } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + case JCS_CMYK: + cinfo->out_color_components = 4; + if (cinfo->jpeg_color_space == JCS_YCCK) { + cconvert->pub.color_convert = ycck_cmyk_convert; + build_ycc_rgb_table(cinfo); + } else if (cinfo->jpeg_color_space == JCS_CMYK) { + cconvert->pub.color_convert = null_convert; + } else + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + + default: + /* Permit null conversion to same output space */ + if (cinfo->out_color_space == cinfo->jpeg_color_space) { + cinfo->out_color_components = cinfo->num_components; + cconvert->pub.color_convert = null_convert; + } else /* unsupported non-null conversion */ + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + break; + } + + if (cinfo->quantize_colors) + cinfo->output_components = 1; /* single colormapped output component */ + else + cinfo->output_components = cinfo->out_color_components; +} diff --git a/freeimage241/Source/LibJPEG/jdct.h b/freeimage241/Source/LibJPEG/jdct.h new file mode 100644 index 0000000..04192a2 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef INT32 DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type INT32. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((INT32) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an INT32 value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/freeimage241/Source/LibJPEG/jddctmgr.c b/freeimage241/Source/LibJPEG/jddctmgr.c new file mode 100644 index 0000000..bbf8d0e --- /dev/null +++ b/freeimage241/Source/LibJPEG/jddctmgr.c @@ -0,0 +1,269 @@ +/* + * jddctmgr.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the inverse-DCT management logic. + * This code selects a particular IDCT implementation to be used, + * and it performs related housekeeping chores. No code in this file + * is executed per IDCT step, only during output pass setup. + * + * Note that the IDCT routines are responsible for performing coefficient + * dequantization as well as the IDCT proper. This module sets up the + * dequantization multiplier table needed by the IDCT routine. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + + +/* + * The decompressor input side (jdinput.c) saves away the appropriate + * quantization table for each component at the start of the first scan + * involving that component. (This is necessary in order to correctly + * decode files that reuse Q-table slots.) + * When we are ready to make an output pass, the saved Q-table is converted + * to a multiplier table that will actually be used by the IDCT routine. + * The multiplier table contents are IDCT-method-dependent. To support + * application changes in IDCT method between scans, we can remake the + * multiplier tables if necessary. + * In buffered-image mode, the first output pass may occur before any data + * has been seen for some components, and thus before their Q-tables have + * been saved away. To handle this case, multiplier tables are preset + * to zeroes; the result of the IDCT will be a neutral gray level. + */ + + +/* Private subobject for this module */ + +typedef struct { + struct jpeg_inverse_dct pub; /* public fields */ + + /* This array contains the IDCT method code that each multiplier table + * is currently set up for, or -1 if it's not yet set up. + * The actual multiplier tables are pointed to by dct_table in the + * per-component comp_info structures. + */ + int cur_method[MAX_COMPONENTS]; +} my_idct_controller; + +typedef my_idct_controller * my_idct_ptr; + + +/* Allocated multiplier tables: big enough for any supported variant */ + +typedef union { + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; +#ifdef DCT_IFAST_SUPPORTED + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; +#endif +#ifdef DCT_FLOAT_SUPPORTED + FLOAT_MULT_TYPE float_array[DCTSIZE2]; +#endif +} multiplier_table; + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + * so be sure to compile that code if either ISLOW or SCALING is requested. + */ +#ifdef DCT_ISLOW_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#else +#ifdef IDCT_SCALING_SUPPORTED +#define PROVIDE_ISLOW_TABLES +#endif +#endif + + +/* + * Prepare for an output pass. + * Here we select the proper IDCT routine for each component and build + * a matching multiplier table. + */ + +METHODDEF(void) +start_pass (j_decompress_ptr cinfo) +{ + my_idct_ptr idct = (my_idct_ptr) cinfo->idct; + int ci, i; + jpeg_component_info *compptr; + int method = 0; + inverse_DCT_method_ptr method_ptr = NULL; + JQUANT_TBL * qtbl; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Select the proper IDCT routine for this component's scaling */ + switch (compptr->DCT_scaled_size) { +#ifdef IDCT_SCALING_SUPPORTED + case 1: + method_ptr = jpeg_idct_1x1; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 2: + method_ptr = jpeg_idct_2x2; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; + case 4: + method_ptr = jpeg_idct_4x4; + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + break; +#endif + case DCTSIZE: + switch (cinfo->dct_method) { +#ifdef DCT_ISLOW_SUPPORTED + case JDCT_ISLOW: + method_ptr = jpeg_idct_islow; + method = JDCT_ISLOW; + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + method_ptr = jpeg_idct_ifast; + method = JDCT_IFAST; + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + method_ptr = jpeg_idct_float; + method = JDCT_FLOAT; + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + break; + default: + ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size); + break; + } + idct->pub.inverse_DCT[ci] = method_ptr; + /* Create multiplier table from quant table. + * However, we can skip this if the component is uninteresting + * or if we already built the table. Also, if no quant table + * has yet been saved for the component, we leave the + * multiplier table all-zero; we'll be reading zeroes from the + * coefficient controller's buffer anyway. + */ + if (! compptr->component_needed || idct->cur_method[ci] == method) + continue; + qtbl = compptr->quant_table; + if (qtbl == NULL) /* happens if no data yet for component */ + continue; + idct->cur_method[ci] = method; + switch (method) { +#ifdef PROVIDE_ISLOW_TABLES + case JDCT_ISLOW: + { + /* For LL&M IDCT method, multipliers are equal to raw quantization + * coefficients, but are stored as ints to ensure access efficiency. + */ + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + for (i = 0; i < DCTSIZE2; i++) { + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i]; + } + } + break; +#endif +#ifdef DCT_IFAST_SUPPORTED + case JDCT_IFAST: + { + /* For AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + * For integer operation, the multiplier table is to be scaled by + * IFAST_SCALE_BITS. + */ + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; +#define CONST_BITS 14 + static const INT16 aanscales[DCTSIZE2] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + }; + SHIFT_TEMPS + + for (i = 0; i < DCTSIZE2; i++) { + ifmtbl[i] = (IFAST_MULT_TYPE) + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i], + (INT32) aanscales[i]), + CONST_BITS-IFAST_SCALE_BITS); + } + } + break; +#endif +#ifdef DCT_FLOAT_SUPPORTED + case JDCT_FLOAT: + { + /* For float AA&N IDCT method, multipliers are equal to quantization + * coefficients scaled by scalefactor[row]*scalefactor[col], where + * scalefactor[0] = 1 + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + */ + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + int row, col; + static const double aanscalefactor[DCTSIZE] = { + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + }; + + i = 0; + for (row = 0; row < DCTSIZE; row++) { + for (col = 0; col < DCTSIZE; col++) { + fmtbl[i] = (FLOAT_MULT_TYPE) + ((double) qtbl->quantval[i] * + aanscalefactor[row] * aanscalefactor[col]); + i++; + } + } + } + break; +#endif + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } + } +} + + +/* + * Initialize IDCT manager. + */ + +GLOBAL(void) +jinit_inverse_dct (j_decompress_ptr cinfo) +{ + my_idct_ptr idct; + int ci; + jpeg_component_info *compptr; + + idct = (my_idct_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_idct_controller)); + cinfo->idct = (struct jpeg_inverse_dct *) idct; + idct->pub.start_pass = start_pass; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Allocate and pre-zero a multiplier table for each component */ + compptr->dct_table = + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(multiplier_table)); + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + /* Mark multiplier table not yet set up for any method */ + idct->cur_method[ci] = -1; + } +} diff --git a/freeimage241/Source/LibJPEG/jdhuff.c b/freeimage241/Source/LibJPEG/jdhuff.c new file mode 100644 index 0000000..b5ba39f --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdhuff.c @@ -0,0 +1,651 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdhuff.h" /* Declarations shared with jdphuff.c */ + + +/* + * Expanded entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; + + /* Precalculated info set up by start_pass for use in decode_mcu: */ + + /* Pointers to derived tables to be used for each block within an MCU */ + d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU]; + /* Whether we care about the DC and AC coefficient values for each block */ + boolean dc_needed[D_MAX_BLOCKS_IN_MCU]; + boolean ac_needed[D_MAX_BLOCKS_IN_MCU]; +} huff_entropy_decoder; + +typedef huff_entropy_decoder * huff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, blkn, dctbl, actbl; + jpeg_component_info * compptr; + + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || + cinfo->Ah != 0 || cinfo->Al != 0) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, + & entropy->ac_derived_tbls[actbl]); + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Precalculate decoding info for each block in an MCU of this scan */ + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + /* Precalculate which table to use for each block */ + entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no]; + /* Decide whether we really care about the coefficient values */ + if (compptr->component_needed) { + entropy->dc_needed[blkn] = TRUE; + /* we don't need the ACs if producing a 1/8th-size image */ + entropy->ac_needed[blkn] = (compptr->DCT_scaled_size > 1); + } else { + entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE; + } + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->pub.insufficient_data = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Compute the derived values for a Huffman table. + * This routine also performs some validation checks on the table. + * + * Note this is also used by jdphuff.c. + */ + +GLOBAL(void) +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno, + d_derived_tbl ** pdtbl) +{ + JHUFF_TBL *htbl; + d_derived_tbl *dtbl; + int p, i, l, si, numsymbols; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Note that huffsize[] and huffcode[] are filled in code-length order, + * paralleling the order of the symbols themselves in htbl->huffval[]. + */ + + /* Find the input Huffman table */ + if (tblno < 0 || tblno >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + htbl = + isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno]; + if (htbl == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno); + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + + p = 0; + for (l = 1; l <= 16; l++) { + i = (int) htbl->bits[l]; + if (i < 0 || p + i > 256) /* protect against table overrun */ + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + while (i--) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + numsymbols = p; + + /* Figure C.2: generate the codes themselves */ + /* We also validate that the counts represent a legal Huffman code tree. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + /* code is now 1 more than the last code used for codelength si; but + * it must still fit in si bits, since no code is allowed to be all ones. + */ + if (((INT32) code) >= (((INT32) 1) << si)) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + /* valoffset[l] = huffval[] index of 1st symbol of code length l, + * minus the minimum code of length l + */ + dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p]; + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } + + /* Validate symbols as being reasonable. + * For AC tables, we make no check, but accept all byte values 0..255. + * For DC tables, we require the symbols to be in range 0..15. + * (Tighter bounds could be applied depending on the data depth and mode, + * but this is sufficient to ensure safe decoding.) + */ + if (isDC) { + for (i = 0; i < numsymbols; i++) { + int sym = htbl->huffval[i]; + if (sym < 0 || sym > 15) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + } + } +} + + +/* + * Out-of-line code for bit fetching (shared with jdphuff.c). + * See jdhuff.h for info about usage. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +GLOBAL(boolean) +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + j_decompress_ptr cinfo = state->cinfo; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + /* We fail to do so only if we hit a marker or are forced to suspend. */ + + if (cinfo->unread_marker == 0) { /* cannot advance past a marker */ + while (bits_left < MIN_GET_BITS) { + register int c; + + /* Attempt to read a byte */ + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + /* Loop here to discard any padding FF's on terminating marker, + * so that we can save a valid unread_marker value. NOTE: we will + * accept multiple FF's followed by a 0 as meaning a single FF data + * byte. This data pattern is not valid according to the standard. + */ + do { + if (bytes_in_buffer == 0) { + if (! (*cinfo->src->fill_input_buffer) (cinfo)) + return FALSE; + next_input_byte = cinfo->src->next_input_byte; + bytes_in_buffer = cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. + * Save the marker code for later use. + * Fine point: it might appear that we should save the marker into + * bitread working state, not straight into permanent state. But + * once we have hit a marker, we cannot need to suspend within the + * current MCU, because we will read no more bytes from the data + * source. So it is OK to update permanent state right away. + */ + cinfo->unread_marker = c; + /* See if we need to insert some fake zero bits. */ + goto no_more_bytes; + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } /* end while */ + } else { + no_more_bytes: + /* We get here if we've read the marker that terminates the compressed + * data segment. There should be enough bits in the buffer register + * to satisfy the request; if so, no problem. + */ + if (nbits > bits_left) { + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * We use a nonvolatile flag to ensure that only one warning message + * appears per data segment. + */ + if (! cinfo->entropy->insufficient_data) { + WARNMS(cinfo, JWRN_HIT_MARKER); + cinfo->entropy->insufficient_data = TRUE; + } + /* Fill the buffer with zero bits */ + get_buffer <<= MIN_GET_BITS - bits_left; + bits_left = MIN_GET_BITS; + } + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Out-of-line code for Huffman code decoding. + * See jdhuff.h for info about usage. + */ + +GLOBAL(int) +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ]; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->pub.insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * Returns FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * this module, since we'll just re-assign them on the next call.) + */ + +METHODDEF(boolean) +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int blkn; + BITREAD_STATE_VARS; + savable_state state; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + JBLOCKROW block = MCU_data[blkn]; + d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn]; + d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn]; + register int s, k, r; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + if (entropy->dc_needed[blkn]) { + /* Convert DC difference to actual value, update last_dc_val */ + int ci = cinfo->MCU_membership[blkn]; + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ + (*block)[0] = (JCOEF) s; + } + + if (entropy->ac_needed[blkn]) { + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + break; + k += 15; + } + } + + } else { + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_huff_decoder; + entropy->pub.decode_mcu = decode_mcu; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } +} diff --git a/freeimage241/Source/LibJPEG/jdhuff.h b/freeimage241/Source/LibJPEG/jdhuff.h new file mode 100644 index 0000000..ae19b6c --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdhuff.h @@ -0,0 +1,201 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + INT32 valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(boolean) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, register bit_buf_type get_buffer, + register int bits_left, d_derived_tbl * htbl, int min_bits)); diff --git a/freeimage241/Source/LibJPEG/jdinput.c b/freeimage241/Source/LibJPEG/jdinput.c new file mode 100644 index 0000000..0c2ac8f --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdinput.c @@ -0,0 +1,381 @@ +/* + * jdinput.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains input control logic for the JPEG decompressor. + * These routines are concerned with controlling the decompressor's input + * processing (marker reading and coefficient decoding). The actual input + * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_input_controller pub; /* public fields */ + + boolean inheaders; /* TRUE until first SOS is reached */ +} my_input_controller; + +typedef my_input_controller * my_inputctl_ptr; + + +/* Forward declarations */ +METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo)); + + +/* + * Routines to calculate various quantities related to the size of the image. + */ + +LOCAL(void) +initial_setup (j_decompress_ptr cinfo) +/* Called once, when first SOS marker is reached */ +{ + int ci; + jpeg_component_info *compptr; + + /* Make sure image isn't bigger than I can handle */ + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + /* For now, precision must match compiled-in value... */ + if (cinfo->data_precision != BITS_IN_JSAMPLE) + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + /* Check that number of components won't exceed internal array sizes */ + if (cinfo->num_components > MAX_COMPONENTS) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + MAX_COMPONENTS); + + /* Compute maximum sampling factors; check factor validity */ + cinfo->max_h_samp_factor = 1; + cinfo->max_v_samp_factor = 1; + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + ERREXIT(cinfo, JERR_BAD_SAMPLING); + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + compptr->h_samp_factor); + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + compptr->v_samp_factor); + } + + /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE. + * In the full decompressor, this will be overridden by jdmaster.c; + * but in the transcoder, jdmaster.c is not used, so we must do it here. + */ + cinfo->min_DCT_scaled_size = DCTSIZE; + + /* Compute dimensions of components */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->DCT_scaled_size = DCTSIZE; + /* Size in DCT blocks */ + compptr->width_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->height_in_blocks = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + /* downsampled_width and downsampled_height will also be overridden by + * jdmaster.c if we are doing full decompression. The transcoder library + * doesn't use these values, but the calling application might. + */ + /* Size in samples */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + (long) cinfo->max_h_samp_factor); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + (long) cinfo->max_v_samp_factor); + /* Mark component needed, until color conversion says otherwise */ + compptr->component_needed = TRUE; + /* Mark no quantization table yet saved for component */ + compptr->quant_table = NULL; + } + + /* Compute number of fully interleaved MCU rows. */ + cinfo->total_iMCU_rows = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + /* Decide whether file contains multiple scans */ + if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) + cinfo->inputctl->has_multiple_scans = TRUE; + else + cinfo->inputctl->has_multiple_scans = FALSE; +} + + +LOCAL(void) +per_scan_setup (j_decompress_ptr cinfo) +/* Do computations that are needed before processing a JPEG scan */ +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ +{ + int ci, mcublks, tmp; + jpeg_component_info *compptr; + + if (cinfo->comps_in_scan == 1) { + + /* Noninterleaved (single-component) scan */ + compptr = cinfo->cur_comp_info[0]; + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = compptr->width_in_blocks; + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + /* For noninterleaved scan, always one block per MCU */ + compptr->MCU_width = 1; + compptr->MCU_height = 1; + compptr->MCU_blocks = 1; + compptr->MCU_sample_width = compptr->DCT_scaled_size; + compptr->last_col_width = 1; + /* For noninterleaved scans, it is convenient to define last_row_height + * as the number of block rows present in the last iMCU row. + */ + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + if (tmp == 0) tmp = compptr->v_samp_factor; + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + cinfo->blocks_in_MCU = 1; + cinfo->MCU_membership[0] = 0; + + } else { + + /* Interleaved (multi-component) scan */ + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + MAX_COMPS_IN_SCAN); + + /* Overall image size in MCUs */ + cinfo->MCUs_per_row = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, + (long) (cinfo->max_h_samp_factor*DCTSIZE)); + cinfo->MCU_rows_in_scan = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + cinfo->blocks_in_MCU = 0; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Sampling factors give # of blocks of component in each MCU */ + compptr->MCU_width = compptr->h_samp_factor; + compptr->MCU_height = compptr->v_samp_factor; + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size; + /* Figure number of non-dummy blocks in last MCU column & row */ + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + if (tmp == 0) tmp = compptr->MCU_width; + compptr->last_col_width = tmp; + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + if (tmp == 0) tmp = compptr->MCU_height; + compptr->last_row_height = tmp; + /* Prepare array describing MCU composition */ + mcublks = compptr->MCU_blocks; + if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + while (mcublks-- > 0) { + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + } + } + + } +} + + +/* + * Save away a copy of the Q-table referenced by each component present + * in the current scan, unless already saved during a prior scan. + * + * In a multiple-scan JPEG file, the encoder could assign different components + * the same Q-table slot number, but change table definitions between scans + * so that each component uses a different Q-table. (The IJG encoder is not + * currently capable of doing this, but other encoders might.) Since we want + * to be able to dequantize all the components at the end of the file, this + * means that we have to save away the table actually used for each component. + * We do this by copying the table at the start of the first scan containing + * the component. + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + * slot between scans of a component using that slot. If the encoder does so + * anyway, this decoder will simply use the Q-table values that were current + * at the start of the first scan for the component. + * + * The decompressor output side looks only at the saved quant tables, + * not at the current Q-table slots. + */ + +LOCAL(void) +latch_quant_tables (j_decompress_ptr cinfo) +{ + int ci, qtblno; + jpeg_component_info *compptr; + JQUANT_TBL * qtbl; + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* No work if we already saved Q-table for this component */ + if (compptr->quant_table != NULL) + continue; + /* Make sure specified quantization table is present */ + qtblno = compptr->quant_tbl_no; + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + cinfo->quant_tbl_ptrs[qtblno] == NULL) + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + /* OK, save away the quantization table */ + qtbl = (JQUANT_TBL *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(JQUANT_TBL)); + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + compptr->quant_table = qtbl; + } +} + + +/* + * Initialize the input modules to read a scan of compressed data. + * The first call to this is done by jdmaster.c after initializing + * the entire decompressor (during jpeg_start_decompress). + * Subsequent calls come from consume_markers, below. + */ + +METHODDEF(void) +start_input_pass (j_decompress_ptr cinfo) +{ + per_scan_setup(cinfo); + latch_quant_tables(cinfo); + (*cinfo->entropy->start_pass) (cinfo); + (*cinfo->coef->start_input_pass) (cinfo); + cinfo->inputctl->consume_input = cinfo->coef->consume_data; +} + + +/* + * Finish up after inputting a compressed-data scan. + * This is called by the coefficient controller after it's read all + * the expected data of the scan. + */ + +METHODDEF(void) +finish_input_pass (j_decompress_ptr cinfo) +{ + cinfo->inputctl->consume_input = consume_markers; +} + + +/* + * Read JPEG markers before, between, or after compressed-data scans. + * Change state as necessary when a new scan is reached. + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + * + * The consume_input method pointer points either here or to the + * coefficient controller's consume_data routine, depending on whether + * we are reading a compressed data segment or inter-segment markers. + */ + +METHODDEF(int) +consume_markers (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + int val; + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + return JPEG_REACHED_EOI; + + val = (*cinfo->marker->read_markers) (cinfo); + + switch (val) { + case JPEG_REACHED_SOS: /* Found SOS */ + if (inputctl->inheaders) { /* 1st SOS */ + initial_setup(cinfo); + inputctl->inheaders = FALSE; + /* Note: start_input_pass must be called by jdmaster.c + * before any more input can be consumed. jdapimin.c is + * responsible for enforcing this sequencing. + */ + } else { /* 2nd or later SOS marker */ + if (! inputctl->pub.has_multiple_scans) + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + start_input_pass(cinfo); + } + break; + case JPEG_REACHED_EOI: /* Found EOI */ + inputctl->pub.eoi_reached = TRUE; + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_NO_SOS); + } else { + /* Prevent infinite loop in coef ctlr's decompress_data routine + * if user set output_scan_number larger than number of scans. + */ + if (cinfo->output_scan_number > cinfo->input_scan_number) + cinfo->output_scan_number = cinfo->input_scan_number; + } + break; + case JPEG_SUSPENDED: + break; + } + + return val; +} + + +/* + * Reset state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + inputctl->pub.consume_input = consume_markers; + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; + /* Reset other modules */ + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + (*cinfo->marker->reset_marker_reader) (cinfo); + /* Reset progression state -- would be cleaner if entropy decoder did this */ + cinfo->coef_bits = NULL; +} + + +/* + * Initialize the input controller module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_input_controller (j_decompress_ptr cinfo) +{ + my_inputctl_ptr inputctl; + + /* Create subobject in permanent pool */ + inputctl = (my_inputctl_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_input_controller)); + cinfo->inputctl = (struct jpeg_input_controller *) inputctl; + /* Initialize method pointers */ + inputctl->pub.consume_input = consume_markers; + inputctl->pub.reset_input_controller = reset_input_controller; + inputctl->pub.start_input_pass = start_input_pass; + inputctl->pub.finish_input_pass = finish_input_pass; + /* Initialize state: can't use reset_input_controller since we don't + * want to try to reset other modules yet. + */ + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + inputctl->pub.eoi_reached = FALSE; + inputctl->inheaders = TRUE; +} diff --git a/freeimage241/Source/LibJPEG/jdmainct.c b/freeimage241/Source/LibJPEG/jdmainct.c new file mode 100644 index 0000000..13c956f --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdmainct.c @@ -0,0 +1,512 @@ +/* + * jdmainct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the main buffer controller for decompression. + * The main buffer lies between the JPEG decompressor proper and the + * post-processor; it holds downsampled data in the JPEG colorspace. + * + * Note that this code is bypassed in raw-data mode, since the application + * supplies the equivalent of the main buffer in that case. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * In the current system design, the main buffer need never be a full-image + * buffer; any full-height buffers will be found inside the coefficient or + * postprocessing controllers. Nonetheless, the main controller is not + * trivial. Its responsibility is to provide context rows for upsampling/ + * rescaling, and doing this in an efficient fashion is a bit tricky. + * + * Postprocessor input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + * sample rows of each component. (We require DCT_scaled_size values to be + * chosen such that these numbers are integers. In practice DCT_scaled_size + * values will likely be powers of two, so we actually have the stronger + * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) + * Upsampling will typically produce max_v_samp_factor pixel rows from each + * row group (times any additional scale factor that the upsampler is + * applying). + * + * The coefficient controller will deliver data to us one iMCU row at a time; + * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or + * exactly min_DCT_scaled_size row groups. (This amount of data corresponds + * to one row of MCUs when the image is fully interleaved.) Note that the + * number of sample rows varies across components, but the number of row + * groups does not. Some garbage sample rows may be included in the last iMCU + * row at the bottom of the image. + * + * Depending on the vertical scaling algorithm used, the upsampler may need + * access to the sample row(s) above and below its current input row group. + * The upsampler is required to set need_context_rows TRUE at global selection + * time if so. When need_context_rows is FALSE, this controller can simply + * obtain one iMCU row at a time from the coefficient controller and dole it + * out as row groups to the postprocessor. + * + * When need_context_rows is TRUE, this controller guarantees that the buffer + * passed to postprocessing contains at least one row group's worth of samples + * above and below the row group(s) being processed. Note that the context + * rows "above" the first passed row group appear at negative row offsets in + * the passed buffer. At the top and bottom of the image, the required + * context rows are manufactured by duplicating the first or last real sample + * row; this avoids having special cases in the upsampling inner loops. + * + * The amount of context is fixed at one row group just because that's a + * convenient number for this controller to work with. The existing + * upsamplers really only need one sample row of context. An upsampler + * supporting arbitrary output rescaling might wish for more than one row + * group of context when shrinking the image; tough, we don't handle that. + * (This is justified by the assumption that downsizing will be handled mostly + * by adjusting the DCT_scaled_size values, so that the actual scale factor at + * the upsample step needn't be much less than one.) + * + * To provide the desired context, we have to retain the last two row groups + * of one iMCU row while reading in the next iMCU row. (The last row group + * can't be processed until we have another row group for its below-context, + * and so we have to save the next-to-last group too for its above-context.) + * We could do this most simply by copying data around in our buffer, but + * that'd be very slow. We can avoid copying any data by creating a rather + * strange pointer structure. Here's how it works. We allocate a workspace + * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number + * of row groups per iMCU row). We create two sets of redundant pointers to + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + * pointer lists look like this: + * M+1 M-1 + * master pointer --> 0 master pointer --> 0 + * 1 1 + * ... ... + * M-3 M-3 + * M-2 M + * M-1 M+1 + * M M-2 + * M+1 M-1 + * 0 0 + * We read alternate iMCU rows using each master pointer; thus the last two + * row groups of the previous iMCU row remain un-overwritten in the workspace. + * The pointer lists are set up so that the required context rows appear to + * be adjacent to the proper places when we pass the pointer lists to the + * upsampler. + * + * The above pictures describe the normal state of the pointer lists. + * At top and bottom of the image, we diddle the pointer lists to duplicate + * the first or last sample row as necessary (this is cheaper than copying + * sample rows around). + * + * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that + * situation each iMCU row provides only one row group so the buffering logic + * must be different (eg, we must read two iMCU rows before we can emit the + * first row group). For now, we simply do not support providing context + * rows when min_DCT_scaled_size is 1. That combination seems unlikely to + * be worth providing --- if someone wants a 1/8th-size preview, they probably + * want it quick and dirty, so a context-free upsampler is sufficient. + */ + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_main_controller pub; /* public fields */ + + /* Pointer to allocated workspace (M or M+2 row groups). */ + JSAMPARRAY buffer[MAX_COMPONENTS]; + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + /* Remaining fields are only used in the context case. */ + + /* These are the master pointers to the funny-order pointer lists. */ + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + int whichptr; /* indicates which pointer set is now in use */ + int context_state; /* process_data state machine status */ + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ +} my_main_controller; + +typedef my_main_controller * my_main_ptr; + +/* context_state values: */ +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + +/* Forward declarations */ +METHODDEF(void) process_data_simple_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +METHODDEF(void) process_data_context_main + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) process_data_crank_post + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); +#endif + + +LOCAL(void) +alloc_funny_pointers (j_decompress_ptr cinfo) +/* Allocate space for the funny pointer lists. + * This is done only once, not once per pass. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + /* Get top-level space for component array pointers. + * We alloc both arrays with one call to save a few cycles. + */ + main->xbuffer[0] = (JSAMPIMAGE) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + /* Get space for pointer lists --- M+4 row groups in each list. + * We alloc both pointer lists with one call to save a few cycles. + */ + xbuf = (JSAMPARRAY) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + xbuf += rgroup; /* want one row group at negative offsets */ + main->xbuffer[0][ci] = xbuf; + xbuf += rgroup * (M + 4); + main->xbuffer[1][ci] = xbuf; + } +} + + +LOCAL(void) +make_funny_pointers (j_decompress_ptr cinfo) +/* Create the funny pointer lists discussed in the comments above. + * The actual workspace is already allocated (in main->buffer), + * and the space for the pointer lists is allocated too. + * This routine just fills in the curiously ordered lists. + * This will be repeated at the beginning of each pass. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY buf, xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + xbuf0 = main->xbuffer[0][ci]; + xbuf1 = main->xbuffer[1][ci]; + /* First copy the workspace pointers as-is */ + buf = main->buffer[ci]; + for (i = 0; i < rgroup * (M + 2); i++) { + xbuf0[i] = xbuf1[i] = buf[i]; + } + /* In the second list, put the last four row groups in swapped order */ + for (i = 0; i < rgroup * 2; i++) { + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + } + /* The wraparound pointers at top and bottom will be filled later + * (see set_wraparound_pointers, below). Initially we want the "above" + * pointers to duplicate the first actual data line. This only needs + * to happen in xbuffer[0]. + */ + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[0]; + } + } +} + + +LOCAL(void) +set_wraparound_pointers (j_decompress_ptr cinfo) +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + * This changes the pointer list state from top-of-image to the normal state. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup; + int M = cinfo->min_DCT_scaled_size; + jpeg_component_info *compptr; + JSAMPARRAY xbuf0, xbuf1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + xbuf0 = main->xbuffer[0][ci]; + xbuf1 = main->xbuffer[1][ci]; + for (i = 0; i < rgroup; i++) { + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + } + } +} + + +LOCAL(void) +set_bottom_pointers (j_decompress_ptr cinfo) +/* Change the pointer lists to duplicate the last sample row at the bottom + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + */ +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + int ci, i, rgroup, iMCUheight, rows_left; + jpeg_component_info *compptr; + JSAMPARRAY xbuf; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Count sample rows in one iMCU row and in one row group */ + iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size; + rgroup = iMCUheight / cinfo->min_DCT_scaled_size; + /* Count nondummy sample rows remaining for this component */ + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + if (rows_left == 0) rows_left = iMCUheight; + /* Count nondummy row groups. Should get same answer for each component, + * so we need only do it once. + */ + if (ci == 0) { + main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + } + /* Duplicate the last real sample row rgroup*2 times; this pads out the + * last partial rowgroup and ensures at least one full rowgroup of context. + */ + xbuf = main->xbuffer[main->whichptr][ci]; + for (i = 0; i < rgroup * 2; i++) { + xbuf[rows_left + i] = xbuf[rows_left-1]; + } + } +} + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->upsample->need_context_rows) { + main->pub.process_data = process_data_context_main; + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + main->context_state = CTX_PREPARE_FOR_IMCU; + main->iMCU_row_ctr = 0; + } else { + /* Simple case with no context needed */ + main->pub.process_data = process_data_simple_main; + } + main->buffer_full = FALSE; /* Mark buffer empty */ + main->rowgroup_ctr = 0; + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_CRANK_DEST: + /* For last pass of 2-pass quantization, just crank the postprocessor */ + main->pub.process_data = process_data_crank_post; + break; +#endif + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } +} + + +/* + * Process some data. + * This handles the simple case where no context is required. + */ + +METHODDEF(void) +process_data_simple_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + JDIMENSION rowgroups_avail; + + /* Read input data if we haven't filled the main buffer yet */ + if (! main->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer)) + return; /* suspension forced, can do nothing more */ + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + } + + /* There are always min_DCT_scaled_size row groups in an iMCU row. */ + rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size; + /* Note: at the bottom of the image, we may pass extra garbage row groups + * to the postprocessor. The postprocessor has to check for bottom + * of image anyway (at row resolution), so no point in us doing it too. + */ + + /* Feed the postprocessor */ + (*cinfo->post->post_process_data) (cinfo, main->buffer, + &main->rowgroup_ctr, rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + if (main->rowgroup_ctr >= rowgroups_avail) { + main->buffer_full = FALSE; + main->rowgroup_ctr = 0; + } +} + + +/* + * Process some data. + * This handles the case where context rows must be provided. + */ + +METHODDEF(void) +process_data_context_main (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_main_ptr main = (my_main_ptr) cinfo->main; + + /* Read input data if we haven't filled the main buffer yet */ + if (! main->buffer_full) { + if (! (*cinfo->coef->decompress_data) (cinfo, + main->xbuffer[main->whichptr])) + return; /* suspension forced, can do nothing more */ + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + main->iMCU_row_ctr++; /* count rows received */ + } + + /* Postprocessor typically will not swallow all the input data it is handed + * in one call (due to filling the output buffer first). Must be prepared + * to exit and restart. This switch lets us keep track of how far we got. + * Note that each case falls through to the next on successful completion. + */ + switch (main->context_state) { + case CTX_POSTPONED_ROW: + /* Call postprocessor using previously set pointers for postponed row */ + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + &main->rowgroup_ctr, main->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (main->rowgroup_ctr < main->rowgroups_avail) + return; /* Need to suspend */ + main->context_state = CTX_PREPARE_FOR_IMCU; + if (*out_row_ctr >= out_rows_avail) + return; /* Postprocessor exactly filled output buf */ + /*FALLTHROUGH*/ + case CTX_PREPARE_FOR_IMCU: + /* Prepare to process first M-1 row groups of this iMCU row */ + main->rowgroup_ctr = 0; + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1); + /* Check for bottom of image: if so, tweak pointers to "duplicate" + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + */ + if (main->iMCU_row_ctr == cinfo->total_iMCU_rows) + set_bottom_pointers(cinfo); + main->context_state = CTX_PROCESS_IMCU; + /*FALLTHROUGH*/ + case CTX_PROCESS_IMCU: + /* Call postprocessor using previously set pointers */ + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + &main->rowgroup_ctr, main->rowgroups_avail, + output_buf, out_row_ctr, out_rows_avail); + if (main->rowgroup_ctr < main->rowgroups_avail) + return; /* Need to suspend */ + /* After the first iMCU, change wraparound pointers to normal state */ + if (main->iMCU_row_ctr == 1) + set_wraparound_pointers(cinfo); + /* Prepare to load new iMCU row using other xbuffer list */ + main->whichptr ^= 1; /* 0=>1 or 1=>0 */ + main->buffer_full = FALSE; + /* Still need to process last row group of this iMCU row, */ + /* which is saved at index M+1 of the other xbuffer */ + main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1); + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2); + main->context_state = CTX_POSTPONED_ROW; + } +} + + +/* + * Process some data. + * Final pass of two-pass quantization: just call the postprocessor. + * Source data will be the postprocessor controller's internal buffer. + */ + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF(void) +process_data_crank_post (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + (JDIMENSION *) NULL, (JDIMENSION) 0, + output_buf, out_row_ctr, out_rows_avail); +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize main buffer controller. + */ + +GLOBAL(void) +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_main_ptr main; + int ci, rgroup, ngroups; + jpeg_component_info *compptr; + + main = (my_main_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_main_controller)); + cinfo->main = (struct jpeg_d_main_controller *) main; + main->pub.start_pass = start_pass_main; + + if (need_full_buffer) /* shouldn't happen */ + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + /* Allocate the workspace. + * ngroups is the number of row groups we need. + */ + if (cinfo->upsample->need_context_rows) { + if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */ + ERREXIT(cinfo, JERR_NOTIMPL); + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + ngroups = cinfo->min_DCT_scaled_size + 2; + } else { + ngroups = cinfo->min_DCT_scaled_size; + } + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + compptr->width_in_blocks * compptr->DCT_scaled_size, + (JDIMENSION) (rgroup * ngroups)); + } +} diff --git a/freeimage241/Source/LibJPEG/jdmarker.c b/freeimage241/Source/LibJPEG/jdmarker.c new file mode 100644 index 0000000..f4cca8c --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdmarker.c @@ -0,0 +1,1360 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* Private state */ + +typedef struct { + struct jpeg_marker_reader pub; /* public fields */ + + /* Application-overridable marker processing methods */ + jpeg_marker_parser_method process_COM; + jpeg_marker_parser_method process_APPn[16]; + + /* Limit on marker data length to save for each marker type */ + unsigned int length_limit_COM; + unsigned int length_limit_APPn[16]; + + /* Status of COM/APPn marker saving */ + jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */ + unsigned int bytes_read; /* data bytes read so far in marker */ + /* Note: cur_marker is not linked into marker_list until it's all read. */ +} my_marker_reader; + +typedef my_marker_reader * my_marker_ptr; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + bytes_in_buffer--; \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters + * can fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments + * that might not fit. If we are simply dropping such a marker, we use + * skip_input_data to get past it, and thereby put the problem on the + * source manager's shoulders. If we are saving the marker's contents + * into memory, we use a slightly different convention: when forced to + * suspend, the marker processor updates the restart point to the end of + * what it's consumed (ie, the end of the buffer) before returning FALSE. + * On resumption, cinfo->unread_marker still contains the marker code, + * but the data source will point to the next chunk of marker data. + * The marker processor must retain internal state to deal with this. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL(boolean) +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */ + cinfo->JFIF_minor_version = 1; + cinfo->density_unit = 0; + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL(boolean) +get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->progressive_mode = is_prog; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another SOS marker */ + cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +#ifdef D_ARITH_CODING_SUPPORTED + +LOCAL(boolean) +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + +#else /* ! D_ARITH_CODING_SUPPORTED */ + +#define get_dac(cinfo) skip_variable(cinfo) + +#endif /* D_ARITH_CODING_SUPPORTED */ + + +LOCAL(boolean) +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 16) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + /* Here we just do minimal validation of the counts to avoid walking + * off the end of our table space. jdhuff.c will check more carefully. + */ + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + /* We convert the zigzag-order table to natural array order. */ + quant_ptr->quantval[jpeg_natural_order[i]] = (UINT16) tmp; + } + + if (cinfo->err->trace_level >= 2) { + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } + + if (length != 0) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Routines for processing APPn and COM markers. + * These are either saved in memory or discarded, per application request. + * APP0 and APP14 are specially checked to see if they are + * JFIF and Adobe markers, respectively. + */ + +#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */ +#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */ +#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */ + + +LOCAL(void) +examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP0. + * Take appropriate action if it is a JFIF marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + INT32 totallen = (INT32) datalen + remaining; + + if (datalen >= APP0_DATA_LEN && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x49 && + GETJOCTET(data[3]) == 0x46 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF APP0 marker: save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->JFIF_major_version = GETJOCTET(data[5]); + cinfo->JFIF_minor_version = GETJOCTET(data[6]); + cinfo->density_unit = GETJOCTET(data[7]); + cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]); + cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]); + /* Check version. + * Major version must be 1, anything else signals an incompatible change. + * (We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec.) + * Minor version should be 0..2, but process anyway if newer. + */ + if (cinfo->JFIF_major_version != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version); + /* Generate trace messages */ + TRACEMS5(cinfo, 1, JTRC_JFIF, + cinfo->JFIF_major_version, cinfo->JFIF_minor_version, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + /* Validate thumbnail dimensions and issue appropriate messages */ + if (GETJOCTET(data[12]) | GETJOCTET(data[13])) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, + GETJOCTET(data[12]), GETJOCTET(data[13])); + totallen -= APP0_DATA_LEN; + if (totallen != + ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen); + } else if (datalen >= 6 && + GETJOCTET(data[0]) == 0x4A && + GETJOCTET(data[1]) == 0x46 && + GETJOCTET(data[2]) == 0x58 && + GETJOCTET(data[3]) == 0x58 && + GETJOCTET(data[4]) == 0) { + /* Found JFIF "JFXX" extension APP0 marker */ + /* The library doesn't actually do anything with these, + * but we try to produce a helpful trace message. + */ + switch (GETJOCTET(data[5])) { + case 0x10: + TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen); + break; + case 0x11: + TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen); + break; + case 0x13: + TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen); + break; + default: + TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, + GETJOCTET(data[5]), (int) totallen); + break; + } + } else { + /* Start of APP0 does not match "JFIF" or "JFXX", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen); + } +} + + +LOCAL(void) +examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data, + unsigned int datalen, INT32 remaining) +/* Examine first few bytes from an APP14. + * Take appropriate action if it is an Adobe marker. + * datalen is # of bytes at data[], remaining is length of rest of marker data. + */ +{ + unsigned int version, flags0, flags1, transform; + + if (datalen >= APP14_DATA_LEN && + GETJOCTET(data[0]) == 0x41 && + GETJOCTET(data[1]) == 0x64 && + GETJOCTET(data[2]) == 0x6F && + GETJOCTET(data[3]) == 0x62 && + GETJOCTET(data[4]) == 0x65) { + /* Found Adobe APP14 marker */ + version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]); + flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]); + flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]); + transform = GETJOCTET(data[11]); + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe", or too short */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining)); + } +} + + +METHODDEF(boolean) +get_interesting_appn (j_decompress_ptr cinfo) +/* Process an APP0 or APP14 marker without saving it */ +{ + INT32 length; + JOCTET b[APPN_DATA_LEN]; + unsigned int i, numtoread; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* get the interesting part of the marker data */ + if (length >= APPN_DATA_LEN) + numtoread = APPN_DATA_LEN; + else if (length > 0) + numtoread = (unsigned int) length; + else + numtoread = 0; + for (i = 0; i < numtoread; i++) + INPUT_BYTE(cinfo, b[i], return FALSE); + length -= numtoread; + + /* process it */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + case M_APP14: + examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length); + break; + default: + /* can't get here unless jpeg_save_markers chooses wrong processor */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +#ifdef SAVE_MARKERS_SUPPORTED + +METHODDEF(boolean) +save_marker (j_decompress_ptr cinfo) +/* Save an APPn or COM marker into the marker list */ +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + jpeg_saved_marker_ptr cur_marker = marker->cur_marker; + unsigned int bytes_read, data_length; + JOCTET FAR * data; + INT32 length = 0; + INPUT_VARS(cinfo); + + if (cur_marker == NULL) { + /* begin reading a marker */ + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + if (length >= 0) { /* watch out for bogus length word */ + /* figure out how much we want to save */ + unsigned int limit; + if (cinfo->unread_marker == (int) M_COM) + limit = marker->length_limit_COM; + else + limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0]; + if ((unsigned int) length < limit) + limit = (unsigned int) length; + /* allocate and initialize the marker item */ + cur_marker = (jpeg_saved_marker_ptr) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(struct jpeg_marker_struct) + limit); + cur_marker->next = NULL; + cur_marker->marker = (UINT8) cinfo->unread_marker; + cur_marker->original_length = (unsigned int) length; + cur_marker->data_length = limit; + /* data area is just beyond the jpeg_marker_struct */ + data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1); + marker->cur_marker = cur_marker; + marker->bytes_read = 0; + bytes_read = 0; + data_length = limit; + } else { + /* deal with bogus length word */ + bytes_read = data_length = 0; + data = NULL; + } + } else { + /* resume reading a marker */ + bytes_read = marker->bytes_read; + data_length = cur_marker->data_length; + data = cur_marker->data + bytes_read; + } + + while (bytes_read < data_length) { + INPUT_SYNC(cinfo); /* move the restart point to here */ + marker->bytes_read = bytes_read; + /* If there's not at least one byte in buffer, suspend */ + MAKE_BYTE_AVAIL(cinfo, return FALSE); + /* Copy bytes with reasonable rapidity */ + while (bytes_read < data_length && bytes_in_buffer > 0) { + *data++ = *next_input_byte++; + bytes_in_buffer--; + bytes_read++; + } + } + + /* Done reading what we want to read */ + if (cur_marker != NULL) { /* will be NULL if bogus length word */ + /* Add new marker to end of list */ + if (cinfo->marker_list == NULL) { + cinfo->marker_list = cur_marker; + } else { + jpeg_saved_marker_ptr prev = cinfo->marker_list; + while (prev->next != NULL) + prev = prev->next; + prev->next = cur_marker; + } + /* Reset pointer & calc remaining data length */ + data = cur_marker->data; + length = cur_marker->original_length - data_length; + } + /* Reset to initial state for next marker */ + marker->cur_marker = NULL; + + /* Process the marker if interesting; else just make a generic trace msg */ + switch (cinfo->unread_marker) { + case M_APP0: + examine_app0(cinfo, data, data_length, length); + break; + case M_APP14: + examine_app14(cinfo, data, data_length, length); + break; + default: + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, + (int) (data_length + length)); + break; + } + + /* skip any remaining data -- could be lots */ + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +METHODDEF(boolean) +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + if (length > 0) + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL(boolean) +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL(boolean) +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + +METHODDEF(int) +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, TRUE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, FALSE, TRUE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, TRUE, TRUE)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[ + cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF(boolean) +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL(boolean) +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF(void) +reset_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + marker->pub.saw_SOI = FALSE; /* set internal state too */ + marker->pub.saw_SOF = FALSE; + marker->pub.discarded_bytes = 0; + marker->cur_marker = NULL; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL(void) +jinit_marker_reader (j_decompress_ptr cinfo) +{ + my_marker_ptr marker; + int i; + + /* Create subobject in permanent pool */ + marker = (my_marker_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_marker_reader)); + cinfo->marker = (struct jpeg_marker_reader *) marker; + /* Initialize public method pointers */ + marker->pub.reset_marker_reader = reset_marker_reader; + marker->pub.read_markers = read_markers; + marker->pub.read_restart_marker = read_restart_marker; + /* Initialize COM/APPn processing. + * By default, we examine and then discard APP0 and APP14, + * but simply discard COM and all other APPn. + */ + marker->process_COM = skip_variable; + marker->length_limit_COM = 0; + for (i = 0; i < 16; i++) { + marker->process_APPn[i] = skip_variable; + marker->length_limit_APPn[i] = 0; + } + marker->process_APPn[0] = get_interesting_appn; + marker->process_APPn[14] = get_interesting_appn; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} + + +/* + * Control saving of COM and APPn markers into marker_list. + */ + +#ifdef SAVE_MARKERS_SUPPORTED + +GLOBAL(void) +jpeg_save_markers (j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + long maxlength; + jpeg_marker_parser_method processor; + + /* Length limit mustn't be larger than what we can allocate + * (should only be a concern in a 16-bit environment). + */ + maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct); + if (((long) length_limit) > maxlength) + length_limit = (unsigned int) maxlength; + + /* Choose processor routine to use. + * APP0/APP14 have special requirements. + */ + if (length_limit) { + processor = save_marker; + /* If saving APP0/APP14, save at least enough for our internal use. */ + if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN) + length_limit = APP0_DATA_LEN; + else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN) + length_limit = APP14_DATA_LEN; + } else { + processor = skip_variable; + /* If discarding APP0/APP14, use our regular on-the-fly processor. */ + if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14) + processor = get_interesting_appn; + } + + if (marker_code == (int) M_COM) { + marker->process_COM = processor; + marker->length_limit_COM = length_limit; + } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) { + marker->process_APPn[marker_code - (int) M_APP0] = processor; + marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit; + } else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} + +#endif /* SAVE_MARKERS_SUPPORTED */ + + +/* + * Install a special processing method for COM or APPn markers. + */ + +GLOBAL(void) +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine) +{ + my_marker_ptr marker = (my_marker_ptr) cinfo->marker; + + if (marker_code == (int) M_COM) + marker->process_COM = routine; + else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) + marker->process_APPn[marker_code - (int) M_APP0] = routine; + else + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); +} diff --git a/freeimage241/Source/LibJPEG/jdmaster.c b/freeimage241/Source/LibJPEG/jdmaster.c new file mode 100644 index 0000000..2802c5b --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdmaster.c @@ -0,0 +1,557 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL(boolean) +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if we've scaled the IDCTs differently */ + if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL(void) +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ +#ifdef IDCT_SCALING_SUPPORTED + int ci; + jpeg_component_info *compptr; +#endif + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + +#ifdef IDCT_SCALING_SUPPORTED + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * 8 <= cinfo->scale_denom) { + /* Provide 1/8 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 8L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 8L); + cinfo->min_DCT_scaled_size = 1; + } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { + /* Provide 1/4 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 4L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 4L); + cinfo->min_DCT_scaled_size = 2; + } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { + /* Provide 1/2 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 2L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 2L); + cinfo->min_DCT_scaled_size = 4; + } else { + /* Provide 1/1 scaling */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + cinfo->min_DCT_scaled_size = DCTSIZE; + } + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code assumes that the supported DCT scalings are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = cinfo->min_DCT_scaled_size; + while (ssize < DCTSIZE && + (compptr->h_samp_factor * ssize * 2 <= + cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) && + (compptr->v_samp_factor * ssize * 2 <= + cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) { + ssize = ssize * 2; + } + compptr->DCT_scaled_size = ssize; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + cinfo->out_color_components = RGB_PIXELSIZE; + break; +#endif /* else share code with YCbCr */ + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL(void) +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL(void) +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + boolean use_c_buffer; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Initialize principal buffer controllers. */ + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapistd.c will crank the pass to completion.) + */ + +METHODDEF(void) +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->idct->start_pass) (cinfo); + (*cinfo->coef->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF(void) +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL(void) +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL(void) +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} diff --git a/freeimage241/Source/LibJPEG/jdmerge.c b/freeimage241/Source/LibJPEG/jdmerge.c new file mode 100644 index 0000000..3744446 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdmerge.c @@ -0,0 +1,400 @@ +/* + * jdmerge.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains code for merged upsampling/color conversion. + * + * This file combines functions from jdsample.c and jdcolor.c; + * read those files first to understand what's going on. + * + * When the chroma components are to be upsampled by simple replication + * (ie, box filtering), we can save some work in color conversion by + * calculating all the output pixels corresponding to a pair of chroma + * samples at one time. In the conversion equations + * R = Y + K1 * Cr + * G = Y + K2 * Cb + K3 * Cr + * B = Y + K4 * Cb + * only the Y term varies among the group of pixels corresponding to a pair + * of chroma samples, so the rest of the terms can be calculated just once. + * At typical sampling ratios, this eliminates half or three-quarters of the + * multiplications needed for color conversion. + * + * This file currently provides implementations for the following cases: + * YCbCr => RGB color conversion only. + * Sampling ratios of 2h1v or 2h2v. + * No scaling needed at upsample time. + * Corner-aligned (non-CCIR601) sampling alignment. + * Other special cases could be added, but in most applications these are + * the only common cases. (For uncommon cases we fall back on the more + * general code in jdsample.c and jdcolor.c.) + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef UPSAMPLE_MERGING_SUPPORTED + + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Pointer to routine to do actual upsampling/conversion of one row group */ + JMETHOD(void, upmethod, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf)); + + /* Private state for YCC->RGB conversion */ + int * Cr_r_tab; /* => table for Cr to R conversion */ + int * Cb_b_tab; /* => table for Cb to B conversion */ + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + + /* For 2:1 vertical sampling, we produce two output rows at a time. + * We need a "spare" row buffer to hold the second output row if the + * application provides just a one-row buffer; we also use the spare + * to discard the dummy last row if the image height is odd. + */ + JSAMPROW spare_row; + boolean spare_full; /* T if spare buffer is occupied */ + + JDIMENSION out_row_width; /* samples per output row */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + * This is taken directly from jdcolor.c; see that file for more info. + */ + +LOCAL(void) +build_ycc_rgb_table (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int i; + INT32 x; + SHIFT_TEMPS + + upsample->Cr_r_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cb_b_tab = (int *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(int)); + upsample->Cr_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + upsample->Cb_g_tab = (INT32 *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + /* Cr=>R value is nearest int to 1.40200 * x */ + upsample->Cr_r_tab[i] = (int) + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + /* Cb=>B value is nearest int to 1.77200 * x */ + upsample->Cb_b_tab[i] = (int) + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + /* Cr=>G value is scaled-up -0.71414 * x */ + upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x; + /* Cb=>G value is scaled-up -0.34414 * x */ + /* We also add in ONE_HALF so that need not do it in inner loop */ + upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + } +} + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_merged_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the spare buffer empty */ + upsample->spare_full = FALSE; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * The control routine just handles the row buffering considerations. + */ + +METHODDEF(void) +merged_2v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 2:1 vertical sampling case: may need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPROW work_ptrs[2]; + JDIMENSION num_rows; /* number of rows returned to caller */ + + if (upsample->spare_full) { + /* If we have a spare row saved from a previous cycle, just return it. */ + jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, + 1, upsample->out_row_width); + num_rows = 1; + upsample->spare_full = FALSE; + } else { + /* Figure number of rows to return to caller. */ + num_rows = 2; + /* Not more than the distance to the end of the image. */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + /* Create output pointer array for upsampler. */ + work_ptrs[0] = output_buf[*out_row_ctr]; + if (num_rows > 1) { + work_ptrs[1] = output_buf[*out_row_ctr + 1]; + } else { + work_ptrs[1] = upsample->spare_row; + upsample->spare_full = TRUE; + } + /* Now do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs); + } + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (! upsample->spare_full) + (*in_row_group_ctr)++; +} + + +METHODDEF(void) +merged_1v_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +/* 1:1 vertical sampling case: much easier, never need a spare row. */ +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Just do the upsampling. */ + (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, + output_buf + *out_row_ctr); + /* Adjust counts */ + (*out_row_ctr)++; + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by the control routines to do + * the actual upsampling/conversion. One row group is processed per call. + * + * Note: since we may be writing directly into application-supplied buffers, + * we have to be honest about the output width; we can't assume the buffer + * has been rounded up to an even width. + */ + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. + */ + +METHODDEF(void) +h2v1_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr; + JSAMPROW inptr0, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr0 = input_buf[0][in_row_group_ctr]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr = output_buf[0]; + /* Loop for each pair of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 2 Y values and emit 2 pixels */ + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr0++); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + outptr += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr0); + outptr[RGB_RED] = range_limit[y + cred]; + outptr[RGB_GREEN] = range_limit[y + cgreen]; + outptr[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. + */ + +METHODDEF(void) +h2v2_merged_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr, + JSAMPARRAY output_buf) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + register int y, cred, cgreen, cblue; + int cb, cr; + register JSAMPROW outptr0, outptr1; + JSAMPROW inptr00, inptr01, inptr1, inptr2; + JDIMENSION col; + /* copy these pointers into registers if possible */ + register JSAMPLE * range_limit = cinfo->sample_range_limit; + int * Crrtab = upsample->Cr_r_tab; + int * Cbbtab = upsample->Cb_b_tab; + INT32 * Crgtab = upsample->Cr_g_tab; + INT32 * Cbgtab = upsample->Cb_g_tab; + SHIFT_TEMPS + + inptr00 = input_buf[0][in_row_group_ctr*2]; + inptr01 = input_buf[0][in_row_group_ctr*2 + 1]; + inptr1 = input_buf[1][in_row_group_ctr]; + inptr2 = input_buf[2][in_row_group_ctr]; + outptr0 = output_buf[0]; + outptr1 = output_buf[1]; + /* Loop for each group of output pixels */ + for (col = cinfo->output_width >> 1; col > 0; col--) { + /* Do the chroma part of the calculation */ + cb = GETJSAMPLE(*inptr1++); + cr = GETJSAMPLE(*inptr2++); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + /* Fetch 4 Y values and emit 4 pixels */ + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr00++); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + outptr0 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + y = GETJSAMPLE(*inptr01++); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + outptr1 += RGB_PIXELSIZE; + } + /* If image width is odd, do the last output column separately */ + if (cinfo->output_width & 1) { + cb = GETJSAMPLE(*inptr1); + cr = GETJSAMPLE(*inptr2); + cred = Crrtab[cr]; + cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS); + cblue = Cbbtab[cb]; + y = GETJSAMPLE(*inptr00); + outptr0[RGB_RED] = range_limit[y + cred]; + outptr0[RGB_GREEN] = range_limit[y + cgreen]; + outptr0[RGB_BLUE] = range_limit[y + cblue]; + y = GETJSAMPLE(*inptr01); + outptr1[RGB_RED] = range_limit[y + cred]; + outptr1[RGB_GREEN] = range_limit[y + cgreen]; + outptr1[RGB_BLUE] = range_limit[y + cblue]; + } +} + + +/* + * Module initialization routine for merged upsampling/color conversion. + * + * NB: this is called under the conditions determined by use_merged_upsample() + * in jdmaster.c. That routine MUST correspond to the actual capabilities + * of this module; no safety checks are made here. + */ + +GLOBAL(void) +jinit_merged_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_merged_upsample; + upsample->pub.need_context_rows = FALSE; + + upsample->out_row_width = cinfo->output_width * cinfo->out_color_components; + + if (cinfo->max_v_samp_factor == 2) { + upsample->pub.upsample = merged_2v_upsample; + upsample->upmethod = h2v2_merged_upsample; + /* Allocate a spare row buffer */ + upsample->spare_row = (JSAMPROW) + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE))); + } else { + upsample->pub.upsample = merged_1v_upsample; + upsample->upmethod = h2v1_merged_upsample; + /* No spare row needed */ + upsample->spare_row = NULL; + } + + build_ycc_rgb_table(cinfo); +} + +#endif /* UPSAMPLE_MERGING_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jdphuff.c b/freeimage241/Source/LibJPEG/jdphuff.c new file mode 100644 index 0000000..2267809 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdphuff.c @@ -0,0 +1,668 @@ +/* + * jdphuff.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines for progressive JPEG. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdhuff.h" /* Declarations shared with jdhuff.c */ + + +#ifdef D_PROGRESSIVE_SUPPORTED + +/* + * Expanded entropy decoder object for progressive Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + unsigned int EOBRUN; /* remaining EOBs in EOBRUN */ + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).EOBRUN = (src).EOBRUN, \ + (dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * derived_tbls[NUM_HUFF_TBLS]; + + d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */ +} phuff_entropy_decoder; + +typedef phuff_entropy_decoder * phuff_entropy_ptr; + +/* Forward declarations */ +METHODDEF(boolean) decode_mcu_DC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_first JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_DC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); +METHODDEF(boolean) decode_mcu_AC_refine JPP((j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF(void) +start_pass_phuff_decoder (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + boolean is_DC_band, bad; + int ci, coefi, tbl; + int *coef_bit_ptr; + jpeg_component_info * compptr; + + is_DC_band = (cinfo->Ss == 0); + + /* Validate scan parameters */ + bad = FALSE; + if (is_DC_band) { + if (cinfo->Se != 0) + bad = TRUE; + } else { + /* need not check Ss/Se < 0 since they came from unsigned bytes */ + if (cinfo->Ss > cinfo->Se || cinfo->Se >= DCTSIZE2) + bad = TRUE; + /* AC scans may have only one component */ + if (cinfo->comps_in_scan != 1) + bad = TRUE; + } + if (cinfo->Ah != 0) { + /* Successive approximation refinement scan: must have Al = Ah-1. */ + if (cinfo->Al != cinfo->Ah-1) + bad = TRUE; + } + if (cinfo->Al > 13) /* need not check for < 0 */ + bad = TRUE; + /* Arguably the maximum Al value should be less than 13 for 8-bit precision, + * but the spec doesn't say so, and we try to be liberal about what we + * accept. Note: large Al values could result in out-of-range DC + * coefficients during early scans, leading to bizarre displays due to + * overflows in the IDCT math. But we won't crash. + */ + if (bad) + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); + /* Update progression status, and verify that scan order is legal. + * Note that inter-scan inconsistencies are treated as warnings + * not fatal errors ... not clear if this is right way to behave. + */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + int cindex = cinfo->cur_comp_info[ci]->component_index; + coef_bit_ptr = & cinfo->coef_bits[cindex][0]; + if (!is_DC_band && coef_bit_ptr[0] < 0) /* AC without prior DC scan */ + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0); + for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) { + int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi]; + if (cinfo->Ah != expected) + WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi); + coef_bit_ptr[coefi] = cinfo->Al; + } + } + + /* Select MCU decoding routine */ + if (cinfo->Ah == 0) { + if (is_DC_band) + entropy->pub.decode_mcu = decode_mcu_DC_first; + else + entropy->pub.decode_mcu = decode_mcu_AC_first; + } else { + if (is_DC_band) + entropy->pub.decode_mcu = decode_mcu_DC_refine; + else + entropy->pub.decode_mcu = decode_mcu_AC_refine; + } + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + /* Make sure requested tables are present, and compute derived tables. + * We may build same derived table more than once, but it's not expensive. + */ + if (is_DC_band) { + if (cinfo->Ah == 0) { /* DC refinement needs no table */ + tbl = compptr->dc_tbl_no; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, + & entropy->derived_tbls[tbl]); + } + } else { + tbl = compptr->ac_tbl_no; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, + & entropy->derived_tbls[tbl]); + /* remember the single active table */ + entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; + } + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->pub.insufficient_data = FALSE; + + /* Initialize private state variables */ + entropy->saved.EOBRUN = 0; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL(boolean) +process_restart (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + /* Re-init EOB run count, too */ + entropy->saved.EOBRUN = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Reset out-of-data flag, unless read_restart_marker left us smack up + * against a marker. In that case we will end up treating the next data + * segment as empty, and we can avoid producing bogus output pixels by + * leaving the flag set. + */ + if (cinfo->unread_marker == 0) + entropy->pub.insufficient_data = FALSE; + + return TRUE; +} + + +/* + * Huffman MCU decoding. + * Each of these routines decodes and returns one MCU's worth of + * Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. + * + * We return FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * spectral selection, since we'll just re-assign them on the next call. + * Successive approximation AC refinement has to be more careful, however.) + */ + +/* + * MCU decoding for DC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Al = cinfo->Al; + register int s, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * tbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + tbl = entropy->derived_tbls[compptr->dc_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, tbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ + (*block)[0] = (JCOEF) (s << Al); + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC initial scan (either spectral selection, + * or first pass of successive approximation). + */ + +METHODDEF(boolean) +decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Se = cinfo->Se; + int Al = cinfo->Al; + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, just leave the MCU set to zeroes. + * This way, we return uniform gray for the remainder of the segment. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state. + * We can avoid loading/saving bitread state if in an EOB run. + */ + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + + if (EOBRUN > 0) /* if it's a band of zeroes... */ + EOBRUN--; /* ...process it now (we do nothing) */ + else { + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + for (k = cinfo->Ss; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, return FALSE, label2); + r = s >> 4; + s &= 15; + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Scale and output coefficient in natural (dezigzagged) order */ + (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al); + } else { + if (r == 15) { /* ZRL */ + k += 15; /* skip 15 zeroes in band */ + } else { /* EOBr, run length is 2^r + appended bits */ + EOBRUN = 1 << r; + if (r) { /* EOBr, r > 0 */ + CHECK_BIT_BUFFER(br_state, r, return FALSE); + r = GET_BITS(r); + EOBRUN += r; + } + EOBRUN--; /* this band is processed at this moment */ + break; /* force end-of-band */ + } + } + } + + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + } + + /* Completed MCU, so update state */ + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for DC successive approximation refinement scan. + * Note: we assume such scans can be multi-component, although the spec + * is not very clear on the point. + */ + +METHODDEF(boolean) +decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int blkn; + JBLOCKROW block; + BITREAD_STATE_VARS; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Not worth the cycles to check insufficient_data here, + * since we will not change the data anyway if we read zeroes. + */ + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + + /* Encoded data is simply the next bit of the two's-complement DC value */ + CHECK_BIT_BUFFER(br_state, 1, return FALSE); + if (GET_BITS(1)) + (*block)[0] |= p1; + /* Note: since we use |=, repeating the assignment later is safe */ + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * MCU decoding for AC successive approximation refinement scan. + */ + +METHODDEF(boolean) +decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; + int Se = cinfo->Se; + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + register int s, k, r; + unsigned int EOBRUN; + JBLOCKROW block; + JCOEFPTR thiscoef; + BITREAD_STATE_VARS; + d_derived_tbl * tbl; + int num_newnz; + int newnz_pos[DCTSIZE2]; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* If we've run out of data, don't modify the MCU. + */ + if (! entropy->pub.insufficient_data) { + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */ + + /* There is always only one block per MCU */ + block = MCU_data[0]; + tbl = entropy->ac_derived_tbl; + + /* If we are forced to suspend, we must undo the assignments to any newly + * nonzero coefficients in the block, because otherwise we'd get confused + * next time about which coefficients were already nonzero. + * But we need not undo addition of bits to already-nonzero coefficients; + * instead, we can test the current bit to see if we already did it. + */ + num_newnz = 0; + + /* initialize coefficient loop counter to start of band */ + k = cinfo->Ss; + + if (EOBRUN == 0) { + for (; k <= Se; k++) { + HUFF_DECODE(s, br_state, tbl, goto undoit, label3); + r = s >> 4; + s &= 15; + if (s) { + if (s != 1) /* size of new coef should always be 1 */ + WARNMS(cinfo, JWRN_HUFF_BAD_CODE); + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) + s = p1; /* newly nonzero coef is positive */ + else + s = m1; /* newly nonzero coef is negative */ + } else { + if (r != 15) { + EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */ + if (r) { + CHECK_BIT_BUFFER(br_state, r, goto undoit); + r = GET_BITS(r); + EOBRUN += r; + } + break; /* rest of block is handled by EOB logic */ + } + /* note s = 0 for processing ZRL */ + } + /* Advance over already-nonzero coefs and r still-zero coefs, + * appending correction bits to the nonzeroes. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + do { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } else { + if (--r < 0) + break; /* reached target zero coefficient */ + } + k++; + } while (k <= Se); + if (s) { + int pos = jpeg_natural_order[k]; + /* Output newly nonzero coefficient */ + (*block)[pos] = (JCOEF) s; + /* Remember its position in case we have to suspend */ + newnz_pos[num_newnz++] = pos; + } + } + } + + if (EOBRUN > 0) { + /* Scan any remaining coefficient positions after the end-of-band + * (the last newly nonzero coefficient, if any). Append a correction + * bit to each already-nonzero coefficient. A correction bit is 1 + * if the absolute value of the coefficient must be increased. + */ + for (; k <= Se; k++) { + thiscoef = *block + jpeg_natural_order[k]; + if (*thiscoef != 0) { + CHECK_BIT_BUFFER(br_state, 1, goto undoit); + if (GET_BITS(1)) { + if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ + if (*thiscoef >= 0) + *thiscoef += p1; + else + *thiscoef += m1; + } + } + } + } + /* Count one block completed in EOB run */ + EOBRUN--; + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */ + } + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; + +undoit: + /* Re-zero any output coefficients that we made newly nonzero */ + while (num_newnz > 0) + (*block)[newnz_pos[--num_newnz]] = 0; + + return FALSE; +} + + +/* + * Module initialization routine for progressive Huffman entropy decoding. + */ + +GLOBAL(void) +jinit_phuff_decoder (j_decompress_ptr cinfo) +{ + phuff_entropy_ptr entropy; + int *coef_bit_ptr; + int ci, i; + + entropy = (phuff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(phuff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_phuff_decoder; + + /* Mark derived tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->derived_tbls[i] = NULL; + } + + /* Create progression status table */ + cinfo->coef_bits = (int (*)[DCTSIZE2]) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components*DCTSIZE2*SIZEOF(int)); + coef_bit_ptr = & cinfo->coef_bits[0][0]; + for (ci = 0; ci < cinfo->num_components; ci++) + for (i = 0; i < DCTSIZE2; i++) + *coef_bit_ptr++ = -1; +} + +#endif /* D_PROGRESSIVE_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jdpostct.c b/freeimage241/Source/LibJPEG/jdpostct.c new file mode 100644 index 0000000..571563d --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdpostct.c @@ -0,0 +1,290 @@ +/* + * jdpostct.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the decompression postprocessing controller. + * This controller manages the upsampling, color conversion, and color + * quantization/reduction steps; specifically, it controls the buffering + * between upsample/color conversion and color quantization/reduction. + * + * If no color quantization/reduction is required, then this module has no + * work to do, and it just hands off to the upsample/color conversion code. + * An integrated upsample/convert/quantize process would replace this module + * entirely. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Private buffer controller object */ + +typedef struct { + struct jpeg_d_post_controller pub; /* public fields */ + + /* Color quantization source buffer: this holds output data from + * the upsample/color conversion step to be passed to the quantizer. + * For two-pass color quantization, we need a full-image buffer; + * for one-pass operation, a strip buffer is sufficient. + */ + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + JDIMENSION strip_height; /* buffer size in rows */ + /* for two-pass mode only: */ + JDIMENSION starting_row; /* row # of first row in current strip */ + JDIMENSION next_row; /* index of next row to fill/empty in strip */ +} my_post_controller; + +typedef my_post_controller * my_post_ptr; + + +/* Forward declarations */ +METHODDEF(void) post_process_1pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#ifdef QUANT_2PASS_SUPPORTED +METHODDEF(void) post_process_prepass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +METHODDEF(void) post_process_2pass + JPP((j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +#endif + + +/* + * Initialize for a processing pass. + */ + +METHODDEF(void) +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + + switch (pass_mode) { + case JBUF_PASS_THRU: + if (cinfo->quantize_colors) { + /* Single-pass processing with color quantization. */ + post->pub.post_process_data = post_process_1pass; + /* We could be doing buffered-image output before starting a 2-pass + * color quantization; in that case, jinit_d_post_controller did not + * allocate a strip buffer. Use the virtual-array buffer as workspace. + */ + if (post->buffer == NULL) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + (JDIMENSION) 0, post->strip_height, TRUE); + } + } else { + /* For single-pass processing without color quantization, + * I have no work to do; just call the upsampler directly. + */ + post->pub.post_process_data = cinfo->upsample->upsample; + } + break; +#ifdef QUANT_2PASS_SUPPORTED + case JBUF_SAVE_AND_PASS: + /* First pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_prepass; + break; + case JBUF_CRANK_DEST: + /* Second pass of 2-pass quantization */ + if (post->whole_image == NULL) + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + post->pub.post_process_data = post_process_2pass; + break; +#endif /* QUANT_2PASS_SUPPORTED */ + default: + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + break; + } + post->starting_row = post->next_row = 0; +} + + +/* + * Process some data in the one-pass (strip buffer) case. + * This is used for color precision reduction as well as one-pass quantization. + */ + +METHODDEF(void) +post_process_1pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Fill the buffer, but not more than what we can dump out in one go. */ + /* Note we rely on the upsampler to detect bottom of image. */ + max_rows = out_rows_avail - *out_row_ctr; + if (max_rows > post->strip_height) + max_rows = post->strip_height; + num_rows = 0; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &num_rows, max_rows); + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + *out_row_ctr += num_rows; +} + + +#ifdef QUANT_2PASS_SUPPORTED + +/* + * Process some data in the first pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_prepass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION old_next_row, num_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, TRUE); + } + + /* Upsample some data (up to a strip height's worth). */ + old_next_row = post->next_row; + (*cinfo->upsample->upsample) (cinfo, + input_buf, in_row_group_ctr, in_row_groups_avail, + post->buffer, &post->next_row, post->strip_height); + + /* Allow quantizer to scan new data. No data is emitted, */ + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + if (post->next_row > old_next_row) { + num_rows = post->next_row - old_next_row; + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + (JSAMPARRAY) NULL, (int) num_rows); + *out_row_ctr += num_rows; + } + + /* Advance if we filled the strip. */ + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + + +/* + * Process some data in the second pass of 2-pass quantization. + */ + +METHODDEF(void) +post_process_2pass (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_post_ptr post = (my_post_ptr) cinfo->post; + JDIMENSION num_rows, max_rows; + + /* Reposition virtual buffer if at start of strip. */ + if (post->next_row == 0) { + post->buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, post->whole_image, + post->starting_row, post->strip_height, FALSE); + } + + /* Determine number of rows to emit. */ + num_rows = post->strip_height - post->next_row; /* available in strip */ + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + if (num_rows > max_rows) + num_rows = max_rows; + /* We have to check bottom of image here, can't depend on upsampler. */ + max_rows = cinfo->output_height - post->starting_row; + if (num_rows > max_rows) + num_rows = max_rows; + + /* Quantize and emit data. */ + (*cinfo->cquantize->color_quantize) (cinfo, + post->buffer + post->next_row, output_buf + *out_row_ctr, + (int) num_rows); + *out_row_ctr += num_rows; + + /* Advance if we filled the strip. */ + post->next_row += num_rows; + if (post->next_row >= post->strip_height) { + post->starting_row += post->strip_height; + post->next_row = 0; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ + + +/* + * Initialize postprocessing controller. + */ + +GLOBAL(void) +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) +{ + my_post_ptr post; + + post = (my_post_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_post_controller)); + cinfo->post = (struct jpeg_d_post_controller *) post; + post->pub.start_pass = start_pass_dpost; + post->whole_image = NULL; /* flag for no virtual arrays */ + post->buffer = NULL; /* flag for no strip buffer */ + + /* Create the quantization buffer, if needed */ + if (cinfo->quantize_colors) { + /* The buffer strip height is max_v_samp_factor, which is typically + * an efficient number of rows for upsampling to return. + * (In the presence of output rescaling, we might want to be smarter?) + */ + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + if (need_full_buffer) { + /* Two-pass color quantization: need full-image storage. */ + /* We round up the number of rows to a multiple of the strip height. */ +#ifdef QUANT_2PASS_SUPPORTED + post->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + cinfo->output_width * cinfo->out_color_components, + (JDIMENSION) jround_up((long) cinfo->output_height, + (long) post->strip_height), + post->strip_height); +#else + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + /* One-pass color quantization: just make a strip buffer. */ + post->buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->out_color_components, + post->strip_height); + } + } +} diff --git a/freeimage241/Source/LibJPEG/jdsample.c b/freeimage241/Source/LibJPEG/jdsample.c new file mode 100644 index 0000000..80ffefb --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdsample.c @@ -0,0 +1,478 @@ +/* + * jdsample.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains upsampling routines. + * + * Upsampling input data is counted in "row groups". A row group + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + * sample rows of each component. Upsampling will normally produce + * max_v_samp_factor pixel rows from each row group (but this could vary + * if the upsampler is applying a scale factor of its own). + * + * An excellent reference for image resampling is + * Digital Image Warping, George Wolberg, 1990. + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Pointer to routine to upsample a single component */ +typedef JMETHOD(void, upsample1_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + +/* Private subobject */ + +typedef struct { + struct jpeg_upsampler pub; /* public fields */ + + /* Color conversion buffer. When using separate upsampling and color + * conversion steps, this buffer holds one upsampled row group until it + * has been color converted and output. + * Note: we do not allocate any storage for component(s) which are full-size, + * ie do not need rescaling. The corresponding entry of color_buf[] is + * simply set to point to the input data array, thereby avoiding copying. + */ + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + /* Per-component upsampling method pointers */ + upsample1_ptr methods[MAX_COMPONENTS]; + + int next_row_out; /* counts rows emitted from color_buf */ + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + /* Height of an input row group for each component. */ + int rowgroup_height[MAX_COMPONENTS]; + + /* These arrays save pixel expansion factors so that int_expand need not + * recompute them each time. They are unused for other upsampling methods. + */ + UINT8 h_expand[MAX_COMPONENTS]; + UINT8 v_expand[MAX_COMPONENTS]; +} my_upsampler; + +typedef my_upsampler * my_upsample_ptr; + + +/* + * Initialize for an upsampling pass. + */ + +METHODDEF(void) +start_pass_upsample (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + /* Mark the conversion buffer empty */ + upsample->next_row_out = cinfo->max_v_samp_factor; + /* Initialize total-height counter for detecting bottom of image */ + upsample->rows_to_go = cinfo->output_height; +} + + +/* + * Control routine to do upsampling (and color conversion). + * + * In this version we upsample each component independently. + * We upsample one row group into the conversion buffer, then apply + * color conversion a row at a time. + */ + +METHODDEF(void) +sep_upsample (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + int ci; + jpeg_component_info * compptr; + JDIMENSION num_rows; + + /* Fill the conversion buffer, if it's empty */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Invoke per-component upsample method. Notice we pass a POINTER + * to color_buf[ci], so that fullsize_upsample can change it. + */ + (*upsample->methods[ci]) (cinfo, compptr, + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + upsample->color_buf + ci); + } + upsample->next_row_out = 0; + } + + /* Color-convert and emit rows */ + + /* How many we have in the buffer: */ + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + /* Not more than the distance to the end of the image. Need this test + * in case the image height is not a multiple of max_v_samp_factor: + */ + if (num_rows > upsample->rows_to_go) + num_rows = upsample->rows_to_go; + /* And not more than what the client can accept: */ + out_rows_avail -= *out_row_ctr; + if (num_rows > out_rows_avail) + num_rows = out_rows_avail; + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + (JDIMENSION) upsample->next_row_out, + output_buf + *out_row_ctr, + (int) num_rows); + + /* Adjust counts */ + *out_row_ctr += num_rows; + upsample->rows_to_go -= num_rows; + upsample->next_row_out += num_rows; + /* When the buffer is emptied, declare this input row group consumed */ + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + (*in_row_group_ctr)++; +} + + +/* + * These are the routines invoked by sep_upsample to upsample pixel values + * of a single component. One row group is processed per call. + */ + + +/* + * For full-size components, we just make color_buf[ci] point at the + * input buffer, and thus avoid copying any data. Note that this is + * safe only because sep_upsample doesn't declare the input row group + * "consumed" until we are done color converting and emitting it. + */ + +METHODDEF(void) +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = input_data; +} + + +/* + * This is a no-op version used for "uninteresting" components. + * These components will not be referenced by color conversion. + */ + +METHODDEF(void) +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + *output_data_ptr = NULL; /* safety check */ +} + + +/* + * This version handles any integral sampling ratios. + * This is not used for typical JPEG files, so it need not be fast. + * Nor, for that matter, is it particularly accurate: the algorithm is + * simple replication of the input pixel onto the corresponding output + * pixels. The hi-falutin sampling literature refers to this as a + * "box filter". A box filter tends to introduce visible artifacts, + * so if you are actually going to use 3:1 or 4:1 sampling ratios + * you would be well advised to improve this code. + */ + +METHODDEF(void) +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + register int h; + JSAMPROW outend; + int h_expand, v_expand; + int inrow, outrow; + + h_expand = upsample->h_expand[compptr->component_index]; + v_expand = upsample->v_expand[compptr->component_index]; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + /* Generate one output row with proper horizontal expansion */ + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + for (h = h_expand; h > 0; h--) { + *outptr++ = invalue; + } + } + /* Generate any additional output rows by duplicating the first one */ + if (v_expand > 1) { + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + v_expand-1, cinfo->output_width); + } + inrow++; + outrow += v_expand; + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + } +} + + +/* + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + * It's still a box filter. + */ + +METHODDEF(void) +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register JSAMPLE invalue; + JSAMPROW outend; + int inrow, outrow; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + inptr = input_data[inrow]; + outptr = output_data[outrow]; + outend = outptr + cinfo->output_width; + while (outptr < outend) { + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + *outptr++ = invalue; + *outptr++ = invalue; + } + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + 1, cinfo->output_width); + inrow++; + outrow += 2; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. + * + * The upsampling algorithm is linear interpolation between pixel centers, + * also known as a "triangle filter". This is a good compromise between + * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 + * of the way between input pixel centers. + * + * A note about the "bias" calculations: when rounding fractional values to + * integer, we do not want to always round 0.5 up to the next integer. + * If we did that, we'd introduce a noticeable bias towards larger values. + * Instead, this code is arranged so that 0.5 will be rounded up or down at + * alternate pixel locations (a simple ordered dither pattern). + */ + +METHODDEF(void) +h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr, outptr; + register int invalue; + register JDIMENSION colctr; + int inrow; + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + inptr = input_data[inrow]; + outptr = output_data[inrow]; + /* Special case for first column */ + invalue = GETJSAMPLE(*inptr++); + *outptr++ = (JSAMPLE) invalue; + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + invalue = GETJSAMPLE(*inptr++) * 3; + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); + } + + /* Special case for last column */ + invalue = GETJSAMPLE(*inptr); + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); + *outptr++ = (JSAMPLE) invalue; + } +} + + +/* + * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. + * Again a triangle filter; see comments for h2v1 case, above. + * + * It is OK for us to reference the adjacent input rows because we demanded + * context from the main buffer controller (see initialization code). + */ + +METHODDEF(void) +h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) +{ + JSAMPARRAY output_data = *output_data_ptr; + register JSAMPROW inptr0, inptr1, outptr; +#if BITS_IN_JSAMPLE == 8 + register int thiscolsum, lastcolsum, nextcolsum; +#else + register INT32 thiscolsum, lastcolsum, nextcolsum; +#endif + register JDIMENSION colctr; + int inrow, outrow, v; + + inrow = outrow = 0; + while (outrow < cinfo->max_v_samp_factor) { + for (v = 0; v < 2; v++) { + /* inptr0 points to nearest input row, inptr1 points to next nearest */ + inptr0 = input_data[inrow]; + if (v == 0) /* next nearest is row above */ + inptr1 = input_data[inrow-1]; + else /* next nearest is row below */ + inptr1 = input_data[inrow+1]; + outptr = output_data[outrow++]; + + /* Special case for first column */ + thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ + /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + } + + /* Special case for last column */ + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); + } + inrow++; + } +} + + +/* + * Module initialization routine for upsampling. + */ + +GLOBAL(void) +jinit_upsampler (j_decompress_ptr cinfo) +{ + my_upsample_ptr upsample; + int ci; + jpeg_component_info * compptr; + boolean need_buffer, do_fancy; + int h_in_group, v_in_group, h_out_group, v_out_group; + + upsample = (my_upsample_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_upsampler)); + cinfo->upsample = (struct jpeg_upsampler *) upsample; + upsample->pub.start_pass = start_pass_upsample; + upsample->pub.upsample = sep_upsample; + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1, + * so don't ask for it. + */ + do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1; + + /* Verify we can handle the sampling factors, select per-component methods, + * and create storage as needed. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Compute size of an "input group" after IDCT scaling. This many samples + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + */ + h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; + v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + cinfo->min_DCT_scaled_size; + h_out_group = cinfo->max_h_samp_factor; + v_out_group = cinfo->max_v_samp_factor; + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + need_buffer = TRUE; + if (! compptr->component_needed) { + /* Don't bother to upsample an uninteresting component. */ + upsample->methods[ci] = noop_upsample; + need_buffer = FALSE; + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + /* Fullsize components can be processed without any work. */ + upsample->methods[ci] = fullsize_upsample; + need_buffer = FALSE; + } else if (h_in_group * 2 == h_out_group && + v_in_group == v_out_group) { + /* Special cases for 2h1v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) + upsample->methods[ci] = h2v1_fancy_upsample; + else + upsample->methods[ci] = h2v1_upsample; + } else if (h_in_group * 2 == h_out_group && + v_in_group * 2 == v_out_group) { + /* Special cases for 2h2v upsampling */ + if (do_fancy && compptr->downsampled_width > 2) { + upsample->methods[ci] = h2v2_fancy_upsample; + upsample->pub.need_context_rows = TRUE; + } else + upsample->methods[ci] = h2v2_upsample; + } else if ((h_out_group % h_in_group) == 0 && + (v_out_group % v_in_group) == 0) { + /* Generic integral-factors upsampling method */ + upsample->methods[ci] = int_upsample; + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + } else + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + if (need_buffer) { + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) jround_up((long) cinfo->output_width, + (long) cinfo->max_h_samp_factor), + (JDIMENSION) cinfo->max_v_samp_factor); + } + } +} diff --git a/freeimage241/Source/LibJPEG/jdtrans.c b/freeimage241/Source/LibJPEG/jdtrans.c new file mode 100644 index 0000000..6c0ab71 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jdtrans.c @@ -0,0 +1,143 @@ +/* + * jdtrans.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains library routines for transcoding decompression, + * that is, reading raw DCT coefficient arrays from an input JPEG file. + * The routines in jdapimin.c will also be needed by a transcoder. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* Forward declarations */ +LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + +/* + * Read the coefficient arrays from a JPEG file. + * jpeg_read_header must be completed before calling this. + * + * The entire image is read into a set of virtual coefficient-block arrays, + * one per component. The return value is a pointer to the array of + * virtual-array descriptors. These can be manipulated directly via the + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + * To release the memory occupied by the virtual arrays, call + * jpeg_finish_decompress() when done with the data. + * + * An alternative usage is to simply obtain access to the coefficient arrays + * during a buffered-image-mode decompression operation. This is allowed + * after any jpeg_finish_output() call. The arrays can be accessed until + * jpeg_finish_decompress() is called. (Note that any call to the library + * may reposition the arrays, so don't rely on access_virt_barray() results + * to stay valid across library calls.) + * + * Returns NULL if suspended. This case need be checked only if + * a suspending data source is used. + */ + +GLOBAL(jvirt_barray_ptr *) +jpeg_read_coefficients (j_decompress_ptr cinfo) +{ + if (cinfo->global_state == DSTATE_READY) { + /* First call: initialize active modules */ + transdecode_master_selection(cinfo); + cinfo->global_state = DSTATE_RDCOEFS; + } + if (cinfo->global_state == DSTATE_RDCOEFS) { + /* Absorb whole file into the coef buffer */ + for (;;) { + int retcode; + /* Call progress monitor hook if present */ + if (cinfo->progress != NULL) + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + /* Absorb some more input */ + retcode = (*cinfo->inputctl->consume_input) (cinfo); + if (retcode == JPEG_SUSPENDED) + return NULL; + if (retcode == JPEG_REACHED_EOI) + break; + /* Advance progress counter if appropriate */ + if (cinfo->progress != NULL && + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + /* startup underestimated number of scans; ratchet up one scan */ + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + } + } + } + /* Set state so that jpeg_finish_decompress does the right thing */ + cinfo->global_state = DSTATE_STOPPING; + } + /* At this point we should be in state DSTATE_STOPPING if being used + * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access + * to the coefficients during a full buffered-image-mode decompression. + */ + if ((cinfo->global_state == DSTATE_STOPPING || + cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) { + return cinfo->coef->coef_arrays; + } + /* Oops, improper usage */ + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + return NULL; /* keep compiler happy */ +} + + +/* + * Master selection of decompression modules for transcoding. + * This substitutes for jdmaster.c's initialization of the full decompressor. + */ + +LOCAL(void) +transdecode_master_selection (j_decompress_ptr cinfo) +{ + /* This is effectively a buffered-image operation. */ + cinfo->buffered_image = TRUE; + + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Always get a full-image coefficient buffer. */ + jinit_d_coef_controller(cinfo, TRUE); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + + /* Initialize progress monitoring. */ + if (cinfo->progress != NULL) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else if (cinfo->inputctl->has_multiple_scans) { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } else { + nscans = 1; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = 1; + } +} diff --git a/freeimage241/Source/LibJPEG/jerror.c b/freeimage241/Source/LibJPEG/jerror.c new file mode 100644 index 0000000..5802b99 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jerror.c @@ -0,0 +1,248 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile, + * you get a Windows-specific hack to display error messages in a dialog box. + * It ain't much, but it beats dropping error messages into the bit bucket, + * which is what happens to output to stderr under most Windows C compilers. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF(void) +error_exit (j_common_ptr cinfo) +{ + /* Always display the message */ + (*cinfo->err->output_message) (cinfo); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + exit(EXIT_FAILURE); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + * + * On Windows, printing to stderr is generally completely useless, + * so we provide optional code to produce an error-dialog popup. + * Most Windows applications will still prefer to override this routine, + * but if they don't, it'll do something at least marginally useful. + * + * NOTE: to use the library in an environment that doesn't support the + * C stdio library, you may have to delete the call to fprintf() entirely, + * not just not use this routine. + */ + +METHODDEF(void) +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + +#ifdef USE_WINDOWS_MESSAGEBOX + /* Display it in a message dialog box */ + MessageBox(GetActiveWindow(), buffer, "JPEG Library Error", + MB_OK | MB_ICONERROR); +#else + /* Send it to stderr, adding a newline */ + fprintf(stderr, "%s\n", buffer); +#endif +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF(void) +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF(void) +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF(void) +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL(struct jpeg_error_mgr *) +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/freeimage241/Source/LibJPEG/jerror.h b/freeimage241/Source/LibJPEG/jerror.h new file mode 100644 index 0000000..fc2fffe --- /dev/null +++ b/freeimage241/Source/LibJPEG/jerror.h @@ -0,0 +1,291 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/freeimage241/Source/LibJPEG/jfdctflt.c b/freeimage241/Source/LibJPEG/jfdctflt.c new file mode 100644 index 0000000..79d7a00 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jfdctflt.c @@ -0,0 +1,168 @@ +/* + * jfdctflt.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * forward DCT (Discrete Cosine Transform). + * + * This implementation should be more accurate than either of the integer + * DCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_float (FAST_FLOAT * data) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + FAST_FLOAT *dataptr; + int ctr; + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jfdctfst.c b/freeimage241/Source/LibJPEG/jfdctfst.c new file mode 100644 index 0000000..ccb378a --- /dev/null +++ b/freeimage241/Source/LibJPEG/jfdctfst.c @@ -0,0 +1,224 @@ +/* + * jfdctfst.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jfdctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * Again to save a few shifts, the intermediate results between pass 1 and + * pass 2 are not upscaled, but are represented only to integral precision. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#define CONST_BITS 8 + + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */ +#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */ +#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */ +#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */ +#else +#define FIX_0_382683433 FIX(0.382683433) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_707106781 FIX(0.707106781) +#define FIX_1_306562965 FIX(1.306562965) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_ifast (DCTELEM * data) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z1, z2, z3, z4, z5, z11, z13; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + dataptr[4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[2] = tmp13 + z1; /* phase 5 */ + dataptr[6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[5] = z13 + z2; /* phase 6 */ + dataptr[3] = z13 - z2; + dataptr[1] = z11 + z4; + dataptr[7] = z11 - z4; + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part */ + + tmp10 = tmp0 + tmp3; /* phase 2 */ + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */ + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + dataptr[DCTSIZE*6] = tmp13 - z1; + + /* Odd part */ + + tmp10 = tmp4 + tmp5; /* phase 2 */ + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */ + z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */ + z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */ + z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */ + + z11 = tmp7 + z3; /* phase 5 */ + z13 = tmp7 - z3; + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + dataptr[DCTSIZE*3] = z13 - z2; + dataptr[DCTSIZE*1] = z11 + z4; + dataptr[DCTSIZE*7] = z11 - z4; + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jfdctint.c b/freeimage241/Source/LibJPEG/jfdctint.c new file mode 100644 index 0000000..0a78b64 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jfdctint.c @@ -0,0 +1,283 @@ +/* + * jfdctint.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * forward DCT (Discrete Cosine Transform). + * + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + * on each column. Direct algorithms are also available, but they are + * much more complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D DCT step produces outputs which are a factor of sqrt(N) + * larger than the true DCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D DCT, + * because the y0 and y4 outputs need not be divided by sqrt(N). + * In the IJG code, this factor of 8 is removed by the quantization step + * (in jcdctmgr.c), NOT in this module. + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (For 12-bit sample data, the intermediate + * array is INT32 anyway.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* + * Perform the forward DCT on one block of samples. + */ + +GLOBAL(void) +jpeg_fdct_islow (DCTELEM * data) +{ + INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + DCTELEM *dataptr; + int ctr; + SHIFT_TEMPS + + /* Pass 1: process rows. */ + /* Note results are scaled up by sqrt(8) compared to a true DCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[0] + dataptr[7]; + tmp7 = dataptr[0] - dataptr[7]; + tmp1 = dataptr[1] + dataptr[6]; + tmp6 = dataptr[1] - dataptr[6]; + tmp2 = dataptr[2] + dataptr[5]; + tmp5 = dataptr[2] - dataptr[5]; + tmp3 = dataptr[3] + dataptr[4]; + tmp4 = dataptr[3] - dataptr[4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS); + dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS-PASS1_BITS); + dataptr[6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS-PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS); + dataptr[5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS); + dataptr[3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS); + dataptr[1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS); + + dataptr += DCTSIZE; /* advance pointer to next row */ + } + + /* Pass 2: process columns. + * We remove the PASS1_BITS scaling, but leave the results scaled up + * by an overall factor of 8. + */ + + dataptr = data; + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + /* Even part per LL&M figure 1 --- note that published figure is faulty; + * rotator "sqrt(2)*c1" should be "sqrt(2)*c6". + */ + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS); + dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS); + + z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); + dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), + CONST_BITS+PASS1_BITS); + + /* Odd part per figure 8 --- note paper omits factor of sqrt(2). + * cK represents cos(K*pi/16). + * i0..i3 in the paper are tmp4..tmp7 here. + */ + + z1 = tmp4 + tmp7; + z2 = tmp5 + tmp6; + z3 = tmp4 + tmp6; + z4 = tmp5 + tmp7; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp4 = MULTIPLY(tmp4, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp5 = MULTIPLY(tmp5, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp6 = MULTIPLY(tmp6, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp7 = MULTIPLY(tmp7, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp4 + z1 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp5 + z2 + z4, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp6 + z2 + z3, + CONST_BITS+PASS1_BITS); + dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp7 + z1 + z4, + CONST_BITS+PASS1_BITS); + + dataptr++; /* advance pointer to next column */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jidctflt.c b/freeimage241/Source/LibJPEG/jidctflt.c new file mode 100644 index 0000000..0188ce3 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jidctflt.c @@ -0,0 +1,242 @@ +/* + * jidctflt.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a floating-point implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * This implementation should be more accurate than either of the integer + * IDCT implementations. However, it may not give the same results on all + * machines because of differences in roundoff behavior. Speed will depend + * on the hardware's floating point capacity. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with a fixed-point + * implementation, accuracy is lost due to imprecise representation of the + * scaled quantization values. However, that problem does not arise if + * we use floating point arithmetic. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_FLOAT_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a float result. + */ + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + FAST_FLOAT z5, z10, z11, z12, z13; + JCOEFPTR inptr; + FLOAT_MULT_TYPE * quantptr; + FAST_FLOAT * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + wsptr[DCTSIZE*7] = tmp0 - tmp7; + wsptr[DCTSIZE*1] = tmp1 + tmp6; + wsptr[DCTSIZE*6] = tmp1 - tmp6; + wsptr[DCTSIZE*2] = tmp2 + tmp5; + wsptr[DCTSIZE*5] = tmp2 - tmp5; + wsptr[DCTSIZE*4] = tmp3 + tmp4; + wsptr[DCTSIZE*3] = tmp3 - tmp4; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * And testing floats for zero is relatively expensive, so we don't bother. + */ + + /* Even part */ + + tmp10 = wsptr[0] + wsptr[4]; + tmp11 = wsptr[0] - wsptr[4]; + + tmp13 = wsptr[2] + wsptr[6]; + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; + + tmp7 = z11 + z13; + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_FLOAT_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jidctfst.c b/freeimage241/Source/LibJPEG/jidctfst.c new file mode 100644 index 0000000..dba4216 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jidctfst.c @@ -0,0 +1,368 @@ +/* + * jidctfst.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a fast, not so accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + * JPEG textbook (see REFERENCES section in file README). The following code + * is based directly on figure 4-8 in P&M. + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + * possible to arrange the computation so that many of the multiplies are + * simple scalings of the final outputs. These multiplies can then be + * folded into the multiplications or divisions by the JPEG quantization + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + * to be done in the DCT itself. + * The primary disadvantage of this method is that with fixed-point math, + * accuracy is lost due to imprecise representation of the scaled + * quantization values. The smaller the quantization table entry, the less + * precise the scaled value, so this implementation does worse with high- + * quality-setting files than with low-quality ones. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_IFAST_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling decisions are generally the same as in the LL&M algorithm; + * see jidctint.c for more details. However, we choose to descale + * (right shift) multiplication products as soon as they are formed, + * rather than carrying additional fractional bits into subsequent additions. + * This compromises accuracy slightly, but it lets us save a few shifts. + * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) + * everywhere except in the multiplications proper; this saves a good deal + * of work on 16-bit-int machines. + * + * The dequantized coefficients are not integers because the AA&N scaling + * factors have been incorporated. We represent them scaled up by PASS1_BITS, + * so that the first and second IDCT rounds have the same input scaling. + * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to + * avoid a descaling shift; this compromises accuracy rather drastically + * for small quantization table entries, but it saves a lot of shifts. + * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, + * so we use a much larger scaling factor to preserve accuracy. + * + * A final compromise is to represent the multiplicative constants to only + * 8 fractional bits, rather than 13. This saves some shifting work on some + * machines, and may also reduce the cost of multiplication (since there + * are fewer one-bits in the constants). + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 8 +#define PASS1_BITS 2 +#else +#define CONST_BITS 8 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 8 +#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */ +#else +#define FIX_1_082392200 FIX(1.082392200) +#define FIX_1_414213562 FIX(1.414213562) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_613125930 FIX(2.613125930) +#endif + + +/* We can gain a little more speed, with a further compromise in accuracy, + * by omitting the addition in a descaling shift. This yields an incorrectly + * rounded result half the time... + */ + +#ifndef USE_ACCURATE_ROUNDING +#undef DESCALE +#define DESCALE(x,n) RIGHT_SHIFT(x, n) +#endif + + +/* Multiply a DCTELEM variable by an INT32 constant, and immediately + * descale to yield a DCTELEM result. + */ + +#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS)) + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce a DCTELEM result. For 8-bit data a 16x16->16 + * multiplication will do. For 12-bit data, the multiplier table is + * declared INT32, so a 32-bit multiply will be used. + */ + +#if BITS_IN_JSAMPLE == 8 +#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval)) +#else +#define DEQUANTIZE(coef,quantval) \ + DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS) +#endif + + +/* Like DESCALE, but applies to a DCTELEM and produces an int. + * We assume that int right shift is unsigned if INT32 right shift is. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define ISHIFT_TEMPS DCTELEM ishift_temp; +#if BITS_IN_JSAMPLE == 8 +#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */ +#else +#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */ +#endif +#define IRIGHT_SHIFT(x,shft) \ + ((ishift_temp = (x)) < 0 ? \ + (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \ + (ishift_temp >> (shft))) +#else +#define ISHIFT_TEMPS +#define IRIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + +#ifdef USE_ACCURATE_ROUNDING +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n)) +#else +#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n)) +#endif + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + DCTELEM tmp10, tmp11, tmp12, tmp13; + DCTELEM z5, z10, z11, z12, z13; + JCOEFPTR inptr; + IFAST_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS /* for DESCALE */ + ISHIFT_TEMPS /* for IDESCALE */ + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (IFAST_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7); + wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7); + wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6); + wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6); + wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5); + wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5); + wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4); + wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]); + tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]); + + tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]); + tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562) + - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3]; + z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3]; + z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7]; + z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_IFAST_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jidctint.c b/freeimage241/Source/LibJPEG/jidctint.c new file mode 100644 index 0000000..a72b320 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jidctint.c @@ -0,0 +1,389 @@ +/* + * jidctint.c + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a slow-but-accurate integer implementation of the + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + * must also perform dequantization of the input coefficients. + * + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + * on each row (or vice versa, but it's more convenient to emit a row at + * a time). Direct algorithms are also available, but they are much more + * complex and seem not to be any faster when reduced to code. + * + * This implementation is based on an algorithm described in + * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT + * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, + * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. + * The primary algorithm described there uses 11 multiplies and 29 adds. + * We use their alternate method with 12 multiplies and 32 adds. + * The advantage of this method is that no data path contains more than one + * multiplication; this allows a very simple and accurate implementation in + * scaled fixed-point arithmetic, with a minimal number of shifts. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef DCT_ISLOW_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* + * The poop on this scaling stuff is as follows: + * + * Each 1-D IDCT step produces outputs which are a factor of sqrt(N) + * larger than the true IDCT outputs. The final outputs are therefore + * a factor of N larger than desired; since N=8 this can be cured by + * a simple right shift at the end of the algorithm. The advantage of + * this arrangement is that we save two multiplications per 1-D IDCT, + * because the y0 and y4 inputs need not be divided by sqrt(N). + * + * We have to do addition and subtraction of the integer inputs, which + * is no problem, and multiplication by fractional constants, which is + * a problem to do in integer arithmetic. We multiply all the constants + * by CONST_SCALE and convert them to integer constants (thus retaining + * CONST_BITS bits of precision in the constants). After doing a + * multiplication we have to divide the product by CONST_SCALE, with proper + * rounding, to produce the correct output. This division can be done + * cheaply as a right shift of CONST_BITS bits. We postpone shifting + * as long as possible so that partial sums can be added together with + * full fractional precision. + * + * The outputs of the first pass are scaled up by PASS1_BITS bits so that + * they are represented to better-than-integral precision. These outputs + * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word + * with the recommended scaling. (To scale up 12-bit sample data further, an + * intermediate INT32 array would be needed.) + * + * To avoid overflow of the 32-bit intermediate results in pass 2, we must + * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis + * shows that the values given below are the most effective. + */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */ +#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */ +#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */ +#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */ +#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */ +#else +#define FIX_0_298631336 FIX(0.298631336) +#define FIX_0_390180644 FIX(0.390180644) +#define FIX_0_541196100 FIX(0.541196100) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_175875602 FIX(1.175875602) +#define FIX_1_501321110 FIX(1.501321110) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_1_961570560 FIX(1.961570560) +#define FIX_2_053119869 FIX(2.053119869) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_072711026 FIX(3.072711026) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients. + */ + +GLOBAL(void) +jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp1, tmp2, tmp3; + INT32 tmp10, tmp11, tmp12, tmp13; + INT32 z1, z2, z3, z4, z5; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + /* Note results are scaled up by sqrt(8) compared to a true IDCT; */ + /* furthermore, we scale the results by 2**PASS1_BITS. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; ctr--) { + /* Due to quantization, we will usually find that many of the input + * coefficients are zero, especially the AC terms. We can exploit this + * by short-circuiting the IDCT calculation for any column in which all + * the AC terms are zero. In that case each output is equal to the + * DC coefficient (with scale factor as needed). + * With typical images and quantization tables, half or more of the + * column DCT calculations can be simplified this way. + */ + + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && + inptr[DCTSIZE*7] == 0) { + /* AC terms all zero */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + wsptr[DCTSIZE*4] = dcval; + wsptr[DCTSIZE*5] = dcval; + wsptr[DCTSIZE*6] = dcval; + wsptr[DCTSIZE*7] = dcval; + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + continue; + } + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + + tmp0 = (z2 + z3) << CONST_BITS; + tmp1 = (z2 - z3) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*7] = (int) DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*6] = (int) DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*5] = (int) DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS); + wsptr[DCTSIZE*4] = (int) DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS); + + inptr++; /* advance pointers to next column */ + quantptr++; + wsptr++; + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + wsptr = workspace; + for (ctr = 0; ctr < DCTSIZE; ctr++) { + outptr = output_buf[ctr] + output_col; + /* Rows of zeroes can be exploited in the same way as we did with columns. + * However, the column calculation has created many nonzero AC terms, so + * the simplification applies less often (typically 5% to 10% of the time). + * On machines with very fast multiplication, it's possible that the + * test takes more time than it's worth. In that case this section + * may be commented out. + */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + outptr[4] = dcval; + outptr[5] = dcval; + outptr[6] = dcval; + outptr[7] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part: reverse the even part of the forward DCT. */ + /* The rotator is sqrt(2)*c(-6). */ + + z2 = (INT32) wsptr[2]; + z3 = (INT32) wsptr[6]; + + z1 = MULTIPLY(z2 + z3, FIX_0_541196100); + tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); + tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); + + tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS; + tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + /* Odd part per figure 8; the matrix is unitary and hence its + * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. + */ + + tmp0 = (INT32) wsptr[7]; + tmp1 = (INT32) wsptr[5]; + tmp2 = (INT32) wsptr[3]; + tmp3 = (INT32) wsptr[1]; + + z1 = tmp0 + tmp3; + z2 = tmp1 + tmp2; + z3 = tmp0 + tmp2; + z4 = tmp1 + tmp3; + z5 = MULTIPLY(z3 + z4, FIX_1_175875602); /* sqrt(2) * c3 */ + + tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */ + tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */ + tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */ + tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */ + z1 = MULTIPLY(z1, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */ + z2 = MULTIPLY(z2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */ + z3 = MULTIPLY(z3, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */ + z4 = MULTIPLY(z4, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */ + + z3 += z5; + z4 += z5; + + tmp0 += z1 + z3; + tmp1 += z2 + z4; + tmp2 += z2 + z3; + tmp3 += z1 + z4; + + /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, + CONST_BITS+PASS1_BITS+3) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + +#endif /* DCT_ISLOW_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jidctred.c b/freeimage241/Source/LibJPEG/jidctred.c new file mode 100644 index 0000000..421f3c7 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jidctred.c @@ -0,0 +1,398 @@ +/* + * jidctred.c + * + * Copyright (C) 1994-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains inverse-DCT routines that produce reduced-size output: + * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. + * + * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) + * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step + * with an 8-to-4 step that produces the four averages of two adjacent outputs + * (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). + * These steps were derived by computing the corresponding values at the end + * of the normal LL&M code, then simplifying as much as possible. + * + * 1x1 is trivial: just take the DC coefficient divided by 8. + * + * See jidctint.c for additional comments. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jdct.h" /* Private declarations for DCT subsystem */ + +#ifdef IDCT_SCALING_SUPPORTED + + +/* + * This module is specialized to the case DCTSIZE = 8. + */ + +#if DCTSIZE != 8 + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ +#endif + + +/* Scaling is the same as in jidctint.c. */ + +#if BITS_IN_JSAMPLE == 8 +#define CONST_BITS 13 +#define PASS1_BITS 2 +#else +#define CONST_BITS 13 +#define PASS1_BITS 1 /* lose a little precision to avoid overflow */ +#endif + +/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus + * causing a lot of useless floating-point operations at run time. + * To get around this we use the following pre-calculated constants. + * If you change CONST_BITS you may want to add appropriate values. + * (With a reasonable C compiler, you can just rely on the FIX() macro...) + */ + +#if CONST_BITS == 13 +#define FIX_0_211164243 ((INT32) 1730) /* FIX(0.211164243) */ +#define FIX_0_509795579 ((INT32) 4176) /* FIX(0.509795579) */ +#define FIX_0_601344887 ((INT32) 4926) /* FIX(0.601344887) */ +#define FIX_0_720959822 ((INT32) 5906) /* FIX(0.720959822) */ +#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */ +#define FIX_0_850430095 ((INT32) 6967) /* FIX(0.850430095) */ +#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */ +#define FIX_1_061594337 ((INT32) 8697) /* FIX(1.061594337) */ +#define FIX_1_272758580 ((INT32) 10426) /* FIX(1.272758580) */ +#define FIX_1_451774981 ((INT32) 11893) /* FIX(1.451774981) */ +#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */ +#define FIX_2_172734803 ((INT32) 17799) /* FIX(2.172734803) */ +#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */ +#define FIX_3_624509785 ((INT32) 29692) /* FIX(3.624509785) */ +#else +#define FIX_0_211164243 FIX(0.211164243) +#define FIX_0_509795579 FIX(0.509795579) +#define FIX_0_601344887 FIX(0.601344887) +#define FIX_0_720959822 FIX(0.720959822) +#define FIX_0_765366865 FIX(0.765366865) +#define FIX_0_850430095 FIX(0.850430095) +#define FIX_0_899976223 FIX(0.899976223) +#define FIX_1_061594337 FIX(1.061594337) +#define FIX_1_272758580 FIX(1.272758580) +#define FIX_1_451774981 FIX(1.451774981) +#define FIX_1_847759065 FIX(1.847759065) +#define FIX_2_172734803 FIX(2.172734803) +#define FIX_2_562915447 FIX(2.562915447) +#define FIX_3_624509785 FIX(3.624509785) +#endif + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + * For 8-bit samples with the recommended scaling, all the variable + * and constant values involved are no more than 16 bits wide, so a + * 16x16->32 bit multiply can be used instead of a full 32x32 multiply. + * For 12-bit samples, a full 32-bit multiplication will be needed. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MULTIPLY(var,const) MULTIPLY16C16(var,const) +#else +#define MULTIPLY(var,const) ((var) * (const)) +#endif + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + * entry; produce an int result. In this module, both inputs and result + * are 16 bits or less, so either int or short multiply will work. + */ + +#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval)) + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 4x4 output block. + */ + +GLOBAL(void) +jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp2, tmp10, tmp12; + INT32 z1, z2, z3, z4; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*4]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process column 4, because second pass won't use it */ + if (ctr == DCTSIZE-4) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 && + inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 && + inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine term 4 for 4x4 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + wsptr[DCTSIZE*2] = dcval; + wsptr[DCTSIZE*3] = dcval; + + continue; + } + + /* Even part */ + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp0 <<= (CONST_BITS+1); + + z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + tmp2 = MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + z2 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + z4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*3] = (int) DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1); + wsptr[DCTSIZE*2] = (int) DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1); + } + + /* Pass 2: process 4 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 4; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && + wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + outptr[2] = dcval; + outptr[3] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1); + + tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065) + + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865); + + tmp10 = tmp0 + tmp2; + tmp12 = tmp0 - tmp2; + + /* Odd part */ + + z1 = (INT32) wsptr[7]; + z2 = (INT32) wsptr[5]; + z3 = (INT32) wsptr[3]; + z4 = (INT32) wsptr[1]; + + tmp0 = MULTIPLY(z1, - FIX_0_211164243) /* sqrt(2) * (c3-c1) */ + + MULTIPLY(z2, FIX_1_451774981) /* sqrt(2) * (c3+c7) */ + + MULTIPLY(z3, - FIX_2_172734803) /* sqrt(2) * (-c1-c5) */ + + MULTIPLY(z4, FIX_1_061594337); /* sqrt(2) * (c5+c7) */ + + tmp2 = MULTIPLY(z1, - FIX_0_509795579) /* sqrt(2) * (c7-c5) */ + + MULTIPLY(z2, - FIX_0_601344887) /* sqrt(2) * (c5-c1) */ + + MULTIPLY(z3, FIX_0_899976223) /* sqrt(2) * (c3-c7) */ + + MULTIPLY(z4, FIX_2_562915447); /* sqrt(2) * (c1+c3) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[3] = range_limit[(int) DESCALE(tmp10 - tmp2, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp12 + tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + outptr[2] = range_limit[(int) DESCALE(tmp12 - tmp0, + CONST_BITS+PASS1_BITS+3+1) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 2x2 output block. + */ + +GLOBAL(void) +jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + INT32 tmp0, tmp10, z1; + JCOEFPTR inptr; + ISLOW_MULT_TYPE * quantptr; + int * wsptr; + JSAMPROW outptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + int ctr; + int workspace[DCTSIZE*2]; /* buffers data between passes */ + SHIFT_TEMPS + + /* Pass 1: process columns from input, store into work array. */ + + inptr = coef_block; + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + wsptr = workspace; + for (ctr = DCTSIZE; ctr > 0; inptr++, quantptr++, wsptr++, ctr--) { + /* Don't bother to process columns 2,4,6 */ + if (ctr == DCTSIZE-2 || ctr == DCTSIZE-4 || ctr == DCTSIZE-6) + continue; + if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 && + inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) { + /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */ + int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + + wsptr[DCTSIZE*0] = dcval; + wsptr[DCTSIZE*1] = dcval; + + continue; + } + + /* Even part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + tmp10 = z1 << (CONST_BITS+2); + + /* Odd part */ + + z1 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + tmp0 = MULTIPLY(z1, - FIX_0_720959822); /* sqrt(2) * (c7-c5+c3-c1) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + tmp0 += MULTIPLY(z1, FIX_0_850430095); /* sqrt(2) * (-c1+c3+c5+c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + tmp0 += MULTIPLY(z1, - FIX_1_272758580); /* sqrt(2) * (-c1+c3-c5-c7) */ + z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + tmp0 += MULTIPLY(z1, FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + wsptr[DCTSIZE*0] = (int) DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2); + wsptr[DCTSIZE*1] = (int) DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2); + } + + /* Pass 2: process 2 rows from work array, store into output array. */ + + wsptr = workspace; + for (ctr = 0; ctr < 2; ctr++) { + outptr = output_buf[ctr] + output_col; + /* It's not clear whether a zero row test is worthwhile here ... */ + +#ifndef NO_ZERO_ROW_TEST + if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) { + /* AC terms all zero */ + JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3) + & RANGE_MASK]; + + outptr[0] = dcval; + outptr[1] = dcval; + + wsptr += DCTSIZE; /* advance pointer to next row */ + continue; + } +#endif + + /* Even part */ + + tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2); + + /* Odd part */ + + tmp0 = MULTIPLY((INT32) wsptr[7], - FIX_0_720959822) /* sqrt(2) * (c7-c5+c3-c1) */ + + MULTIPLY((INT32) wsptr[5], FIX_0_850430095) /* sqrt(2) * (-c1+c3+c5+c7) */ + + MULTIPLY((INT32) wsptr[3], - FIX_1_272758580) /* sqrt(2) * (-c1+c3-c5-c7) */ + + MULTIPLY((INT32) wsptr[1], FIX_3_624509785); /* sqrt(2) * (c1+c3+c5+c7) */ + + /* Final output stage */ + + outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + outptr[1] = range_limit[(int) DESCALE(tmp10 - tmp0, + CONST_BITS+PASS1_BITS+3+2) + & RANGE_MASK]; + + wsptr += DCTSIZE; /* advance pointer to next row */ + } +} + + +/* + * Perform dequantization and inverse DCT on one block of coefficients, + * producing a reduced-size 1x1 output block. + */ + +GLOBAL(void) +jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col) +{ + int dcval; + ISLOW_MULT_TYPE * quantptr; + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + SHIFT_TEMPS + + /* We hardly need an inverse DCT routine for this: just take the + * average pixel value, which is one-eighth of the DC coefficient. + */ + quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table; + dcval = DEQUANTIZE(coef_block[0], quantptr[0]); + dcval = (int) DESCALE((INT32) dcval, 3); + + output_buf[0][output_col] = range_limit[dcval & RANGE_MASK]; +} + +#endif /* IDCT_SCALING_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jinclude.h b/freeimage241/Source/LibJPEG/jinclude.h new file mode 100644 index 0000000..0a4f151 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/freeimage241/Source/LibJPEG/jmemansi.c b/freeimage241/Source/LibJPEG/jmemansi.c new file mode 100644 index 0000000..2d93e49 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemansi.c @@ -0,0 +1,167 @@ +/* + * jmemansi.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a simple generic implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that you have the ANSI-standard library routine tmpfile(). + * Also, the problem of determining the amount of memory available + * is shoved onto the user. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ +#define SEEK_SET 0 /* if not, assume 0 is correct */ +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFREAD(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFWRITE(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + fclose(info->temp_file); + /* Since this implementation uses tmpfile() to create the file, + * no explicit file deletion is needed. + */ +} + + +/* + * Initial opening of a backing-store object. + * + * This version uses tmpfile(), which constructs a suitable file name + * behind the scenes. We don't have to use info->temp_name[] at all; + * indeed, we can't even find out the actual name of the temp file. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + if ((info->temp_file = tmpfile()) == NULL) + ERREXITS(cinfo, JERR_TFILE_CREATE, ""); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/freeimage241/Source/LibJPEG/jmemdos.c b/freeimage241/Source/LibJPEG/jmemdos.c new file mode 100644 index 0000000..60b45c6 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemdos.c @@ -0,0 +1,638 @@ +/* + * jmemdos.c + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides an MS-DOS-compatible implementation of the system- + * dependent portion of the JPEG memory manager. Temporary data can be + * stored in extended or expanded memory as well as in regular DOS files. + * + * If you use this file, you must be sure that NEED_FAR_POINTERS is defined + * if you compile in a small-data memory model; it should NOT be defined if + * you use a large-data memory model. This file is not recommended if you + * are using a flat-memory-space 386 environment such as DJGCC or Watcom C. + * Also, this code will NOT work if struct fields are aligned on greater than + * 2-byte boundaries. + * + * Based on code contributed by Ge' Weijers. + */ + +/* + * If you have both extended and expanded memory, you may want to change the + * order in which they are tried in jopen_backing_store. On a 286 machine + * expanded memory is usually faster, since extended memory access involves + * an expensive protected-mode-and-back switch. On 386 and better, extended + * memory is usually faster. As distributed, the code tries extended memory + * first (what? not everyone has a 386? :-). + * + * You can disable use of extended/expanded memory entirely by altering these + * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0). + */ + +#ifndef XMS_SUPPORTED +#define XMS_SUPPORTED 1 +#endif +#ifndef EMS_SUPPORTED +#define EMS_SUPPORTED 1 +#endif + + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare these */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +extern char * getenv JPP((const char * name)); +#endif + +#ifdef NEED_FAR_POINTERS + +#ifdef __TURBOC__ +/* These definitions work for Borland C (Turbo C) */ +#include /* need farmalloc(), farfree() */ +#define far_malloc(x) farmalloc(x) +#define far_free(x) farfree(x) +#else +/* These definitions work for Microsoft C and compatible compilers */ +#include /* need _fmalloc(), _ffree() */ +#define far_malloc(x) _fmalloc(x) +#define far_free(x) _ffree(x) +#endif + +#else /* not NEED_FAR_POINTERS */ + +#define far_malloc(x) malloc(x) +#define far_free(x) free(x) + +#endif /* NEED_FAR_POINTERS */ + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#else +#define READ_BINARY "rb" +#endif + +#ifndef USE_MSDOS_MEMMGR /* make sure user got configuration right */ + You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */ +#endif + +#if MAX_ALLOC_CHUNK >= 65535L /* make sure jconfig.h got this right */ + MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */ +#endif + + +/* + * Declarations for assembly-language support routines (see jmemdosa.asm). + * + * The functions are declared "far" as are all their pointer arguments; + * this ensures the assembly source code will work regardless of the + * compiler memory model. We assume "short" is 16 bits, "long" is 32. + */ + +typedef void far * XMSDRIVER; /* actually a pointer to code */ +typedef struct { /* registers for calling XMS driver */ + unsigned short ax, dx, bx; + void far * ds_si; + } XMScontext; +typedef struct { /* registers for calling EMS driver */ + unsigned short ax, dx, bx; + void far * ds_si; + } EMScontext; + +extern short far jdos_open JPP((short far * handle, char far * filename)); +extern short far jdos_close JPP((short handle)); +extern short far jdos_seek JPP((short handle, long offset)); +extern short far jdos_read JPP((short handle, void far * buffer, + unsigned short count)); +extern short far jdos_write JPP((short handle, void far * buffer, + unsigned short count)); +extern void far jxms_getdriver JPP((XMSDRIVER far *)); +extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *)); +extern short far jems_available JPP((void)); +extern void far jems_calldriver JPP((EMScontext far *)); + + +/* + * Selection of a file name for a temporary file. + * This is highly system-dependent, and you may want to customize it. + */ + +static int next_file_num; /* to distinguish among several temp files */ + +LOCAL(void) +select_file_name (char * fname) +{ + const char * env; + char * ptr; + FILE * tfile; + + /* Keep generating file names till we find one that's not in use */ + for (;;) { + /* Get temp directory name from environment TMP or TEMP variable; + * if none, use "." + */ + if ((env = (const char *) getenv("TMP")) == NULL) + if ((env = (const char *) getenv("TEMP")) == NULL) + env = "."; + if (*env == '\0') /* null string means "." */ + env = "."; + ptr = fname; /* copy name to fname */ + while (*env != '\0') + *ptr++ = *env++; + if (ptr[-1] != '\\' && ptr[-1] != '/') + *ptr++ = '\\'; /* append backslash if not in env variable */ + /* Append a suitable file name */ + next_file_num++; /* advance counter */ + sprintf(ptr, "JPG%03d.TMP", next_file_num); + /* Probe to see if file name is already in use */ + if ((tfile = fopen(fname, READ_BINARY)) == NULL) + break; + fclose(tfile); /* oops, it's there; close tfile & try again */ + } +} + + +/* + * Near-memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are allocated in far memory, if possible + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) far_malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + far_free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + +/* + * For MS-DOS we support three types of backing storage: + * 1. Conventional DOS files. We access these by direct DOS calls rather + * than via the stdio package. This provides a bit better performance, + * but the real reason is that the buffers to be read or written are FAR. + * The stdio library for small-data memory models can't cope with that. + * 2. Extended memory, accessed per the XMS V2.0 specification. + * 3. Expanded memory, accessed per the LIM/EMS 4.0 specification. + * You'll need copies of those specs to make sense of the related code. + * The specs are available by Internet FTP from the SIMTEL archives + * (oak.oakland.edu and its various mirror sites). See files + * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip. + */ + + +/* + * Access methods for a DOS file. + */ + + +METHODDEF(void) +read_file_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (jdos_seek(info->handle.file_handle, file_offset)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */ + if (byte_count > 65535L) /* safety check */ + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + if (jdos_read(info->handle.file_handle, buffer_address, + (unsigned short) byte_count)) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_file_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (jdos_seek(info->handle.file_handle, file_offset)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */ + if (byte_count > 65535L) /* safety check */ + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + if (jdos_write(info->handle.file_handle, buffer_address, + (unsigned short) byte_count)) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_file_store (j_common_ptr cinfo, backing_store_ptr info) +{ + jdos_close(info->handle.file_handle); /* close the file */ + remove(info->temp_name); /* delete the file */ +/* If your system doesn't have remove(), try unlink() instead. + * remove() is the ANSI-standard name for this function, but + * unlink() was more common in pre-ANSI systems. + */ + TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name); +} + + +LOCAL(boolean) +open_file_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + short handle; + + select_file_name(info->temp_name); + if (jdos_open((short far *) & handle, (char far *) info->temp_name)) { + /* might as well exit since jpeg_open_backing_store will fail anyway */ + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + return FALSE; + } + info->handle.file_handle = handle; + info->read_backing_store = read_file_store; + info->write_backing_store = write_file_store; + info->close_backing_store = close_file_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); + return TRUE; /* succeeded */ +} + + +/* + * Access methods for extended memory. + */ + +#if XMS_SUPPORTED + +static XMSDRIVER xms_driver; /* saved address of XMS driver */ + +typedef union { /* either long offset or real-mode pointer */ + long offset; + void far * ptr; + } XMSPTR; + +typedef struct { /* XMS move specification structure */ + long length; + XMSH src_handle; + XMSPTR src; + XMSH dst_handle; + XMSPTR dst; + } XMSspec; + +#define ODD(X) (((X) & 1L) != 0) + + +METHODDEF(void) +read_xms_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + XMScontext ctx; + XMSspec spec; + char endbuffer[2]; + + /* The XMS driver can't cope with an odd length, so handle the last byte + * specially if byte_count is odd. We don't expect this to be common. + */ + + spec.length = byte_count & (~ 1L); + spec.src_handle = info->handle.xms_handle; + spec.src.offset = file_offset; + spec.dst_handle = 0; + spec.dst.ptr = buffer_address; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x0b00; /* EMB move */ + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + ERREXIT(cinfo, JERR_XMS_READ); + + if (ODD(byte_count)) { + read_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0]; + } +} + + +METHODDEF(void) +write_xms_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + XMScontext ctx; + XMSspec spec; + char endbuffer[2]; + + /* The XMS driver can't cope with an odd length, so handle the last byte + * specially if byte_count is odd. We don't expect this to be common. + */ + + spec.length = byte_count & (~ 1L); + spec.src_handle = 0; + spec.src.ptr = buffer_address; + spec.dst_handle = info->handle.xms_handle; + spec.dst.offset = file_offset; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x0b00; /* EMB move */ + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + ERREXIT(cinfo, JERR_XMS_WRITE); + + if (ODD(byte_count)) { + read_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L]; + write_xms_store(cinfo, info, (void FAR *) endbuffer, + file_offset + byte_count - 1L, 2L); + } +} + + +METHODDEF(void) +close_xms_store (j_common_ptr cinfo, backing_store_ptr info) +{ + XMScontext ctx; + + ctx.dx = info->handle.xms_handle; + ctx.ax = 0x0a00; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle); + /* we ignore any error return from the driver */ +} + + +LOCAL(boolean) +open_xms_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + XMScontext ctx; + + /* Get address of XMS driver */ + jxms_getdriver((XMSDRIVER far *) & xms_driver); + if (xms_driver == NULL) + return FALSE; /* no driver to be had */ + + /* Get version number, must be >= 2.00 */ + ctx.ax = 0x0000; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax < (unsigned short) 0x0200) + return FALSE; + + /* Try to get space (expressed in kilobytes) */ + ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10); + ctx.ax = 0x0900; + jxms_calldriver(xms_driver, (XMScontext far *) & ctx); + if (ctx.ax != 1) + return FALSE; + + /* Succeeded, save the handle and away we go */ + info->handle.xms_handle = ctx.dx; + info->read_backing_store = read_xms_store; + info->write_backing_store = write_xms_store; + info->close_backing_store = close_xms_store; + TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx); + return TRUE; /* succeeded */ +} + +#endif /* XMS_SUPPORTED */ + + +/* + * Access methods for expanded memory. + */ + +#if EMS_SUPPORTED + +/* The EMS move specification structure requires word and long fields aligned + * at odd byte boundaries. Some compilers will align struct fields at even + * byte boundaries. While it's usually possible to force byte alignment, + * that causes an overall performance penalty and may pose problems in merging + * JPEG into a larger application. Instead we accept some rather dirty code + * here. Note this code would fail if the hardware did not allow odd-byte + * word & long accesses, but all 80x86 CPUs do. + */ + +typedef void far * EMSPTR; + +typedef union { /* EMS move specification structure */ + long length; /* It's easy to access first 4 bytes */ + char bytes[18]; /* Misaligned fields in here! */ + } EMSspec; + +/* Macros for accessing misaligned fields */ +#define FIELD_AT(spec,offset,type) (*((type *) &(spec.bytes[offset]))) +#define SRC_TYPE(spec) FIELD_AT(spec,4,char) +#define SRC_HANDLE(spec) FIELD_AT(spec,5,EMSH) +#define SRC_OFFSET(spec) FIELD_AT(spec,7,unsigned short) +#define SRC_PAGE(spec) FIELD_AT(spec,9,unsigned short) +#define SRC_PTR(spec) FIELD_AT(spec,7,EMSPTR) +#define DST_TYPE(spec) FIELD_AT(spec,11,char) +#define DST_HANDLE(spec) FIELD_AT(spec,12,EMSH) +#define DST_OFFSET(spec) FIELD_AT(spec,14,unsigned short) +#define DST_PAGE(spec) FIELD_AT(spec,16,unsigned short) +#define DST_PTR(spec) FIELD_AT(spec,14,EMSPTR) + +#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */ + +#define HIBYTE(W) (((W) >> 8) & 0xFF) +#define LOBYTE(W) ((W) & 0xFF) + + +METHODDEF(void) +read_ems_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + EMScontext ctx; + EMSspec spec; + + spec.length = byte_count; + SRC_TYPE(spec) = 1; + SRC_HANDLE(spec) = info->handle.ems_handle; + SRC_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE); + SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE); + DST_TYPE(spec) = 0; + DST_HANDLE(spec) = 0; + DST_PTR(spec) = buffer_address; + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x5700; /* move memory region */ + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + ERREXIT(cinfo, JERR_EMS_READ); +} + + +METHODDEF(void) +write_ems_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + EMScontext ctx; + EMSspec spec; + + spec.length = byte_count; + SRC_TYPE(spec) = 0; + SRC_HANDLE(spec) = 0; + SRC_PTR(spec) = buffer_address; + DST_TYPE(spec) = 1; + DST_HANDLE(spec) = info->handle.ems_handle; + DST_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE); + DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE); + + ctx.ds_si = (void far *) & spec; + ctx.ax = 0x5700; /* move memory region */ + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + ERREXIT(cinfo, JERR_EMS_WRITE); +} + + +METHODDEF(void) +close_ems_store (j_common_ptr cinfo, backing_store_ptr info) +{ + EMScontext ctx; + + ctx.ax = 0x4500; + ctx.dx = info->handle.ems_handle; + jems_calldriver((EMScontext far *) & ctx); + TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle); + /* we ignore any error return from the driver */ +} + + +LOCAL(boolean) +open_ems_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + EMScontext ctx; + + /* Is EMS driver there? */ + if (! jems_available()) + return FALSE; + + /* Get status, make sure EMS is OK */ + ctx.ax = 0x4000; + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + return FALSE; + + /* Get version, must be >= 4.0 */ + ctx.ax = 0x4600; + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40) + return FALSE; + + /* Try to allocate requested space */ + ctx.ax = 0x4300; + ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE); + jems_calldriver((EMScontext far *) & ctx); + if (HIBYTE(ctx.ax) != 0) + return FALSE; + + /* Succeeded, save the handle and away we go */ + info->handle.ems_handle = ctx.dx; + info->read_backing_store = read_ems_store; + info->write_backing_store = write_ems_store; + info->close_backing_store = close_ems_store; + TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx); + return TRUE; /* succeeded */ +} + +#endif /* EMS_SUPPORTED */ + + +/* + * Initial opening of a backing-store object. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + /* Try extended memory, then expanded memory, then regular file. */ +#if XMS_SUPPORTED + if (open_xms_store(cinfo, info, total_bytes_needed)) + return; +#endif +#if EMS_SUPPORTED + if (open_ems_store(cinfo, info, total_bytes_needed)) + return; +#endif + if (open_file_store(cinfo, info, total_bytes_needed)) + return; + ERREXITS(cinfo, JERR_TFILE_CREATE, ""); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; /* initialize temp file name generator */ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* Microsoft C, at least in v6.00A, will not successfully reclaim freed + * blocks of size > 32Kbytes unless we give it a kick in the rear, like so: + */ +#ifdef NEED_FHEAPMIN + _fheapmin(); +#endif +} diff --git a/freeimage241/Source/LibJPEG/jmemdosa.asm b/freeimage241/Source/LibJPEG/jmemdosa.asm new file mode 100644 index 0000000..ecd4372 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemdosa.asm @@ -0,0 +1,379 @@ +; +; jmemdosa.asm +; +; Copyright (C) 1992, Thomas G. Lane. +; This file is part of the Independent JPEG Group's software. +; For conditions of distribution and use, see the accompanying README file. +; +; This file contains low-level interface routines to support the MS-DOS +; backing store manager (jmemdos.c). Routines are provided to access disk +; files through direct DOS calls, and to access XMS and EMS drivers. +; +; This file should assemble with Microsoft's MASM or any compatible +; assembler (including Borland's Turbo Assembler). If you haven't got +; a compatible assembler, better fall back to jmemansi.c or jmemname.c. +; +; To minimize dependence on the C compiler's register usage conventions, +; we save and restore all 8086 registers, even though most compilers only +; require SI,DI,DS to be preserved. Also, we use only 16-bit-wide return +; values, which everybody returns in AX. +; +; Based on code contributed by Ge' Weijers. +; + +JMEMDOSA_TXT segment byte public 'CODE' + + assume cs:JMEMDOSA_TXT + + public _jdos_open + public _jdos_close + public _jdos_seek + public _jdos_read + public _jdos_write + public _jxms_getdriver + public _jxms_calldriver + public _jems_available + public _jems_calldriver + +; +; short far jdos_open (short far * handle, char far * filename) +; +; Create and open a temporary file +; +_jdos_open proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov cx,0 ; normal file attributes + lds dx,dword ptr [bp+10] ; get filename pointer + mov ah,3ch ; create file + int 21h + jc open_err ; if failed, return error code + lds bx,dword ptr [bp+6] ; get handle pointer + mov word ptr [bx],ax ; save the handle + xor ax,ax ; return zero for OK +open_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_open endp + + +; +; short far jdos_close (short handle) +; +; Close the file handle +; +_jdos_close proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + mov ah,3eh ; close file + int 21h + jc close_err ; if failed, return error code + xor ax,ax ; return zero for OK +close_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_close endp + + +; +; short far jdos_seek (short handle, long offset) +; +; Set file position +; +_jdos_seek proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + mov dx,word ptr [bp+8] ; LS offset + mov cx,word ptr [bp+10] ; MS offset + mov ax,4200h ; absolute seek + int 21h + jc seek_err ; if failed, return error code + xor ax,ax ; return zero for OK +seek_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_seek endp + + +; +; short far jdos_read (short handle, void far * buffer, unsigned short count) +; +; Read from file +; +_jdos_read proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + lds dx,dword ptr [bp+8] ; buffer address + mov cx,word ptr [bp+12] ; number of bytes + mov ah,3fh ; read file + int 21h + jc read_err ; if failed, return error code + cmp ax,word ptr [bp+12] ; make sure all bytes were read + je read_ok + mov ax,1 ; else return 1 for not OK + jmp short read_err +read_ok: xor ax,ax ; return zero for OK +read_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_read endp + + +; +; short far jdos_write (short handle, void far * buffer, unsigned short count) +; +; Write to file +; +_jdos_write proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov bx,word ptr [bp+6] ; file handle + lds dx,dword ptr [bp+8] ; buffer address + mov cx,word ptr [bp+12] ; number of bytes + mov ah,40h ; write file + int 21h + jc write_err ; if failed, return error code + cmp ax,word ptr [bp+12] ; make sure all bytes written + je write_ok + mov ax,1 ; else return 1 for not OK + jmp short write_err +write_ok: xor ax,ax ; return zero for OK +write_err: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jdos_write endp + + +; +; void far jxms_getdriver (XMSDRIVER far *) +; +; Get the address of the XMS driver, or NULL if not available +; +_jxms_getdriver proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov ax,4300h ; call multiplex interrupt with + int 2fh ; a magic cookie, hex 4300 + cmp al,80h ; AL should contain hex 80 + je xmsavail + xor dx,dx ; no XMS driver available + xor ax,ax ; return a nil pointer + jmp short xmsavail_done +xmsavail: mov ax,4310h ; fetch driver address with + int 2fh ; another magic cookie + mov dx,es ; copy address to dx:ax + mov ax,bx +xmsavail_done: les bx,dword ptr [bp+6] ; get pointer to return value + mov word ptr es:[bx],ax + mov word ptr es:[bx+2],dx + pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jxms_getdriver endp + + +; +; void far jxms_calldriver (XMSDRIVER, XMScontext far *) +; +; The XMScontext structure contains values for the AX,DX,BX,SI,DS registers. +; These are loaded, the XMS call is performed, and the new values of the +; AX,DX,BX registers are written back to the context structure. +; +_jxms_calldriver proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + les bx,dword ptr [bp+10] ; get XMScontext pointer + mov ax,word ptr es:[bx] ; load registers + mov dx,word ptr es:[bx+2] + mov si,word ptr es:[bx+6] + mov ds,word ptr es:[bx+8] + mov bx,word ptr es:[bx+4] + call dword ptr [bp+6] ; call the driver + mov cx,bx ; save returned BX for a sec + les bx,dword ptr [bp+10] ; get XMScontext pointer + mov word ptr es:[bx],ax ; put back ax,dx,bx + mov word ptr es:[bx+2],dx + mov word ptr es:[bx+4],cx + pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jxms_calldriver endp + + +; +; short far jems_available (void) +; +; Have we got an EMS driver? (this comes straight from the EMS 4.0 specs) +; +_jems_available proc far + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + mov ax,3567h ; get interrupt vector 67h + int 21h + push cs + pop ds + mov di,000ah ; check offs 10 in returned seg + lea si,ASCII_device_name ; against literal string + mov cx,8 + cld + repe cmpsb + jne no_ems + mov ax,1 ; match, it's there + jmp short avail_done +no_ems: xor ax,ax ; it's not there +avail_done: pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + ret + +ASCII_device_name db "EMMXXXX0" + +_jems_available endp + + +; +; void far jems_calldriver (EMScontext far *) +; +; The EMScontext structure contains values for the AX,DX,BX,SI,DS registers. +; These are loaded, the EMS trap is performed, and the new values of the +; AX,DX,BX registers are written back to the context structure. +; +_jems_calldriver proc far + push bp ; linkage + mov bp,sp + push si ; save all registers for safety + push di + push bx + push cx + push dx + push es + push ds + les bx,dword ptr [bp+6] ; get EMScontext pointer + mov ax,word ptr es:[bx] ; load registers + mov dx,word ptr es:[bx+2] + mov si,word ptr es:[bx+6] + mov ds,word ptr es:[bx+8] + mov bx,word ptr es:[bx+4] + int 67h ; call the EMS driver + mov cx,bx ; save returned BX for a sec + les bx,dword ptr [bp+6] ; get EMScontext pointer + mov word ptr es:[bx],ax ; put back ax,dx,bx + mov word ptr es:[bx+2],dx + mov word ptr es:[bx+4],cx + pop ds ; restore registers and exit + pop es + pop dx + pop cx + pop bx + pop di + pop si + pop bp + ret +_jems_calldriver endp + +JMEMDOSA_TXT ends + + end diff --git a/freeimage241/Source/LibJPEG/jmemmac.c b/freeimage241/Source/LibJPEG/jmemmac.c new file mode 100644 index 0000000..106f9be --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemmac.c @@ -0,0 +1,289 @@ +/* + * jmemmac.c + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * jmemmac.c provides an Apple Macintosh implementation of the system- + * dependent portion of the JPEG memory manager. + * + * If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the + * JPEG_INTERNALS part of jconfig.h. + * + * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr + * instead of malloc and free. It accurately determines the amount of + * memory available by using CompactMem. Notice that if left to its + * own devices, this code can chew up all available space in the + * application's zone, with the exception of the rather small "slop" + * factor computed in jpeg_mem_available(). The application can ensure + * that more space is left over by reducing max_memory_to_use. + * + * Large images are swapped to disk using temporary files and System 7.0+'s + * temporary folder functionality. + * + * Note that jmemmac.c depends on two features of MacOS that were first + * introduced in System 7: FindFolder and the FSSpec-based calls. + * If your application uses jmemmac.c and is run under System 6 or earlier, + * and the jpeg library decides it needs a temporary file, it will abort, + * printing error messages about requiring System 7. (If no temporary files + * are created, it will run fine.) + * + * If you want to use jmemmac.c in an application that might be used with + * System 6 or earlier, then you should remove dependencies on FindFolder + * and the FSSpec calls. You will need to replace FindFolder with some + * other mechanism for finding a place to put temporary files, and you + * should replace the FSSpec calls with their HFS equivalents: + * + * FSpDelete -> HDelete + * FSpGetFInfo -> HGetFInfo + * FSpCreate -> HCreate + * FSpOpenDF -> HOpen *** Note: not HOpenDF *** + * FSMakeFSSpec -> (fill in spec by hand.) + * + * (Use HOpen instead of HOpenDF. HOpen is just a glue-interface to PBHOpen, + * which is on all HFS macs. HOpenDF is a System 7 addition which avoids the + * ages-old problem of names starting with a period.) + * + * Contributed by Sam Bushell (jsam@iagu.on.net) and + * Dan Gildor (gyld@in-touch.com). + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef USE_MAC_MEMMGR /* make sure user got configuration right */ + You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */ +#endif + +#include /* we use the MacOS memory manager */ +#include /* we use the MacOS File stuff */ +#include /* we use the MacOS HFS stuff */ +#include /* for smSystemScript */ +#include /* we use Gestalt to test for specific functionality */ + +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "JPG%03d.TMP" +#endif + +static int next_file_num; /* to distinguish among several temp files */ + + +/* + * Memory allocation and freeing are controlled by the MacOS library + * routines NewPtr() and DisposePtr(), which allocate fixed-address + * storage. Unfortunately, the IJG library isn't smart enough to cope + * with relocatable storage. + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) NewPtr(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + DisposePtr((Ptr) object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: we include FAR keywords in the routine declarations simply for + * consistency with the rest of the IJG code; FAR should expand to empty + * on rational architectures like the Mac. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) NewPtr(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + DisposePtr((Ptr) object); +} + + +/* + * This routine computes the total memory space available for allocation. + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + long limit = cinfo->mem->max_memory_to_use - already_allocated; + long slop, mem; + + /* Don't ask for more than what application has told us we may use */ + if (max_bytes_needed > limit && limit > 0) + max_bytes_needed = limit; + /* Find whether there's a big enough free block in the heap. + * CompactMem tries to create a contiguous block of the requested size, + * and then returns the size of the largest free block (which could be + * much more or much less than we asked for). + * We add some slop to ensure we don't use up all available memory. + */ + slop = max_bytes_needed / 16 + 32768L; + mem = CompactMem(max_bytes_needed + slop) - slop; + if (mem < 0) + mem = 0; /* sigh, couldn't even get the slop */ + /* Don't take more than the application says we can have */ + if (mem > limit && limit > 0) + mem = limit; + return mem; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + long bytes = byte_count; + long retVal; + + if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr ) + ERREXIT(cinfo, JERR_TFILE_SEEK); + + retVal = FSRead ( info->temp_file, &bytes, + (unsigned char *) buffer_address ); + if ( retVal != noErr || bytes != byte_count ) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + long bytes = byte_count; + long retVal; + + if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr ) + ERREXIT(cinfo, JERR_TFILE_SEEK); + + retVal = FSWrite ( info->temp_file, &bytes, + (unsigned char *) buffer_address ); + if ( retVal != noErr || bytes != byte_count ) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + FSClose ( info->temp_file ); + FSpDelete ( &(info->tempSpec) ); +} + + +/* + * Initial opening of a backing-store object. + * + * This version uses FindFolder to find the Temporary Items folder, + * and puts the temporary file in there. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + short tmpRef, vRefNum; + long dirID; + FInfo finderInfo; + FSSpec theSpec; + Str255 fName; + OSErr osErr; + long gestaltResponse = 0; + + /* Check that FSSpec calls are available. */ + osErr = Gestalt( gestaltFSAttr, &gestaltResponse ); + if ( ( osErr != noErr ) + || !( gestaltResponse & (1<temp_name, TEMP_FILE_NAME, next_file_num); + strcpy ( (Ptr)fName+1, info->temp_name ); + *fName = strlen (info->temp_name); + osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec ); + + if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr ) + break; + } + + osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript ); + if ( osErr != noErr ) + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + + osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) ); + if ( osErr != noErr ) + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + + info->tempSpec = theSpec; + + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; + + /* max_memory_to_use will be initialized to FreeMem()'s result; + * the calling application might later reduce it, for example + * to leave room to invoke multiple JPEG objects. + * Note that FreeMem returns the total number of free bytes; + * it may not be possible to allocate a single block of this size. + */ + return FreeMem(); +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/freeimage241/Source/LibJPEG/jmemmgr.c b/freeimage241/Source/LibJPEG/jmemmgr.c new file mode 100644 index 0000000..d801b32 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemmgr.c @@ -0,0 +1,1118 @@ +/* + * jmemmgr.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains the JPEG system-independent memory management + * routines. This code is usable across a wide variety of machines; most + * of the system dependencies have been isolated in a separate file. + * The major functions provided here are: + * * pool-based allocation and freeing of memory; + * * policy decisions about how to divide available memory among the + * virtual arrays; + * * control logic for swapping virtual arrays between main memory and + * backing storage. + * The separate system-dependent file provides the actual backing-storage + * access code, and it contains the policy decision about how much total + * main memory to use. + * This file is system-dependent in the sense that some of its functions + * are unnecessary in some systems. For example, if there is enough virtual + * memory so that backing storage will never be used, much of the virtual + * array control logic could be removed. (Of course, if you have that much + * memory then you shouldn't care about a little bit of unused code...) + */ + +#define JPEG_INTERNALS +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef NO_GETENV +#ifndef HAVE_STDLIB_H /* should declare getenv() */ +extern char * getenv JPP((const char * name)); +#endif +#endif + + +/* + * Some important notes: + * The allocation routines provided here must never return NULL. + * They should exit to error_exit if unsuccessful. + * + * It's not a good idea to try to merge the sarray and barray routines, + * even though they are textually almost the same, because samples are + * usually stored as bytes while coefficients are shorts or ints. Thus, + * in machines where byte pointers have a different representation from + * word pointers, the resulting machine code could not be the same. + */ + + +/* + * Many machines require storage alignment: longs must start on 4-byte + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + * always returns pointers that are multiples of the worst-case alignment + * requirement, and we had better do so too. + * There isn't any really portable way to determine the worst-case alignment + * requirement. This module assumes that the alignment requirement is + * multiples of sizeof(ALIGN_TYPE). + * By default, we define ALIGN_TYPE as double. This is necessary on some + * workstations (where doubles really do need 8-byte alignment) and will work + * fine on nearly everything. If your machine has lesser alignment needs, + * you can save a few bytes by making ALIGN_TYPE smaller. + * The only place I know of where this will NOT work is certain Macintosh + * 680x0 compilers that define double as a 10-byte IEEE extended float. + * Doing 10-byte alignment is counterproductive because longwords won't be + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + * such a compiler. + */ + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ +#define ALIGN_TYPE double +#endif + + +/* + * We allocate objects from "pools", where each pool is gotten with a single + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + * overhead within a pool, except for alignment padding. Each pool has a + * header with a link to the next pool of the same class. + * Small and large pool headers are identical except that the latter's + * link pointer must be FAR on 80x86 machines. + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + * of the alignment requirement of ALIGN_TYPE. + */ + +typedef union small_pool_struct * small_pool_ptr; + +typedef union small_pool_struct { + struct { + small_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} small_pool_hdr; + +typedef union large_pool_struct FAR * large_pool_ptr; + +typedef union large_pool_struct { + struct { + large_pool_ptr next; /* next in list of pools */ + size_t bytes_used; /* how many bytes already used within pool */ + size_t bytes_left; /* bytes still available in this pool */ + } hdr; + ALIGN_TYPE dummy; /* included in union to ensure alignment */ +} large_pool_hdr; + + +/* + * Here is the full definition of a memory manager object. + */ + +typedef struct { + struct jpeg_memory_mgr pub; /* public fields */ + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + /* Since we only have one lifetime class of virtual arrays, only one + * linked list is necessary (for each datatype). Note that the virtual + * array control blocks being linked together are actually stored somewhere + * in the small-pool list. + */ + jvirt_sarray_ptr virt_sarray_list; + jvirt_barray_ptr virt_barray_list; + + /* This counts total space obtained from jpeg_get_small/large */ + long total_space_allocated; + + /* alloc_sarray and alloc_barray set this value for use by virtual + * array routines. + */ + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ +} my_memory_mgr; + +typedef my_memory_mgr * my_mem_ptr; + + +/* + * The control blocks for virtual arrays. + * Note that these blocks are allocated in the "small" pool area. + * System-dependent info for the associated backing store (if any) is hidden + * inside the backing_store_info struct. + */ + +struct jvirt_sarray_control { + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + +struct jvirt_barray_control { + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + JDIMENSION rows_in_array; /* total virtual array height */ + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + JDIMENSION rows_in_mem; /* height of memory buffer */ + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + boolean pre_zero; /* pre-zero mode requested? */ + boolean dirty; /* do current buffer contents need written? */ + boolean b_s_open; /* is backing-store data valid? */ + jvirt_barray_ptr next; /* link to next virtual barray control block */ + backing_store_info b_s_info; /* System-dependent control info */ +}; + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + +LOCAL(void) +print_mem_stats (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + + /* Since this is only a debugging stub, we can cheat a little by using + * fprintf directly rather than going through the trace message code. + * This is helpful because message parm array can't handle longs. + */ + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + pool_id, mem->total_space_allocated); + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + lhdr_ptr = lhdr_ptr->hdr.next) { + fprintf(stderr, " Large chunk used %ld\n", + (long) lhdr_ptr->hdr.bytes_used); + } + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + shdr_ptr = shdr_ptr->hdr.next) { + fprintf(stderr, " Small chunk used %ld free %ld\n", + (long) shdr_ptr->hdr.bytes_used, + (long) shdr_ptr->hdr.bytes_left); + } +} + +#endif /* MEM_STATS */ + + +LOCAL(void) +out_of_memory (j_common_ptr cinfo, int which) +/* Report an out-of-memory error and stop execution */ +/* If we compiled MEM_STATS support, report alloc requests before dying */ +{ +#ifdef MEM_STATS + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ +#endif + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); +} + + +/* + * Allocation of "small" objects. + * + * For these, we use pooled storage. When a new pool must be created, + * we try to get enough space for the current request plus a "slop" factor, + * where the slop will be the amount of leftover space in the new pool. + * The speed vs. space tradeoff is largely determined by the slop values. + * A different slop value is provided for each pool class (lifetime), + * and we also distinguish the first pool of a class from later ones. + * NOTE: the values given work fairly well on both 16- and 32-bit-int + * machines, but may be too small if longs are 64 bits or more. + */ + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = +{ + 1600, /* first PERMANENT pool */ + 16000 /* first IMAGE pool */ +}; + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = +{ + 0, /* additional PERMANENT pools */ + 5000 /* additional IMAGE pools */ +}; + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + +METHODDEF(void *) +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "small" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr hdr_ptr, prev_hdr_ptr; + char * data_ptr; + size_t odd_bytes, min_request, slop; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* See if space is available in any existing pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + prev_hdr_ptr = NULL; + hdr_ptr = mem->small_list[pool_id]; + while (hdr_ptr != NULL) { + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + break; /* found pool with enough space */ + prev_hdr_ptr = hdr_ptr; + hdr_ptr = hdr_ptr->hdr.next; + } + + /* Time to make a new pool? */ + if (hdr_ptr == NULL) { + /* min_request is what we need now, slop is what will be leftover */ + min_request = sizeofobject + SIZEOF(small_pool_hdr); + if (prev_hdr_ptr == NULL) /* first pool in class? */ + slop = first_pool_slop[pool_id]; + else + slop = extra_pool_slop[pool_id]; + /* Don't ask for more than MAX_ALLOC_CHUNK */ + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + /* Try to get space, if fail reduce slop and try again */ + for (;;) { + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + if (hdr_ptr != NULL) + break; + slop /= 2; + if (slop < MIN_SLOP) /* give up when it gets real small */ + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + } + mem->total_space_allocated += min_request + slop; + /* Success, initialize the new pool header and add to end of list */ + hdr_ptr->hdr.next = NULL; + hdr_ptr->hdr.bytes_used = 0; + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + if (prev_hdr_ptr == NULL) /* first pool in class? */ + mem->small_list[pool_id] = hdr_ptr; + else + prev_hdr_ptr->hdr.next = hdr_ptr; + } + + /* OK, allocate the object from the current pool */ + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + hdr_ptr->hdr.bytes_used += sizeofobject; + hdr_ptr->hdr.bytes_left -= sizeofobject; + + return (void *) data_ptr; +} + + +/* + * Allocation of "large" objects. + * + * The external semantics of these are the same as "small" objects, + * except that FAR pointers are used on 80x86. However the pool + * management heuristics are quite different. We assume that each + * request is large enough that it may as well be passed directly to + * jpeg_get_large; the pool management just links everything together + * so that we can free it all on demand. + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + * structures. The routines that create these structures (see below) + * deliberately bunch rows together to ensure a large request size. + */ + +METHODDEF(void FAR *) +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) +/* Allocate a "large" object */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + large_pool_ptr hdr_ptr; + size_t odd_bytes; + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + if (odd_bytes > 0) + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + /* Always make a new pool */ + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + SIZEOF(large_pool_hdr)); + if (hdr_ptr == NULL) + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + /* Success, initialize the new pool header and add to list */ + hdr_ptr->hdr.next = mem->large_list[pool_id]; + /* We maintain space counts in each pool header for statistical purposes, + * even though they are not needed for allocation. + */ + hdr_ptr->hdr.bytes_used = sizeofobject; + hdr_ptr->hdr.bytes_left = 0; + mem->large_list[pool_id] = hdr_ptr; + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ +} + + +/* + * Creation of 2-D sample arrays. + * The pointers are in near heap, the samples themselves in FAR heap. + * + * To minimize allocation overhead and to allow I/O of large contiguous + * blocks, we allocate the sample rows in groups of as many rows as possible + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + * NB: the virtual array control routines, later in this file, know about + * this chunking of rows. The rowsperchunk value is left in the mem manager + * object so that it can be saved away if this sarray is the workspace for + * a virtual array. + */ + +METHODDEF(JSAMPARRAY) +alloc_sarray (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +/* Allocate a 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JSAMPARRAY result; + JSAMPROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) samplesperrow * SIZEOF(JSAMPLE)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JSAMPROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + * SIZEOF(JSAMPLE))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += samplesperrow; + } + } + + return result; +} + + +/* + * Creation of 2-D coefficient-block arrays. + * This is essentially the same as the code for sample arrays, above. + */ + +METHODDEF(JBLOCKARRAY) +alloc_barray (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, JDIMENSION numrows) +/* Allocate a 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + JBLOCKARRAY result; + JBLOCKROW workspace; + JDIMENSION rowsperchunk, currow, i; + long ltemp; + + /* Calculate max # of rows allowed in one allocation chunk */ + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + ((long) blocksperrow * SIZEOF(JBLOCK)); + if (ltemp <= 0) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + if (ltemp < (long) numrows) + rowsperchunk = (JDIMENSION) ltemp; + else + rowsperchunk = numrows; + mem->last_rowsperchunk = rowsperchunk; + + /* Get space for row pointers (small object) */ + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + /* Get the rows themselves (large objects) */ + currow = 0; + while (currow < numrows) { + rowsperchunk = MIN(rowsperchunk, numrows - currow); + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + * SIZEOF(JBLOCK))); + for (i = rowsperchunk; i > 0; i--) { + result[currow++] = workspace; + workspace += blocksperrow; + } + } + + return result; +} + + +/* + * About virtual array management: + * + * The above "normal" array routines are only used to allocate strip buffers + * (as wide as the image, but just a few rows high). Full-image-sized buffers + * are handled as "virtual" arrays. The array is still accessed a strip at a + * time, but the memory manager must save the whole array for repeated + * accesses. The intended implementation is that there is a strip buffer in + * memory (as high as is possible given the desired memory limit), plus a + * backing file that holds the rest of the array. + * + * The request_virt_array routines are told the total size of the image and + * the maximum number of rows that will be accessed at once. The in-memory + * buffer must be at least as large as the maxaccess value. + * + * The request routines create control blocks but not the in-memory buffers. + * That is postponed until realize_virt_arrays is called. At that time the + * total amount of space needed is known (approximately, anyway), so free + * memory can be divided up fairly. + * + * The access_virt_array routines are responsible for making a specific strip + * area accessible (after reading or writing the backing file, if necessary). + * Note that the access routines are told whether the caller intends to modify + * the accessed strip; during a read-only pass this saves having to rewrite + * data to disk. The access routines are also responsible for pre-zeroing + * any newly accessed rows, if pre-zeroing was requested. + * + * In current usage, the access requests are usually for nonoverlapping + * strips; that is, successive access start_row numbers differ by exactly + * num_rows = maxaccess. This means we can get good performance with simple + * buffer dump/reload logic, by making the in-memory buffer be a multiple + * of the access height; then there will never be accesses across bufferload + * boundaries. The code will still work with overlapping access requests, + * but it doesn't handle bufferload overlaps very efficiently. + */ + + +METHODDEF(jvirt_sarray_ptr) +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION samplesperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D sample array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_sarray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_sarray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->samplesperrow = samplesperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + mem->virt_sarray_list = result; + + return result; +} + + +METHODDEF(jvirt_barray_ptr) +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + JDIMENSION blocksperrow, JDIMENSION numrows, + JDIMENSION maxaccess) +/* Request a virtual 2-D coefficient-block array */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + jvirt_barray_ptr result; + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + if (pool_id != JPOOL_IMAGE) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + /* get control block */ + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + SIZEOF(struct jvirt_barray_control)); + + result->mem_buffer = NULL; /* marks array not yet realized */ + result->rows_in_array = numrows; + result->blocksperrow = blocksperrow; + result->maxaccess = maxaccess; + result->pre_zero = pre_zero; + result->b_s_open = FALSE; /* no associated backing-store object */ + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + mem->virt_barray_list = result; + + return result; +} + + +METHODDEF(void) +realize_virt_arrays (j_common_ptr cinfo) +/* Allocate the in-memory buffers for any unrealized virtual arrays */ +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + long space_per_minheight, maximum_space, avail_mem; + long minheights, max_minheights; + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + /* Compute the minimum space needed (maxaccess rows in each buffer) + * and the maximum space needed (full image height in each buffer). + * These may be of use to the system-dependent jpeg_mem_available routine. + */ + space_per_minheight = 0; + maximum_space = 0; + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) sptr->maxaccess * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + maximum_space += (long) sptr->rows_in_array * + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + } + } + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + space_per_minheight += (long) bptr->maxaccess * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + maximum_space += (long) bptr->rows_in_array * + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + } + } + + if (space_per_minheight <= 0) + return; /* no unrealized arrays, no work */ + + /* Determine amount of memory to actually use; this is system-dependent. */ + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + mem->total_space_allocated); + + /* If the maximum space needed is available, make all the buffers full + * height; otherwise parcel it out with the same number of minheights + * in each buffer. + */ + if (avail_mem >= maximum_space) + max_minheights = 1000000000L; + else { + max_minheights = avail_mem / space_per_minheight; + /* If there doesn't seem to be enough space, try to get the minimum + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + */ + if (max_minheights <= 0) + max_minheights = 1; + } + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + sptr->rows_in_mem = sptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + (long) sptr->rows_in_array * + (long) sptr->samplesperrow * + (long) SIZEOF(JSAMPLE)); + sptr->b_s_open = TRUE; + } + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + sptr->samplesperrow, sptr->rows_in_mem); + sptr->rowsperchunk = mem->last_rowsperchunk; + sptr->cur_start_row = 0; + sptr->first_undef_row = 0; + sptr->dirty = FALSE; + } + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + if (minheights <= max_minheights) { + /* This buffer fits in memory */ + bptr->rows_in_mem = bptr->rows_in_array; + } else { + /* It doesn't fit in memory, create backing store. */ + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + (long) bptr->rows_in_array * + (long) bptr->blocksperrow * + (long) SIZEOF(JBLOCK)); + bptr->b_s_open = TRUE; + } + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + bptr->blocksperrow, bptr->rows_in_mem); + bptr->rowsperchunk = mem->last_rowsperchunk; + bptr->cur_start_row = 0; + bptr->first_undef_row = 0; + bptr->dirty = FALSE; + } + } +} + + +LOCAL(void) +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual sample array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +LOCAL(void) +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) +/* Do backing store read or write of a virtual coefficient-block array */ +{ + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + file_offset = ptr->cur_start_row * bytesperrow; + /* Loop to read or write each allocation chunk in mem_buffer */ + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + /* One chunk, but check for short chunk at end of buffer */ + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + /* Transfer no more than is currently defined */ + thisrow = (long) ptr->cur_start_row + i; + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + /* Transfer no more than fits in file */ + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + if (rows <= 0) /* this chunk might be past end of file! */ + break; + byte_count = rows * bytesperrow; + if (writing) + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + else + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + (void FAR *) ptr->mem_buffer[i], + file_offset, byte_count); + file_offset += byte_count; + } +} + + +METHODDEF(JSAMPARRAY) +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual sample array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_sarray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_sarray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +METHODDEF(JBLOCKARRAY) +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + JDIMENSION start_row, JDIMENSION num_rows, + boolean writable) +/* Access the part of a virtual block array starting at start_row */ +/* and extending for num_rows rows. writable is true if */ +/* caller intends to modify the accessed area. */ +{ + JDIMENSION end_row = start_row + num_rows; + JDIMENSION undef_row; + + /* debugging check */ + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + ptr->mem_buffer == NULL) + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + /* Make the desired part of the virtual array accessible */ + if (start_row < ptr->cur_start_row || + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + if (! ptr->b_s_open) + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + /* Flush old buffer contents if necessary */ + if (ptr->dirty) { + do_barray_io(cinfo, ptr, TRUE); + ptr->dirty = FALSE; + } + /* Decide what part of virtual array to access. + * Algorithm: if target address > current window, assume forward scan, + * load starting at target address. If target address < current window, + * assume backward scan, load so that target area is top of window. + * Note that when switching from forward write to forward read, will have + * start_row = 0, so the limiting case applies and we load from 0 anyway. + */ + if (start_row > ptr->cur_start_row) { + ptr->cur_start_row = start_row; + } else { + /* use long arithmetic here to avoid overflow & unsigned problems */ + long ltemp; + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + if (ltemp < 0) + ltemp = 0; /* don't fall off front end of file */ + ptr->cur_start_row = (JDIMENSION) ltemp; + } + /* Read in the selected part of the array. + * During the initial write pass, we will do no actual read + * because the selected part is all undefined. + */ + do_barray_io(cinfo, ptr, FALSE); + } + /* Ensure the accessed part of the array is defined; prezero if needed. + * To improve locality of access, we only prezero the part of the array + * that the caller is about to access, not the entire in-memory array. + */ + if (ptr->first_undef_row < end_row) { + if (ptr->first_undef_row < start_row) { + if (writable) /* writer skipped over a section of array */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + undef_row = start_row; /* but reader is allowed to read ahead */ + } else { + undef_row = ptr->first_undef_row; + } + if (writable) + ptr->first_undef_row = end_row; + if (ptr->pre_zero) { + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + end_row -= ptr->cur_start_row; + while (undef_row < end_row) { + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + undef_row++; + } + } else { + if (! writable) /* reader looking at undefined data */ + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + } + } + /* Flag the buffer dirty if caller will write in it */ + if (writable) + ptr->dirty = TRUE; + /* Return address of proper part of the buffer */ + return ptr->mem_buffer + (start_row - ptr->cur_start_row); +} + + +/* + * Release all objects belonging to a specified pool. + */ + +METHODDEF(void) +free_pool (j_common_ptr cinfo, int pool_id) +{ + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + small_pool_ptr shdr_ptr; + large_pool_ptr lhdr_ptr; + size_t space_freed; + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + +#ifdef MEM_STATS + if (cinfo->err->trace_level > 1) + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ +#endif + + /* If freeing IMAGE pool, close any virtual arrays first */ + if (pool_id == JPOOL_IMAGE) { + jvirt_sarray_ptr sptr; + jvirt_barray_ptr bptr; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + if (sptr->b_s_open) { /* there may be no backing store */ + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + } + } + mem->virt_sarray_list = NULL; + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + if (bptr->b_s_open) { /* there may be no backing store */ + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + } + } + mem->virt_barray_list = NULL; + } + + /* Release large objects */ + lhdr_ptr = mem->large_list[pool_id]; + mem->large_list[pool_id] = NULL; + + while (lhdr_ptr != NULL) { + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + space_freed = lhdr_ptr->hdr.bytes_used + + lhdr_ptr->hdr.bytes_left + + SIZEOF(large_pool_hdr); + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + lhdr_ptr = next_lhdr_ptr; + } + + /* Release small objects */ + shdr_ptr = mem->small_list[pool_id]; + mem->small_list[pool_id] = NULL; + + while (shdr_ptr != NULL) { + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + space_freed = shdr_ptr->hdr.bytes_used + + shdr_ptr->hdr.bytes_left + + SIZEOF(small_pool_hdr); + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + mem->total_space_allocated -= space_freed; + shdr_ptr = next_shdr_ptr; + } +} + + +/* + * Close up shop entirely. + * Note that this cannot be called unless cinfo->mem is non-NULL. + */ + +METHODDEF(void) +self_destruct (j_common_ptr cinfo) +{ + int pool; + + /* Close all backing store, release all memory. + * Releasing pools in reverse order might help avoid fragmentation + * with some (brain-damaged) malloc libraries. + */ + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + free_pool(cinfo, pool); + } + + /* Release the memory manager control block too. */ + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + cinfo->mem = NULL; /* ensures I will be called only once */ + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ +} + + +/* + * Memory manager initialization. + * When this is called, only the error manager pointer is valid in cinfo! + */ + +GLOBAL(void) +jinit_memory_mgr (j_common_ptr cinfo) +{ + my_mem_ptr mem; + long max_to_use; + int pool; + size_t test_mac; + + cinfo->mem = NULL; /* for safety if init fails */ + + /* Check for configuration errors. + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + * doesn't reflect any real hardware alignment requirement. + * The test is a little tricky: for X>0, X and X-1 have no one-bits + * in common if and only if X is a power of 2, ie has only one one-bit. + * Some compilers may give an "unreachable code" warning here; ignore it. + */ + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + * a multiple of SIZEOF(ALIGN_TYPE). + * Again, an "unreachable code" warning may be ignored here. + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + */ + test_mac = (size_t) MAX_ALLOC_CHUNK; + if ((long) test_mac != MAX_ALLOC_CHUNK || + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + /* Attempt to allocate memory manager's control block */ + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + if (mem == NULL) { + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + } + + /* OK, fill in the method pointers */ + mem->pub.alloc_small = alloc_small; + mem->pub.alloc_large = alloc_large; + mem->pub.alloc_sarray = alloc_sarray; + mem->pub.alloc_barray = alloc_barray; + mem->pub.request_virt_sarray = request_virt_sarray; + mem->pub.request_virt_barray = request_virt_barray; + mem->pub.realize_virt_arrays = realize_virt_arrays; + mem->pub.access_virt_sarray = access_virt_sarray; + mem->pub.access_virt_barray = access_virt_barray; + mem->pub.free_pool = free_pool; + mem->pub.self_destruct = self_destruct; + + /* Make MAX_ALLOC_CHUNK accessible to other modules */ + mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK; + + /* Initialize working state */ + mem->pub.max_memory_to_use = max_to_use; + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + mem->small_list[pool] = NULL; + mem->large_list[pool] = NULL; + } + mem->virt_sarray_list = NULL; + mem->virt_barray_list = NULL; + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + /* Declare ourselves open for business */ + cinfo->mem = & mem->pub; + + /* Check for an environment variable JPEGMEM; if found, override the + * default max_memory setting from jpeg_mem_init. Note that the + * surrounding application may again override this value. + * If your system doesn't support getenv(), define NO_GETENV to disable + * this feature. + */ +#ifndef NO_GETENV + { char * memenv; + + if ((memenv = getenv("JPEGMEM")) != NULL) { + char ch = 'x'; + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + if (ch == 'm' || ch == 'M') + max_to_use *= 1000L; + mem->pub.max_memory_to_use = max_to_use * 1000L; + } + } + } +#endif + +} diff --git a/freeimage241/Source/LibJPEG/jmemname.c b/freeimage241/Source/LibJPEG/jmemname.c new file mode 100644 index 0000000..ed96dee --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemname.c @@ -0,0 +1,276 @@ +/* + * jmemname.c + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a generic implementation of the system-dependent + * portion of the JPEG memory manager. This implementation assumes that + * you must explicitly construct a name for each temp file. + * Also, the problem of determining the amount of memory available + * is shoved onto the user. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + +#ifndef SEEK_SET /* pre-ANSI systems may not define this; */ +#define SEEK_SET 0 /* if not, assume 0 is correct */ +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define RW_BINARY "w+" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define RW_BINARY "w+b", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define RW_BINARY "w+b" +#endif +#endif + + +/* + * Selection of a file name for a temporary file. + * This is system-dependent! + * + * The code as given is suitable for most Unix systems, and it is easily + * modified for most non-Unix systems. Some notes: + * 1. The temp file is created in the directory named by TEMP_DIRECTORY. + * The default value is /usr/tmp, which is the conventional place for + * creating large temp files on Unix. On other systems you'll probably + * want to change the file location. You can do this by editing the + * #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h. + * + * 2. If you need to change the file name as well as its location, + * you can override the TEMP_FILE_NAME macro. (Note that this is + * actually a printf format string; it must contain %s and %d.) + * Few people should need to do this. + * + * 3. mktemp() is used to ensure that multiple processes running + * simultaneously won't select the same file names. If your system + * doesn't have mktemp(), define NO_MKTEMP to do it the hard way. + * (If you don't have , also define NO_ERRNO_H.) + * + * 4. You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c + * will cause the temp files to be removed if you stop the program early. + */ + +#ifndef TEMP_DIRECTORY /* can override from jconfig.h or Makefile */ +#define TEMP_DIRECTORY "/usr/tmp/" /* recommended setting for Unix */ +#endif + +static int next_file_num; /* to distinguish among several temp files */ + +#ifdef NO_MKTEMP + +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "%sJPG%03d.TMP" +#endif + +#ifndef NO_ERRNO_H +#include /* to define ENOENT */ +#endif + +/* ANSI C specifies that errno is a macro, but on older systems it's more + * likely to be a plain int variable. And not all versions of errno.h + * bother to declare it, so we have to in order to be most portable. Thus: + */ +#ifndef errno +extern int errno; +#endif + + +LOCAL(void) +select_file_name (char * fname) +{ + FILE * tfile; + + /* Keep generating file names till we find one that's not in use */ + for (;;) { + next_file_num++; /* advance counter */ + sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num); + if ((tfile = fopen(fname, READ_BINARY)) == NULL) { + /* fopen could have failed for a reason other than the file not + * being there; for example, file there but unreadable. + * If isn't available, then we cannot test the cause. + */ +#ifdef ENOENT + if (errno != ENOENT) + continue; +#endif + break; + } + fclose(tfile); /* oops, it's there; close tfile & try again */ + } +} + +#else /* ! NO_MKTEMP */ + +/* Note that mktemp() requires the initial filename to end in six X's */ +#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */ +#define TEMP_FILE_NAME "%sJPG%dXXXXXX" +#endif + +LOCAL(void) +select_file_name (char * fname) +{ + next_file_num++; /* advance counter */ + sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num); + mktemp(fname); /* make sure file name is unique */ + /* mktemp replaces the trailing XXXXXX with a unique string of characters */ +} + +#endif /* NO_MKTEMP */ + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * It's impossible to do this in a portable way; our current solution is + * to make the user tell us (with a default value set at compile time). + * If you can actually get the available space, it's a good idea to subtract + * a slop factor of 5% or so. + */ + +#ifndef DEFAULT_MAX_MEM /* so can override from makefile */ +#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */ +#endif + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return cinfo->mem->max_memory_to_use - already_allocated; +} + + +/* + * Backing store (temporary file) management. + * Backing store objects are only used when the value returned by + * jpeg_mem_available is less than the total space needed. You can dispense + * with these routines if you have plenty of virtual memory; see jmemnobs.c. + */ + + +METHODDEF(void) +read_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFREAD(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_READ); +} + + +METHODDEF(void) +write_backing_store (j_common_ptr cinfo, backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count) +{ + if (fseek(info->temp_file, file_offset, SEEK_SET)) + ERREXIT(cinfo, JERR_TFILE_SEEK); + if (JFWRITE(info->temp_file, buffer_address, byte_count) + != (size_t) byte_count) + ERREXIT(cinfo, JERR_TFILE_WRITE); +} + + +METHODDEF(void) +close_backing_store (j_common_ptr cinfo, backing_store_ptr info) +{ + fclose(info->temp_file); /* close the file */ + unlink(info->temp_name); /* delete the file */ +/* If your system doesn't have unlink(), use remove() instead. + * remove() is the ANSI-standard name for this function, but if + * your system was ANSI you'd be using jmemansi.c, right? + */ + TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name); +} + + +/* + * Initial opening of a backing-store object. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + select_file_name(info->temp_name); + if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL) + ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name); + info->read_backing_store = read_backing_store; + info->write_backing_store = write_backing_store; + info->close_backing_store = close_backing_store; + TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + next_file_num = 0; /* initialize temp file name generator */ + return DEFAULT_MAX_MEM; /* default for max_memory_to_use */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/freeimage241/Source/LibJPEG/jmemnobs.c b/freeimage241/Source/LibJPEG/jmemnobs.c new file mode 100644 index 0000000..eb8c337 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemnobs.c @@ -0,0 +1,109 @@ +/* + * jmemnobs.c + * + * Copyright (C) 1992-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides a really simple implementation of the system- + * dependent portion of the JPEG memory manager. This implementation + * assumes that no backing-store files are needed: all required space + * can be obtained from malloc(). + * This is very portable in the sense that it'll compile on almost anything, + * but you'd better have lots of main memory (or virtual memory) if you want + * to process big images. + * Note that the max_memory_to_use option is ignored by this implementation. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" +#include "jmemsys.h" /* import the system-dependent declarations */ + +#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ +extern void * malloc JPP((size_t size)); +extern void free JPP((void *ptr)); +#endif + + +/* + * Memory allocation and freeing are controlled by the regular library + * routines malloc() and free(). + */ + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + return (void FAR *) malloc(sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + free(object); +} + + +/* + * This routine computes the total memory space available for allocation. + * Here we always say, "we got all you want bud!" + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + return max_bytes_needed; +} + + +/* + * Backing store (temporary file) management. + * Since jpeg_mem_available always promised the moon, + * this should never be called and we can just error out. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + ERREXIT(cinfo, JERR_NO_BACKING_STORE); +} + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. Here, there isn't any. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + return 0; /* just set max_memory_to_use to 0 */ +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + /* no work */ +} diff --git a/freeimage241/Source/LibJPEG/jmemsys.h b/freeimage241/Source/LibJPEG/jmemsys.h new file mode 100644 index 0000000..6c3c6d3 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/freeimage241/Source/LibJPEG/jmorecfg.h b/freeimage241/Source/LibJPEG/jmorecfg.h new file mode 100644 index 0000000..771decf --- /dev/null +++ b/freeimage241/Source/LibJPEG/jmorecfg.h @@ -0,0 +1,363 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* UINT8 must hold at least the values 0..255. */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char UINT8; +#else /* not HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char UINT8; +#else /* not CHAR_IS_UNSIGNED */ +typedef short UINT8; +#endif /* CHAR_IS_UNSIGNED */ +#endif /* HAVE_UNSIGNED_CHAR */ + +/* UINT16 must hold at least the values 0..65535. */ + +#ifdef HAVE_UNSIGNED_SHORT +typedef unsigned short UINT16; +#else /* not HAVE_UNSIGNED_SHORT */ +typedef unsigned int UINT16; +#endif /* HAVE_UNSIGNED_SHORT */ + +/* INT16 must hold at least the values -32768..32767. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ +typedef short INT16; +#endif + +/* INT32 must hold at least signed 32-bit values. */ + +#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +typedef long INT32; +#endif + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* a reference to a GLOBAL function: */ +#define EXTERN(type) extern type + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#define FAR +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef HAVE_BOOLEAN +typedef int boolean; +#endif +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#undef DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#undef IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#undef QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 2 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 0 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/freeimage241/Source/LibJPEG/jpegint.h b/freeimage241/Source/LibJPEG/jpegint.h new file mode 100644 index 0000000..95b00d4 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jpegint.h @@ -0,0 +1,392 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean call_pass_startup; /* True if pass_startup must be called */ + boolean is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + boolean has_multiple_scans; /* True if file has multiple scans */ + boolean eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + boolean saw_SOI; /* found SOI? */ + boolean saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + boolean insufficient_data; /* set TRUE after emitting warning */ +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + boolean need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS INT32 shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + boolean transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + boolean need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/freeimage241/Source/LibJPEG/jpeglib.h b/freeimage241/Source/LibJPEG/jpeglib.h new file mode 100644 index 0000000..24f6d9b --- /dev/null +++ b/freeimage241/Source/LibJPEG/jpeglib.h @@ -0,0 +1,1098 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +#include + + /* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + boolean is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + UINT8 JFIF_major_version; /* What to write for the JFIF version number */ + UINT8 JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + UINT8 JFIF_major_version; /* JFIF version number */ + UINT8 JFIF_minor_version; + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/freeimage241/Source/LibJPEG/jpegtran.c b/freeimage241/Source/LibJPEG/jpegtran.c new file mode 100644 index 0000000..20ef111 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jpegtran.c @@ -0,0 +1,504 @@ +/* + * jpegtran.c + * + * Copyright (C) 1995-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a command-line user interface for JPEG transcoding. + * It is very similar to cjpeg.c, but provides lossless transcoding between + * different JPEG file formats. It also provides some lossless and sort-of- + * lossless transformations of JPEG data. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include "transupp.h" /* Support routines for jpegtran */ +#include "jversion.h" /* for version message */ + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + + +/* + * Argument-parsing code. + * The switch parser is designed to be useful with DOS-style command line + * syntax, ie, intermixed switches and file names, where only the switches + * to the left of a given file name affect processing of that file. + * The main program in this file doesn't actually use this capability... + */ + + +static const char * progname; /* program name for error messages */ +static char * outfilename; /* for -outfile switch */ +static JCOPY_OPTION copyoption; /* -copy switch */ +static jpeg_transform_info transformoption; /* image transformation options */ + + +LOCAL(void) +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -copy none Copy no extra markers from source file\n"); + fprintf(stderr, " -copy comments Copy only comment markers (default)\n"); + fprintf(stderr, " -copy all Copy all extra markers\n"); +#ifdef ENTROPY_OPT_SUPPORTED + fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); +#endif +#ifdef C_PROGRESSIVE_SUPPORTED + fprintf(stderr, " -progressive Create progressive JPEG file\n"); +#endif +#if TRANSFORMS_SUPPORTED + fprintf(stderr, "Switches for modifying the image:\n"); + fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n"); + fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n"); + fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n"); + fprintf(stderr, " -transpose Transpose image\n"); + fprintf(stderr, " -transverse Transverse transpose image\n"); + fprintf(stderr, " -trim Drop non-transformable edge blocks\n"); +#endif /* TRANSFORMS_SUPPORTED */ + fprintf(stderr, "Switches for advanced users:\n"); + fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n"); + fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n"); + fprintf(stderr, " -outfile name Specify name for output file\n"); + fprintf(stderr, " -verbose or -debug Emit debug output\n"); + fprintf(stderr, "Switches for wizards:\n"); +#ifdef C_ARITH_CODING_SUPPORTED + fprintf(stderr, " -arithmetic Use arithmetic coding\n"); +#endif +#ifdef C_MULTISCAN_FILES_SUPPORTED + fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n"); +#endif + exit(EXIT_FAILURE); +} + + +LOCAL(void) +select_transform (JXFORM_CODE transform) +/* Silly little routine to detect multiple transform options, + * which we can't handle. + */ +{ +#if TRANSFORMS_SUPPORTED + if (transformoption.transform == JXFORM_NONE || + transformoption.transform == transform) { + transformoption.transform = transform; + } else { + fprintf(stderr, "%s: can only do one image transformation at a time\n", + progname); + usage(); + } +#else + fprintf(stderr, "%s: sorry, image transformation was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif +} + + +LOCAL(int) +parse_switches (j_compress_ptr cinfo, int argc, char **argv, + int last_file_arg_seen, boolean for_real) +/* Parse optional switches. + * Returns argv[] index of first file-name argument (== argc if none). + * Any file names with indexes <= last_file_arg_seen are ignored; + * they have presumably been processed in a previous iteration. + * (Pass 0 for last_file_arg_seen on the first or only iteration.) + * for_real is FALSE on the first (dummy) pass; we may skip any expensive + * processing. + */ +{ + int argn; + char * arg; + boolean simple_progressive; + char * scansarg = NULL; /* saves -scans parm if any */ + + /* Set up default JPEG parameters. */ + simple_progressive = FALSE; + outfilename = NULL; + copyoption = JCOPYOPT_DEFAULT; + transformoption.transform = JXFORM_NONE; + transformoption.trim = FALSE; + transformoption.force_grayscale = FALSE; + cinfo->err->trace_level = 0; + + /* Scan command line options, adjust parameters */ + + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (*arg != '-') { + /* Not a switch, must be a file name argument */ + if (argn <= last_file_arg_seen) { + outfilename = NULL; /* -outfile applies to just one input file */ + continue; /* ignore this name if previously processed */ + } + break; /* else done parsing switches */ + } + arg++; /* advance past switch marker character */ + + if (keymatch(arg, "arithmetic", 1)) { + /* Use arithmetic coding. */ +#ifdef C_ARITH_CODING_SUPPORTED + cinfo->arith_code = TRUE; +#else + fprintf(stderr, "%s: sorry, arithmetic coding not supported\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "copy", 1)) { + /* Select which extra markers to copy. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "none", 1)) { + copyoption = JCOPYOPT_NONE; + } else if (keymatch(argv[argn], "comments", 1)) { + copyoption = JCOPYOPT_COMMENTS; + } else if (keymatch(argv[argn], "all", 1)) { + copyoption = JCOPYOPT_ALL; + } else + usage(); + + } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) { + /* Enable debug printouts. */ + /* On first -d, print version identification */ + static boolean printed_version = FALSE; + + if (! printed_version) { + fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n", + JVERSION, JCOPYRIGHT); + printed_version = TRUE; + } + cinfo->err->trace_level++; + + } else if (keymatch(arg, "flip", 1)) { + /* Mirror left-right or top-bottom. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "horizontal", 1)) + select_transform(JXFORM_FLIP_H); + else if (keymatch(argv[argn], "vertical", 1)) + select_transform(JXFORM_FLIP_V); + else + usage(); + + } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) { + /* Force to grayscale. */ +#if TRANSFORMS_SUPPORTED + transformoption.force_grayscale = TRUE; +#else + select_transform(JXFORM_NONE); /* force an error */ +#endif + + } else if (keymatch(arg, "maxmemory", 3)) { + /* Maximum memory in Kb (or Mb with 'm'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (ch == 'm' || ch == 'M') + lval *= 1000L; + cinfo->mem->max_memory_to_use = lval * 1000L; + + } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) { + /* Enable entropy parm optimization. */ +#ifdef ENTROPY_OPT_SUPPORTED + cinfo->optimize_coding = TRUE; +#else + fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "outfile", 4)) { + /* Set output file name. */ + if (++argn >= argc) /* advance to next argument */ + usage(); + outfilename = argv[argn]; /* save it away for later use */ + + } else if (keymatch(arg, "progressive", 1)) { + /* Select simple progressive mode. */ +#ifdef C_PROGRESSIVE_SUPPORTED + simple_progressive = TRUE; + /* We must postpone execution until num_components is known. */ +#else + fprintf(stderr, "%s: sorry, progressive output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "restart", 1)) { + /* Restart interval in MCU rows (or in MCUs with 'b'). */ + long lval; + char ch = 'x'; + + if (++argn >= argc) /* advance to next argument */ + usage(); + if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1) + usage(); + if (lval < 0 || lval > 65535L) + usage(); + if (ch == 'b' || ch == 'B') { + cinfo->restart_interval = (unsigned int) lval; + cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */ + } else { + cinfo->restart_in_rows = (int) lval; + /* restart_interval will be computed during startup */ + } + + } else if (keymatch(arg, "rotate", 2)) { + /* Rotate 90, 180, or 270 degrees (measured clockwise). */ + if (++argn >= argc) /* advance to next argument */ + usage(); + if (keymatch(argv[argn], "90", 2)) + select_transform(JXFORM_ROT_90); + else if (keymatch(argv[argn], "180", 3)) + select_transform(JXFORM_ROT_180); + else if (keymatch(argv[argn], "270", 3)) + select_transform(JXFORM_ROT_270); + else + usage(); + + } else if (keymatch(arg, "scans", 1)) { + /* Set scan script. */ +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (++argn >= argc) /* advance to next argument */ + usage(); + scansarg = argv[argn]; + /* We must postpone reading the file in case -progressive appears. */ +#else + fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n", + progname); + exit(EXIT_FAILURE); +#endif + + } else if (keymatch(arg, "transpose", 1)) { + /* Transpose (across UL-to-LR axis). */ + select_transform(JXFORM_TRANSPOSE); + + } else if (keymatch(arg, "transverse", 6)) { + /* Transverse transpose (across UR-to-LL axis). */ + select_transform(JXFORM_TRANSVERSE); + + } else if (keymatch(arg, "trim", 3)) { + /* Trim off any partial edge MCUs that the transform can't handle. */ + transformoption.trim = TRUE; + + } else { + usage(); /* bogus switch */ + } + } + + /* Post-switch-scanning cleanup */ + + if (for_real) { + +#ifdef C_PROGRESSIVE_SUPPORTED + if (simple_progressive) /* process -progressive; -scans can override */ + jpeg_simple_progression(cinfo); +#endif + +#ifdef C_MULTISCAN_FILES_SUPPORTED + if (scansarg != NULL) /* process -scans if it was present */ + if (! read_scan_script(cinfo, scansarg)) + usage(); +#endif + } + + return argn; /* return index of next arg (file name) */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + struct jpeg_decompress_struct srcinfo; + struct jpeg_compress_struct dstinfo; + struct jpeg_error_mgr jsrcerr, jdsterr; +#ifdef PROGRESS_REPORT + struct cdjpeg_progress_mgr progress; +#endif + jvirt_barray_ptr * src_coef_arrays; + jvirt_barray_ptr * dst_coef_arrays; + int file_index; + FILE * input_file; + FILE * output_file; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "jpegtran"; /* in case C library doesn't provide it */ + + /* Initialize the JPEG decompression object with default error handling. */ + srcinfo.err = jpeg_std_error(&jsrcerr); + jpeg_create_decompress(&srcinfo); + /* Initialize the JPEG compression object with default error handling. */ + dstinfo.err = jpeg_std_error(&jdsterr); + jpeg_create_compress(&dstinfo); + + /* Now safe to enable signal catcher. + * Note: we assume only the decompression object will have virtual arrays. + */ +#ifdef NEED_SIGNAL_CATCHER + enable_signal_catcher((j_common_ptr) &srcinfo); +#endif + + /* Scan command line to find file names. + * It is convenient to use just one switch-parsing routine, but the switch + * values read here are mostly ignored; we will rescan the switches after + * opening the input file. Also note that most of the switches affect the + * destination JPEG object, so we parse into that and then copy over what + * needs to affects the source too. + */ + + file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); + jsrcerr.trace_level = jdsterr.trace_level; + srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; + +#ifdef TWO_FILE_COMMANDLINE + /* Must have either -outfile switch or explicit output file name */ + if (outfilename == NULL) { + if (file_index != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + outfilename = argv[file_index+1]; + } else { + if (file_index != argc-1) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + } +#else + /* Unix style: expect zero or one file name */ + if (file_index < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } +#endif /* TWO_FILE_COMMANDLINE */ + + /* Open the input file. */ + if (file_index < argc) { + if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ + input_file = read_stdin(); + } + + /* Open the output file. */ + if (outfilename != NULL) { + if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, outfilename); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + output_file = write_stdout(); + } + +#ifdef PROGRESS_REPORT + start_progress_monitor((j_common_ptr) &dstinfo, &progress); +#endif + + /* Specify data source for decompression */ + jpeg_stdio_src(&srcinfo, input_file); + + /* Enable saving of extra markers that we want to copy */ + jcopy_markers_setup(&srcinfo, copyoption); + + /* Read file header */ + (void) jpeg_read_header(&srcinfo, TRUE); + + /* Any space needed by a transform option must be requested before + * jpeg_read_coefficients so that memory allocation will be done right. + */ +#if TRANSFORMS_SUPPORTED + jtransform_request_workspace(&srcinfo, &transformoption); +#endif + + /* Read source file as DCT coefficients */ + src_coef_arrays = jpeg_read_coefficients(&srcinfo); + + /* Initialize destination compression parameters from source values */ + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + + /* Adjust destination parameters if required by transform options; + * also find out which set of coefficient arrays will hold the output. + */ +#if TRANSFORMS_SUPPORTED + dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, + src_coef_arrays, + &transformoption); +#else + dst_coef_arrays = src_coef_arrays; +#endif + + /* Adjust default compression parameters by re-parsing the options */ + file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); + + /* Specify data destination for compression */ + jpeg_stdio_dest(&dstinfo, output_file); + + /* Start compressor (note no image data is actually written here) */ + jpeg_write_coefficients(&dstinfo, dst_coef_arrays); + + /* Copy to the output file any extra markers that we want to preserve */ + jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); + + /* Execute image transformation, if any */ +#if TRANSFORMS_SUPPORTED + jtransform_execute_transformation(&srcinfo, &dstinfo, + src_coef_arrays, + &transformoption); +#endif + + /* Finish compression and release memory */ + jpeg_finish_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + (void) jpeg_finish_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + + /* Close files, if we opened them */ + if (input_file != stdin) + fclose(input_file); + if (output_file != stdout) + fclose(output_file); + +#ifdef PROGRESS_REPORT + end_progress_monitor((j_common_ptr) &dstinfo); +#endif + + /* All done. */ + exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/freeimage241/Source/LibJPEG/jquant1.c b/freeimage241/Source/LibJPEG/jquant1.c new file mode 100644 index 0000000..b2f96aa --- /dev/null +++ b/freeimage241/Source/LibJPEG/jquant1.c @@ -0,0 +1,856 @@ +/* + * jquant1.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 1-pass color quantization (color mapping) routines. + * These routines provide mapping to a fixed color map using equally spaced + * color values. Optional Floyd-Steinberg or ordered dithering is available. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_1PASS_SUPPORTED + + +/* + * The main purpose of 1-pass quantization is to provide a fast, if not very + * high quality, colormapped output capability. A 2-pass quantizer usually + * gives better visual quality; however, for quantized grayscale output this + * quantizer is perfectly adequate. Dithering is highly recommended with this + * quantizer, though you can turn it off if you really want to. + * + * In 1-pass quantization the colormap must be chosen in advance of seeing the + * image. We use a map consisting of all combinations of Ncolors[i] color + * values for the i'th component. The Ncolors[] values are chosen so that + * their product, the total number of colors, is no more than that requested. + * (In most cases, the product will be somewhat less.) + * + * Since the colormap is orthogonal, the representative value for each color + * component can be determined without considering the other components; + * then these indexes can be combined into a colormap index by a standard + * N-dimensional-array-subscript calculation. Most of the arithmetic involved + * can be precalculated and stored in the lookup table colorindex[]. + * colorindex[i][j] maps pixel value j in component i to the nearest + * representative value (grid plane) for that component; this index is + * multiplied by the array stride for component i, so that the + * index of the colormap entry closest to a given pixel value is just + * sum( colorindex[component-number][pixel-component-value] ) + * Aside from being fast, this scheme allows for variable spacing between + * representative values with no additional lookup cost. + * + * If gamma correction has been applied in color conversion, it might be wise + * to adjust the color grid spacing so that the representative colors are + * equidistant in linear space. At this writing, gamma correction is not + * implemented by jdcolor, so nothing is done here. + */ + + +/* Declarations for ordered dithering. + * + * We use a standard 16x16 ordered dither array. The basic concept of ordered + * dithering is described in many references, for instance Dale Schumacher's + * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). + * In place of Schumacher's comparisons against a "threshold" value, we add a + * "dither" value to the input pixel and then round the result to the nearest + * output value. The dither value is equivalent to (0.5 - threshold) times + * the distance between output values. For ordered dithering, we assume that + * the output colors are equally spaced; if not, results will probably be + * worse, since the dither may be too much or too little at a given point. + * + * The normal calculation would be to form pixel value + dither, range-limit + * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. + * We can skip the separate range-limiting step by extending the colorindex + * table in both directions. + */ + +#define ODITHER_SIZE 16 /* dimension of dither matrix */ +/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */ +#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */ +#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */ + +typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE]; +typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE]; + +static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = { + /* Bayer's order-4 dither array. Generated by the code given in + * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. + * The values in this array must range from 0 to ODITHER_CELLS-1. + */ + { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, + { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, + { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, + { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, + { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, + { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, + { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, + { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, + { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, + { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, + { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, + { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, + { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, + { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, + { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, + { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } +}; + + +/* Declarations for Floyd-Steinberg dithering. + * + * Errors are accumulated into the array fserrors[], at a resolution of + * 1/16th of a pixel count. The error at a given pixel is propagated + * to its not-yet-processed neighbors using the standard F-S fractions, + * ... (here) 7/16 + * 3/16 5/16 1/16 + * We work left-to-right on even rows, right-to-left on odd rows. + * + * We can get away with a single array (holding one row's worth of errors) + * by using it to store the current row's errors at pixel columns not yet + * processed, but the next row's errors at columns already processed. We + * need only a few extra variables to hold the errors immediately around the + * current column. (If we are lucky, those variables are in registers, but + * even if not, they're probably cheaper to access than array elements are.) + * + * The fserrors[] array is indexed [component#][position]. + * We provide (#columns + 2) entries per component; the extra entry at each + * end saves us from special-casing the first and last pixels. + * + * Note: on a wide image, we might not have enough room in a PC's near data + * segment to hold the error array; so it is allocated with alloc_large. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef INT16 FSERROR; /* 16 bits should be enough */ +typedef int LOCFSERROR; /* use 'int' for calculation temps */ +#else +typedef INT32 FSERROR; /* may need more than 16 bits */ +typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */ +#endif + +typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */ + + +/* Private subobject */ + +#define MAX_Q_COMPS 4 /* max components I can handle */ + +typedef struct { + struct jpeg_color_quantizer pub; /* public fields */ + + /* Initially allocated colormap is saved here */ + JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */ + int sv_actual; /* number of entries in use */ + + JSAMPARRAY colorindex; /* Precomputed mapping for speed */ + /* colorindex[i][j] = index of color closest to pixel value j in component i, + * premultiplied as described above. Since colormap indexes must fit into + * JSAMPLEs, the entries of this array will too. + */ + boolean is_padded; /* is the colorindex padded for odither? */ + + int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */ + + /* Variables for ordered dithering */ + int row_index; /* cur row's vertical index in dither matrix */ + ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */ + + /* Variables for Floyd-Steinberg dithering */ + FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */ + boolean on_odd_row; /* flag to remember which row we are on */ +} my_cquantizer; + +typedef my_cquantizer * my_cquantize_ptr; + + +/* + * Policy-making subroutines for create_colormap and create_colorindex. + * These routines determine the colormap to be used. The rest of the module + * only assumes that the colormap is orthogonal. + * + * * select_ncolors decides how to divvy up the available colors + * among the components. + * * output_value defines the set of representative values for a component. + * * largest_input_value defines the mapping from input values to + * representative values for a component. + * Note that the latter two routines may impose different policies for + * different components, though this is not currently done. + */ + + +LOCAL(int) +select_ncolors (j_decompress_ptr cinfo, int Ncolors[]) +/* Determine allocation of desired colors to components, */ +/* and fill in Ncolors[] array to indicate choice. */ +/* Return value is total number of colors (product of Ncolors[] values). */ +{ + int nc = cinfo->out_color_components; /* number of color components */ + int max_colors = cinfo->desired_number_of_colors; + int total_colors, iroot, i, j; + boolean changed; + long temp; + static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE }; + + /* We can allocate at least the nc'th root of max_colors per component. */ + /* Compute floor(nc'th root of max_colors). */ + iroot = 1; + do { + iroot++; + temp = iroot; /* set temp = iroot ** nc */ + for (i = 1; i < nc; i++) + temp *= iroot; + } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */ + iroot--; /* now iroot = floor(root) */ + + /* Must have at least 2 color values per component */ + if (iroot < 2) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp); + + /* Initialize to iroot color values for each component */ + total_colors = 1; + for (i = 0; i < nc; i++) { + Ncolors[i] = iroot; + total_colors *= iroot; + } + /* We may be able to increment the count for one or more components without + * exceeding max_colors, though we know not all can be incremented. + * Sometimes, the first component can be incremented more than once! + * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) + * In RGB colorspace, try to increment G first, then R, then B. + */ + do { + changed = FALSE; + for (i = 0; i < nc; i++) { + j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i); + /* calculate new total_colors if Ncolors[j] is incremented */ + temp = total_colors / Ncolors[j]; + temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */ + if (temp > (long) max_colors) + break; /* won't fit, done with this pass */ + Ncolors[j]++; /* OK, apply the increment */ + total_colors = (int) temp; + changed = TRUE; + } + } while (changed); + + return total_colors; +} + + +LOCAL(int) +output_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return j'th output value, where j will range from 0 to maxj */ +/* The output values must fall in 0..MAXJSAMPLE in increasing order */ +{ + /* We always provide values 0 and MAXJSAMPLE for each component; + * any additional values are equally spaced between these limits. + * (Forcing the upper and lower values to the limits ensures that + * dithering can't produce a color outside the selected gamut.) + */ + return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj); +} + + +LOCAL(int) +largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj) +/* Return largest input value that should map to j'th output value */ +/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */ +{ + /* Breakpoints are halfway between values returned by output_value */ + return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj)); +} + + +/* + * Create the colormap. + */ + +LOCAL(void) +create_colormap (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colormap; /* Created colormap */ + int total_colors; /* Number of distinct output colors */ + int i,j,k, nci, blksize, blkdist, ptr, val; + + /* Select number of colors for each component */ + total_colors = select_ncolors(cinfo, cquantize->Ncolors); + + /* Report selected color counts */ + if (cinfo->out_color_components == 3) + TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS, + total_colors, cquantize->Ncolors[0], + cquantize->Ncolors[1], cquantize->Ncolors[2]); + else + TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors); + + /* Allocate and fill in the colormap. */ + /* The colors are ordered in the map in standard row-major order, */ + /* i.e. rightmost (highest-indexed) color changes most rapidly. */ + + colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + /* blkdist is distance between groups of identical entries for a component */ + blkdist = total_colors; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colormap entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blkdist / nci; + for (j = 0; j < nci; j++) { + /* Compute j'th output value (out of nci) for component */ + val = output_value(cinfo, i, j, nci-1); + /* Fill in all colormap entries that have this value of this component */ + for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) { + /* fill in blksize entries beginning at ptr */ + for (k = 0; k < blksize; k++) + colormap[i][ptr+k] = (JSAMPLE) val; + } + } + blkdist = blksize; /* blksize of this color is blkdist of next */ + } + + /* Save the colormap in private storage, + * where it will survive color quantization mode changes. + */ + cquantize->sv_colormap = colormap; + cquantize->sv_actual = total_colors; +} + + +/* + * Create the color index table. + */ + +LOCAL(void) +create_colorindex (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPROW indexptr; + int i,j,k, nci, blksize, val, pad; + + /* For ordered dither, we pad the color index tables by MAXJSAMPLE in + * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). + * This is not necessary in the other dithering modes. However, we + * flag whether it was done in case user changes dithering mode. + */ + if (cinfo->dither_mode == JDITHER_ORDERED) { + pad = MAXJSAMPLE*2; + cquantize->is_padded = TRUE; + } else { + pad = 0; + cquantize->is_padded = FALSE; + } + + cquantize->colorindex = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1 + pad), + (JDIMENSION) cinfo->out_color_components); + + /* blksize is number of adjacent repeated entries for a component */ + blksize = cquantize->sv_actual; + + for (i = 0; i < cinfo->out_color_components; i++) { + /* fill in colorindex entries for i'th color component */ + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + blksize = blksize / nci; + + /* adjust colorindex pointers to provide padding at negative indexes. */ + if (pad) + cquantize->colorindex[i] += MAXJSAMPLE; + + /* in loop, val = index of current output value, */ + /* and k = largest j that maps to current val */ + indexptr = cquantize->colorindex[i]; + val = 0; + k = largest_input_value(cinfo, i, 0, nci-1); + for (j = 0; j <= MAXJSAMPLE; j++) { + while (j > k) /* advance val if past boundary */ + k = largest_input_value(cinfo, i, ++val, nci-1); + /* premultiply so that no multiplication needed in main processing */ + indexptr[j] = (JSAMPLE) (val * blksize); + } + /* Pad at both ends if necessary */ + if (pad) + for (j = 1; j <= MAXJSAMPLE; j++) { + indexptr[-j] = indexptr[0]; + indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE]; + } + } +} + + +/* + * Create an ordered-dither array for a component having ncolors + * distinct output values. + */ + +LOCAL(ODITHER_MATRIX_PTR) +make_odither_array (j_decompress_ptr cinfo, int ncolors) +{ + ODITHER_MATRIX_PTR odither; + int j,k; + INT32 num,den; + + odither = (ODITHER_MATRIX_PTR) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ODITHER_MATRIX)); + /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). + * Hence the dither value for the matrix cell with fill order f + * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). + * On 16-bit-int machine, be careful to avoid overflow. + */ + den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1)); + for (j = 0; j < ODITHER_SIZE; j++) { + for (k = 0; k < ODITHER_SIZE; k++) { + num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k]))) + * MAXJSAMPLE; + /* Ensure round towards zero despite C's lack of consistency + * about rounding negative values in integer division... + */ + odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den); + } + } + return odither; +} + + +/* + * Create the ordered-dither tables. + * Components having the same number of representative colors may + * share a dither table. + */ + +LOCAL(void) +create_odither_tables (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + ODITHER_MATRIX_PTR odither; + int i, j, nci; + + for (i = 0; i < cinfo->out_color_components; i++) { + nci = cquantize->Ncolors[i]; /* # of distinct values for this color */ + odither = NULL; /* search for matching prior component */ + for (j = 0; j < i; j++) { + if (nci == cquantize->Ncolors[j]) { + odither = cquantize->odither[j]; + break; + } + } + if (odither == NULL) /* need a new table? */ + odither = make_odither_array(cinfo, nci); + cquantize->odither[i] = odither; + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + JSAMPARRAY colorindex = cquantize->colorindex; + register int pixcode, ci; + register JSAMPROW ptrin, ptrout; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + register int nc = cinfo->out_color_components; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = 0; + for (ci = 0; ci < nc; ci++) { + pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]); + } + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW ptrin, ptrout; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptrin = input_buf[row]; + ptrout = output_buf[row]; + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]); + *ptrout++ = (JSAMPLE) pixcode; + } + } +} + + +METHODDEF(void) +quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + int * dither; /* points to active row of dither matrix */ + int row_index, col_index; /* current indexes into dither matrix */ + int nc = cinfo->out_color_components; + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + row_index = cquantize->row_index; + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + colorindex_ci = cquantize->colorindex[ci]; + dither = cquantize->odither[ci][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE, + * select output value, accumulate into output code for this pixel. + * Range-limiting need not be done explicitly, as we have extended + * the colorindex table to produce the right answers for out-of-range + * inputs. The maximum dither is +- MAXJSAMPLE; this sets the + * required amount of padding. + */ + *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]]; + input_ptr += nc; + output_ptr++; + col_index = (col_index + 1) & ODITHER_MASK; + } + } + /* Advance row index for next row */ + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* Fast path for out_color_components==3, with ordered dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register int pixcode; + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex0 = cquantize->colorindex[0]; + JSAMPROW colorindex1 = cquantize->colorindex[1]; + JSAMPROW colorindex2 = cquantize->colorindex[2]; + int * dither0; /* points to active row of dither matrix */ + int * dither1; + int * dither2; + int row_index, col_index; /* current indexes into dither matrix */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + row_index = cquantize->row_index; + input_ptr = input_buf[row]; + output_ptr = output_buf[row]; + dither0 = cquantize->odither[0][row_index]; + dither1 = cquantize->odither[1][row_index]; + dither2 = cquantize->odither[2][row_index]; + col_index = 0; + + for (col = width; col > 0; col--) { + pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) + + dither0[col_index]]); + pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) + + dither1[col_index]]); + pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) + + dither2[col_index]]); + *output_ptr++ = (JSAMPLE) pixcode; + col_index = (col_index + 1) & ODITHER_MASK; + } + row_index = (row_index + 1) & ODITHER_MASK; + cquantize->row_index = row_index; + } +} + + +METHODDEF(void) +quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +/* General case, with Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + register LOCFSERROR cur; /* current error or pixel value */ + LOCFSERROR belowerr; /* error for pixel below cur */ + LOCFSERROR bpreverr; /* error for below/prev col */ + LOCFSERROR bnexterr; /* error for below/next col */ + LOCFSERROR delta; + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + register JSAMPROW input_ptr; + register JSAMPROW output_ptr; + JSAMPROW colorindex_ci; + JSAMPROW colormap_ci; + int pixcode; + int nc = cinfo->out_color_components; + int dir; /* 1 for left-to-right, -1 for right-to-left */ + int dirnc; /* dir * nc */ + int ci; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + /* Initialize output values to 0 so can process components separately */ + jzero_far((void FAR *) output_buf[row], + (size_t) (width * SIZEOF(JSAMPLE))); + for (ci = 0; ci < nc; ci++) { + input_ptr = input_buf[row] + ci; + output_ptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + input_ptr += (width-1) * nc; /* so point to rightmost pixel */ + output_ptr += width-1; + dir = -1; + dirnc = -nc; + errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */ + } else { + /* work left to right in this row */ + dir = 1; + dirnc = nc; + errorptr = cquantize->fserrors[ci]; /* => entry before first column */ + } + colorindex_ci = cquantize->colorindex[ci]; + colormap_ci = cquantize->sv_colormap[ci]; + /* Preset error values: no error propagated to first pixel from left */ + cur = 0; + /* and no error propagated to row below yet */ + belowerr = bpreverr = 0; + + for (col = width; col > 0; col--) { + /* cur holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4); + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE; this sets the required size + * of the range_limit array. + */ + cur += GETJSAMPLE(*input_ptr); + cur = GETJSAMPLE(range_limit[cur]); + /* Select output value, accumulate into output code for this pixel */ + pixcode = GETJSAMPLE(colorindex_ci[cur]); + *output_ptr += (JSAMPLE) pixcode; + /* Compute actual representation error at this pixel */ + /* Note: we can do this even though we don't have the final */ + /* pixel code, because the colormap is orthogonal. */ + cur -= GETJSAMPLE(colormap_ci[pixcode]); + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + bnexterr = cur; + delta = cur * 2; + cur += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr + cur); + cur += delta; /* form error * 5 */ + bpreverr = belowerr + cur; + belowerr = bnexterr; + cur += delta; /* form error * 7 */ + /* At this point cur contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + input_ptr += dirnc; /* advance input ptr to next column */ + output_ptr += dir; /* advance output ptr to next column */ + errorptr += dir; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error value into the + * final fserrors[] entry. Note we need not unload belowerr because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */ + } + cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE); + } +} + + +/* + * Allocate workspace for Floyd-Steinberg errors. + */ + +LOCAL(void) +alloc_fs_workspace (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) { + cquantize->fserrors[i] = (FSERRPTR) + (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + } +} + + +/* + * Initialize for one-pass color quantization. + */ + +METHODDEF(void) +start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + size_t arraysize; + int i; + + /* Install my colormap. */ + cinfo->colormap = cquantize->sv_colormap; + cinfo->actual_number_of_colors = cquantize->sv_actual; + + /* Initialize for desired dithering mode. */ + switch (cinfo->dither_mode) { + case JDITHER_NONE: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = color_quantize3; + else + cquantize->pub.color_quantize = color_quantize; + break; + case JDITHER_ORDERED: + if (cinfo->out_color_components == 3) + cquantize->pub.color_quantize = quantize3_ord_dither; + else + cquantize->pub.color_quantize = quantize_ord_dither; + cquantize->row_index = 0; /* initialize state for ordered dither */ + /* If user changed to ordered dither from another mode, + * we must recreate the color index table with padding. + * This will cost extra space, but probably isn't very likely. + */ + if (! cquantize->is_padded) + create_colorindex(cinfo); + /* Create ordered-dither tables if we didn't already. */ + if (cquantize->odither[0] == NULL) + create_odither_tables(cinfo); + break; + case JDITHER_FS: + cquantize->pub.color_quantize = quantize_fs_dither; + cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */ + /* Allocate Floyd-Steinberg workspace if didn't already. */ + if (cquantize->fserrors[0] == NULL) + alloc_fs_workspace(cinfo); + /* Initialize the propagated errors to zero. */ + arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR)); + for (i = 0; i < cinfo->out_color_components; i++) + jzero_far((void FAR *) cquantize->fserrors[i], arraysize); + break; + default: + ERREXIT(cinfo, JERR_NOT_COMPILED); + break; + } +} + + +/* + * Finish up at the end of the pass. + */ + +METHODDEF(void) +finish_pass_1_quant (j_decompress_ptr cinfo) +{ + /* no work in 1-pass case */ +} + + +/* + * Switch to a new external colormap between output passes. + * Shouldn't get to this module! + */ + +METHODDEF(void) +new_color_map_1_quant (j_decompress_ptr cinfo) +{ + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + + +/* + * Module initialization routine for 1-pass color quantization. + */ + +GLOBAL(void) +jinit_1pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_1_quant; + cquantize->pub.finish_pass = finish_pass_1_quant; + cquantize->pub.new_color_map = new_color_map_1_quant; + cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */ + cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */ + + /* Make sure my internal arrays won't overflow */ + if (cinfo->out_color_components > MAX_Q_COMPS) + ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); + + /* Create the colormap and color index table. */ + create_colormap(cinfo); + create_colorindex(cinfo); + + /* Allocate Floyd-Steinberg workspace now if requested. + * We do this now since it is FAR storage and may affect the memory + * manager's space calculations. If the user changes to FS dither + * mode in a later pass, we will allocate the space then, and will + * possibly overrun the max_memory_to_use setting. + */ + if (cinfo->dither_mode == JDITHER_FS) + alloc_fs_workspace(cinfo); +} + +#endif /* QUANT_1PASS_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jquant2.c b/freeimage241/Source/LibJPEG/jquant2.c new file mode 100644 index 0000000..af601e3 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jquant2.c @@ -0,0 +1,1310 @@ +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + +#ifdef QUANT_2PASS_SUPPORTED + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +LOCAL(boxptr) +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +LOCAL(boxptr) +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +LOCAL(void) +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +LOCAL(int) +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if (numboxes*2 <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +LOCAL(void) +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +LOCAL(void) +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes); +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +LOCAL(void) +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +LOCAL(void) +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +METHODDEF(void) +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +METHODDEF(void) +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + SHIFT_TEMPS + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = FALSE; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = TRUE; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +LOCAL(void) +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +METHODDEF(void) +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = TRUE; +} + + +METHODDEF(void) +finish_pass2 (j_decompress_ptr cinfo) +{ + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +METHODDEF(void) +start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int i; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = TRUE; /* Always zero histogram */ + } else { + /* Set up method pointers */ + if (cinfo->dither_mode == JDITHER_FS) + cquantize->pub.color_quantize = pass2_fs_dither; + else + cquantize->pub.color_quantize = pass2_no_dither; + cquantize->pub.finish_pass = finish_pass2; + + /* Make sure color count is acceptable */ + i = cinfo->actual_number_of_colors; + if (i < 1) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1); + if (i > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + + if (cinfo->dither_mode == JDITHER_FS) { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * SIZEOF(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize); + /* Initialize the propagated errors to zero. */ + jzero_far((void FAR *) cquantize->fserrors, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = FALSE; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (i = 0; i < HIST_C0_ELEMS; i++) { + jzero_far((void FAR *) histogram[i], + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = FALSE; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +METHODDEF(void) +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = TRUE; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +GLOBAL(void) +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_cquantizer)); + cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + /* Make sure jdmaster didn't give me a case I can't handle */ + if (cinfo->out_color_components != 3) + ERREXIT(cinfo, JERR_NOTIMPL); + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); + } + cquantize->needs_zeroed = TRUE; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is FAR storage and may affect + * the memory manager's space calculations. + */ + if (cinfo->enable_2pass_quant) { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */ + if (desired < 8) + ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8); + /* Make sure colormap indexes can be represented by JSAMPLEs */ + if (desired > MAXNUMCOLORS) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); + cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3); + cquantize->desired = desired; + } else + cquantize->sv_colormap = NULL; + + /* Only F-S dithering or no dithering is supported. */ + /* If user asks for ordered dither, give him F-S. */ + if (cinfo->dither_mode != JDITHER_NONE) + cinfo->dither_mode = JDITHER_FS; + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is FAR storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + if (cinfo->dither_mode == JDITHER_FS) { + cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/jutils.c b/freeimage241/Source/LibJPEG/jutils.c new file mode 100644 index 0000000..d18a955 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jutils.c @@ -0,0 +1,179 @@ +/* + * jutils.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains tables and miscellaneous utility routines needed + * for both compression and decompression. + * Note we prefix all global names with "j" to minimize conflicts with + * a surrounding application. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "jpeglib.h" + + +/* + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + * of a DCT block read in natural order (left to right, top to bottom). + */ + +#if 0 /* This table is not actually needed in v6a */ + +const int jpeg_zigzag_order[DCTSIZE2] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +#endif + +/* + * jpeg_natural_order[i] is the natural-order position of the i'th element + * of zigzag order. + * + * When reading corrupted data, the Huffman decoders could attempt + * to reference an entry beyond the end of this array (if the decoded + * zero run length reaches past the end of the block). To prevent + * wild stores without adding an inner-loop test, we put some extra + * "63"s after the real entries. This will cause the extra coefficient + * to be stored in location 63 of the block, not somewhere random. + * The worst case would be a run-length of 15, which means we need 16 + * fake entries. + */ + +const int jpeg_natural_order[DCTSIZE2+16] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + 63, 63, 63, 63, 63, 63, 63, 63 +}; + + +/* + * Arithmetic utilities + */ + +GLOBAL(long) +jdiv_round_up (long a, long b) +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ +/* Assumes a >= 0, b > 0 */ +{ + return (a + b - 1L) / b; +} + + +GLOBAL(long) +jround_up (long a, long b) +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ +/* Assumes a >= 0, b > 0 */ +{ + a += b - 1L; + return a - (a % b); +} + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + * and coefficient-block arrays. This won't work on 80x86 because the arrays + * are FAR and we're assuming a small-pointer memory model. However, some + * DOS compilers provide far-pointer versions of memcpy() and memset() even + * in the small-model libraries. These will be used if USE_FMEM is defined. + * Otherwise, the routines below do it the hard way. (The performance cost + * is not all that great, because these routines aren't very heavily used.) + */ + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) +#define FMEMZERO(target,size) MEMZERO(target,size) +#else /* 80x86 case, define if we can */ +#ifdef USE_FMEM +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) +#endif +#endif + + +GLOBAL(void) +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols) +/* Copy some rows of samples from one place to another. + * num_rows rows are copied from input_array[source_row++] + * to output_array[dest_row++]; these areas may overlap for duplication. + * The source and destination arrays must be at least as wide as num_cols. + */ +{ + register JSAMPROW inptr, outptr; +#ifdef FMEMCOPY + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); +#else + register JDIMENSION count; +#endif + register int row; + + input_array += source_row; + output_array += dest_row; + + for (row = num_rows; row > 0; row--) { + inptr = *input_array++; + outptr = *output_array++; +#ifdef FMEMCOPY + FMEMCOPY(outptr, inptr, count); +#else + for (count = num_cols; count > 0; count--) + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ +#endif + } +} + + +GLOBAL(void) +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks) +/* Copy a row of coefficient blocks from one place to another. */ +{ +#ifdef FMEMCOPY + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); +#else + register JCOEFPTR inptr, outptr; + register long count; + + inptr = (JCOEFPTR) input_row; + outptr = (JCOEFPTR) output_row; + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + *outptr++ = *inptr++; + } +#endif +} + + +GLOBAL(void) +jzero_far (void FAR * target, size_t bytestozero) +/* Zero out a chunk of FAR memory. */ +/* This might be sample-array data, block-array data, or alloc_large data. */ +{ +#ifdef FMEMZERO + FMEMZERO(target, bytestozero); +#else + register char FAR * ptr = (char FAR *) target; + register size_t count; + + for (count = bytestozero; count > 0; count--) { + *ptr++ = 0; + } +#endif +} diff --git a/freeimage241/Source/LibJPEG/jversion.h b/freeimage241/Source/LibJPEG/jversion.h new file mode 100644 index 0000000..6472c58 --- /dev/null +++ b/freeimage241/Source/LibJPEG/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/freeimage241/Source/LibJPEG/mssccprj.scc b/freeimage241/Source/LibJPEG/mssccprj.scc new file mode 100644 index 0000000..81e63d9 --- /dev/null +++ b/freeimage241/Source/LibJPEG/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[LibJPEG.dsp] +SCC_Aux_Path = "\\ASIMOV\Magenta\SourceSafe" +SCC_Project_Name = "$/FreeImage/LibJPEG", IHAAAAAA diff --git a/freeimage241/Source/LibJPEG/rdbmp.c b/freeimage241/Source/LibJPEG/rdbmp.c new file mode 100644 index 0000000..b05fe2a --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdbmp.c @@ -0,0 +1,439 @@ +/* + * rdbmp.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Microsoft "BMP" + * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors). + * Currently, only 8-bit and 24-bit images are supported, not 1-bit or + * 4-bit (feeding such low-depth images into JPEG would be silly anyway). + * Also, we don't support RLE-compressed files. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed BMP format). + * + * This code contributed by James Arthur Boucher. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef BMP_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char U_CHAR; +#define UCH(x) ((int) (x)) +#else +typedef char U_CHAR; +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* Private version of data source object */ + +typedef struct _bmp_source_struct * bmp_source_ptr; + +typedef struct _bmp_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + j_compress_ptr cinfo; /* back link saves passing separate parm */ + + JSAMPARRAY colormap; /* BMP colormap (converted to my format) */ + + jvirt_sarray_ptr whole_image; /* Needed to reverse row order */ + JDIMENSION source_row; /* Current source row number */ + JDIMENSION row_width; /* Physical width of scanlines in file */ + + int bits_per_pixel; /* remembers 8- or 24-bit format */ +} bmp_source_struct; + + +LOCAL(int) +read_byte (bmp_source_ptr sinfo) +/* Read next byte from BMP file */ +{ + register FILE *infile = sinfo->pub.input_file; + register int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + return c; +} + + +LOCAL(void) +read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize) +/* Read the colormap from a BMP file */ +{ + int i; + + switch (mapentrysize) { + case 3: + /* BGR format (occurs in OS/2 files) */ + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + } + break; + case 4: + /* BGR0 format (occurs in MS Windows files) */ + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + (void) read_byte(sinfo); + } + break; + default: + ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP); + break; + } +} + + +/* + * Read one row of pixels. + * The image has been read into the whole_image array, but is otherwise + * unprocessed. We must read it out in top-to-bottom row order, and if + * it is an 8-bit image, we must expand colormapped pixels to 24bit format. + */ + +METHODDEF(JDIMENSION) +get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit colormap indexes */ +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register JSAMPARRAY colormap = source->colormap; + JSAMPARRAY image_ptr; + register int t; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + + /* Fetch next row from virtual array */ + source->source_row--; + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + source->source_row, (JDIMENSION) 1, FALSE); + + /* Expand the colormap indexes to real data */ + inptr = image_ptr[0]; + outptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + t = GETJSAMPLE(*inptr++); + *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */ + *outptr++ = colormap[1][t]; + *outptr++ = colormap[2][t]; + } + + return 1; +} + + +METHODDEF(JDIMENSION) +get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 24-bit pixels */ +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + + /* Fetch next row from virtual array */ + source->source_row--; + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + source->source_row, (JDIMENSION) 1, FALSE); + + /* Transfer data. Note source values are in BGR order + * (even though Microsoft's own documents say the opposite). + */ + inptr = image_ptr[0]; + outptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } + + return 1; +} + + +/* + * This method loads the image into whole_image during the first call on + * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call + * get_8bit_row or get_24bit_row on subsequent calls. + */ + +METHODDEF(JDIMENSION) +preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + register FILE *infile = source->pub.input_file; + register int c; + register JSAMPROW out_ptr; + JSAMPARRAY image_ptr; + JDIMENSION row, col; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Read the data into a virtual array in input-file row order. */ + for (row = 0; row < cinfo->image_height; row++) { + if (progress != NULL) { + progress->pub.pass_counter = (long) row; + progress->pub.pass_limit = (long) cinfo->image_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + row, (JDIMENSION) 1, TRUE); + out_ptr = image_ptr[0]; + for (col = source->row_width; col > 0; col--) { + /* inline copy of read_byte() for speed */ + if ((c = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_INPUT_EOF); + *out_ptr++ = (JSAMPLE) c; + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Set up to read from the virtual array in top-to-bottom order */ + switch (source->bits_per_pixel) { + case 8: + source->pub.get_pixel_rows = get_8bit_row; + break; + case 24: + source->pub.get_pixel_rows = get_24bit_row; + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + } + source->source_row = cinfo->image_height; + + /* And read the first row */ + return (*source->pub.get_pixel_rows) (cinfo, sinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + bmp_source_ptr source = (bmp_source_ptr) sinfo; + U_CHAR bmpfileheader[14]; + U_CHAR bmpinfoheader[64]; +#define GET_2B(array,offset) ((unsigned int) UCH(array[offset]) + \ + (((unsigned int) UCH(array[offset+1])) << 8)) +#define GET_4B(array,offset) ((INT32) UCH(array[offset]) + \ + (((INT32) UCH(array[offset+1])) << 8) + \ + (((INT32) UCH(array[offset+2])) << 16) + \ + (((INT32) UCH(array[offset+3])) << 24)) + INT32 bfOffBits; + INT32 headerSize; + INT32 biWidth = 0; /* initialize to avoid compiler warning */ + INT32 biHeight = 0; + unsigned int biPlanes; + INT32 biCompression; + INT32 biXPelsPerMeter,biYPelsPerMeter; + INT32 biClrUsed = 0; + int mapentrysize = 0; /* 0 indicates no colormap */ + INT32 bPad; + JDIMENSION row_width; + + /* Read and verify the bitmap file header */ + if (! ReadOK(source->pub.input_file, bmpfileheader, 14)) + ERREXIT(cinfo, JERR_INPUT_EOF); + if (GET_2B(bmpfileheader,0) != 0x4D42) /* 'BM' */ + ERREXIT(cinfo, JERR_BMP_NOT); + bfOffBits = (INT32) GET_4B(bmpfileheader,10); + /* We ignore the remaining fileheader fields */ + + /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows), + * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which. + */ + if (! ReadOK(source->pub.input_file, bmpinfoheader, 4)) + ERREXIT(cinfo, JERR_INPUT_EOF); + headerSize = (INT32) GET_4B(bmpinfoheader,0); + if (headerSize < 12 || headerSize > 64) + ERREXIT(cinfo, JERR_BMP_BADHEADER); + if (! ReadOK(source->pub.input_file, bmpinfoheader+4, headerSize-4)) + ERREXIT(cinfo, JERR_INPUT_EOF); + + switch ((int) headerSize) { + case 12: + /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */ + biWidth = (INT32) GET_2B(bmpinfoheader,4); + biHeight = (INT32) GET_2B(bmpinfoheader,6); + biPlanes = GET_2B(bmpinfoheader,8); + source->bits_per_pixel = (int) GET_2B(bmpinfoheader,10); + + switch (source->bits_per_pixel) { + case 8: /* colormapped image */ + mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */ + TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight); + break; + case 24: /* RGB image */ + TRACEMS2(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight); + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + break; + } + if (biPlanes != 1) + ERREXIT(cinfo, JERR_BMP_BADPLANES); + break; + case 40: + case 64: + /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */ + /* or OS/2 2.x header, which has additional fields that we ignore */ + biWidth = GET_4B(bmpinfoheader,4); + biHeight = GET_4B(bmpinfoheader,8); + biPlanes = GET_2B(bmpinfoheader,12); + source->bits_per_pixel = (int) GET_2B(bmpinfoheader,14); + biCompression = GET_4B(bmpinfoheader,16); + biXPelsPerMeter = GET_4B(bmpinfoheader,24); + biYPelsPerMeter = GET_4B(bmpinfoheader,28); + biClrUsed = GET_4B(bmpinfoheader,32); + /* biSizeImage, biClrImportant fields are ignored */ + + switch (source->bits_per_pixel) { + case 8: /* colormapped image */ + mapentrysize = 4; /* Windows uses RGBQUAD colormap */ + TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight); + break; + case 24: /* RGB image */ + TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight); + break; + default: + ERREXIT(cinfo, JERR_BMP_BADDEPTH); + break; + } + if (biPlanes != 1) + ERREXIT(cinfo, JERR_BMP_BADPLANES); + if (biCompression != 0) + ERREXIT(cinfo, JERR_BMP_COMPRESSED); + + if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) { + /* Set JFIF density parameters from the BMP data */ + cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */ + cinfo->Y_density = (UINT16) (biYPelsPerMeter/100); + cinfo->density_unit = 2; /* dots/cm */ + } + break; + default: + ERREXIT(cinfo, JERR_BMP_BADHEADER); + break; + } + + /* Compute distance to bitmap data --- will adjust for colormap below */ + bPad = bfOffBits - (headerSize + 14); + + /* Read the colormap, if any */ + if (mapentrysize > 0) { + if (biClrUsed <= 0) + biClrUsed = 256; /* assume it's 256 */ + else if (biClrUsed > 256) + ERREXIT(cinfo, JERR_BMP_BADCMAP); + /* Allocate space to store the colormap */ + source->colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) biClrUsed, (JDIMENSION) 3); + /* and read it from the file */ + read_colormap(source, (int) biClrUsed, mapentrysize); + /* account for size of colormap */ + bPad -= biClrUsed * mapentrysize; + } + + /* Skip any remaining pad bytes */ + if (bPad < 0) /* incorrect bfOffBits value? */ + ERREXIT(cinfo, JERR_BMP_BADHEADER); + while (--bPad >= 0) { + (void) read_byte(source); + } + + /* Compute row width in file, including padding to 4-byte boundary */ + if (source->bits_per_pixel == 24) + row_width = (JDIMENSION) (biWidth * 3); + else + row_width = (JDIMENSION) biWidth; + while ((row_width & 3) != 0) row_width++; + source->row_width = row_width; + + /* Allocate space for inversion array, prepare for preload pass */ + source->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + row_width, (JDIMENSION) biHeight, (JDIMENSION) 1); + source->pub.get_pixel_rows = preload_image; + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + + /* Allocate one-row buffer for returned data */ + source->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (biWidth * 3), (JDIMENSION) 1); + source->pub.buffer_height = 1; + + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = 3; + cinfo->data_precision = 8; + cinfo->image_width = (JDIMENSION) biWidth; + cinfo->image_height = (JDIMENSION) biHeight; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for BMP format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_bmp (j_compress_ptr cinfo) +{ + bmp_source_ptr source; + + /* Create module interface object */ + source = (bmp_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(bmp_source_struct)); + source->cinfo = cinfo; /* make back link for subroutines */ + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_bmp; + source->pub.finish_input = finish_input_bmp; + + return (cjpeg_source_ptr) source; +} + +#endif /* BMP_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/rdcolmap.c b/freeimage241/Source/LibJPEG/rdcolmap.c new file mode 100644 index 0000000..42b3437 --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdcolmap.c @@ -0,0 +1,253 @@ +/* + * rdcolmap.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file implements djpeg's "-map file" switch. It reads a source image + * and constructs a colormap to be supplied to the JPEG decompressor. + * + * Currently, these file formats are supported for the map file: + * GIF: the contents of the GIF's global colormap are used. + * PPM (either text or raw flavor): the entire file is read and + * each unique pixel value is entered in the map. + * Note that reading a large PPM file will be horrendously slow. + * Typically, a PPM-format map file should contain just one pixel + * of each desired color. Such a file can be extracted from an + * ordinary image PPM file with ppmtomap(1). + * + * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not + * currently implemented. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */ + +/* Portions of this code are based on the PBMPLUS library, which is: +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + + +/* + * Add a (potentially) new color to the color map. + */ + +LOCAL(void) +add_map_entry (j_decompress_ptr cinfo, int R, int G, int B) +{ + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + int ncolors = cinfo->actual_number_of_colors; + int index; + + /* Check for duplicate color. */ + for (index = 0; index < ncolors; index++) { + if (GETJSAMPLE(colormap0[index]) == R && + GETJSAMPLE(colormap1[index]) == G && + GETJSAMPLE(colormap2[index]) == B) + return; /* color is already in map */ + } + + /* Check for map overflow. */ + if (ncolors >= (MAXJSAMPLE+1)) + ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1)); + + /* OK, add color to map. */ + colormap0[ncolors] = (JSAMPLE) R; + colormap1[ncolors] = (JSAMPLE) G; + colormap2[ncolors] = (JSAMPLE) B; + cinfo->actual_number_of_colors++; +} + + +/* + * Extract color map from a GIF file. + */ + +LOCAL(void) +read_gif_map (j_decompress_ptr cinfo, FILE * infile) +{ + int header[13]; + int i, colormaplen; + int R, G, B; + + /* Initial 'G' has already been read by read_color_map */ + /* Read the rest of the GIF header and logical screen descriptor */ + for (i = 1; i < 13; i++) { + if ((header[i] = getc(infile)) == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + } + + /* Verify GIF Header */ + if (header[1] != 'I' || header[2] != 'F') + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* There must be a global color map. */ + if ((header[10] & 0x80) == 0) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* OK, fetch it. */ + colormaplen = 2 << (header[10] & 0x07); + + for (i = 0; i < colormaplen; i++) { + R = getc(infile); + G = getc(infile); + B = getc(infile); + if (R == EOF || G == EOF || B == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + add_map_entry(cinfo, + R << (BITS_IN_JSAMPLE-8), + G << (BITS_IN_JSAMPLE-8), + B << (BITS_IN_JSAMPLE-8)); + } +} + + +/* Support routines for reading PPM */ + + +LOCAL(int) +pbm_getc (FILE * infile) +/* Read next char, skipping over any comments */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(infile); + if (ch == '#') { + do { + ch = getc(infile); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(unsigned int) +read_pbm_integer (j_decompress_ptr cinfo, FILE * infile) +/* Read an unsigned decimal integer from the PPM file */ +/* Swallows one trailing character after the integer */ +/* Note that on a 16-bit-int machine, only values up to 64k can be read. */ +/* This should not be a problem in practice. */ +{ + register int ch; + register unsigned int val; + + /* Skip any leading whitespace */ + do { + ch = pbm_getc(infile); + if (ch == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + val = ch - '0'; + while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') { + val *= 10; + val += ch - '0'; + } + return val; +} + + +/* + * Extract color map from a PPM file. + */ + +LOCAL(void) +read_ppm_map (j_decompress_ptr cinfo, FILE * infile) +{ + int c; + unsigned int w, h, maxval, row, col; + int R, G, B; + + /* Initial 'P' has already been read by read_color_map */ + c = getc(infile); /* save format discriminator for a sec */ + + /* while we fetch the remaining header info */ + w = read_pbm_integer(cinfo, infile); + h = read_pbm_integer(cinfo, infile); + maxval = read_pbm_integer(cinfo, infile); + + if (w <= 0 || h <= 0 || maxval <= 0) /* error check */ + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + /* For now, we don't support rescaling from an unusual maxval. */ + if (maxval != (unsigned int) MAXJSAMPLE) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + + switch (c) { + case '3': /* it's a text-format PPM file */ + for (row = 0; row < h; row++) { + for (col = 0; col < w; col++) { + R = read_pbm_integer(cinfo, infile); + G = read_pbm_integer(cinfo, infile); + B = read_pbm_integer(cinfo, infile); + add_map_entry(cinfo, R, G, B); + } + } + break; + + case '6': /* it's a raw-format PPM file */ + for (row = 0; row < h; row++) { + for (col = 0; col < w; col++) { + R = getc(infile); + G = getc(infile); + B = getc(infile); + if (R == EOF || G == EOF || B == EOF) + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + add_map_entry(cinfo, R, G, B); + } + } + break; + + default: + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + break; + } +} + + +/* + * Main entry point from djpeg.c. + * Input: opened input file (from file name argument on command line). + * Output: colormap and actual_number_of_colors fields are set in cinfo. + */ + +GLOBAL(void) +read_color_map (j_decompress_ptr cinfo, FILE * infile) +{ + /* Allocate space for a color map of maximum supported size. */ + cinfo->colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3); + cinfo->actual_number_of_colors = 0; /* initialize map to empty */ + + /* Read first byte to determine file format */ + switch (getc(infile)) { + case 'G': + read_gif_map(cinfo, infile); + break; + case 'P': + read_ppm_map(cinfo, infile); + break; + default: + ERREXIT(cinfo, JERR_BAD_CMAP_FILE); + break; + } +} + +#endif /* QUANT_2PASS_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/rdgif.c b/freeimage241/Source/LibJPEG/rdgif.c new file mode 100644 index 0000000..b27c167 --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdgif.c @@ -0,0 +1,38 @@ +/* + * rdgif.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in GIF format. + * + ***************************************************************************** + * NOTE: to avoid entanglements with Unisys' patent on LZW compression, * + * the ability to read GIF files has been removed from the IJG distribution. * + * Sorry about that. * + ***************************************************************************** + * + * We are required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef GIF_SUPPORTED + +/* + * The module selection routine for GIF format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_gif (j_compress_ptr cinfo) +{ + fprintf(stderr, "GIF input is unsupported for legal reasons. Sorry.\n"); + exit(EXIT_FAILURE); + return NULL; /* keep compiler happy */ +} + +#endif /* GIF_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/rdjpgcom.c b/freeimage241/Source/LibJPEG/rdjpgcom.c new file mode 100644 index 0000000..ffe6fc6 --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdjpgcom.c @@ -0,0 +1,496 @@ +/* + * rdjpgcom.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a very simple stand-alone application that displays + * the text in COM (comment) markers in a JFIF file. + * This may be useful as an example of the minimum logic needed to parse + * JPEG markers. + */ + +#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ +#include "jinclude.h" /* get auto-config symbols, */ + +#include /* to declare isupper(), tolower() */ +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif + + +/* + * These macros are used to read the input file. + * To reuse this code in another application, you might need to change these. + */ + +static FILE * infile; /* input JPEG file */ + +/* Return next input byte, or EOF if no more */ +#define NEXTBYTE() getc(infile) + + +/* Error exit handler */ +#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) + + +/* Read one byte, testing for EOF */ +static int +read_1_byte (void) +{ + int c; + + c = NEXTBYTE(); + if (c == EOF) + ERREXIT("Premature EOF in JPEG file"); + return c; +} + +/* Read 2 bytes, convert to unsigned int */ +/* All 2-byte quantities in JPEG markers are MSB first */ +static unsigned int +read_2_bytes (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + if (c1 == EOF) + ERREXIT("Premature EOF in JPEG file"); + c2 = NEXTBYTE(); + if (c2 == EOF) + ERREXIT("Premature EOF in JPEG file"); + return (((unsigned int) c1) << 8) + ((unsigned int) c2); +} + + +/* + * JPEG markers consist of one or more 0xFF bytes, followed by a marker + * code byte (which is not an FF). Here are the marker codes of interest + * in this program. (See jdmarker.c for a more complete list.) + */ + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_APP0 0xE0 /* Application-specific marker, type N */ +#define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */ +#define M_COM 0xFE /* COMment */ + + +/* + * Find the next JPEG marker and return its marker code. + * We expect at least one FF byte, possibly more if the compressor used FFs + * to pad the file. + * There could also be non-FF garbage between markers. The treatment of such + * garbage is unspecified; we choose to skip over it but emit a warning msg. + * NB: this routine must not be used after seeing SOS marker, since it will + * not deal correctly with FF/00 sequences in the compressed image data... + */ + +static int +next_marker (void) +{ + int c; + int discarded_bytes = 0; + + /* Find 0xFF byte; count and skip any non-FFs. */ + c = read_1_byte(); + while (c != 0xFF) { + discarded_bytes++; + c = read_1_byte(); + } + /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs + * are legal as pad bytes, so don't count them in discarded_bytes. + */ + do { + c = read_1_byte(); + } while (c == 0xFF); + + if (discarded_bytes != 0) { + fprintf(stderr, "Warning: garbage data found in JPEG file\n"); + } + + return c; +} + + +/* + * Read the initial marker, which should be SOI. + * For a JFIF file, the first two bytes of the file should be literally + * 0xFF M_SOI. To be more general, we could use next_marker, but if the + * input file weren't actually JPEG at all, next_marker might read the whole + * file and then return a misleading error message... + */ + +static int +first_marker (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + c2 = NEXTBYTE(); + if (c1 != 0xFF || c2 != M_SOI) + ERREXIT("Not a JPEG file"); + return c2; +} + + +/* + * Most types of marker are followed by a variable-length parameter segment. + * This routine skips over the parameters for any marker we don't otherwise + * want to process. + * Note that we MUST skip the parameter segment explicitly in order not to + * be fooled by 0xFF bytes that might appear within the parameter segment; + * such bytes do NOT introduce new markers. + */ + +static void +skip_variable (void) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + (void) read_1_byte(); + length--; + } +} + + +/* + * Process a COM marker. + * We want to print out the marker contents as legible text; + * we must guard against non-text junk and varying newline representations. + */ + +static void +process_COM (void) +{ + unsigned int length; + int ch; + int lastch = 0; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + + while (length > 0) { + ch = read_1_byte(); + /* Emit the character in a readable form. + * Nonprintables are converted to \nnn form, + * while \ is converted to \\. + * Newlines in CR, CR/LF, or LF form will be printed as one newline. + */ + if (ch == '\r') { + printf("\n"); + } else if (ch == '\n') { + if (lastch != '\r') + printf("\n"); + } else if (ch == '\\') { + printf("\\\\"); + } else if (isprint(ch)) { + putc(ch, stdout); + } else { + printf("\\%03o", ch); + } + lastch = ch; + length--; + } + printf("\n"); +} + + +/* + * Process a SOFn marker. + * This code is only needed if you want to know the image dimensions... + */ + +static void +process_SOFn (int marker) +{ + unsigned int length; + unsigned int image_height, image_width; + int data_precision, num_components; + const char * process; + int ci; + + length = read_2_bytes(); /* usual parameter length count */ + + data_precision = read_1_byte(); + image_height = read_2_bytes(); + image_width = read_2_bytes(); + num_components = read_1_byte(); + + switch (marker) { + case M_SOF0: process = "Baseline"; break; + case M_SOF1: process = "Extended sequential"; break; + case M_SOF2: process = "Progressive"; break; + case M_SOF3: process = "Lossless"; break; + case M_SOF5: process = "Differential sequential"; break; + case M_SOF6: process = "Differential progressive"; break; + case M_SOF7: process = "Differential lossless"; break; + case M_SOF9: process = "Extended sequential, arithmetic coding"; break; + case M_SOF10: process = "Progressive, arithmetic coding"; break; + case M_SOF11: process = "Lossless, arithmetic coding"; break; + case M_SOF13: process = "Differential sequential, arithmetic coding"; break; + case M_SOF14: process = "Differential progressive, arithmetic coding"; break; + case M_SOF15: process = "Differential lossless, arithmetic coding"; break; + default: process = "Unknown"; break; + } + + printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n", + image_width, image_height, num_components, data_precision); + printf("JPEG process: %s\n", process); + + if (length != (unsigned int) (8 + num_components * 3)) + ERREXIT("Bogus SOF marker length"); + + for (ci = 0; ci < num_components; ci++) { + (void) read_1_byte(); /* Component ID code */ + (void) read_1_byte(); /* H, V sampling factors */ + (void) read_1_byte(); /* Quantization table number */ + } +} + + +/* + * Parse the marker stream until SOS or EOI is seen; + * display any COM markers. + * While the companion program wrjpgcom will always insert COM markers before + * SOFn, other implementations might not, so we scan to SOS before stopping. + * If we were only interested in the image dimensions, we would stop at SOFn. + * (Conversely, if we only cared about COM markers, there would be no need + * for special code to handle SOFn; we could treat it like other markers.) + */ + +static int +scan_JPEG_header (int verbose) +{ + int marker; + + /* Expect SOI at start of file */ + if (first_marker() != M_SOI) + ERREXIT("Expected SOI marker first"); + + /* Scan miscellaneous markers until we reach SOS. */ + for (;;) { + marker = next_marker(); + switch (marker) { + /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, + * treated as SOFn. C4 in particular is actually DHT. + */ + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + case M_SOF2: /* Progressive, Huffman */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_SOF9: /* Extended sequential, arithmetic */ + case M_SOF10: /* Progressive, arithmetic */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + if (verbose) + process_SOFn(marker); + else + skip_variable(); + break; + + case M_SOS: /* stop before hitting compressed data */ + return marker; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + return marker; + + case M_COM: + process_COM(); + break; + + case M_APP12: + /* Some digital camera makers put useful textual information into + * APP12 markers, so we print those out too when in -verbose mode. + */ + if (verbose) { + printf("APP12 contains:\n"); + process_COM(); + } else + skip_variable(); + break; + + default: /* Anything else just gets skipped */ + skip_variable(); /* we assume it has a parameter count... */ + break; + } + } /* end loop */ +} + + +/* Command line parsing code */ + +static const char * progname; /* program name for error messages */ + + +static void +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n"); + + fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname); + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -verbose Also display dimensions of JPEG image\n"); + + exit(EXIT_FAILURE); +} + + +static int +keymatch (char * arg, const char * keyword, int minchars) +/* Case-insensitive matching of (possibly abbreviated) keyword switches. */ +/* keyword is the constant keyword (must be lower case already), */ +/* minchars is length of minimum legal abbreviation. */ +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return 0; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return 0; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return 0; + return 1; /* A-OK */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int argn; + char * arg; + int verbose = 0; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "rdjpgcom"; /* in case C library doesn't provide it */ + + /* Parse switches, if any */ + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (arg[0] != '-') + break; /* not switch, must be file name */ + arg++; /* advance over '-' */ + if (keymatch(arg, "verbose", 1)) { + verbose++; + } else + usage(); + } + + /* Open the input file. */ + /* Unix style: expect zero or one file name */ + if (argn < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } + if (argn < argc) { + if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdin\n", progname); + exit(EXIT_FAILURE); + } +#else + infile = stdin; +#endif + } + + /* Scan the JPEG headers. */ + (void) scan_JPEG_header(verbose); + + /* All done. */ + exit(EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/freeimage241/Source/LibJPEG/rdppm.c b/freeimage241/Source/LibJPEG/rdppm.c new file mode 100644 index 0000000..1df35c1 --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdppm.c @@ -0,0 +1,458 @@ +/* + * rdppm.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in PPM/PGM format. + * The extended 2-byte-per-sample raw PPM/PGM formats are supported. + * The PBMPLUS library is NOT required to compile this software + * (but it is highly useful as a set of PPM image manipulation programs). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed PPM format). + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef PPM_SUPPORTED + + +/* Portions of this code are based on the PBMPLUS library, which is: +** +** Copyright (C) 1988 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char U_CHAR; +#define UCH(x) ((int) (x)) +#else +typedef char U_CHAR; +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* + * On most systems, reading individual bytes with getc() is drastically less + * efficient than buffering a row at a time with fread(). On PCs, we must + * allocate the buffer in near data space, because we are assuming small-data + * memory model, wherein fread() can't reach far memory. If you need to + * process very wide images on a PC, you might have to compile in large-memory + * model, or else replace fread() with a getc() loop --- which will be much + * slower. + */ + + +/* Private version of data source object */ + +typedef struct { + struct cjpeg_source_struct pub; /* public fields */ + + U_CHAR *iobuffer; /* non-FAR pointer to I/O buffer */ + JSAMPROW pixrow; /* FAR pointer to same */ + size_t buffer_width; /* width of I/O buffer */ + JSAMPLE *rescale; /* => maxval-remapping array, or NULL */ +} ppm_source_struct; + +typedef ppm_source_struct * ppm_source_ptr; + + +LOCAL(int) +pbm_getc (FILE * infile) +/* Read next char, skipping over any comments */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(infile); + if (ch == '#') { + do { + ch = getc(infile); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(unsigned int) +read_pbm_integer (j_compress_ptr cinfo, FILE * infile) +/* Read an unsigned decimal integer from the PPM file */ +/* Swallows one trailing character after the integer */ +/* Note that on a 16-bit-int machine, only values up to 64k can be read. */ +/* This should not be a problem in practice. */ +{ + register int ch; + register unsigned int val; + + /* Skip any leading whitespace */ + do { + ch = pbm_getc(infile); + if (ch == EOF) + ERREXIT(cinfo, JERR_INPUT_EOF); + } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); + + if (ch < '0' || ch > '9') + ERREXIT(cinfo, JERR_PPM_NONNUMERIC); + + val = ch - '0'; + while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') { + val *= 10; + val += ch - '0'; + } + return val; +} + + +/* + * Read one row of pixels. + * + * We provide several different versions depending on input file format. + * In all cases, input is scaled to the size of JSAMPLE. + * + * A really fast path is provided for reading byte/sample raw files with + * maxval = MAXJSAMPLE, which is the normal case for 8-bit data. + */ + + +METHODDEF(JDIMENSION) +get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading text-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + FILE * infile = source->pub.input_file; + register JSAMPROW ptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading text-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + FILE * infile = source->pub.input_file; + register JSAMPROW ptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + *ptr++ = rescale[read_pbm_integer(cinfo, infile)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[UCH(*bufferptr++)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + *ptr++ = rescale[UCH(*bufferptr++)]; + *ptr++ = rescale[UCH(*bufferptr++)]; + *ptr++ = rescale[UCH(*bufferptr++)]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE. + * In this case we just read right into the JSAMPLE buffer! + * Note that same code works for PPM and PGM files. + */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + return 1; +} + + +METHODDEF(JDIMENSION) +get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-word-format PGM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register int temp; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + } + return 1; +} + + +METHODDEF(JDIMENSION) +get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading raw-word-format PPM files with any maxval */ +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + register JSAMPROW ptr; + register U_CHAR * bufferptr; + register JSAMPLE *rescale = source->rescale; + JDIMENSION col; + + if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width)) + ERREXIT(cinfo, JERR_INPUT_EOF); + ptr = source->pub.buffer[0]; + bufferptr = source->iobuffer; + for (col = cinfo->image_width; col > 0; col--) { + register int temp; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + temp = UCH(*bufferptr++); + temp |= UCH(*bufferptr++) << 8; + *ptr++ = rescale[temp]; + } + return 1; +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + ppm_source_ptr source = (ppm_source_ptr) sinfo; + int c; + unsigned int w, h, maxval; + boolean need_iobuffer, use_raw_buffer, need_rescale; + + if (getc(source->pub.input_file) != 'P') + ERREXIT(cinfo, JERR_PPM_NOT); + + c = getc(source->pub.input_file); /* subformat discriminator character */ + + /* detect unsupported variants (ie, PBM) before trying to read header */ + switch (c) { + case '2': /* it's a text-format PGM file */ + case '3': /* it's a text-format PPM file */ + case '5': /* it's a raw-format PGM file */ + case '6': /* it's a raw-format PPM file */ + break; + default: + ERREXIT(cinfo, JERR_PPM_NOT); + break; + } + + /* fetch the remaining header info */ + w = read_pbm_integer(cinfo, source->pub.input_file); + h = read_pbm_integer(cinfo, source->pub.input_file); + maxval = read_pbm_integer(cinfo, source->pub.input_file); + + if (w <= 0 || h <= 0 || maxval <= 0) /* error check */ + ERREXIT(cinfo, JERR_PPM_NOT); + + cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */ + cinfo->image_width = (JDIMENSION) w; + cinfo->image_height = (JDIMENSION) h; + + /* initialize flags to most common settings */ + need_iobuffer = TRUE; /* do we need an I/O buffer? */ + use_raw_buffer = FALSE; /* do we map input buffer onto I/O buffer? */ + need_rescale = TRUE; /* do we need a rescale array? */ + + switch (c) { + case '2': /* it's a text-format PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h); + source->pub.get_pixel_rows = get_text_gray_row; + need_iobuffer = FALSE; + break; + + case '3': /* it's a text-format PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = JCS_RGB; + TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h); + source->pub.get_pixel_rows = get_text_rgb_row; + need_iobuffer = FALSE; + break; + + case '5': /* it's a raw-format PGM file */ + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_PGM, w, h); + if (maxval > 255) { + source->pub.get_pixel_rows = get_word_gray_row; + } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) { + source->pub.get_pixel_rows = get_raw_row; + use_raw_buffer = TRUE; + need_rescale = FALSE; + } else { + source->pub.get_pixel_rows = get_scaled_gray_row; + } + break; + + case '6': /* it's a raw-format PPM file */ + cinfo->input_components = 3; + cinfo->in_color_space = JCS_RGB; + TRACEMS2(cinfo, 1, JTRC_PPM, w, h); + if (maxval > 255) { + source->pub.get_pixel_rows = get_word_rgb_row; + } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) { + source->pub.get_pixel_rows = get_raw_row; + use_raw_buffer = TRUE; + need_rescale = FALSE; + } else { + source->pub.get_pixel_rows = get_scaled_rgb_row; + } + break; + } + + /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */ + if (need_iobuffer) { + source->buffer_width = (size_t) w * cinfo->input_components * + ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR))); + source->iobuffer = (U_CHAR *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + source->buffer_width); + } + + /* Create compressor input buffer. */ + if (use_raw_buffer) { + /* For unscaled raw-input case, we can just map it onto the I/O buffer. */ + /* Synthesize a JSAMPARRAY pointer structure */ + /* Cast here implies near->far pointer conversion on PCs */ + source->pixrow = (JSAMPROW) source->iobuffer; + source->pub.buffer = & source->pixrow; + source->pub.buffer_height = 1; + } else { + /* Need to translate anyway, so make a separate sample buffer. */ + source->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1); + source->pub.buffer_height = 1; + } + + /* Compute the rescaling array if required. */ + if (need_rescale) { + INT32 val, half_maxval; + + /* On 16-bit-int machines we have to be careful of maxval = 65535 */ + source->rescale = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE))); + half_maxval = maxval / 2; + for (val = 0; val <= (INT32) maxval; val++) { + /* The multiplication here must be done in 32 bits to avoid overflow */ + source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval); + } + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for PPM format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_ppm (j_compress_ptr cinfo) +{ + ppm_source_ptr source; + + /* Create module interface object */ + source = (ppm_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ppm_source_struct)); + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_ppm; + source->pub.finish_input = finish_input_ppm; + + return (cjpeg_source_ptr) source; +} + +#endif /* PPM_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/rdrle.c b/freeimage241/Source/LibJPEG/rdrle.c new file mode 100644 index 0000000..542bc37 --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdrle.c @@ -0,0 +1,387 @@ +/* + * rdrle.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Utah RLE format. + * The Utah Raster Toolkit library is required (version 3.1 or later). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed RLE format). + * + * Based on code contributed by Mike Lijewski, + * with updates from Robert Hutchinson. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef RLE_SUPPORTED + +/* rle.h is provided by the Utah Raster Toolkit. */ + +#include + +/* + * We assume that JSAMPLE has the same representation as rle_pixel, + * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * We support the following types of RLE files: + * + * GRAYSCALE - 8 bits, no colormap + * MAPPEDGRAY - 8 bits, 1 channel colomap + * PSEUDOCOLOR - 8 bits, 3 channel colormap + * TRUECOLOR - 24 bits, 3 channel colormap + * DIRECTCOLOR - 24 bits, no colormap + * + * For now, we ignore any alpha channel in the image. + */ + +typedef enum + { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind; + + +/* + * Since RLE stores scanlines bottom-to-top, we have to invert the image + * to conform to JPEG's top-to-bottom order. To do this, we read the + * incoming image into a virtual array on the first get_pixel_rows call, + * then fetch the required row from the virtual array on subsequent calls. + */ + +typedef struct _rle_source_struct * rle_source_ptr; + +typedef struct _rle_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + rle_kind visual; /* actual type of input file */ + jvirt_sarray_ptr image; /* virtual array to hold the image */ + JDIMENSION row; /* current row # in the virtual array */ + rle_hdr header; /* Input file information */ + rle_pixel** rle_row; /* holds a row returned by rle_getrow() */ + +} rle_source_struct; + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JDIMENSION width, height; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Use RLE library routine to get the header info */ + source->header = *rle_hdr_init(NULL); + source->header.rle_file = source->pub.input_file; + switch (rle_get_setup(&(source->header))) { + case RLE_SUCCESS: + /* A-OK */ + break; + case RLE_NOT_RLE: + ERREXIT(cinfo, JERR_RLE_NOT); + break; + case RLE_NO_SPACE: + ERREXIT(cinfo, JERR_RLE_MEM); + break; + case RLE_EMPTY: + ERREXIT(cinfo, JERR_RLE_EMPTY); + break; + case RLE_EOF: + ERREXIT(cinfo, JERR_RLE_EOF); + break; + default: + ERREXIT(cinfo, JERR_RLE_BADERROR); + break; + } + + /* Figure out what we have, set private vars and return values accordingly */ + + width = source->header.xmax - source->header.xmin + 1; + height = source->header.ymax - source->header.ymin + 1; + source->header.xmin = 0; /* realign horizontally */ + source->header.xmax = width-1; + + cinfo->image_width = width; + cinfo->image_height = height; + cinfo->data_precision = 8; /* we can only handle 8 bit data */ + + if (source->header.ncolors == 1 && source->header.ncmap == 0) { + source->visual = GRAYSCALE; + TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height); + } else if (source->header.ncolors == 1 && source->header.ncmap == 1) { + source->visual = MAPPEDGRAY; + TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 1 && source->header.ncmap == 3) { + source->visual = PSEUDOCOLOR; + TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 3 && source->header.ncmap == 3) { + source->visual = TRUECOLOR; + TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height, + 1 << source->header.cmaplen); + } else if (source->header.ncolors == 3 && source->header.ncmap == 0) { + source->visual = DIRECTCOLOR; + TRACEMS2(cinfo, 1, JTRC_RLE, width, height); + } else + ERREXIT(cinfo, JERR_RLE_UNSUPPORTED); + + if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) { + cinfo->in_color_space = JCS_GRAYSCALE; + cinfo->input_components = 1; + } else { + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = 3; + } + + /* + * A place to hold each scanline while it's converted. + * (GRAYSCALE scanlines don't need converting) + */ + if (source->visual != GRAYSCALE) { + source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) width, (JDIMENSION) cinfo->input_components); + } + + /* request a virtual array to hold the image */ + source->image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) (width * source->header.ncolors), + (JDIMENSION) height, (JDIMENSION) 1); + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + /* count file input as separate pass */ + progress->total_extra_passes++; + } +#endif + + source->pub.buffer_height = 1; +} + + +/* + * Read one row of pixels. + * Called only after load_image has read the image into the virtual array. + * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images. + */ + +METHODDEF(JDIMENSION) +get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + + source->row--; + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE); + + return 1; +} + +/* + * Read one row of pixels. + * Called only after load_image has read the image into the virtual array. + * Used for PSEUDOCOLOR images. + */ + +METHODDEF(JDIMENSION) +get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JSAMPROW src_row, dest_row; + JDIMENSION col; + rle_map *colormap; + int val; + + colormap = source->header.cmap; + dest_row = source->pub.buffer[0]; + source->row--; + src_row = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE); + + for (col = cinfo->image_width; col > 0; col--) { + val = GETJSAMPLE(*src_row++); + *dest_row++ = (JSAMPLE) (colormap[val ] >> 8); + *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8); + *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8); + } + + return 1; +} + + +/* + * Load the image into a virtual array. We have to do this because RLE + * files start at the lower left while the JPEG standard has them starting + * in the upper left. This is called the first time we want to get a row + * of input. What we do is load the RLE data into the array and then call + * the appropriate routine to read one row from the array. Before returning, + * we set source->pub.get_pixel_rows so that subsequent calls go straight to + * the appropriate row-reading routine. + */ + +METHODDEF(JDIMENSION) +load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + rle_source_ptr source = (rle_source_ptr) sinfo; + JDIMENSION row, col; + JSAMPROW scanline, red_ptr, green_ptr, blue_ptr; + rle_pixel **rle_row; + rle_map *colormap; + char channel; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + colormap = source->header.cmap; + rle_row = source->rle_row; + + /* Read the RLE data into our virtual array. + * We assume here that (a) rle_pixel is represented the same as JSAMPLE, + * and (b) we are not on a machine where FAR pointers differ from regular. + */ + RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */ + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_limit = cinfo->image_height; + progress->pub.pass_counter = 0; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + + switch (source->visual) { + + case GRAYSCALE: + case PSEUDOCOLOR: + for (row = 0; row < cinfo->image_height; row++) { + rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + rle_getrow(&source->header, rle_row); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + break; + + case MAPPEDGRAY: + case TRUECOLOR: + for (row = 0; row < cinfo->image_height; row++) { + scanline = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + rle_row = source->rle_row; + rle_getrow(&source->header, rle_row); + + for (col = 0; col < cinfo->image_width; col++) { + for (channel = 0; channel < source->header.ncolors; channel++) { + *scanline++ = (JSAMPLE) + (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8); + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + break; + + case DIRECTCOLOR: + for (row = 0; row < cinfo->image_height; row++) { + scanline = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE); + rle_getrow(&source->header, rle_row); + + red_ptr = rle_row[0]; + green_ptr = rle_row[1]; + blue_ptr = rle_row[2]; + + for (col = cinfo->image_width; col > 0; col--) { + *scanline++ = *red_ptr++; + *scanline++ = *green_ptr++; + *scanline++ = *blue_ptr++; + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) + progress->completed_extra_passes++; +#endif + + /* Set up to call proper row-extraction routine in future */ + if (source->visual == PSEUDOCOLOR) { + source->pub.buffer = source->rle_row; + source->pub.get_pixel_rows = get_pseudocolor_row; + } else { + source->pub.get_pixel_rows = get_rle_row; + } + source->row = cinfo->image_height; + + /* And fetch the topmost (bottommost) row */ + return (*source->pub.get_pixel_rows) (cinfo, sinfo); +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for RLE format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_rle (j_compress_ptr cinfo) +{ + rle_source_ptr source; + + /* Create module interface object */ + source = (rle_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(rle_source_struct)); + /* Fill in method ptrs */ + source->pub.start_input = start_input_rle; + source->pub.finish_input = finish_input_rle; + source->pub.get_pixel_rows = load_image; + + return (cjpeg_source_ptr) source; +} + +#endif /* RLE_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/rdswitch.c b/freeimage241/Source/LibJPEG/rdswitch.c new file mode 100644 index 0000000..4f4bb4f --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdswitch.c @@ -0,0 +1,332 @@ +/* + * rdswitch.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to process some of cjpeg's more complicated + * command-line switches. Switches processed here are: + * -qtables file Read quantization tables from text file + * -scans file Read scan script from text file + * -qslots N[,N,...] Set component quantization table selectors + * -sample HxV[,HxV,...] Set component sampling factors + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ +#include /* to declare isdigit(), isspace() */ + + +LOCAL(int) +text_getc (FILE * file) +/* Read next char, skipping over any comments (# to end of line) */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(file); + if (ch == '#') { + do { + ch = getc(file); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +LOCAL(boolean) +read_text_integer (FILE * file, long * result, int * termchar) +/* Read an unsigned decimal integer from a file, store it in result */ +/* Reads one trailing character after the integer; returns it in termchar */ +{ + register int ch; + register long val; + + /* Skip any leading whitespace, detect EOF */ + do { + ch = text_getc(file); + if (ch == EOF) { + *termchar = ch; + return FALSE; + } + } while (isspace(ch)); + + if (! isdigit(ch)) { + *termchar = ch; + return FALSE; + } + + val = ch - '0'; + while ((ch = text_getc(file)) != EOF) { + if (! isdigit(ch)) + break; + val *= 10; + val += ch - '0'; + } + *result = val; + *termchar = ch; + return TRUE; +} + + +GLOBAL(boolean) +read_quant_tables (j_compress_ptr cinfo, char * filename, + int scale_factor, boolean force_baseline) +/* Read a set of quantization tables from the specified file. + * The file is plain ASCII text: decimal numbers with whitespace between. + * Comments preceded by '#' may be included in the file. + * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values. + * The tables are implicitly numbered 0,1,etc. + * NOTE: does not affect the qslots mapping, which will default to selecting + * table 0 for luminance (or primary) components, 1 for chrominance components. + * You must use -qslots if you want a different component->table mapping. + */ +{ + FILE * fp; + int tblno, i, termchar; + long val; + unsigned int table[DCTSIZE2]; + + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Can't open table file %s\n", filename); + return FALSE; + } + tblno = 0; + + while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */ + if (tblno >= NUM_QUANT_TBLS) { + fprintf(stderr, "Too many tables in file %s\n", filename); + fclose(fp); + return FALSE; + } + table[0] = (unsigned int) val; + for (i = 1; i < DCTSIZE2; i++) { + if (! read_text_integer(fp, &val, &termchar)) { + fprintf(stderr, "Invalid table data in file %s\n", filename); + fclose(fp); + return FALSE; + } + table[i] = (unsigned int) val; + } + jpeg_add_quant_table(cinfo, tblno, table, scale_factor, force_baseline); + tblno++; + } + + if (termchar != EOF) { + fprintf(stderr, "Non-numeric data in file %s\n", filename); + fclose(fp); + return FALSE; + } + + fclose(fp); + return TRUE; +} + + +#ifdef C_MULTISCAN_FILES_SUPPORTED + +LOCAL(boolean) +read_scan_integer (FILE * file, long * result, int * termchar) +/* Variant of read_text_integer that always looks for a non-space termchar; + * this simplifies parsing of punctuation in scan scripts. + */ +{ + register int ch; + + if (! read_text_integer(file, result, termchar)) + return FALSE; + ch = *termchar; + while (ch != EOF && isspace(ch)) + ch = text_getc(file); + if (isdigit(ch)) { /* oops, put it back */ + if (ungetc(ch, file) == EOF) + return FALSE; + ch = ' '; + } else { + /* Any separators other than ';' and ':' are ignored; + * this allows user to insert commas, etc, if desired. + */ + if (ch != EOF && ch != ';' && ch != ':') + ch = ' '; + } + *termchar = ch; + return TRUE; +} + + +GLOBAL(boolean) +read_scan_script (j_compress_ptr cinfo, char * filename) +/* Read a scan script from the specified text file. + * Each entry in the file defines one scan to be emitted. + * Entries are separated by semicolons ';'. + * An entry contains one to four component indexes, + * optionally followed by a colon ':' and four progressive-JPEG parameters. + * The component indexes denote which component(s) are to be transmitted + * in the current scan. The first component has index 0. + * Sequential JPEG is used if the progressive-JPEG parameters are omitted. + * The file is free format text: any whitespace may appear between numbers + * and the ':' and ';' punctuation marks. Also, other punctuation (such + * as commas or dashes) can be placed between numbers if desired. + * Comments preceded by '#' may be included in the file. + * Note: we do very little validity checking here; + * jcmaster.c will validate the script parameters. + */ +{ + FILE * fp; + int scanno, ncomps, termchar; + long val; + jpeg_scan_info * scanptr; +#define MAX_SCANS 100 /* quite arbitrary limit */ + jpeg_scan_info scans[MAX_SCANS]; + + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Can't open scan definition file %s\n", filename); + return FALSE; + } + scanptr = scans; + scanno = 0; + + while (read_scan_integer(fp, &val, &termchar)) { + if (scanno >= MAX_SCANS) { + fprintf(stderr, "Too many scans defined in file %s\n", filename); + fclose(fp); + return FALSE; + } + scanptr->component_index[0] = (int) val; + ncomps = 1; + while (termchar == ' ') { + if (ncomps >= MAX_COMPS_IN_SCAN) { + fprintf(stderr, "Too many components in one scan in file %s\n", + filename); + fclose(fp); + return FALSE; + } + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scanptr->component_index[ncomps] = (int) val; + ncomps++; + } + scanptr->comps_in_scan = ncomps; + if (termchar == ':') { + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Ss = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Se = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scanptr->Ah = (int) val; + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scanptr->Al = (int) val; + } else { + /* set non-progressive parameters */ + scanptr->Ss = 0; + scanptr->Se = DCTSIZE2-1; + scanptr->Ah = 0; + scanptr->Al = 0; + } + if (termchar != ';' && termchar != EOF) { +bogus: + fprintf(stderr, "Invalid scan entry format in file %s\n", filename); + fclose(fp); + return FALSE; + } + scanptr++, scanno++; + } + + if (termchar != EOF) { + fprintf(stderr, "Non-numeric data in file %s\n", filename); + fclose(fp); + return FALSE; + } + + if (scanno > 0) { + /* Stash completed scan list in cinfo structure. + * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data, + * but if you want to compress multiple images you'd want JPOOL_PERMANENT. + */ + scanptr = (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + scanno * SIZEOF(jpeg_scan_info)); + MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info)); + cinfo->scan_info = scanptr; + cinfo->num_scans = scanno; + } + + fclose(fp); + return TRUE; +} + +#endif /* C_MULTISCAN_FILES_SUPPORTED */ + + +GLOBAL(boolean) +set_quant_slots (j_compress_ptr cinfo, char *arg) +/* Process a quantization-table-selectors parameter string, of the form + * N[,N,...] + * If there are more components than parameters, the last value is replicated. + */ +{ + int val = 0; /* default table # */ + int ci; + char ch; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c", &val, &ch) < 1) + return FALSE; + if (ch != ',') /* syntax check */ + return FALSE; + if (val < 0 || val >= NUM_QUANT_TBLS) { + fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n", + NUM_QUANT_TBLS-1); + return FALSE; + } + cinfo->comp_info[ci].quant_tbl_no = val; + while (*arg && *arg++ != ',') /* advance to next segment of arg string */ + ; + } else { + /* reached end of parameter, set remaining components to last table */ + cinfo->comp_info[ci].quant_tbl_no = val; + } + } + return TRUE; +} + + +GLOBAL(boolean) +set_sample_factors (j_compress_ptr cinfo, char *arg) +/* Process a sample-factors parameter string, of the form + * HxV[,HxV,...] + * If there are more components than parameters, "1x1" is assumed for the rest. + */ +{ + int ci, val1, val2; + char ch1, ch2; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch2 = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3) + return FALSE; + if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */ + return FALSE; + if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) { + fprintf(stderr, "JPEG sampling factors must be 1..4\n"); + return FALSE; + } + cinfo->comp_info[ci].h_samp_factor = val1; + cinfo->comp_info[ci].v_samp_factor = val2; + while (*arg && *arg++ != ',') /* advance to next segment of arg string */ + ; + } else { + /* reached end of parameter, set remaining components to 1x1 sampling */ + cinfo->comp_info[ci].h_samp_factor = 1; + cinfo->comp_info[ci].v_samp_factor = 1; + } + } + return TRUE; +} diff --git a/freeimage241/Source/LibJPEG/rdtarga.c b/freeimage241/Source/LibJPEG/rdtarga.c new file mode 100644 index 0000000..4c2cd26 --- /dev/null +++ b/freeimage241/Source/LibJPEG/rdtarga.c @@ -0,0 +1,500 @@ +/* + * rdtarga.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to read input images in Targa format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume input from + * an ordinary stdio stream. They further assume that reading begins + * at the start of the file; start_input may need work if the + * user interface has already read some data (e.g., to determine that + * the file is indeed Targa format). + * + * Based on code contributed by Lee Daniel Crocker. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef TARGA_SUPPORTED + + +/* Macros to deal with unsigned chars as efficiently as compiler allows */ + +#ifdef HAVE_UNSIGNED_CHAR +typedef unsigned char U_CHAR; +#define UCH(x) ((int) (x)) +#else /* !HAVE_UNSIGNED_CHAR */ +#ifdef CHAR_IS_UNSIGNED +typedef char U_CHAR; +#define UCH(x) ((int) (x)) +#else +typedef char U_CHAR; +#define UCH(x) ((int) (x) & 0xFF) +#endif +#endif /* HAVE_UNSIGNED_CHAR */ + + +#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len))) + + +/* Private version of data source object */ + +typedef struct _tga_source_struct * tga_source_ptr; + +typedef struct _tga_source_struct { + struct cjpeg_source_struct pub; /* public fields */ + + j_compress_ptr cinfo; /* back link saves passing separate parm */ + + JSAMPARRAY colormap; /* Targa colormap (converted to my format) */ + + jvirt_sarray_ptr whole_image; /* Needed if funny input row order */ + JDIMENSION current_row; /* Current logical row number to read */ + + /* Pointer to routine to extract next Targa pixel from input file */ + JMETHOD(void, read_pixel, (tga_source_ptr sinfo)); + + /* Result of read_pixel is delivered here: */ + U_CHAR tga_pixel[4]; + + int pixel_size; /* Bytes per Targa pixel (1 to 4) */ + + /* State info for reading RLE-coded pixels; both counts must be init to 0 */ + int block_count; /* # of pixels remaining in RLE block */ + int dup_pixel_count; /* # of times to duplicate previous pixel */ + + /* This saves the correct pixel-row-expansion method for preload_image */ + JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo, + cjpeg_source_ptr sinfo)); +} tga_source_struct; + + +/* For expanding 5-bit pixel values to 8-bit with best rounding */ + +static const UINT8 c5to8bits[32] = { + 0, 8, 16, 25, 33, 41, 49, 58, + 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, + 197, 206, 214, 222, 230, 239, 247, 255 +}; + + + +LOCAL(int) +read_byte (tga_source_ptr sinfo) +/* Read next byte from Targa file */ +{ + register FILE *infile = sinfo->pub.input_file; + register int c; + + if ((c = getc(infile)) == EOF) + ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); + return c; +} + + +LOCAL(void) +read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize) +/* Read the colormap from a Targa file */ +{ + int i; + + /* Presently only handles 24-bit BGR format */ + if (mapentrysize != 24) + ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP); + + for (i = 0; i < cmaplen; i++) { + sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo); + sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo); + } +} + + +/* + * read_pixel methods: get a single pixel from Targa file into tga_pixel[] + */ + +METHODDEF(void) +read_non_rle_pixel (tga_source_ptr sinfo) +/* Read one Targa pixel from the input file; no RLE expansion */ +{ + register FILE *infile = sinfo->pub.input_file; + register int i; + + for (i = 0; i < sinfo->pixel_size; i++) { + sinfo->tga_pixel[i] = (U_CHAR) getc(infile); + } +} + + +METHODDEF(void) +read_rle_pixel (tga_source_ptr sinfo) +/* Read one Targa pixel from the input file, expanding RLE data as needed */ +{ + register FILE *infile = sinfo->pub.input_file; + register int i; + + /* Duplicate previously read pixel? */ + if (sinfo->dup_pixel_count > 0) { + sinfo->dup_pixel_count--; + return; + } + + /* Time to read RLE block header? */ + if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */ + i = read_byte(sinfo); + if (i & 0x80) { /* Start of duplicate-pixel block? */ + sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */ + sinfo->block_count = 0; /* then read new block header */ + } else { + sinfo->block_count = i & 0x7F; /* number of pixels after this one */ + } + } + + /* Read next pixel */ + for (i = 0; i < sinfo->pixel_size; i++) { + sinfo->tga_pixel[i] = (U_CHAR) getc(infile); + } +} + + +/* + * Read one row of pixels. + * + * We provide several different versions depending on input file format. + */ + + +METHODDEF(JDIMENSION) +get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit grayscale pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]); + } + return 1; +} + +METHODDEF(JDIMENSION) +get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 8-bit colormap indexes */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register int t; + register JSAMPROW ptr; + register JDIMENSION col; + register JSAMPARRAY colormap = source->colormap; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + t = UCH(source->tga_pixel[0]); + *ptr++ = colormap[0][t]; + *ptr++ = colormap[1][t]; + *ptr++ = colormap[2][t]; + } + return 1; +} + +METHODDEF(JDIMENSION) +get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 16-bit pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register int t; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + t = UCH(source->tga_pixel[0]); + t += UCH(source->tga_pixel[1]) << 8; + /* We expand 5 bit data to 8 bit sample width. + * The format of the 16-bit (LSB first) input word is + * xRRRRRGGGGGBBBBB + */ + ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F]; + t >>= 5; + ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F]; + t >>= 5; + ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F]; + ptr += 3; + } + return 1; +} + +METHODDEF(JDIMENSION) +get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +/* This version is for reading 24-bit pixels */ +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = source->pub.buffer[0]; + for (col = cinfo->image_width; col > 0; col--) { + (*source->read_pixel) (source); /* Load next pixel into tga_pixel */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */ + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]); + *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]); + } + return 1; +} + +/* + * Targa also defines a 32-bit pixel format with order B,G,R,A. + * We presently ignore the attribute byte, so the code for reading + * these pixels is identical to the 24-bit routine above. + * This works because the actual pixel length is only known to read_pixel. + */ + +#define get_32bit_row get_24bit_row + + +/* + * This method is for re-reading the input data in standard top-down + * row order. The entire image has already been read into whole_image + * with proper conversion of pixel format, but it's in a funny row order. + */ + +METHODDEF(JDIMENSION) +get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + JDIMENSION source_row; + + /* Compute row of source that maps to current_row of normal order */ + /* For now, assume image is bottom-up and not interlaced. */ + /* NEEDS WORK to support interlaced images! */ + source_row = cinfo->image_height - source->current_row - 1; + + /* Fetch that row from virtual array */ + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, + source_row, (JDIMENSION) 1, FALSE); + + source->current_row++; + return 1; +} + + +/* + * This method loads the image into whole_image during the first call on + * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call + * get_memory_row on subsequent calls. + */ + +METHODDEF(JDIMENSION) +preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + JDIMENSION row; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Read the data into a virtual array in input-file row order. */ + for (row = 0; row < cinfo->image_height; row++) { + if (progress != NULL) { + progress->pub.pass_counter = (long) row; + progress->pub.pass_limit = (long) cinfo->image_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + source->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE); + (*source->get_pixel_rows) (cinfo, sinfo); + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Set up to read from the virtual array in unscrambled order */ + source->pub.get_pixel_rows = get_memory_row; + source->current_row = 0; + /* And read the first row */ + return get_memory_row(cinfo, sinfo); +} + + +/* + * Read the file header; return image size and component count. + */ + +METHODDEF(void) +start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + tga_source_ptr source = (tga_source_ptr) sinfo; + U_CHAR targaheader[18]; + int idlen, cmaptype, subtype, flags, interlace_type, components; + unsigned int width, height, maplen; + boolean is_bottom_up; + +#define GET_2B(offset) ((unsigned int) UCH(targaheader[offset]) + \ + (((unsigned int) UCH(targaheader[offset+1])) << 8)) + + if (! ReadOK(source->pub.input_file, targaheader, 18)) + ERREXIT(cinfo, JERR_INPUT_EOF); + + /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */ + if (targaheader[16] == 15) + targaheader[16] = 16; + + idlen = UCH(targaheader[0]); + cmaptype = UCH(targaheader[1]); + subtype = UCH(targaheader[2]); + maplen = GET_2B(5); + width = GET_2B(12); + height = GET_2B(14); + source->pixel_size = UCH(targaheader[16]) >> 3; + flags = UCH(targaheader[17]); /* Image Descriptor byte */ + + is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */ + interlace_type = flags >> 6; /* bits 6/7 are interlace code */ + + if (cmaptype > 1 || /* cmaptype must be 0 or 1 */ + source->pixel_size < 1 || source->pixel_size > 4 || + (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */ + interlace_type != 0) /* currently don't allow interlaced image */ + ERREXIT(cinfo, JERR_TGA_BADPARMS); + + if (subtype > 8) { + /* It's an RLE-coded file */ + source->read_pixel = read_rle_pixel; + source->block_count = source->dup_pixel_count = 0; + subtype -= 8; + } else { + /* Non-RLE file */ + source->read_pixel = read_non_rle_pixel; + } + + /* Now should have subtype 1, 2, or 3 */ + components = 3; /* until proven different */ + cinfo->in_color_space = JCS_RGB; + + switch (subtype) { + case 1: /* Colormapped image */ + if (source->pixel_size == 1 && cmaptype == 1) + source->get_pixel_rows = get_8bit_row; + else + ERREXIT(cinfo, JERR_TGA_BADPARMS); + TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height); + break; + case 2: /* RGB image */ + switch (source->pixel_size) { + case 2: + source->get_pixel_rows = get_16bit_row; + break; + case 3: + source->get_pixel_rows = get_24bit_row; + break; + case 4: + source->get_pixel_rows = get_32bit_row; + break; + default: + ERREXIT(cinfo, JERR_TGA_BADPARMS); + break; + } + TRACEMS2(cinfo, 1, JTRC_TGA, width, height); + break; + case 3: /* Grayscale image */ + components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + if (source->pixel_size == 1) + source->get_pixel_rows = get_8bit_gray_row; + else + ERREXIT(cinfo, JERR_TGA_BADPARMS); + TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height); + break; + default: + ERREXIT(cinfo, JERR_TGA_BADPARMS); + break; + } + + if (is_bottom_up) { + /* Create a virtual array to buffer the upside-down image. */ + source->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1); + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + /* source->pub.buffer will point to the virtual array. */ + source->pub.buffer_height = 1; /* in case anyone looks at it */ + source->pub.get_pixel_rows = preload_image; + } else { + /* Don't need a virtual array, but do need a one-row input buffer. */ + source->whole_image = NULL; + source->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + (JDIMENSION) width * components, (JDIMENSION) 1); + source->pub.buffer_height = 1; + source->pub.get_pixel_rows = source->get_pixel_rows; + } + + while (idlen--) /* Throw away ID field */ + (void) read_byte(source); + + if (maplen > 0) { + if (maplen > 256 || GET_2B(3) != 0) + ERREXIT(cinfo, JERR_TGA_BADCMAP); + /* Allocate space to store the colormap */ + source->colormap = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3); + /* and read it from the file */ + read_colormap(source, (int) maplen, UCH(targaheader[7])); + } else { + if (cmaptype) /* but you promised a cmap! */ + ERREXIT(cinfo, JERR_TGA_BADPARMS); + source->colormap = NULL; + } + + cinfo->input_components = components; + cinfo->data_precision = 8; + cinfo->image_width = width; + cinfo->image_height = height; +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) +{ + /* no work */ +} + + +/* + * The module selection routine for Targa format input. + */ + +GLOBAL(cjpeg_source_ptr) +jinit_read_targa (j_compress_ptr cinfo) +{ + tga_source_ptr source; + + /* Create module interface object */ + source = (tga_source_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(tga_source_struct)); + source->cinfo = cinfo; /* make back link for subroutines */ + /* Fill in method ptrs, except get_pixel_rows which start_input sets */ + source->pub.start_input = start_input_tga; + source->pub.finish_input = finish_input_tga; + + return (cjpeg_source_ptr) source; +} + +#endif /* TARGA_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/tca.map b/freeimage241/Source/LibJPEG/tca.map new file mode 100644 index 0000000..c891ee2 Binary files /dev/null and b/freeimage241/Source/LibJPEG/tca.map differ diff --git a/freeimage241/Source/LibJPEG/transupp.c b/freeimage241/Source/LibJPEG/transupp.c new file mode 100644 index 0000000..e5ec564 --- /dev/null +++ b/freeimage241/Source/LibJPEG/transupp.c @@ -0,0 +1,928 @@ +/* + * transupp.c + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains image transformation routines and other utility code + * used by the jpegtran sample application. These are NOT part of the core + * JPEG library. But we keep these routines separate from jpegtran.c to + * ease the task of maintaining jpegtran-like programs that have other user + * interfaces. + */ + +/* Although this file really shouldn't have access to the library internals, + * it's helpful to let it call jround_up() and jcopy_block_row(). + */ +#define JPEG_INTERNALS + +#include "jinclude.h" +#include "jpeglib.h" +#include "transupp.h" /* My own external interface */ + + +#if TRANSFORMS_SUPPORTED + +/* + * Lossless image transformation routines. These routines work on DCT + * coefficient arrays and thus do not require any lossy decompression + * or recompression of the image. + * Thanks to Guido Vollbeding for the initial design and code of this feature. + * + * Horizontal flipping is done in-place, using a single top-to-bottom + * pass through the virtual source array. It will thus be much the + * fastest option for images larger than main memory. + * + * The other routines require a set of destination virtual arrays, so they + * need twice as much memory as jpegtran normally does. The destination + * arrays are always written in normal scan order (top to bottom) because + * the virtual array manager expects this. The source arrays will be scanned + * in the corresponding order, which means multiple passes through the source + * arrays for most of the transforms. That could result in much thrashing + * if the image is larger than main memory. + * + * Some notes about the operating environment of the individual transform + * routines: + * 1. Both the source and destination virtual arrays are allocated from the + * source JPEG object, and therefore should be manipulated by calling the + * source's memory manager. + * 2. The destination's component count should be used. It may be smaller + * than the source's when forcing to grayscale. + * 3. Likewise the destination's sampling factors should be used. When + * forcing to grayscale the destination's sampling factors will be all 1, + * and we may as well take that as the effective iMCU size. + * 4. When "trim" is in effect, the destination's dimensions will be the + * trimmed values but the source's will be untrimmed. + * 5. All the routines assume that the source and destination buffers are + * padded out to a full iMCU boundary. This is true, although for the + * source buffer it is an undocumented property of jdcoefct.c. + * Notes 2,3,4 boil down to this: generally we should use the destination's + * dimensions and ignore the source's. + */ + + +LOCAL(void) +do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays) +/* Horizontal flip; done in-place, so no separate dest array is required */ +{ + JDIMENSION MCU_cols, comp_width, blk_x, blk_y; + int ci, k, offset_y; + JBLOCKARRAY buffer; + JCOEFPTR ptr1, ptr2; + JCOEF temp1, temp2; + jpeg_component_info *compptr; + + /* Horizontal mirroring of DCT blocks is accomplished by swapping + * pairs of blocks in-place. Within a DCT block, we perform horizontal + * mirroring by changing the signs of odd-numbered columns. + * Partial iMCUs at the right edge are left untouched. + */ + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + for (blk_y = 0; blk_y < compptr->height_in_blocks; + blk_y += compptr->v_samp_factor) { + buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { + ptr1 = buffer[offset_y][blk_x]; + ptr2 = buffer[offset_y][comp_width - blk_x - 1]; + /* this unrolled loop doesn't need to know which row it's on... */ + for (k = 0; k < DCTSIZE2; k += 2) { + temp1 = *ptr1; /* swap even column */ + temp2 = *ptr2; + *ptr1++ = temp2; + *ptr2++ = temp1; + temp1 = *ptr1; /* swap odd column with sign change */ + temp2 = *ptr2; + *ptr1++ = -temp2; + *ptr2++ = -temp1; + } + } + } + } + } +} + + +LOCAL(void) +do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Vertical flip */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* We output into a separate array because we can't touch different + * rows of the source virtual array simultaneously. Otherwise, this + * is a pretty straightforward analog of horizontal flip. + * Within a DCT block, vertical mirroring is done by changing the signs + * of odd-numbered rows. + * Partial iMCUs at the bottom edge are copied verbatim. + */ + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge blocks will be copied verbatim. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + /* copy even row */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + /* copy odd row with sign change */ + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Just copy row verbatim. */ + jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y], + compptr->width_in_blocks); + } + } + } + } +} + + +LOCAL(void) +do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transpose source into destination */ +{ + JDIMENSION dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Transposing pixels within a block just requires transposing the + * DCT coefficients. + * Partial iMCUs at the edges require no special treatment; we simply + * process all the available DCT blocks for every component. + */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } +} + + +LOCAL(void) +do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 90 degree rotation is equivalent to + * 1. Transposing the image; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) right edge properly. They just get transposed and + * not mirrored. + */ + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + if (dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* Edge blocks are transposed but not mirrored. */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 270 degree rotation is equivalent to + * 1. Horizontal mirroring; + * 2. Transposing the image. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + /* Because of the horizontal mirror step, we can't process partial iMCUs + * at the (output) bottom edge properly. They just get transposed and + * not mirrored. + */ + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + if (dst_blk_y < comp_height) { + /* Block is within the mirrorable area. */ + src_ptr = src_buffer[offset_x] + [comp_height - dst_blk_y - offset_y - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Edge blocks are transposed but not mirrored. */ + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } +} + + +LOCAL(void) +do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* 180 degree rotation is equivalent to + * 1. Vertical mirroring; + * 2. Horizontal mirroring. + * These two steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JBLOCKROW src_row_ptr, dst_row_ptr; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + if (dst_blk_y < comp_height) { + /* Row is within the vertically mirrorable area. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], + comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } else { + /* Bottom-edge rows are only mirrored horizontally. */ + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, FALSE); + } + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + if (dst_blk_y < comp_height) { + /* Row is within the mirrorable area. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; + /* Process the blocks that can be mirrored both ways. */ + for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE; i += 2) { + /* For even row, negate every odd column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + /* For odd row, negate every even column. */ + for (j = 0; j < DCTSIZE; j += 2) { + *dst_ptr++ = - *src_ptr++; + *dst_ptr++ = *src_ptr++; + } + } + } + /* Any remaining right-edge blocks are only mirrored vertically. */ + for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE; i += 2) { + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = *src_ptr++; + for (j = 0; j < DCTSIZE; j++) + *dst_ptr++ = - *src_ptr++; + } + } + } else { + /* Remaining rows are just mirrored horizontally. */ + dst_row_ptr = dst_buffer[offset_y]; + src_row_ptr = src_buffer[offset_y]; + /* Process the blocks that can be mirrored. */ + for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[comp_width - dst_blk_x - 1]; + for (i = 0; i < DCTSIZE2; i += 2) { + *dst_ptr++ = *src_ptr++; + *dst_ptr++ = - *src_ptr++; + } + } + /* Any remaining right-edge blocks are only copied. */ + for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { + dst_ptr = dst_row_ptr[dst_blk_x]; + src_ptr = src_row_ptr[dst_blk_x]; + for (i = 0; i < DCTSIZE2; i++) + *dst_ptr++ = *src_ptr++; + } + } + } + } + } +} + + +LOCAL(void) +do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jvirt_barray_ptr *dst_coef_arrays) +/* Transverse transpose is equivalent to + * 1. 180 degree rotation; + * 2. Transposition; + * or + * 1. Horizontal mirroring; + * 2. Transposition; + * 3. Horizontal mirroring. + * These steps are merged into a single processing routine. + */ +{ + JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; + int ci, i, j, offset_x, offset_y; + JBLOCKARRAY src_buffer, dst_buffer; + JCOEFPTR src_ptr, dst_ptr; + jpeg_component_info *compptr; + + MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); + MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); + + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + comp_width = MCU_cols * compptr->h_samp_factor; + comp_height = MCU_rows * compptr->v_samp_factor; + for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; + dst_blk_y += compptr->v_samp_factor) { + dst_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, + (JDIMENSION) compptr->v_samp_factor, TRUE); + for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { + for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; + dst_blk_x += compptr->h_samp_factor) { + src_buffer = (*srcinfo->mem->access_virt_barray) + ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x, + (JDIMENSION) compptr->h_samp_factor, FALSE); + for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { + if (dst_blk_y < comp_height) { + src_ptr = src_buffer[offset_x] + [comp_height - dst_blk_y - offset_y - 1]; + if (dst_blk_x < comp_width) { + /* Block is within the mirrorable area. */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + i++; + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } else { + /* Right-edge blocks are mirrored in y only */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) { + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + j++; + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } + } + } else { + src_ptr = src_buffer[offset_x][dst_blk_y + offset_y]; + if (dst_blk_x < comp_width) { + /* Bottom-edge blocks are mirrored in x only */ + dst_ptr = dst_buffer[offset_y] + [comp_width - dst_blk_x - offset_x - 1]; + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + i++; + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; + } + } else { + /* At lower right corner, just transpose, no mirroring */ + dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; + for (i = 0; i < DCTSIZE; i++) + for (j = 0; j < DCTSIZE; j++) + dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; + } + } + } + } + } + } + } +} + + +/* Request any required workspace. + * + * We allocate the workspace virtual arrays from the source decompression + * object, so that all the arrays (both the original data and the workspace) + * will be taken into account while making memory management decisions. + * Hence, this routine must be called after jpeg_read_header (which reads + * the image dimensions) and before jpeg_read_coefficients (which realizes + * the source's virtual arrays). + */ + +GLOBAL(void) +jtransform_request_workspace (j_decompress_ptr srcinfo, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *coef_arrays = NULL; + jpeg_component_info *compptr; + int ci; + + if (info->force_grayscale && + srcinfo->jpeg_color_space == JCS_YCbCr && + srcinfo->num_components == 3) { + /* We'll only process the first component */ + info->num_components = 1; + } else { + /* Process all the components */ + info->num_components = srcinfo->num_components; + } + + switch (info->transform) { + case JXFORM_NONE: + case JXFORM_FLIP_H: + /* Don't need a workspace array */ + break; + case JXFORM_FLIP_V: + case JXFORM_ROT_180: + /* Need workspace arrays having same dimensions as source image. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) compptr->v_samp_factor); + } + break; + case JXFORM_TRANSPOSE: + case JXFORM_TRANSVERSE: + case JXFORM_ROT_90: + case JXFORM_ROT_270: + /* Need workspace arrays having transposed dimensions. + * Note that we allocate arrays padded out to the next iMCU boundary, + * so that transform routines need not worry about missing edge blocks. + */ + coef_arrays = (jvirt_barray_ptr *) + (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, + SIZEOF(jvirt_barray_ptr) * info->num_components); + for (ci = 0; ci < info->num_components; ci++) { + compptr = srcinfo->comp_info + ci; + coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) + ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + (long) compptr->v_samp_factor), + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + (long) compptr->h_samp_factor), + (JDIMENSION) compptr->h_samp_factor); + } + break; + } + info->workspace_coef_arrays = coef_arrays; +} + + +/* Transpose destination image parameters */ + +LOCAL(void) +transpose_critical_parameters (j_compress_ptr dstinfo) +{ + int tblno, i, j, ci, itemp; + jpeg_component_info *compptr; + JQUANT_TBL *qtblptr; + JDIMENSION dtemp; + UINT16 qtemp; + + /* Transpose basic image dimensions */ + dtemp = dstinfo->image_width; + dstinfo->image_width = dstinfo->image_height; + dstinfo->image_height = dtemp; + + /* Transpose sampling factors */ + for (ci = 0; ci < dstinfo->num_components; ci++) { + compptr = dstinfo->comp_info + ci; + itemp = compptr->h_samp_factor; + compptr->h_samp_factor = compptr->v_samp_factor; + compptr->v_samp_factor = itemp; + } + + /* Transpose quantization tables */ + for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { + qtblptr = dstinfo->quant_tbl_ptrs[tblno]; + if (qtblptr != NULL) { + for (i = 0; i < DCTSIZE; i++) { + for (j = 0; j < i; j++) { + qtemp = qtblptr->quantval[i*DCTSIZE+j]; + qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; + qtblptr->quantval[j*DCTSIZE+i] = qtemp; + } + } + } + } +} + + +/* Trim off any partial iMCUs on the indicated destination edge */ + +LOCAL(void) +trim_right_edge (j_compress_ptr dstinfo) +{ + int ci, max_h_samp_factor; + JDIMENSION MCU_cols; + + /* We have to compute max_h_samp_factor ourselves, + * because it hasn't been set yet in the destination + * (and we don't want to use the source's value). + */ + max_h_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor; + max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor); + } + MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE); + if (MCU_cols > 0) /* can't trim to 0 pixels */ + dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE); +} + +LOCAL(void) +trim_bottom_edge (j_compress_ptr dstinfo) +{ + int ci, max_v_samp_factor; + JDIMENSION MCU_rows; + + /* We have to compute max_v_samp_factor ourselves, + * because it hasn't been set yet in the destination + * (and we don't want to use the source's value). + */ + max_v_samp_factor = 1; + for (ci = 0; ci < dstinfo->num_components; ci++) { + int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor; + max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor); + } + MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE); + if (MCU_rows > 0) /* can't trim to 0 pixels */ + dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE); +} + + +/* Adjust output image parameters as needed. + * + * This must be called after jpeg_copy_critical_parameters() + * and before jpeg_write_coefficients(). + * + * The return value is the set of virtual coefficient arrays to be written + * (either the ones allocated by jtransform_request_workspace, or the + * original source data arrays). The caller will need to pass this value + * to jpeg_write_coefficients(). + */ + +GLOBAL(jvirt_barray_ptr *) +jtransform_adjust_parameters (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + /* If force-to-grayscale is requested, adjust destination parameters */ + if (info->force_grayscale) { + /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed + * properly. Among other things, the target h_samp_factor & v_samp_factor + * will get set to 1, which typically won't match the source. + * In fact we do this even if the source is already grayscale; that + * provides an easy way of coercing a grayscale JPEG with funny sampling + * factors to the customary 1,1. (Some decoders fail on other factors.) + */ + if ((dstinfo->jpeg_color_space == JCS_YCbCr && + dstinfo->num_components == 3) || + (dstinfo->jpeg_color_space == JCS_GRAYSCALE && + dstinfo->num_components == 1)) { + /* We have to preserve the source's quantization table number. */ + int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; + jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); + dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; + } else { + /* Sorry, can't do it */ + ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); + } + } + + /* Correct the destination's image dimensions etc if necessary */ + switch (info->transform) { + case JXFORM_NONE: + /* Nothing to do */ + break; + case JXFORM_FLIP_H: + if (info->trim) + trim_right_edge(dstinfo); + break; + case JXFORM_FLIP_V: + if (info->trim) + trim_bottom_edge(dstinfo); + break; + case JXFORM_TRANSPOSE: + transpose_critical_parameters(dstinfo); + /* transpose does NOT have to trim anything */ + break; + case JXFORM_TRANSVERSE: + transpose_critical_parameters(dstinfo); + if (info->trim) { + trim_right_edge(dstinfo); + trim_bottom_edge(dstinfo); + } + break; + case JXFORM_ROT_90: + transpose_critical_parameters(dstinfo); + if (info->trim) + trim_right_edge(dstinfo); + break; + case JXFORM_ROT_180: + if (info->trim) { + trim_right_edge(dstinfo); + trim_bottom_edge(dstinfo); + } + break; + case JXFORM_ROT_270: + transpose_critical_parameters(dstinfo); + if (info->trim) + trim_bottom_edge(dstinfo); + break; + } + + /* Return the appropriate output data set */ + if (info->workspace_coef_arrays != NULL) + return info->workspace_coef_arrays; + return src_coef_arrays; +} + + +/* Execute the actual transformation, if any. + * + * This must be called *after* jpeg_write_coefficients, because it depends + * on jpeg_write_coefficients to have computed subsidiary values such as + * the per-component width and height fields in the destination object. + * + * Note that some transformations will modify the source data arrays! + */ + +GLOBAL(void) +jtransform_execute_transformation (j_decompress_ptr srcinfo, + j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info) +{ + jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; + + switch (info->transform) { + case JXFORM_NONE: + break; + case JXFORM_FLIP_H: + do_flip_h(srcinfo, dstinfo, src_coef_arrays); + break; + case JXFORM_FLIP_V: + do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSPOSE: + do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_TRANSVERSE: + do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_90: + do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_180: + do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + case JXFORM_ROT_270: + do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays); + break; + } +} + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* Setup decompression object to save desired markers in memory. + * This must be called before jpeg_read_header() to have the desired effect. + */ + +GLOBAL(void) +jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) +{ +#ifdef SAVE_MARKERS_SUPPORTED + int m; + + /* Save comments except under NONE option */ + if (option != JCOPYOPT_NONE) { + jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); + } + /* Save all types of APPn markers iff ALL option */ + if (option == JCOPYOPT_ALL) { + for (m = 0; m < 16; m++) + jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); + } +#endif /* SAVE_MARKERS_SUPPORTED */ +} + +/* Copy markers saved in the given source object to the destination object. + * This should be called just after jpeg_start_compress() or + * jpeg_write_coefficients(). + * Note that those routines will have written the SOI, and also the + * JFIF APP0 or Adobe APP14 markers if selected. + */ + +GLOBAL(void) +jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option) +{ + jpeg_saved_marker_ptr marker; + + /* In the current implementation, we don't actually need to examine the + * option flag here; we just copy everything that got saved. + * But to avoid confusion, we do not output JFIF and Adobe APP14 markers + * if the encoder library already wrote one. + */ + for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { + if (dstinfo->write_JFIF_header && + marker->marker == JPEG_APP0 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x4A && + GETJOCTET(marker->data[1]) == 0x46 && + GETJOCTET(marker->data[2]) == 0x49 && + GETJOCTET(marker->data[3]) == 0x46 && + GETJOCTET(marker->data[4]) == 0) + continue; /* reject duplicate JFIF */ + if (dstinfo->write_Adobe_marker && + marker->marker == JPEG_APP0+14 && + marker->data_length >= 5 && + GETJOCTET(marker->data[0]) == 0x41 && + GETJOCTET(marker->data[1]) == 0x64 && + GETJOCTET(marker->data[2]) == 0x6F && + GETJOCTET(marker->data[3]) == 0x62 && + GETJOCTET(marker->data[4]) == 0x65) + continue; /* reject duplicate Adobe */ +#ifdef NEED_FAR_POINTERS + /* We could use jpeg_write_marker if the data weren't FAR... */ + { + unsigned int i; + jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); + for (i = 0; i < marker->data_length; i++) + jpeg_write_m_byte(dstinfo, marker->data[i]); + } +#else + jpeg_write_marker(dstinfo, marker->marker, + marker->data, marker->data_length); +#endif + } +} diff --git a/freeimage241/Source/LibJPEG/transupp.h b/freeimage241/Source/LibJPEG/transupp.h new file mode 100644 index 0000000..5c2d32a --- /dev/null +++ b/freeimage241/Source/LibJPEG/transupp.h @@ -0,0 +1,135 @@ +/* + * transupp.h + * + * Copyright (C) 1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for image transformation routines and + * other utility code used by the jpegtran sample application. These are + * NOT part of the core JPEG library. But we keep these routines separate + * from jpegtran.c to ease the task of maintaining jpegtran-like programs + * that have other user interfaces. + * + * NOTE: all the routines declared here have very specific requirements + * about when they are to be executed during the reading and writing of the + * source and destination files. See the comments in transupp.c, or see + * jpegtran.c for an example of correct usage. + */ + +/* If you happen not to want the image transform support, disable it here */ +#ifndef TRANSFORMS_SUPPORTED +#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ +#endif + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jtransform_request_workspace jTrRequest +#define jtransform_adjust_parameters jTrAdjust +#define jtransform_execute_transformation jTrExec +#define jcopy_markers_setup jCMrkSetup +#define jcopy_markers_execute jCMrkExec +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * Codes for supported types of image transformations. + */ + +typedef enum { + JXFORM_NONE, /* no transformation */ + JXFORM_FLIP_H, /* horizontal flip */ + JXFORM_FLIP_V, /* vertical flip */ + JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ + JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ + JXFORM_ROT_90, /* 90-degree clockwise rotation */ + JXFORM_ROT_180, /* 180-degree rotation */ + JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ +} JXFORM_CODE; + +/* + * Although rotating and flipping data expressed as DCT coefficients is not + * hard, there is an asymmetry in the JPEG format specification for images + * whose dimensions aren't multiples of the iMCU size. The right and bottom + * image edges are padded out to the next iMCU boundary with junk data; but + * no padding is possible at the top and left edges. If we were to flip + * the whole image including the pad data, then pad garbage would become + * visible at the top and/or left, and real pixels would disappear into the + * pad margins --- perhaps permanently, since encoders & decoders may not + * bother to preserve DCT blocks that appear to be completely outside the + * nominal image area. So, we have to exclude any partial iMCUs from the + * basic transformation. + * + * Transpose is the only transformation that can handle partial iMCUs at the + * right and bottom edges completely cleanly. flip_h can flip partial iMCUs + * at the bottom, but leaves any partial iMCUs at the right edge untouched. + * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. + * The other transforms are defined as combinations of these basic transforms + * and process edge blocks in a way that preserves the equivalence. + * + * The "trim" option causes untransformable partial iMCUs to be dropped; + * this is not strictly lossless, but it usually gives the best-looking + * result for odd-size images. Note that when this option is active, + * the expected mathematical equivalences between the transforms may not hold. + * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim + * followed by -rot 180 -trim trims both edges.) + * + * We also offer a "force to grayscale" option, which simply discards the + * chrominance channels of a YCbCr image. This is lossless in the sense that + * the luminance channel is preserved exactly. It's not the same kind of + * thing as the rotate/flip transformations, but it's convenient to handle it + * as part of this package, mainly because the transformation routines have to + * be aware of the option to know how many components to work on. + */ + +typedef struct { + /* Options: set by caller */ + JXFORM_CODE transform; /* image transform operator */ + boolean trim; /* if TRUE, trim partial MCUs as needed */ + boolean force_grayscale; /* if TRUE, convert color image to grayscale */ + + /* Internal workspace: caller should not touch these */ + int num_components; /* # of components in workspace */ + jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ +} jpeg_transform_info; + + +#if TRANSFORMS_SUPPORTED + +/* Request any required workspace */ +EXTERN(void) jtransform_request_workspace + JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); +/* Adjust output image parameters */ +EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); +/* Execute the actual transformation, if any */ +EXTERN(void) jtransform_execute_transformation + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + jvirt_barray_ptr *src_coef_arrays, + jpeg_transform_info *info)); + +#endif /* TRANSFORMS_SUPPORTED */ + + +/* + * Support for copying optional markers from source to destination file. + */ + +typedef enum { + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL /* copy all optional markers */ +} JCOPY_OPTION; + +#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ + +/* Setup decompression object to save desired markers in memory */ +EXTERN(void) jcopy_markers_setup + JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); +/* Copy markers saved in the given source object to the destination object */ +EXTERN(void) jcopy_markers_execute + JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, + JCOPY_OPTION option)); diff --git a/freeimage241/Source/LibJPEG/vssver.scc b/freeimage241/Source/LibJPEG/vssver.scc new file mode 100644 index 0000000..4710178 Binary files /dev/null and b/freeimage241/Source/LibJPEG/vssver.scc differ diff --git a/freeimage241/Source/LibJPEG/wrbmp.c b/freeimage241/Source/LibJPEG/wrbmp.c new file mode 100644 index 0000000..3283b0f --- /dev/null +++ b/freeimage241/Source/LibJPEG/wrbmp.c @@ -0,0 +1,442 @@ +/* + * wrbmp.c + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Microsoft "BMP" + * format (MS Windows 3.x and OS/2 1.x flavors). + * Either 8-bit colormapped or 24-bit full-color format can be written. + * No compression is supported. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * This code contributed by James Arthur Boucher. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef BMP_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * Since BMP stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * BMP file during finish_output. The virtual array contains one JSAMPLE per + * pixel if the output is grayscale or colormapped, three if it is full color. + */ + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + boolean is_os2; /* saves the OS2 format request flag */ + + jvirt_sarray_ptr whole_image; /* needed to reverse row order */ + JDIMENSION data_width; /* JSAMPLEs per row */ + JDIMENSION row_width; /* physical width of one row in the BMP file */ + int pad_bytes; /* number of padding bytes needed per row */ + JDIMENSION cur_output_row; /* next row# to write to virtual array */ +} bmp_dest_struct; + +typedef bmp_dest_struct * bmp_dest_ptr; + + +/* Forward declarations */ +LOCAL(void) write_colormap + JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size)); + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for writing 24-bit pixels */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, + dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. Note destination values must be in BGR order + * (even though Microsoft's own documents say the opposite). + */ + inptr = dest->pub.buffer[0]; + outptr = image_ptr[0]; + for (col = cinfo->output_width; col > 0; col--) { + outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ + outptr[1] = *inptr++; + outptr[0] = *inptr++; + outptr += 3; + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* This version is for grayscale OR quantized color output */ +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + JSAMPARRAY image_ptr; + register JSAMPROW inptr, outptr; + register JDIMENSION col; + int pad; + + /* Access next row in virtual array */ + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, + dest->cur_output_row, (JDIMENSION) 1, TRUE); + dest->cur_output_row++; + + /* Transfer data. */ + inptr = dest->pub.buffer[0]; + outptr = image_ptr[0]; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */ + } + + /* Zero out the pad bytes. */ + pad = dest->pad_bytes; + while (--pad >= 0) + *outptr++ = 0; +} + + +/* + * Startup: normally writes the file header. + * In this module we may as well postpone everything until finish_output. + */ + +METHODDEF(void) +start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* no work here */ +} + + +/* + * Finish up at the end of the file. + * + * Here is where we really output the BMP file. + * + * First, routines to write the Windows and OS/2 variants of the file header. + */ + +LOCAL(void) +write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write a Windows-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpinfoheader[40]; +#define PUT_2B(array,offset,value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF)) +#define PUT_4B(array,offset,value) \ + (array[offset] = (char) ((value) & 0xFF), \ + array[offset+1] = (char) (((value) >> 8) & 0xFF), \ + array[offset+2] = (char) (((value) >> 16) & 0xFF), \ + array[offset+3] = (char) (((value) >> 24) & 0xFF)) + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */ + PUT_2B(bmpinfoheader, 0, 40); /* biSize */ + PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */ + PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */ + PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */ + PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */ + /* we leave biCompression = 0, for none */ + /* we leave biSizeImage = 0; this is correct for uncompressed data */ + if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */ + PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */ + PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */ + } + PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */ + /* we leave biClrImportant = 0 */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 4); +} + + +LOCAL(void) +write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest) +/* Write an OS2-style BMP file header, including colormap if needed */ +{ + char bmpfileheader[14]; + char bmpcoreheader[12]; + INT32 headersize, bfSize; + int bits_per_pixel, cmap_entries; + + /* Compute colormap size and total file size */ + if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* Colormapped RGB */ + bits_per_pixel = 8; + cmap_entries = 256; + } else { + /* Unquantized, full color RGB */ + bits_per_pixel = 24; + cmap_entries = 0; + } + } else { + /* Grayscale output. We need to fake a 256-entry colormap. */ + bits_per_pixel = 8; + cmap_entries = 256; + } + /* File size */ + headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */ + bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height; + + /* Set unused fields of header to 0 */ + MEMZERO(bmpfileheader, SIZEOF(bmpfileheader)); + MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader)); + + /* Fill the file header */ + bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ + bmpfileheader[1] = 0x4D; + PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */ + /* we leave bfReserved1 & bfReserved2 = 0 */ + PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */ + + /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */ + PUT_2B(bmpcoreheader, 0, 12); /* bcSize */ + PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */ + PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */ + PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */ + PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */ + + if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14) + ERREXIT(cinfo, JERR_FILE_WRITE); + if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12) + ERREXIT(cinfo, JERR_FILE_WRITE); + + if (cmap_entries > 0) + write_colormap(cinfo, dest, cmap_entries, 3); +} + + +/* + * Write the colormap. + * Windows uses BGR0 map entries; OS/2 uses BGR entries. + */ + +LOCAL(void) +write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest, + int map_colors, int map_entry_size) +{ + JSAMPARRAY colormap = cinfo->colormap; + int num_colors = cinfo->actual_number_of_colors; + FILE * outfile = dest->pub.output_file; + int i; + + if (colormap != NULL) { + if (cinfo->out_color_components == 3) { + /* Normal case with RGB colormap */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[2][i]), outfile); + putc(GETJSAMPLE(colormap[1][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } else { + /* Grayscale colormap (only happens with grayscale quantization) */ + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + putc(GETJSAMPLE(colormap[0][i]), outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + } else { + /* If no colormap, must be grayscale data. Generate a linear "map". */ + for (i = 0; i < 256; i++) { + putc(i, outfile); + putc(i, outfile); + putc(i, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } + } + /* Pad colormap with zeros to ensure specified number of colormap entries */ + if (i > map_colors) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i); + for (; i < map_colors; i++) { + putc(0, outfile); + putc(0, outfile); + putc(0, outfile); + if (map_entry_size == 4) + putc(0, outfile); + } +} + + +METHODDEF(void) +finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + bmp_dest_ptr dest = (bmp_dest_ptr) dinfo; + register FILE * outfile = dest->pub.output_file; + JSAMPARRAY image_ptr; + register JSAMPROW data_ptr; + JDIMENSION row; + register JDIMENSION col; + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + + /* Write the header and colormap */ + if (dest->is_os2) + write_os2_header(cinfo, dest); + else + write_bmp_header(cinfo, dest); + + /* Write the file body from our virtual array */ + for (row = cinfo->output_height; row > 0; row--) { + if (progress != NULL) { + progress->pub.pass_counter = (long) (cinfo->output_height - row); + progress->pub.pass_limit = (long) cinfo->output_height; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } + image_ptr = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE); + data_ptr = image_ptr[0]; + for (col = dest->row_width; col > 0; col--) { + putc(GETJSAMPLE(*data_ptr), outfile); + data_ptr++; + } + } + if (progress != NULL) + progress->completed_extra_passes++; + + /* Make sure we wrote the output file OK */ + fflush(outfile); + if (ferror(outfile)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for BMP format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2) +{ + bmp_dest_ptr dest; + JDIMENSION row_width; + + /* Create module interface object, fill in method pointers */ + dest = (bmp_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(bmp_dest_struct)); + dest->pub.start_output = start_output_bmp; + dest->pub.finish_output = finish_output_bmp; + dest->is_os2 = is_os2; + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + dest->pub.put_pixel_rows = put_gray_rows; + } else if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) + dest->pub.put_pixel_rows = put_gray_rows; + else + dest->pub.put_pixel_rows = put_pixel_rows; + } else { + ERREXIT(cinfo, JERR_BMP_COLORSPACE); + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Determine width of rows in the BMP file (padded to 4-byte boundary). */ + row_width = cinfo->output_width * cinfo->output_components; + dest->data_width = row_width; + while ((row_width & 3) != 0) row_width++; + dest->row_width = row_width; + dest->pad_bytes = (int) (row_width - dest->data_width); + + /* Allocate space for inversion array, prepare for write pass */ + dest->whole_image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + row_width, cinfo->output_height, (JDIMENSION) 1); + dest->cur_output_row = 0; + if (cinfo->progress != NULL) { + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; + progress->total_extra_passes++; /* count file input as separate pass */ + } + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* BMP_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/wrgif.c b/freeimage241/Source/LibJPEG/wrgif.c new file mode 100644 index 0000000..5fe8328 --- /dev/null +++ b/freeimage241/Source/LibJPEG/wrgif.c @@ -0,0 +1,399 @@ +/* + * wrgif.c + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in GIF format. + * + ************************************************************************** + * NOTE: to avoid entanglements with Unisys' patent on LZW compression, * + * this code has been modified to output "uncompressed GIF" files. * + * There is no trace of the LZW algorithm in this file. * + ************************************************************************** + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +/* + * This code is loosely based on ppmtogif from the PBMPLUS distribution + * of Feb. 1991. That file contains the following copyright notice: + * Based on GIFENCODE by David Rowley . + * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al. + * Copyright (C) 1989 by Jef Poskanzer. + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + * + * We are also required to state that + * "The Graphics Interchange Format(c) is the Copyright property of + * CompuServe Incorporated. GIF(sm) is a Service Mark property of + * CompuServe Incorporated." + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef GIF_SUPPORTED + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + j_decompress_ptr cinfo; /* back link saves passing separate parm */ + + /* State for packing variable-width codes into a bitstream */ + int n_bits; /* current number of bits/code */ + int maxcode; /* maximum code, given n_bits */ + INT32 cur_accum; /* holds bits not yet output */ + int cur_bits; /* # of bits in cur_accum */ + + /* State for GIF code assignment */ + int ClearCode; /* clear code (doesn't change) */ + int EOFCode; /* EOF code (ditto) */ + int code_counter; /* counts output symbols */ + + /* GIF data packet construction buffer */ + int bytesinpkt; /* # of bytes in current packet */ + char packetbuf[256]; /* workspace for accumulating packet */ + +} gif_dest_struct; + +typedef gif_dest_struct * gif_dest_ptr; + +/* Largest value that will fit in N bits */ +#define MAXCODE(n_bits) ((1 << (n_bits)) - 1) + + +/* + * Routines to package finished data bytes into GIF data blocks. + * A data block consists of a count byte (1..255) and that many data bytes. + */ + +LOCAL(void) +flush_packet (gif_dest_ptr dinfo) +/* flush any accumulated data */ +{ + if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */ + dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++; + if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt) + != (size_t) dinfo->bytesinpkt) + ERREXIT(dinfo->cinfo, JERR_FILE_WRITE); + dinfo->bytesinpkt = 0; + } +} + + +/* Add a character to current packet; flush to disk if necessary */ +#define CHAR_OUT(dinfo,c) \ + { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c); \ + if ((dinfo)->bytesinpkt >= 255) \ + flush_packet(dinfo); \ + } + + +/* Routine to convert variable-width codes into a byte stream */ + +LOCAL(void) +output (gif_dest_ptr dinfo, int code) +/* Emit a code of n_bits bits */ +/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */ +{ + dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits; + dinfo->cur_bits += dinfo->n_bits; + + while (dinfo->cur_bits >= 8) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + dinfo->cur_accum >>= 8; + dinfo->cur_bits -= 8; + } +} + + +/* The pseudo-compression algorithm. + * + * In this module we simply output each pixel value as a separate symbol; + * thus, no compression occurs. In fact, there is expansion of one bit per + * pixel, because we use a symbol width one bit wider than the pixel width. + * + * GIF ordinarily uses variable-width symbols, and the decoder will expect + * to ratchet up the symbol width after a fixed number of symbols. + * To simplify the logic and keep the expansion penalty down, we emit a + * GIF Clear code to reset the decoder just before the width would ratchet up. + * Thus, all the symbols in the output file will have the same bit width. + * Note that emitting the Clear codes at the right times is a mere matter of + * counting output symbols and is in no way dependent on the LZW patent. + * + * With a small basic pixel width (low color count), Clear codes will be + * needed very frequently, causing the file to expand even more. So this + * simplistic approach wouldn't work too well on bilevel images, for example. + * But for output of JPEG conversions the pixel width will usually be 8 bits + * (129 to 256 colors), so the overhead added by Clear symbols is only about + * one symbol in every 256. + */ + +LOCAL(void) +compress_init (gif_dest_ptr dinfo, int i_bits) +/* Initialize pseudo-compressor */ +{ + /* init all the state variables */ + dinfo->n_bits = i_bits; + dinfo->maxcode = MAXCODE(dinfo->n_bits); + dinfo->ClearCode = (1 << (i_bits - 1)); + dinfo->EOFCode = dinfo->ClearCode + 1; + dinfo->code_counter = dinfo->ClearCode + 2; + /* init output buffering vars */ + dinfo->bytesinpkt = 0; + dinfo->cur_accum = 0; + dinfo->cur_bits = 0; + /* GIF specifies an initial Clear code */ + output(dinfo, dinfo->ClearCode); +} + + +LOCAL(void) +compress_pixel (gif_dest_ptr dinfo, int c) +/* Accept and "compress" one pixel value. + * The given value must be less than n_bits wide. + */ +{ + /* Output the given pixel value as a symbol. */ + output(dinfo, c); + /* Issue Clear codes often enough to keep the reader from ratcheting up + * its symbol size. + */ + if (dinfo->code_counter < dinfo->maxcode) { + dinfo->code_counter++; + } else { + output(dinfo, dinfo->ClearCode); + dinfo->code_counter = dinfo->ClearCode + 2; /* reset the counter */ + } +} + + +LOCAL(void) +compress_term (gif_dest_ptr dinfo) +/* Clean up at end */ +{ + /* Send an EOF code */ + output(dinfo, dinfo->EOFCode); + /* Flush the bit-packing buffer */ + if (dinfo->cur_bits > 0) { + CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF); + } + /* Flush the packet buffer */ + flush_packet(dinfo); +} + + +/* GIF header construction */ + + +LOCAL(void) +put_word (gif_dest_ptr dinfo, unsigned int w) +/* Emit a 16-bit word, LSB first */ +{ + putc(w & 0xFF, dinfo->pub.output_file); + putc((w >> 8) & 0xFF, dinfo->pub.output_file); +} + + +LOCAL(void) +put_3bytes (gif_dest_ptr dinfo, int val) +/* Emit 3 copies of same byte value --- handy subr for colormap construction */ +{ + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); + putc(val, dinfo->pub.output_file); +} + + +LOCAL(void) +emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap) +/* Output the GIF file header, including color map */ +/* If colormap==NULL, synthesize a gray-scale colormap */ +{ + int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte; + int cshift = dinfo->cinfo->data_precision - 8; + int i; + + if (num_colors > 256) + ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors); + /* Compute bits/pixel and related values */ + BitsPerPixel = 1; + while (num_colors > (1 << BitsPerPixel)) + BitsPerPixel++; + ColorMapSize = 1 << BitsPerPixel; + if (BitsPerPixel <= 1) + InitCodeSize = 2; + else + InitCodeSize = BitsPerPixel; + /* + * Write the GIF header. + * Note that we generate a plain GIF87 header for maximum compatibility. + */ + putc('G', dinfo->pub.output_file); + putc('I', dinfo->pub.output_file); + putc('F', dinfo->pub.output_file); + putc('8', dinfo->pub.output_file); + putc('7', dinfo->pub.output_file); + putc('a', dinfo->pub.output_file); + /* Write the Logical Screen Descriptor */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + FlagByte = 0x80; /* Yes, there is a global color table */ + FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */ + FlagByte |= (BitsPerPixel-1); /* size of global color table */ + putc(FlagByte, dinfo->pub.output_file); + putc(0, dinfo->pub.output_file); /* Background color index */ + putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */ + /* Write the Global Color Map */ + /* If the color map is more than 8 bits precision, */ + /* we reduce it to 8 bits by shifting */ + for (i=0; i < ColorMapSize; i++) { + if (i < num_colors) { + if (colormap != NULL) { + if (dinfo->cinfo->out_color_space == JCS_RGB) { + /* Normal case: RGB color map */ + putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file); + putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file); + } else { + /* Grayscale "color map": possible if quantizing grayscale image */ + put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift); + } + } else { + /* Create a gray-scale map of num_colors values, range 0..255 */ + put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1)); + } + } else { + /* fill out the map to a power of 2 */ + put_3bytes(dinfo, 0); + } + } + /* Write image separator and Image Descriptor */ + putc(',', dinfo->pub.output_file); /* separator */ + put_word(dinfo, 0); /* left/top offset */ + put_word(dinfo, 0); + put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */ + put_word(dinfo, (unsigned int) dinfo->cinfo->output_height); + /* flag byte: not interlaced, no local color map */ + putc(0x00, dinfo->pub.output_file); + /* Write Initial Code Size byte */ + putc(InitCodeSize, dinfo->pub.output_file); + + /* Initialize for "compression" of image data */ + compress_init(dinfo, InitCodeSize+1); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + if (cinfo->quantize_colors) + emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap); + else + emit_header(dest, 256, (JSAMPARRAY) NULL); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + for (col = cinfo->output_width; col > 0; col--) { + compress_pixel(dest, GETJSAMPLE(*ptr++)); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + gif_dest_ptr dest = (gif_dest_ptr) dinfo; + + /* Flush "compression" mechanism */ + compress_term(dest); + /* Write a zero-length data block to end the series */ + putc(0, dest->pub.output_file); + /* Write the GIF terminator mark */ + putc(';', dest->pub.output_file); + /* Make sure we wrote the output file OK */ + fflush(dest->pub.output_file); + if (ferror(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for GIF format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_gif (j_decompress_ptr cinfo) +{ + gif_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (gif_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(gif_dest_struct)); + dest->cinfo = cinfo; /* make back link for subroutines */ + dest->pub.start_output = start_output_gif; + dest->pub.put_pixel_rows = put_pixel_rows; + dest->pub.finish_output = finish_output_gif; + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_GIF_COLORSPACE); + + /* Force quantization if color or if > 8 bits input */ + if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) { + /* Force quantization to at most 256 colors */ + cinfo->quantize_colors = TRUE; + if (cinfo->desired_number_of_colors > 256) + cinfo->desired_number_of_colors = 256; + } + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + if (cinfo->output_components != 1) /* safety check: just one component? */ + ERREXIT(cinfo, JERR_GIF_BUG); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* GIF_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/wrjpgcom.c b/freeimage241/Source/LibJPEG/wrjpgcom.c new file mode 100644 index 0000000..8c04b05 --- /dev/null +++ b/freeimage241/Source/LibJPEG/wrjpgcom.c @@ -0,0 +1,583 @@ +/* + * wrjpgcom.c + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains a very simple stand-alone application that inserts + * user-supplied text as a COM (comment) marker in a JFIF file. + * This may be useful as an example of the minimum logic needed to parse + * JPEG markers. + */ + +#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ +#include "jinclude.h" /* get auto-config symbols, */ + +#ifndef HAVE_STDLIB_H /* should declare malloc() */ +extern void * malloc (); +#endif +#include /* to declare isupper(), tolower() */ +#ifdef USE_SETMODE +#include /* to declare setmode()'s parameter macros */ +/* If you have setmode() but not , just delete this line: */ +#include /* to declare setmode() */ +#endif + +#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ +#ifdef __MWERKS__ +#include /* Metrowerks needs this */ +#include /* ... and this */ +#endif +#ifdef THINK_C +#include /* Think declares it here */ +#endif +#endif + +#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ +#define READ_BINARY "r" +#define WRITE_BINARY "w" +#else +#ifdef VMS /* VMS is very nonstandard */ +#define READ_BINARY "rb", "ctx=stm" +#define WRITE_BINARY "wb", "ctx=stm" +#else /* standard ANSI-compliant case */ +#define READ_BINARY "rb" +#define WRITE_BINARY "wb" +#endif +#endif + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif +#ifndef EXIT_SUCCESS +#ifdef VMS +#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ +#else +#define EXIT_SUCCESS 0 +#endif +#endif + +/* Reduce this value if your malloc() can't allocate blocks up to 64K. + * On DOS, compiling in large model is usually a better solution. + */ + +#ifndef MAX_COM_LENGTH +#define MAX_COM_LENGTH 65000L /* must be <= 65533 in any case */ +#endif + + +/* + * These macros are used to read the input file and write the output file. + * To reuse this code in another application, you might need to change these. + */ + +static FILE * infile; /* input JPEG file */ + +/* Return next input byte, or EOF if no more */ +#define NEXTBYTE() getc(infile) + +static FILE * outfile; /* output JPEG file */ + +/* Emit an output byte */ +#define PUTBYTE(x) putc((x), outfile) + + +/* Error exit handler */ +#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) + + +/* Read one byte, testing for EOF */ +static int +read_1_byte (void) +{ + int c; + + c = NEXTBYTE(); + if (c == EOF) + ERREXIT("Premature EOF in JPEG file"); + return c; +} + +/* Read 2 bytes, convert to unsigned int */ +/* All 2-byte quantities in JPEG markers are MSB first */ +static unsigned int +read_2_bytes (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + if (c1 == EOF) + ERREXIT("Premature EOF in JPEG file"); + c2 = NEXTBYTE(); + if (c2 == EOF) + ERREXIT("Premature EOF in JPEG file"); + return (((unsigned int) c1) << 8) + ((unsigned int) c2); +} + + +/* Routines to write data to output file */ + +static void +write_1_byte (int c) +{ + PUTBYTE(c); +} + +static void +write_2_bytes (unsigned int val) +{ + PUTBYTE((val >> 8) & 0xFF); + PUTBYTE(val & 0xFF); +} + +static void +write_marker (int marker) +{ + PUTBYTE(0xFF); + PUTBYTE(marker); +} + +static void +copy_rest_of_file (void) +{ + int c; + + while ((c = NEXTBYTE()) != EOF) + PUTBYTE(c); +} + + +/* + * JPEG markers consist of one or more 0xFF bytes, followed by a marker + * code byte (which is not an FF). Here are the marker codes of interest + * in this program. (See jdmarker.c for a more complete list.) + */ + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_COM 0xFE /* COMment */ + + +/* + * Find the next JPEG marker and return its marker code. + * We expect at least one FF byte, possibly more if the compressor used FFs + * to pad the file. (Padding FFs will NOT be replicated in the output file.) + * There could also be non-FF garbage between markers. The treatment of such + * garbage is unspecified; we choose to skip over it but emit a warning msg. + * NB: this routine must not be used after seeing SOS marker, since it will + * not deal correctly with FF/00 sequences in the compressed image data... + */ + +static int +next_marker (void) +{ + int c; + int discarded_bytes = 0; + + /* Find 0xFF byte; count and skip any non-FFs. */ + c = read_1_byte(); + while (c != 0xFF) { + discarded_bytes++; + c = read_1_byte(); + } + /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs + * are legal as pad bytes, so don't count them in discarded_bytes. + */ + do { + c = read_1_byte(); + } while (c == 0xFF); + + if (discarded_bytes != 0) { + fprintf(stderr, "Warning: garbage data found in JPEG file\n"); + } + + return c; +} + + +/* + * Read the initial marker, which should be SOI. + * For a JFIF file, the first two bytes of the file should be literally + * 0xFF M_SOI. To be more general, we could use next_marker, but if the + * input file weren't actually JPEG at all, next_marker might read the whole + * file and then return a misleading error message... + */ + +static int +first_marker (void) +{ + int c1, c2; + + c1 = NEXTBYTE(); + c2 = NEXTBYTE(); + if (c1 != 0xFF || c2 != M_SOI) + ERREXIT("Not a JPEG file"); + return c2; +} + + +/* + * Most types of marker are followed by a variable-length parameter segment. + * This routine skips over the parameters for any marker we don't otherwise + * want to process. + * Note that we MUST skip the parameter segment explicitly in order not to + * be fooled by 0xFF bytes that might appear within the parameter segment; + * such bytes do NOT introduce new markers. + */ + +static void +copy_variable (void) +/* Copy an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + write_2_bytes(length); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + write_1_byte(read_1_byte()); + length--; + } +} + +static void +skip_variable (void) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + unsigned int length; + + /* Get the marker parameter length count */ + length = read_2_bytes(); + /* Length includes itself, so must be at least 2 */ + if (length < 2) + ERREXIT("Erroneous JPEG marker length"); + length -= 2; + /* Skip over the remaining bytes */ + while (length > 0) { + (void) read_1_byte(); + length--; + } +} + + +/* + * Parse the marker stream until SOFn or EOI is seen; + * copy data to output, but discard COM markers unless keep_COM is true. + */ + +static int +scan_JPEG_header (int keep_COM) +{ + int marker; + + /* Expect SOI at start of file */ + if (first_marker() != M_SOI) + ERREXIT("Expected SOI marker first"); + write_marker(M_SOI); + + /* Scan miscellaneous markers until we reach SOFn. */ + for (;;) { + marker = next_marker(); + switch (marker) { + /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, + * treated as SOFn. C4 in particular is actually DHT. + */ + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + case M_SOF2: /* Progressive, Huffman */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_SOF9: /* Extended sequential, arithmetic */ + case M_SOF10: /* Progressive, arithmetic */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + return marker; + + case M_SOS: /* should not see compressed data before SOF */ + ERREXIT("SOS without prior SOFn"); + break; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + return marker; + + case M_COM: /* Existing COM: conditionally discard */ + if (keep_COM) { + write_marker(marker); + copy_variable(); + } else { + skip_variable(); + } + break; + + default: /* Anything else just gets copied */ + write_marker(marker); + copy_variable(); /* we assume it has a parameter count... */ + break; + } + } /* end loop */ +} + + +/* Command line parsing code */ + +static const char * progname; /* program name for error messages */ + + +static void +usage (void) +/* complain about bad command line */ +{ + fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n"); + fprintf(stderr, "You can add to or replace any existing comment(s).\n"); + + fprintf(stderr, "Usage: %s [switches] ", progname); +#ifdef TWO_FILE_COMMANDLINE + fprintf(stderr, "inputfile outputfile\n"); +#else + fprintf(stderr, "[inputfile]\n"); +#endif + + fprintf(stderr, "Switches (names may be abbreviated):\n"); + fprintf(stderr, " -replace Delete any existing comments\n"); + fprintf(stderr, " -comment \"text\" Insert comment with given text\n"); + fprintf(stderr, " -cfile name Read comment from named file\n"); + fprintf(stderr, "Notice that you must put quotes around the comment text\n"); + fprintf(stderr, "when you use -comment.\n"); + fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n"); + fprintf(stderr, "then the comment text is read from standard input.\n"); + fprintf(stderr, "It can be multiple lines, up to %u characters total.\n", + (unsigned int) MAX_COM_LENGTH); +#ifndef TWO_FILE_COMMANDLINE + fprintf(stderr, "You must specify an input JPEG file name when supplying\n"); + fprintf(stderr, "comment text from standard input.\n"); +#endif + + exit(EXIT_FAILURE); +} + + +static int +keymatch (char * arg, const char * keyword, int minchars) +/* Case-insensitive matching of (possibly abbreviated) keyword switches. */ +/* keyword is the constant keyword (must be lower case already), */ +/* minchars is length of minimum legal abbreviation. */ +{ + register int ca, ck; + register int nmatched = 0; + + while ((ca = *arg++) != '\0') { + if ((ck = *keyword++) == '\0') + return 0; /* arg longer than keyword, no good */ + if (isupper(ca)) /* force arg to lcase (assume ck is already) */ + ca = tolower(ca); + if (ca != ck) + return 0; /* no good */ + nmatched++; /* count matched characters */ + } + /* reached end of argument; fail if it's too short for unique abbrev */ + if (nmatched < minchars) + return 0; + return 1; /* A-OK */ +} + + +/* + * The main program. + */ + +int +main (int argc, char **argv) +{ + int argn; + char * arg; + int keep_COM = 1; + char * comment_arg = NULL; + FILE * comment_file = NULL; + unsigned int comment_length = 0; + int marker; + + /* On Mac, fetch a command line. */ +#ifdef USE_CCOMMAND + argc = ccommand(&argv); +#endif + + progname = argv[0]; + if (progname == NULL || progname[0] == 0) + progname = "wrjpgcom"; /* in case C library doesn't provide it */ + + /* Parse switches, if any */ + for (argn = 1; argn < argc; argn++) { + arg = argv[argn]; + if (arg[0] != '-') + break; /* not switch, must be file name */ + arg++; /* advance over '-' */ + if (keymatch(arg, "replace", 1)) { + keep_COM = 0; + } else if (keymatch(arg, "cfile", 2)) { + if (++argn >= argc) usage(); + if ((comment_file = fopen(argv[argn], "r")) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else if (keymatch(arg, "comment", 1)) { + if (++argn >= argc) usage(); + comment_arg = argv[argn]; + /* If the comment text starts with '"', then we are probably running + * under MS-DOG and must parse out the quoted string ourselves. Sigh. + */ + if (comment_arg[0] == '"') { + comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); + if (comment_arg == NULL) + ERREXIT("Insufficient memory"); + strcpy(comment_arg, argv[argn]+1); + for (;;) { + comment_length = (unsigned int) strlen(comment_arg); + if (comment_length > 0 && comment_arg[comment_length-1] == '"') { + comment_arg[comment_length-1] = '\0'; /* zap terminating quote */ + break; + } + if (++argn >= argc) + ERREXIT("Missing ending quote mark"); + strcat(comment_arg, " "); + strcat(comment_arg, argv[argn]); + } + } + comment_length = (unsigned int) strlen(comment_arg); + } else + usage(); + } + + /* Cannot use both -comment and -cfile. */ + if (comment_arg != NULL && comment_file != NULL) + usage(); + /* If there is neither -comment nor -cfile, we will read the comment text + * from stdin; in this case there MUST be an input JPEG file name. + */ + if (comment_arg == NULL && comment_file == NULL && argn >= argc) + usage(); + + /* Open the input file. */ + if (argn < argc) { + if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); + exit(EXIT_FAILURE); + } + } else { + /* default input file is stdin */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdin), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdin\n", progname); + exit(EXIT_FAILURE); + } +#else + infile = stdin; +#endif + } + + /* Open the output file. */ +#ifdef TWO_FILE_COMMANDLINE + /* Must have explicit output file name */ + if (argn != argc-2) { + fprintf(stderr, "%s: must name one input and one output file\n", + progname); + usage(); + } + if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]); + exit(EXIT_FAILURE); + } +#else + /* Unix style: expect zero or one file name */ + if (argn < argc-1) { + fprintf(stderr, "%s: only one input file\n", progname); + usage(); + } + /* default output file is stdout */ +#ifdef USE_SETMODE /* need to hack file mode? */ + setmode(fileno(stdout), O_BINARY); +#endif +#ifdef USE_FDOPEN /* need to re-open in binary mode? */ + if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { + fprintf(stderr, "%s: can't open stdout\n", progname); + exit(EXIT_FAILURE); + } +#else + outfile = stdout; +#endif +#endif /* TWO_FILE_COMMANDLINE */ + + /* Collect comment text from comment_file or stdin, if necessary */ + if (comment_arg == NULL) { + FILE * src_file; + int c; + + comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); + if (comment_arg == NULL) + ERREXIT("Insufficient memory"); + comment_length = 0; + src_file = (comment_file != NULL ? comment_file : stdin); + while ((c = getc(src_file)) != EOF) { + if (comment_length >= (unsigned int) MAX_COM_LENGTH) { + fprintf(stderr, "Comment text may not exceed %u bytes\n", + (unsigned int) MAX_COM_LENGTH); + exit(EXIT_FAILURE); + } + comment_arg[comment_length++] = (char) c; + } + if (comment_file != NULL) + fclose(comment_file); + } + + /* Copy JPEG headers until SOFn marker; + * we will insert the new comment marker just before SOFn. + * This (a) causes the new comment to appear after, rather than before, + * existing comments; and (b) ensures that comments come after any JFIF + * or JFXX markers, as required by the JFIF specification. + */ + marker = scan_JPEG_header(keep_COM); + /* Insert the new COM marker, but only if nonempty text has been supplied */ + if (comment_length > 0) { + write_marker(M_COM); + write_2_bytes(comment_length + 2); + while (comment_length > 0) { + write_1_byte(*comment_arg++); + comment_length--; + } + } + /* Duplicate the remainder of the source file. + * Note that any COM markers occuring after SOF will not be touched. + */ + write_marker(marker); + copy_rest_of_file(); + + /* All done. */ + exit(EXIT_SUCCESS); + return 0; /* suppress no-return-value warnings */ +} diff --git a/freeimage241/Source/LibJPEG/wrppm.c b/freeimage241/Source/LibJPEG/wrppm.c new file mode 100644 index 0000000..6c6d908 --- /dev/null +++ b/freeimage241/Source/LibJPEG/wrppm.c @@ -0,0 +1,268 @@ +/* + * wrppm.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in PPM/PGM format. + * The extended 2-byte-per-sample raw PPM/PGM formats are supported. + * The PBMPLUS library is NOT required to compile this software + * (but it is highly useful as a set of PPM image manipulation programs). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef PPM_SUPPORTED + + +/* + * For 12-bit JPEG data, we either downscale the values to 8 bits + * (to write standard byte-per-sample PPM/PGM files), or output + * nonstandard word-per-sample PPM/PGM files. Downscaling is done + * if PPM_NORAWWORD is defined (this can be done in the Makefile + * or in jconfig.h). + * (When the core library supports data precision reduction, a cleaner + * implementation will be to ask for that instead.) + */ + +#if BITS_IN_JSAMPLE == 8 +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +#ifdef PPM_NORAWWORD +#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8)) +#define BYTESPERSAMPLE 1 +#define PPM_MAXVAL 255 +#else +/* The word-per-sample format always puts the LSB first. */ +#define PUTPPMSAMPLE(ptr,v) \ + { register int val_ = v; \ + *ptr++ = (char) (val_ & 0xFF); \ + *ptr++ = (char) ((val_ >> 8) & 0xFF); \ + } +#define BYTESPERSAMPLE 2 +#define PPM_MAXVAL ((1<pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * This code is used when we have to copy the data and apply a pixel + * format translation. Typically this only happens in 12-bit mode. + */ + +METHODDEF(void) +copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = dest->samples_per_row; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++)); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some pixel data when color quantization is in effect. + * We have to demap the color index values to straight data. + */ + +METHODDEF(void) +put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register int pixval; + register JSAMPROW ptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JSAMPROW color_map1 = cinfo->colormap[1]; + register JSAMPROW color_map2 = cinfo->colormap[2]; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + pixval = GETJSAMPLE(*ptr++); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval])); + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + register char * bufferptr; + register JSAMPROW ptr; + register JSAMPROW color_map = cinfo->colormap[0]; + register JDIMENSION col; + + ptr = dest->pub.buffer[0]; + bufferptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map[GETJSAMPLE(*ptr++)])); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + ppm_dest_ptr dest = (ppm_dest_ptr) dinfo; + + /* Emit file header */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + /* emit header for raw PGM format */ + fprintf(dest->pub.output_file, "P5\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + case JCS_RGB: + /* emit header for raw PPM format */ + fprintf(dest->pub.output_file, "P6\n%ld %ld\n%d\n", + (long) cinfo->output_width, (long) cinfo->output_height, + PPM_MAXVAL); + break; + default: + ERREXIT(cinfo, JERR_PPM_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + fflush(dinfo->output_file); + if (ferror(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for PPM format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_ppm (j_decompress_ptr cinfo) +{ + ppm_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (ppm_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(ppm_dest_struct)); + dest->pub.start_output = start_output_ppm; + dest->pub.finish_output = finish_output_ppm; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create physical I/O buffer. Note we make this near on a PC. */ + dest->samples_per_row = cinfo->output_width * cinfo->out_color_components; + dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char)); + dest->iobuffer = (char *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width); + + if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 || + SIZEOF(JSAMPLE) != SIZEOF(char)) { + /* When quantizing, we need an output buffer for colormap indexes + * that's separate from the physical I/O buffer. We also need a + * separate buffer if pixel format translation must take place. + */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width * cinfo->output_components, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + if (! cinfo->quantize_colors) + dest->pub.put_pixel_rows = copy_pixel_rows; + else if (cinfo->out_color_space == JCS_GRAYSCALE) + dest->pub.put_pixel_rows = put_demapped_gray; + else + dest->pub.put_pixel_rows = put_demapped_rgb; + } else { + /* We will fwrite() directly from decompressor output buffer. */ + /* Synthesize a JSAMPARRAY pointer structure */ + /* Cast here implies near->far pointer conversion on PCs */ + dest->pixrow = (JSAMPROW) dest->iobuffer; + dest->pub.buffer = & dest->pixrow; + dest->pub.buffer_height = 1; + dest->pub.put_pixel_rows = put_pixel_rows; + } + + return (djpeg_dest_ptr) dest; +} + +#endif /* PPM_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/wrrle.c b/freeimage241/Source/LibJPEG/wrrle.c new file mode 100644 index 0000000..a4e7337 --- /dev/null +++ b/freeimage241/Source/LibJPEG/wrrle.c @@ -0,0 +1,305 @@ +/* + * wrrle.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in RLE format. + * The Utah Raster Toolkit library is required (version 3.1 or later). + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Mike Lijewski, + * with updates from Robert Hutchinson. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef RLE_SUPPORTED + +/* rle.h is provided by the Utah Raster Toolkit. */ + +#include + +/* + * We assume that JSAMPLE has the same representation as rle_pixel, + * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + + +/* + * Since RLE stores scanlines bottom-to-top, we have to invert the image + * from JPEG's top-to-bottom order. To do this, we save the outgoing data + * in a virtual array during put_pixel_row calls, then actually emit the + * RLE file during finish_output. + */ + + +/* + * For now, if we emit an RLE color map then it is always 256 entries long, + * though not all of the entries need be used. + */ + +#define CMAPBITS 8 +#define CMAPLENGTH (1<<(CMAPBITS)) + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + jvirt_sarray_ptr image; /* virtual array to store the output image */ + rle_map *colormap; /* RLE-style color map, or NULL if none */ + rle_pixel **rle_row; /* To pass rows to rle_putrow() */ + +} rle_dest_struct; + +typedef rle_dest_struct * rle_dest_ptr; + +/* Forward declarations */ +METHODDEF(void) rle_put_pixel_rows + JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied)); + + +/* + * Write the file header. + * + * In this module it's easier to wait till finish_output to write anything. + */ + +METHODDEF(void) +start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + size_t cmapsize; + int i, ci; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* + * Make sure the image can be stored in RLE format. + * + * - RLE stores image dimensions as *signed* 16 bit integers. JPEG + * uses unsigned, so we have to check the width. + * + * - Colorspace is expected to be grayscale or RGB. + * + * - The number of channels (components) is expected to be 1 (grayscale/ + * pseudocolor) or 3 (truecolor/directcolor). + * (could be 2 or 4 if using an alpha channel, but we aren't) + */ + + if (cinfo->output_width > 32767 || cinfo->output_height > 32767) + ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width, + cinfo->output_height); + + if (cinfo->out_color_space != JCS_GRAYSCALE && + cinfo->out_color_space != JCS_RGB) + ERREXIT(cinfo, JERR_RLE_COLORSPACE); + + if (cinfo->output_components != 1 && cinfo->output_components != 3) + ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components); + + /* Convert colormap, if any, to RLE format. */ + + dest->colormap = NULL; + + if (cinfo->quantize_colors) { + /* Allocate storage for RLE-style cmap, zero any extra entries */ + cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map); + dest->colormap = (rle_map *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize); + MEMZERO(dest->colormap, cmapsize); + + /* Save away data in RLE format --- note 8-bit left shift! */ + /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */ + for (ci = 0; ci < cinfo->out_color_components; ci++) { + for (i = 0; i < cinfo->actual_number_of_colors; i++) { + dest->colormap[ci * CMAPLENGTH + i] = + GETJSAMPLE(cinfo->colormap[ci][i]) << 8; + } + } + } + + /* Set the output buffer to the first row */ + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE); + dest->pub.buffer_height = 1; + + dest->pub.put_pixel_rows = rle_put_pixel_rows; + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->total_extra_passes++; /* count file writing as separate pass */ + } +#endif +} + + +/* + * Write some pixel data. + * + * This routine just saves the data away in a virtual array. + */ + +METHODDEF(void) +rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + + if (cinfo->output_scanline < cinfo->output_height) { + dest->pub.buffer = (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + cinfo->output_scanline, (JDIMENSION) 1, TRUE); + } +} + +/* + * Finish up at the end of the file. + * + * Here is where we really output the RLE file. + */ + +METHODDEF(void) +finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + rle_dest_ptr dest = (rle_dest_ptr) dinfo; + rle_hdr header; /* Output file information */ + rle_pixel **rle_row, *red, *green, *blue; + JSAMPROW output_row; + char cmapcomment[80]; + int row, col; + int ci; +#ifdef PROGRESS_REPORT + cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; +#endif + + /* Initialize the header info */ + header = *rle_hdr_init(NULL); + header.rle_file = dest->pub.output_file; + header.xmin = 0; + header.xmax = cinfo->output_width - 1; + header.ymin = 0; + header.ymax = cinfo->output_height - 1; + header.alpha = 0; + header.ncolors = cinfo->output_components; + for (ci = 0; ci < cinfo->output_components; ci++) { + RLE_SET_BIT(header, ci); + } + if (cinfo->quantize_colors) { + header.ncmap = cinfo->out_color_components; + header.cmaplen = CMAPBITS; + header.cmap = dest->colormap; + /* Add a comment to the output image with the true colormap length. */ + sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors); + rle_putcom(cmapcomment, &header); + } + + /* Emit the RLE header and color map (if any) */ + rle_put_setup(&header); + + /* Now output the RLE data from our virtual array. + * We assume here that (a) rle_pixel is represented the same as JSAMPLE, + * and (b) we are not on a machine where FAR pointers differ from regular. + */ + +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_limit = cinfo->output_height; + progress->pub.pass_counter = 0; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + + if (cinfo->output_components == 1) { + for (row = cinfo->output_height-1; row >= 0; row--) { + rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } else { + for (row = cinfo->output_height-1; row >= 0; row--) { + rle_row = (rle_pixel **) dest->rle_row; + output_row = * (*cinfo->mem->access_virt_sarray) + ((j_common_ptr) cinfo, dest->image, + (JDIMENSION) row, (JDIMENSION) 1, FALSE); + red = rle_row[0]; + green = rle_row[1]; + blue = rle_row[2]; + for (col = cinfo->output_width; col > 0; col--) { + *red++ = GETJSAMPLE(*output_row++); + *green++ = GETJSAMPLE(*output_row++); + *blue++ = GETJSAMPLE(*output_row++); + } + rle_putrow(rle_row, (int) cinfo->output_width, &header); +#ifdef PROGRESS_REPORT + if (progress != NULL) { + progress->pub.pass_counter++; + (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); + } +#endif + } + } + +#ifdef PROGRESS_REPORT + if (progress != NULL) + progress->completed_extra_passes++; +#endif + + /* Emit file trailer */ + rle_puteof(&header); + fflush(dest->pub.output_file); + if (ferror(dest->pub.output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for RLE format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_rle (j_decompress_ptr cinfo) +{ + rle_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (rle_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(rle_dest_struct)); + dest->pub.start_output = start_output_rle; + dest->pub.finish_output = finish_output_rle; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Allocate a work array for output to the RLE library. */ + dest->rle_row = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->output_width, (JDIMENSION) cinfo->output_components); + + /* Allocate a virtual array to hold the image. */ + dest->image = (*cinfo->mem->request_virt_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + (JDIMENSION) (cinfo->output_width * cinfo->output_components), + cinfo->output_height, (JDIMENSION) 1); + + return (djpeg_dest_ptr) dest; +} + +#endif /* RLE_SUPPORTED */ diff --git a/freeimage241/Source/LibJPEG/wrtarga.c b/freeimage241/Source/LibJPEG/wrtarga.c new file mode 100644 index 0000000..cf104d2 --- /dev/null +++ b/freeimage241/Source/LibJPEG/wrtarga.c @@ -0,0 +1,253 @@ +/* + * wrtarga.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to write output images in Targa format. + * + * These routines may need modification for non-Unix environments or + * specialized applications. As they stand, they assume output to + * an ordinary stdio stream. + * + * Based on code contributed by Lee Daniel Crocker. + */ + +#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ + +#ifdef TARGA_SUPPORTED + + +/* + * To support 12-bit JPEG data, we'd have to scale output down to 8 bits. + * This is not yet implemented. + */ + +#if BITS_IN_JSAMPLE != 8 + Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */ +#endif + +/* + * The output buffer needs to be writable by fwrite(). On PCs, we must + * allocate the buffer in near data space, because we are assuming small-data + * memory model, wherein fwrite() can't reach far memory. If you need to + * process very wide images on a PC, you might have to compile in large-memory + * model, or else replace fwrite() with a putc() loop --- which will be much + * slower. + */ + + +/* Private version of data destination object */ + +typedef struct { + struct djpeg_dest_struct pub; /* public fields */ + + char *iobuffer; /* physical I/O buffer */ + JDIMENSION buffer_width; /* width of one row */ +} tga_dest_struct; + +typedef tga_dest_struct * tga_dest_ptr; + + +LOCAL(void) +write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors) +/* Create and write a Targa header */ +{ + char targaheader[18]; + + /* Set unused fields of header to 0 */ + MEMZERO(targaheader, SIZEOF(targaheader)); + + if (num_colors > 0) { + targaheader[1] = 1; /* color map type 1 */ + targaheader[5] = (char) (num_colors & 0xFF); + targaheader[6] = (char) (num_colors >> 8); + targaheader[7] = 24; /* 24 bits per cmap entry */ + } + + targaheader[12] = (char) (cinfo->output_width & 0xFF); + targaheader[13] = (char) (cinfo->output_width >> 8); + targaheader[14] = (char) (cinfo->output_height & 0xFF); + targaheader[15] = (char) (cinfo->output_height >> 8); + targaheader[17] = 0x20; /* Top-down, non-interlaced */ + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + targaheader[2] = 3; /* image type = uncompressed gray-scale */ + targaheader[16] = 8; /* bits per pixel */ + } else { /* must be RGB */ + if (num_colors > 0) { + targaheader[2] = 1; /* image type = colormapped RGB */ + targaheader[16] = 8; + } else { + targaheader[2] = 2; /* image type = uncompressed RGB */ + targaheader[16] = 24; + } + } + + if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * Write some pixel data. + * In this module rows_supplied will always be 1. + */ + +METHODDEF(void) +put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for unquantized full-color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */ + outptr[1] = (char) GETJSAMPLE(inptr[1]); + outptr[2] = (char) GETJSAMPLE(inptr[0]); + inptr += 3, outptr += 3; + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + +METHODDEF(void) +put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +/* used for grayscale OR quantized color output */ +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(*inptr++); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Write some demapped pixel data when color quantization is in effect. + * For Targa, this is only applied to grayscale data. + */ + +METHODDEF(void) +put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, + JDIMENSION rows_supplied) +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + register JSAMPROW inptr; + register char * outptr; + register JSAMPROW color_map0 = cinfo->colormap[0]; + register JDIMENSION col; + + inptr = dest->pub.buffer[0]; + outptr = dest->iobuffer; + for (col = cinfo->output_width; col > 0; col--) { + *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]); + } + (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); +} + + +/* + * Startup: write the file header. + */ + +METHODDEF(void) +start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + tga_dest_ptr dest = (tga_dest_ptr) dinfo; + int num_colors, i; + FILE *outfile; + + if (cinfo->out_color_space == JCS_GRAYSCALE) { + /* Targa doesn't have a mapped grayscale format, so we will */ + /* demap quantized gray output. Never emit a colormap. */ + write_header(cinfo, dinfo, 0); + if (cinfo->quantize_colors) + dest->pub.put_pixel_rows = put_demapped_gray; + else + dest->pub.put_pixel_rows = put_gray_rows; + } else if (cinfo->out_color_space == JCS_RGB) { + if (cinfo->quantize_colors) { + /* We only support 8-bit colormap indexes, so only 256 colors */ + num_colors = cinfo->actual_number_of_colors; + if (num_colors > 256) + ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors); + write_header(cinfo, dinfo, num_colors); + /* Write the colormap. Note Targa uses BGR byte order */ + outfile = dest->pub.output_file; + for (i = 0; i < num_colors; i++) { + putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile); + putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile); + } + dest->pub.put_pixel_rows = put_gray_rows; + } else { + write_header(cinfo, dinfo, 0); + dest->pub.put_pixel_rows = put_pixel_rows; + } + } else { + ERREXIT(cinfo, JERR_TGA_COLORSPACE); + } +} + + +/* + * Finish up at the end of the file. + */ + +METHODDEF(void) +finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) +{ + /* Make sure we wrote the output file OK */ + fflush(dinfo->output_file); + if (ferror(dinfo->output_file)) + ERREXIT(cinfo, JERR_FILE_WRITE); +} + + +/* + * The module selection routine for Targa format output. + */ + +GLOBAL(djpeg_dest_ptr) +jinit_write_targa (j_decompress_ptr cinfo) +{ + tga_dest_ptr dest; + + /* Create module interface object, fill in method pointers */ + dest = (tga_dest_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(tga_dest_struct)); + dest->pub.start_output = start_output_tga; + dest->pub.finish_output = finish_output_tga; + + /* Calculate output image dimensions so we can allocate space */ + jpeg_calc_output_dimensions(cinfo); + + /* Create I/O buffer. Note we make this near on a PC. */ + dest->buffer_width = cinfo->output_width * cinfo->output_components; + dest->iobuffer = (char *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (size_t) (dest->buffer_width * SIZEOF(char))); + + /* Create decompressor output buffer. */ + dest->pub.buffer = (*cinfo->mem->alloc_sarray) + ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1); + dest->pub.buffer_height = 1; + + return (djpeg_dest_ptr) dest; +} + +#endif /* TARGA_SUPPORTED */ diff --git a/freeimage241/Source/LibMNG/Changes b/freeimage241/Source/LibMNG/Changes new file mode 100644 index 0000000..6a9f8ef --- /dev/null +++ b/freeimage241/Source/LibMNG/Changes @@ -0,0 +1,792 @@ +----------------------------------------------------------- + +1.0.2 (Jul 7th 2001) +-------------------- + +in short: + +Another maintenance release with a few added extra's. + +------------------- + +bugfixes: +- B421427 - writes wrong format in bKGD and tRNS +- B434583 - compiler-warning if MNG_STORE_CHUNKS undefined + +core: +- added optimization option for MNG-video playback +- added processterm callback +- added late binding errorcode (not used internally) +- fixed memory-leak with delta-images (Thanks Michael!) +- added option to turn off progressive refresh for large images + +samples: + +contrib: + +doc: + +makefiles: + +autoconf: + +----------------------------------------------------------- + +1.0.1 (May 2nd 2001) +-------------------- + +in short: + +Maintenance release. +Fixed several memory-leaks with the help of Gregg Kelly, added/fixed some CMS +handling, exported JPEG functions from standard DLL, and some other minor fixes. + +The CMS fix now makes libmng automagically work in MNG_FULL_CMS mode as a +sRGB compliant system. YOU WILL NEED TO CHANGE THIS IF YOU ARE NOT ON AN sRGB +COMPLIANT SYSTEM AND WANT TO USE CMS!!!! +(look in libmng.h for the proper function-calls) + +------------------- + +bugfixes: + +core: +- added MEND processing callback +- fixed first FRAM_MODE=4 timing problem +- added handle status-copy function (use with care) +- exported JPEG functions from standard DLL +- added BGRA8 canvas with premultiplied alpha (contrib by Gregg Kelly) +- fixed problem with display_reset/display_resume (Thanks Gregg!) +- fixed several memory-leaks (Thanks Gregg!) +- fixed reset_rundata to drop all objects (Thanks again, Gregg!) +- fixed problem with cms profile being created multiple times when both + iCCP & cHRM/gAMA are present (And again... Gregg) +- moved mng_clear_cms to libmng_cms +- added "default" sRGB generation (Thanks Marti!) + +samples: + +contrib: + +doc: + +makefiles: + +autoconf: + +----------------------------------------------------------- + +1.0.0 (Feb 6th 2001) +-------------------- + +in short: + +First public release. Finally(!) + +This is the 0.9.5 CVS version, which will never be released, because I feel it +is now ready for a public release. So apart from the version-numbers here and +there, all other changes are listed under 0.9.5. + +This library will work with every MNG/JNG known and available to me. Note that +there are still parts that need to be coded, and that MNG support is around +90-95% (JNG at 100%). It is however compliant with the latest and greatest +MNG 1.0 specification. + +I hope to dedicate a bit more time this year to finish up full support and fill +in the remaining blanks. But this is coming out of my spare time. And extra +help is always appreciated. + +Please enjoy! + +Gerard + +----------------------------------------------------------- + +0.9.5 (no release) +------------------ + +in short: + +intermediate CVS + +------------------- + +bugfixes: +B129681 - fixed compiler warnings SGI/Irix (thanks Dimitri) + +core: +- fixed compiler-warnings Mozilla (thanks Tim) +- fixed timing-problem with switching framing_modes +- fixed some small compiler warnings (thanks Nikki) + +samples: + +contrib: +- fixed library-paths for MSVC DLL project (thanks Chad) + +doc: + +makefiles: +- added makefile for DJGPP (thanks Silvio) + +autoconf: + +----------------------------------------------------------- + +0.9.4 (Jan 19th 2001) +---------------------- + +in short: + +Now that the MNG spec is at 1.0, this should be the last beta. There's a few +small changes to make it inline with the spec, and a couple of bug-fixes. +This is a serious release-candidate for libmng-1.0!! +Please... test test test test!! + +------------------- + +bugfixes: +B123314 - fixed number of TERM related problems +B123322 - fixed unwanted repetition in mng_readdisplay() +B123443 - fixed by Ralph +B124910 - fixed definition for WIN32_LEAN_AND_MEAN (thanks Chad) +B125750 - fixed by Ralph +B125756 - fixed mixup of data- & function-pointers (thanks Dimitri) +B127517 - changed inclusion of the lcms header file for non-windows platforms + +core: +- version numbers +- fixed possible loop in display_resume() (Thanks Vova!) +- fixed unwanted repetition in mng_readdisplay() +- changed inclusion of the lcms header file for non-windows platforms +- changed IHDR filter_method check for PNGs +- moved restore of object 0 to libmng_display +- added restore of object 0 to TERM processing (B123314) +- fixed TERM delay processing (B123314) +- fixed TERM end processing when count = 0 (B123314) +- changed callback convention for MSVC (Thanks Chad) +- fixed mixup of data- & function-pointers (thanks Dimitri) +- added support for "nEED MNG-1.0" +- added errorcode for MAGN methods +- added errorchecking for MAGN methods +- removed "old" MAGN methods 3 & 4 +- added "new" MAGN methods 3, 4 & 5 +- removed test filter-methods 1 & 65 +- set default level-set for filtertype=64 to all zeroes + +samples: + +contrib: +- added GTK mng-view example by Vova Babin +- added MSVC MNGview sample by Nikolaus Brennig +- updated Jason Summer's mngplg to version 0.9.2 + (that's mngplg-0.9.2 based on libmng-0.9.3 !!!) +- rearranged contrib directory slightly +- added MSVC project to build libmng.dll by Chad Austin + +doc: +- added README.dll +- added README.config + +makefiles: +- added a makefile for MS Visual C++ (Thanks to Atsushi Matsuda) + +autoconf: +- fixed configure.in for lcms (FreeBSD port by Mikhail Teterin) +- by default configure includes CMS support if lcms is present + +----------------------------------------------------------- + +0.9.3 (October 29th 2000) +------------------------- + +in short: + +Another beta release. The number of changes in the MNG specification have +resulted in a lot of new code and some changed code. At the same time I saw +no need to withhold some new functionality as it was pretty clear there was +going to be another beta-round. If things go well, I'm going to try to release +libmng 1.0.0 very shortly after this one. + +Many thanks to a lot of people for helping out, sending contributions, making +suggestions and testing this little baby. This would get nowhere without YOU!!! + +- fixed bug 111300/117103 +- added workaround for faulty PhotoShop iCCP chunk +- added MAGN/JDAA chunks +- added support for new filter_types +- added PNG/MNG spec version indicators +- added BCB mngview contribution by Andy Protano +- added BCB mngdump; a GUI-based MNG dumping utility (Andy Protano) +- implemented support for nEED "draft nn" +- implemented app-defined support for bKGD for PNG images +- removed trace-options from default SO/DLL builds (!!!) +- raised initial maximum canvas size to 10000x10000 (!!!) + (an App that wants to protect from overly large images should call + mng_set_maxcanvassize() with appropriate values) +- fixed other assorted stuff + +------------------- + +bugfixes: +B111300 - fixup for improved portability +B117103 - fixed compilation errors on *nix with lcms (thanks Ralph!) + +core: +- fixed compiler-warnings from Mozilla +- added check for simplicity-bits in MHDR +- added workaround for faulty PhotoShop iCCP chunk +- fixed app-supplied background restore +- fixed TERM processing delay of 0 msecs +- fixed write-code for zTXt & iTXt +- fixed read-code for iTXt +- added MAGN chunk +- fixed sRGB precedence for gamma_only corection +- added support for new filter_types +- fixed problem with no refresh after TERM +- fixed DEFI behavior +- fixed inclusion parameters to make the external libs work together +- added export of zlib functions from windows dll +- fixed timing & refresh behavior for single PNG/JNG +- removed trace-options from default SO/DLL builds (!!!) +- fixed MAGN rounding errors (thanks Matthias!) +- fixed small timing problem when FRAM delay = 0 +- fixed simplicity-check in compliance with draft 81/0.98a +- fixed alpha-blending for all alpha-canvasstyles +- added support for alpha-depth prediction +- fixed processing of unknown critical chunks +- removed test-MaGN +- added PNG/MNG spec version indicators +- implemented support for nEED +- added support for JDAA +- added functions to retrieve PNG/JNG specific header-info +- added optional support for bKGD for PNG images +- raised initial maximum canvas size to 10000x10000 +- added support for delta-JNG +- added callback to process non-critical unknown chunks +- fixed support for delta-images during read() / display() +- added closestream() processing for mng_cleanup() +- fixed delta-processing behavior +- added storage for pixel-/alpha-sampledepth for delta's +- implemented delayed delta-processing +- fixed putchunk_plte() to set bEmpty parameter (thanks Ben!) +- added errorcode for delayed delta-processing +- added get/set for bKGD preference setting +- added get function for interlace/progressive display +- fixed bug in empty PLTE handling +- fixed seperate read() & display() processing +- fixed tRNS processing for gray-image < 8-bits + +samples: +- added BCB mngview contribution by Andy Protano + +contrib: +- added BCB mngdump; a GUI-based MNG dumping utility (Andy Protano) + +doc: +- updated RPM spec-file by MATSUURA Takanori +- updated README.contrib + +makefiles: +- fixed some stuff in automake/autoconf/libtool +- fixed auto* for bug B117103 + +----------------------------------------------------------- + +0.9.2 (August 7th 2000) +----------------------- + +in short: + +Third beta release! Last one??? + +!!IMPORTANT!! All file-names are now prefixed with "libmng_" !!IMPORTANT!! + +Many thanks to Albert Chin-A-Young for his contribution of the +autoconf/automake/libtool stuff and to Ralph Giles for helping me +put it in the right places. + +There's a special README.autoconf so please read it! + +- fixed bug 110320/110546/110547/111096 +- added several status retrieval functions +- fixed other small bugs in display processing +- fixed number of small problems and documentation typos +- added autoconf/automake/libtool +- added latest MNG plugin (0.9.0) by Jason Summers + +------------------- + +bugfixes: +B110320 - fixed GCC warning about mix-sized pointer math +B110546 - fixed for improperly returning UNEXPECTEDEOF +B110547 - fixed bug in interlace code +B111096 - fixed large-buffer read-suspension + +core: +- version numbers +- fixed small bugs in display processing +- removed Nextbackxxx fields (no longer used) +- fixed problem with trace-functions improperly wrapped +- put specific code in add_chunk() inside MNG_SUPPORT_WRITE wrapper +- fixed documentation typos +- fixed wrapping of suspension parameters +- added status_xxxx functions +- added trace-codes/-strings for status_xxxxx functions +- changed file-prefixes +- added function to set simplicity field +- added trace-code/-string for updatemngsimplicity +- fixed putchunk_unknown() function + +samples: + +contrib: +- added latest MNG plugin (0.9.0) by Jason Summers + +doc: +- version numbers +- added autoconf readme +- version numbers in RPM stuff + +makefiles: +- fixed for new file-prefix +- added autoconf/automake/libtool + +----------------------------------------------------------- + +0.9.1 (July 26th 2000) +---------------------- + +in short: + +Second beta release. + +Given the enormous amount of bug-reports (not ;-), this will most likely +be one of the last betas. If things remain upright, the first public release +(1.0.0) is fairly eminent in the weeks to come... + +- added SDL mng player by Ralph Giles to contributions +- fixed timing and added internal buffering for I/O-suspension scenarios +- added get routines for internal display-state variables (frame/layer/playtime) +- changed read-processing for improved I/O-suspension (internal buffering) +- fixed several problems with create- & write-support +- added a load of documentation +- lots of small stuff + +------------------- + +bugfixes: + +core: +- fixed mandatory BACK color to be opaque +- changed mng_display_resume to allow to be called after a suspension + return with MNG_NEEDMOREDATA +- changed comments to indicate modified behavior for timer & suspension breaks +- added variables for go_xxxx processing +- implemented support for freeze/reset/resume & go_xxxx +- added trace-codes/-strings for special display processing +- added variables for improved timing support +- added support for improved timing +- added get routines for internal display variables +- added get/set routines for suspensionmode variable +- added trace-code/-string for get/set suspensionmode +- added trace-codes/-strings for get/set display variables +- added support for improved I/O-suspension +- changed read-processing for improved I/O-suspension +- added trace-code/-string for read_databuffer (I/O-suspension) +- added suspendbuffer constants +- changed EOF processing behavior +- fixed TERM delay processing +- changed pre-draft48 frame_mode=3 to frame_mode=1 +- added callbacks for SAVE/SEEK processing +- added trace-codes/-strings for SAVE/SEEK callbacks +- added variable for NEEDSECTIONWAIT breaks +- added trace-codes/-strings for get/set sectionbreaks +- added NEEDSECTIONWAIT error-code/-string +- added macro + routine to set returncode without calling error callback +- added trace-code/-string for special error routine +- changed default readbuffer size from 1024 to 4200 +- added variable for freeze & reset processing +- fixed storage of images during mng_read() +- fixed support for mng_display() after mng_read() +- added error cleanup processing +- fixed support for mng_display_reset() +- fixed suspension-buffering for 32K+ chunks +- added function to set frame-/layer-count & playtime +- added trace-code/-string for updatemngheader +- added error-code/-string for updatemngheader if not a MNG +- fixed creation-code +- fixed writing of signature +- fixed several chunk-writing routines + +samples: +- fixed the libmng.pas module in line with libmng.h + +contrib: +- added the SDL based mngplay viewer by Ralph Giles + +doc: +- extended the RPM contribution by MATSUURA Takanori +- added libmng.txt, a full description of the library and its usage +- added man-pages for mng(5), jng(5) and libmng(3) + +makefiles: + +----------------------------------------------------------- + +0.9.0 (June 30th 2000) +---------------------- + +in short: + +This is the first beta!!! Yippee!!! + +Thanks to all the people who helped to guide me in the right direction. +You know who you are! + +A special thanks to the guys with early implementations, who stood by and +put up with my whims :-) + +changes over 0.5.3: + +- updated mngplg to 0.4.1 (the latest & greatest) +- changed refresh parameters to 'x,y,width,height' + +----------------------------------------------------------- + +0.5.3 (never released) +---------------------- + +in short: + +This is a working version only; the next release will be 0.9.0 (first Beta!) + +There are a few incompatible changes with previous versions. The userdata +variable has been changed from mng_uint32 to mng_ptr to accomodate 64-bit +systems. For the same reason memory allocation size parameters have been +changed to a mng_size_t type which is a typedef of size_t. + +Thanks to Aleks Jakulin for helping to iron out some 64-bit platform issues! + +- implemented the update-region parameters of the refresh callback +- added support for most common delta-image options +- added an animation-speed modifier +- added an image-level parameter for the processtext callback +- updated mngplg to 0.4.0 (supports JNG, full CMS, and other enhancements!) +- fixed a lot of small things +- added support for PPLT chunk +- fixed to support 64-bit platforms + +------------------- + +bugfixes: + +core: +- added processing of color-info on delta-image +- fixed handling of empty SAVE chunk +- fixed display of stored JNG images +- fixed problem with BASI-IEND as object 0 +- changed the version parameters (obviously) +- added update-region parms for refresh calback +- added Needrefresh parameter +- added initialization of update-region for refresh +- added initialization of Needrefresh parameter +- changed progressive-display processing +- added tracecodes for tracing JPEG progression +- added tracing of JPEG calls +- added Deltaimmediate parm for faster delta-processing +- added extra checks for delta-images +- many changes to support delta-images +- optimized some store_xxx routines +- fixed some small things (as precaution) +- fixed possible trouble if IEND display-processing got broken up +- fixed nasty bug with embedded PNG after delta-image +- added processing of PLTE & tRNS for delta-images +- added processing of PLTE/tRNS & color-info for delta-images in the + ani_objects chain +- fixed problem with color-correction for stored images +- added get/set for speedtype to facilitate testing +- added trace-codes & -strings for get/set speedtype +- added speed-modifier to timing routine +- added get-routine of imagelevel for processtext callback +- added trace-code & -string for get imagelevel +- added administration of imagelevel parameter +- added support for PPLT chunk +- added trace-codes & -strings for PPLT chunk processing +- fixed problem with incorrect gamma-correction +- fixed inclusion of IJG read/write code +- fixed problem with 16-bit GA format +- fixed problem with cheap transparency for 4-bit gray +- fixed display_xxxx routines for interlaced images +- added precaution against faulty iCCP chunks from PS +- changed userdata variable to mng_ptr +- added typedef for mng_size_t +- changed size parameter for memory allocation to mng_size_t +- fixed compiler-warning for non-initialized iB variable +- changed definition for 32-bit ints (64-bit platforms) +- changed definition for mng_handle (64-bit platforms) +- swapped refresh parameters +- fixed initialization routine for new mng_handle type +- added inclusion of stdlib.h for abs() +- fixed some 64-bit warnings +- fixed incompatible return-types + +samples: + +contrib: +- updated mngplg to 0.3.0 (supports JNG & full color-correction!) +- updated mngplg to 0.4.0 (Jason is picking up the pace ;-) + +doc: +- added rpm directory with rpm spec-file (contributed by MATSUURA Takanori) + +makefiles: +- changed makefile.linux to reflect versionnr for shared-lib +- changed makefile.linux to depend on mng_conf.h & mng_types.h + +----------------------------------------------------------- + +0.5.2 (June 10th 2000) +---------------------- + +in short: + +This is the third release for developers +Another milestone since JNG is now fully supported +The next release will most likely be numbered 0.9.0 as the first Beta!! + +Fixed bug 106017 & 106019 +Added many constants regarding chunk-property values +Implemented full JNG support +Added all the error- & trace-strings +Added get/set routines for default ZLIB/IJG parameters +Added a generic makefile for Unix platforms (contributed by Tim Rowley) +Added canvasstyle for separate RGB + A canvas (eg. mozilla-style) +Separated configuration-options into a separate file: "mng_conf.h" +Fixed stuff for generic Unix compilation (contributed by Tim Rowley) +Upgraded to lcms1.0.6 (now supports 16-bit endian-peculiarities) +Added a makefile for Linux ELF & fixed some code-issues to go along with gcc +Added support for suspended input-buffer processing +Implemented the display-routines for RGBA/ARGB/BGRA/ABGR canvasstyles +Implemented the application background-restore functionality +Fixed & tested the mngtree Unix-sample (runs on Linux-RH6.2 with libmng.so) +Upgraded mngplg to v0.2.2 (based on the latest code including JNG) +Fixed a lot of other assorted stuff + +------------------- + +bugfixes: +B003(106017) - fixed problem with being proprietary to BCB +B004(106019) - fixed problem when MNG_SUPPORT_WRITE not defined + +core: +- bumped version-numbers up to 0.5.2 (yeah, really) +- fixed support for IJGSRC6B +- cleaned up some code regarding mixed support-options +- complemented constants for chunk-property values +- fixed MNG_UINT_pHYg value +- implemented JNG support +- fixed problem with DEFI clipping +- added error telltale strings & support +- added trace telltale strings & support +- added support for global color-chunks inside TERM/LOOP +- added support for global PLTE,tRNS,bKGD inside TERM/LOOP +- added default IJG compression parameters and such +- moved init of default zlib parms to "mng_hlapi.c" +- added init of default IJG parms +- added support for get/set of zlib/IJG default parms +- added tracestrings for global animation color-chunks +- added tracestrings for get/set of default ZLIB/IJG parms +- added tracestrings for global PLTE,tRNS,bKGD +- added framenr/layernr/playtime to object header +- added initialization of framenr/layernr/playtime +- changed ani_create calls not returning object pointer +- create ani objects always (not just inside TERM/LOOP) +- fixed inconsistancy with freeing global iCCP profile +- fixed minor bugs 16-bit pixel-handling +- added object promotion routine (PROM handling) +- added trace-codes & -strings for image-object promotion +- added trace-codes & -strings for delta-image processing +- added error-codes & -strings for delta-image processing +- added support for delta-image processing +- added ani-object routines for delta-image processing +- added delta-image fields +- added compression/filter/interlace fields to object-buffer for + delta-image processing +- added delta-image row-processing routines +- fixed up punctuation in several files (contributed by Tim Rowley) +- removed useless definition in "mng_chunks.h" (contributed by Tim Rowley) +- fixed pointer confusion in "mng_display.c" (contributed by Tim Rowley) +- fixed inclusion for memcpy (contributed by Tim Rowley) +- added mng_int32p (contributed by Tim Rowley) +- added internal delta-image processing callbacks +- separated configuration-options into "mng_conf.h" +- changed to most likely configuration +- added RGB8_A8 canvasstyle +- added getalphaline callback for RGB8_A8 canvasstyle +- fixed some makeup for Linux gcc compile +- implemented app bkgd restore routines +- implemented RGBA8, ARGB8, BGRA8 & ABGR8 display routines +- added support for RGB8_A8 canvasstyle +- added support for suspended input-buffer processing +- added mng_read_resume HLAPI function to support read-suspension +- fixed timer-handling to run with Mozilla (Tim Rowley) +- fixed alpha-handling for alpha canvasstyles +- fixed some compilation-warnings (contrib Jason Morris) + +samples: +- fixed mngview(delphi) to work with the new core +- synchronized libmng.pas(delphi) with the new libmng.h header +- removed the error- & trace-strings from libmng.pas(delphi) +- fixed mngtree(Unix) to compile on Linux (runs with libmng.so) +- added makefile.linux for mngtree(Unix) (tested on RedHat6.2) + +contrib: +- updated mngplg to 0.2.2 (based on latest code; supports JNG!) + +doc: +- this file obviously +- added Tim Rowley as contributing author +- changed the examples.readme doc +- updated the design-schematics in line with the current code + +makefiles: +- changed the directory to "makefiles" to avoid name-conflicts +- added generic Unix makefile (thanks to Tim Rowley) +- added Linux ELF makefile (tested on RedHat6.2) + +----------------------------------------------------------- + +0.5.1 May 16th 2000 +------------------- + +in short: + +This is the second release for developers +It's a bit of a milestone since all the chunk functionality is in place and +functioning (read, examine, create & write) +This version is incompatible with 0.5.0 since some of the callback prototypes +have changed (should be the last time that happens!) +There are a few more samples and even a real contribution! + +Fixed bug 105795 & 105797 +Fixed a mis-alignment in animation-timing +Added chunk-access functions +Finished all chunk-storage routine-bits +Finished all chunk-write routines +Changed the callback prototypes to allow error-reporting back to the library +Fixed some routines to allow for callback error-reporting +Added version-control functions & constants +Added two functions to set display- & sRGB-profile from memory +Moved CRC table to dynamic structure (for improved thread-safety) +Added SAVE & SEEK save&restore functionality +Finished the application-based CMS-callbacks +Fixed a few BCB specifics +Changed the Win32 DLL and samples to use __stdcall +Did some more assorted little changes +Added 2 BCB samples +Added 1 Unix sample +Added the MNG plugin by Jason Summers in the contrib section +Changed some documents to reflect these changes + +------------------- + +bugfixes: +B001(105795) - fixed wrong lcms call & memory-leak for gammatables +B002(105797) - fixed problem with missing sRGB profile + +core: +- changed chunk iteration function +- added chunk access functions +- added version control constants & functions +- changed strict-ANSI stuff +- added set_outputprofile2 & set_srgbprofile2 +- added empty-chunk put-routines +- added version_dll & VERSION_DLL (for consistency) +- added version control explanatory text & samples +- added iteratechunk callback definition +- improved definitions for DLL support +- added 8-bit palette definition +- added general array definitions +- added MNG_NULL definition +- changed most callback prototypes to allow the app + to report errors during callback processing +- added CRC table to main structure (for thread-safety) +- added iPLTEentries for checking hIST-length +- changed palette definition to exported palette-type +- removed frozen indicator +- added create/write indicators +- added eMNGma hack (will be removed in 1.0.0 !!!) +- added TERM animation object pointer (easier reference) +- added saved-data structure for SAVE/SEEK processing +- added some errorcodes +- added application errorcodes (used with callbacks) +- moved chunk-access errorcodes to severity 5 +- added chunk-access function trace-codes +- changed trace to macro for callback error-reporting +- added save_state & restore_state trace-codes +- put in some extra comments +- fixed layout for sBIT, PPLT +- changed write callback definition +- fixed layout for PPLT again (missed deltatype ?!?) +- cleaned up left-over teststuff in the BACK chunk routine +- changed CRC initialization to use dynamic structure + (wasn't thread-safe the old way !) +- filled in many missing sequence&length checks +- filled in many missing chunk-store snippets +- added checks for running animations +- filled remaining write routines +- fixed read_pplt with regard to deltatype +- added callback error-reporting support +- added pre-draft48 support (short MHDR, frame_mode, LOOP) +- fixed chunk-storage bit in several routines +- supplemented the SAVE & SEEK display processing +- added init of iPLTEcount +- changed calling-convention definition +- changed status-handling of display-routines +- added versioning-control routines +- filled the write routine +- fixed frame_delay misalignment +- added sanity check for frozen status +- changed display_mend to reset state to initial or SAVE +- added save_state and restore_state for SAVE/SEEK/TERM + processing +- added process_save & process_seek routines +- changed and filled iterate-chunk function +- added getchunk functions +- added putchunk functions +- added empty-chunk put-routines +- filled application-based color-management routines +- added creatememprofile +- filled the deflatedata routine +- added cleanup of saved-data (SAVE/SEEK processing) +- moved the actual write_graphic functionality from mng_hlapi.c + to it's appropriate function in the mng_write.c module +- moved standard header includes into mng_types.h + (stdlib/mem for mem-mngmt & math for fp gamma-calc) +- added getimgdata & putimgdata functions + +samples: +- fixed mngview(delphi) to work with the new core +- synchronized libmng.pas(delphi) with the new libmng.h header +- added mngtree(bcb) sample +- added bogus(bcb) sample +- added mngtree(unix) sample + +contrib: +- added mngplg 0.1.0 / a MNG plugin for Win32 by Jason Summers + +doc: +- added this changes.readme file +- changed the samples.readme doc accordingly +- changed the contrib.readme doc accordingly + +----------------------------------------------------------- + +0.5.0 May 1st 2000 +------------------ + +in short: + +This is the first developers release. +It's roughly about 60% done. diff --git a/freeimage241/Source/LibMNG/LICENSE b/freeimage241/Source/LibMNG/LICENSE new file mode 100644 index 0000000..bae3a82 --- /dev/null +++ b/freeimage241/Source/LibMNG/LICENSE @@ -0,0 +1,56 @@ +/* ************************************************************************** */ +/* * * */ +/* * COPYRIGHT NOTICE: * */ +/* * * */ +/* * Copyright (c) 2000 Gerard Juyn (gerard@libmng.com) * */ +/* * [You may insert additional notices after this sentence if you modify * */ +/* * this source] * */ +/* * * */ +/* * For the purposes of this copyright and license, "Contributing Authors" * */ +/* * is defined as the following set of individuals: * */ +/* * * */ +/* * Gerard Juyn * */ +/* * * */ +/* * The MNG Library is supplied "AS IS". The Contributing Authors * */ +/* * disclaim all warranties, expressed or implied, including, without * */ +/* * limitation, the warranties of merchantability and of fitness for any * */ +/* * purpose. The Contributing Authors assume no liability for direct, * */ +/* * indirect, incidental, special, exemplary, or consequential damages, * */ +/* * which may result from the use of the MNG Library, even if advised of * */ +/* * the possibility of such damage. * */ +/* * * */ +/* * Permission is hereby granted to use, copy, modify, and distribute this * */ +/* * source code, or portions hereof, for any purpose, without fee, subject * */ +/* * to the following restrictions: * */ +/* * * */ +/* * 1. The origin of this source code must not be misrepresented; * */ +/* * you must not claim that you wrote the original software. * */ +/* * * */ +/* * 2. Altered versions must be plainly marked as such and must not be * */ +/* * misrepresented as being the original source. * */ +/* * * */ +/* * 3. This Copyright notice may not be removed or altered from any source * */ +/* * or altered source distribution. * */ +/* * * */ +/* * The Contributing Authors specifically permit, without fee, and * */ +/* * encourage the use of this source code as a component to supporting * */ +/* * the MNG and JNG file format in commercial products. If you use this * */ +/* * source code in a product, acknowledgment would be highly appreciated. * */ +/* * * */ +/* ************************************************************************** */ +/* * * */ +/* * Parts of this software have been adapted from the libpng package. * */ +/* * Although this library supports all features from the PNG specification * */ +/* * (as MNG descends from it) it does not require the libpng package. * */ +/* * It does require the zlib library and optionally the IJG jpeg library, * */ +/* * and/or the "little-cms" library by Marti Maria (depending on the * */ +/* * inclusion of support for JNG and Full-Color-Management respectively. * */ +/* * * */ +/* * This library's function is primarily to read and display MNG * */ +/* * animations. It is not meant as a full-featured image-editing * */ +/* * component! It does however offer creation and editing functionality * */ +/* * at the chunk level. * */ +/* * (future modifications may include some more support for creation * */ +/* * and or editing) * */ +/* * * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/LibMNG.dsp b/freeimage241/Source/LibMNG/LibMNG.dsp new file mode 100644 index 0000000..a672f53 --- /dev/null +++ b/freeimage241/Source/LibMNG/LibMNG.dsp @@ -0,0 +1,248 @@ +# Microsoft Developer Studio Project File - Name="LibMNG" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=LibMNG - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LibMNG.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LibMNG.mak" CFG="LibMNG - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LibMNG - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "LibMNG - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LibMNG - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "..\Zlib" /I "..\libjpeg" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "LibMNG - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\Zlib" /I "..\libjpeg" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "LibMNG - Win32 Release" +# Name "LibMNG - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\libmng_callback_xs.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_chunk_io.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_chunk_prc.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_chunk_xs.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_cms.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_display.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_dither.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_error.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_filter.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_hlapi.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_jpeg.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_object_prc.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_pixels.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_prop_xs.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_read.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_trace.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_write.c +# End Source File +# Begin Source File + +SOURCE=.\libmng_zlib.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\libmng.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_chunk_io.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_chunk_prc.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_chunks.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_cms.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_conf.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_data.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_display.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_dither.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_error.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_filter.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_jpeg.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_memory.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_object_prc.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_objects.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_pixels.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_read.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_trace.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_types.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_write.h +# End Source File +# Begin Source File + +SOURCE=.\libmng_zlib.h +# End Source File +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/LibMNG/README b/freeimage241/Source/LibMNG/README new file mode 100644 index 0000000..99c460f --- /dev/null +++ b/freeimage241/Source/LibMNG/README @@ -0,0 +1,38 @@ +libmng 1.0.1 +------------ + +First maintenance release! + +There's been some changes in the CMS profile handling, that should make it +easier for sRGB-compliant systems. Non-sRGB compliant systems will still need +some extra work if they want to use MNG_FULL_CMS with lcms. But this has always +been so, so it's not an extra step anyway. +(Many thanks to Marti, Ivan & Warwick for their help & comments!) + +Gregg Kelly has been helpful in locating a couple of memory-leaks, and make +the library even better. + +The default Windows DLL that's part of the Windows zip-files now also exports +the JPEG library function calls (ijgsrc6b). Note that there's a new Delphi +component (TNGImage) that makes it a snap to work with PNG/JNG & MNG images +within Delphi. + +Please enjoy! + +Gerard + + +For more information please visit: + +The official libmng web-site: + http://www.libmng.com + +Libmng's community on SourceForge: + https://sourceforge.net/project/?group_id=5635 + +The official MNG homepage: + http://www.libpng.org/pub/mng + +The official PNG homepage: + http://www.libpng.org/pub/png + diff --git a/freeimage241/Source/LibMNG/README.config b/freeimage241/Source/LibMNG/README.config new file mode 100644 index 0000000..d5cd454 --- /dev/null +++ b/freeimage241/Source/LibMNG/README.config @@ -0,0 +1,104 @@ +Configuration options in libmng +=============================== + +The library is fairly configurable through the use of a number of defines. +Please note however that certain defines are for internal use only. +The following list gives a summary of options that can be used externally to +define the functionality of the library: + +======================================== + +#define MNG_BUILD_DLL + +This is used to indicate that a "standard" DLL should result from compiling +the library. Please note the remarks in README.dll if you intend to work +with the library as a DLL. The purpose of this option is to ensure that +DLL builds have the same set of functions. + +#define MNG_BUILD_SO + +This is used to indicate that a "standard" shared library (SO) should result +from a compilation. The purpose of this option is to ensure that all +shared libraries generated this way will have the same set of functions. + +#define MNG_USE_DLL / #define MNG_USE_SO + +These should be used when including the library header in the compilation +of an application to indicate that the compiler/linker must take the +necessary steps to make the binary executable to use the standard DLL +or shared library (SO). + +#define MNG_SKIP_ZLIB / #define MNG_SKIP_LCMS / #define MNG_SKIP_IJG6B + +Use these in conjunction with MNG_USE_DLL / MNG_USE_SO. This is useful if +you only need the external definitions of the MNG library and not the others, +which will speed up the compilation process. + +#define MNG_SUPPORT_FULL / #define MNG_SUPPORT_LC / #define MNG_SUPPORT_VLC + +These can be used to indicate the level of MNG spec compliance required. +Currently only full MNG compliance is supported. + +#define MNG_SUPPORT_IJG6B + +This can be used to indicate if JNG support is required. This option will +include the IJG JPEG-library. Note that MNG_SUPPORT_FULL will automatically +set this option. Use this only if you need JNG support with MNG-(V)LC. + +#define MNG_FULL_CMS / #define MNG_GAMMA_ONLY / #define MNG_NO_CMS / +#define MNG_APP_CMS + +These indicate the color-correction support level of the library. +If you are on a platform that supports lcms (Little CMS by Marti Maria Saguar) +then it is highly recommended to define MNG_FULL_CMS. +If your platform has it's own CMS then select MNG_APP_CMS and be sure to +include the appropriate callbacks in your app. +In all other cases it is recommended to define MNG_GAMMA_ONLY. + +#define MNG_SUPPORT_READ / #define MNG_SUPPORT_WRITE / +#define MNG_SUPPORT_DISPLAY + +These indicate the high-level support for reading, writing and/or +displaying files. Note that in order to display a file, you'll need to read +it first. (yes, really!) + +#define MNG_STORE_CHUNKS + +This indicates that the library should store chunk-information when reading +a file. This information can then be processed through the +MNG_ITERATE_CHUNKS() function. Note that you must specify this option if +you want to create and write a new file. + +#define MNG_ACCESS_CHUNKS + +This is used to indicate that the app may need access to internally stored +chunk information. MNG_STORE_CHUNKS must be defined as well for this option +to function properly. + +#define MNG_INTERNAL_MEMMNGMT + +You can use this to have the library handle it's own memory allocation and +deallocation through the "standard" memory functions. This option is turned +off by default, which means your app must define the memory callbacks. + +#define MNG_ERROR_TELLTALE + +Set this on to allow human-readable error-messages to be included in the +library and the error function and callback. + +#define MNG_BIGENDIAN_SUPPORTED + +This option should be used to indicate the hardware is based on big endian +integers. + +#define MNG_SUPPORT_TRACE / #define MNG_TRACE_TELLTALE + +These two can be used when debugging an app. You'll need to have the trace +callback setup also. This allows for a rather thorough investigation of the +libraries function paths. + +======================================== + +Any other optional defines you may encounter are for internal use only. +please do not specify them externally. In case of doubt, consult the +support email lists. More info can be found on http://www.libmng.com diff --git a/freeimage241/Source/LibMNG/README.contrib b/freeimage241/Source/LibMNG/README.contrib new file mode 100644 index 0000000..386b6d5 --- /dev/null +++ b/freeimage241/Source/LibMNG/README.contrib @@ -0,0 +1,66 @@ +The contrib directory contains contributions made by fellow enthousiasts. +(Check the web-sites for the latest versions) + +---------------------------------------------------------------------- + +mngplg - A Netscape plugin for MNG - by Jason Summers + +http://pobox.com/~jason1/imaging/mngplg/ + +The very first contribution, and what a start! +GIF look out, MNG is on the prowl and ready to swat you like a fly! + +---------------------------------------------------------------------- + +mngplay - An SDL based MNG viewer - by Ralph Giles + +http://snow.ashlu.bc.ca/~giles/mng/ + +Another nice contribution. View MNG files on practically any platform +with this standalone viewer. +Source-code only; Requires SDL library and libmng.so + +---------------------------------------------------------------------- + +mngview - A BCB port of the Delphi sample - by Andy Protano + +I have added this nice little port to the BCB samples directory. +It adds a nifty progressbar while reading a file. Excellent work! +Requires libmng.dll +(note: this is in the BCB samples directory) + +---------------------------------------------------------------------- + +mngdump - A BCB GUI-based dump utility - by Andy Protano + +Andy has sent me this fully functional MNG dump utility, that gives +detailed information of the contents of any MNG file. +Requires libmng.dll + +---------------------------------------------------------------------- + +mng-view - A GTK-based MNG viewer - by Vova Babin + +Vova has been hacking away with the libmng code and has come up with +this nice little sample how to write a MNG viewer using GTK. +Thanks mate! +Source-code only +Requires GTK+ (1.2 or higher) and libmng (0.9.2 or higher) + +---------------------------------------------------------------------- + +mngview - Another MNG viewer; this one for MSVC - by Nicholaus Brennig + +A welcome contribution from Nicholaus. Author of SlowView. A very nice +image-handling utility for Windows. A welcome contribution since there +have been numerous questions about linking libmng with MSVC. +Well, look no further. Here it is! + +---------------------------------------------------------------------- + +MSVC libmng project - A MSVC project to build libmng.dll - by Chad Austin + +Chad has contributed some project-files that you could use to build +libmng.dll with MSVC. Please be sure to read the README file included. + +---------------------------------------------------------------------- diff --git a/freeimage241/Source/LibMNG/README.examples b/freeimage241/Source/LibMNG/README.examples new file mode 100644 index 0000000..66dc5cb --- /dev/null +++ b/freeimage241/Source/LibMNG/README.examples @@ -0,0 +1,43 @@ +The samples are in platform-specific directories. + +!!! contributions are very welcome !!! + + +bcb - Borland C++ Builder (3.0) +------------------------------- + +win32dll - sample project to create a Windows dll. Requires zlib1.1.3, + IJG jpgsrc6b and lcms1.0.6. The directories containing these + libraries must be at the same level as the libmng directory. + So if you're in the directory with this file and the libmng + sources, they should be in ..\zlib , ..\jpgsrc6b and ..\lcms + respectively. + +!!! To run the other Win32 samples you need to copy the libmng.dll + file from here into the sample's directory !!! + +mngtree - sample project to create a little command-line tool that dumps + the chunk-structure of a given file onto stdout. + +bogus - a completely bogus example on how to create a perfectly valid + (though slightly biased) MNG. + +mngview - port of the Delphi mngview sample. contributed by Andy Protano. + see also README.contrib + + +delphi - Borland Delphi (3.0+) +------------------------------ + +mngview - sample project for a simple mng-viewer. The general unit in + the delphi directory was translated from libmng.h It can be + used in other projects to access libmng.dll created with the + win32dll example above. + + +unix - Unix +----------- + +mngtree - basically a copy of the BCB sample. It includes a makefile for + Linux and it's been tested on RedHat6.2 + diff --git a/freeimage241/Source/LibMNG/README.packaging b/freeimage241/Source/LibMNG/README.packaging new file mode 100644 index 0000000..da0db3e --- /dev/null +++ b/freeimage241/Source/LibMNG/README.packaging @@ -0,0 +1,24 @@ +Packaging Libmng for distribution +--------------------------------- + +These are some notes for those building binaries for distribution. + +We're interested to hear about anywhere libmng is helpful, so let us +know if you're including it with your application or OS. Also, if your +build is publicly accessible, we'd be happy to link to it from +the libmng site. + +However, We respectfully request that you *not* distribute binaries as a +shared library (DLL) with any of the major features disabled. While +there is support for this in terms of #ifdef directives (in +libmng_conf.h) and autoconf switches they are intended for embedded +application and testing. The default compilation options support the +full MNG specification, and we wish to avoid the confusion among +general users that partial support would engender. + + +Platform specific notes: + +We have a basic .spec file for generating rpms. Send us a note if you'd +like to clean it up. + diff --git a/freeimage241/Source/LibMNG/autogen.sh b/freeimage241/Source/LibMNG/autogen.sh new file mode 100644 index 0000000..0ed4a8b --- /dev/null +++ b/freeimage241/Source/LibMNG/autogen.sh @@ -0,0 +1,34 @@ +# autogen.sh +# +# invoke the auto* tools to create the configureation system + +# move out configure.in +if ! test -f configure.in; then + echo "copying out configure.in" + ln -s makefiles/configure.in +fi + +# move out the macros and run aclocal +if ! test -f acinclude.m4; then + echo "copying configure macros" + ln -s makefiles/acinclude.m4 . +fi +aclocal + +# build the configure script +autoconf + +# set up libtool +libtoolize --force + +# copy up our Makefile template and invoke automake +if ! test -f Makefile.am; then + echo "copying automake template" + ln -s makefiles/Makefile.am . +fi +automake --foreign --add-missing + +# and finally invoke our new configure +./configure $* + +# end diff --git a/freeimage241/Source/LibMNG/libmng.h b/freeimage241/Source/LibMNG/libmng.h new file mode 100644 index 0000000..18b98e0 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng.h @@ -0,0 +1,2501 @@ +/* ************************************************************************** */ +/* * * */ +/* * COPYRIGHT NOTICE: * */ +/* * * */ +/* * Copyright (c) 2000,2001 Gerard Juyn (gerard@libmng.com) * */ +/* * [You may insert additional notices after this sentence if you modify * */ +/* * this source] * */ +/* * * */ +/* * For the purposes of this copyright and license, "Contributing Authors" * */ +/* * is defined as the following set of individuals: * */ +/* * * */ +/* * Gerard Juyn (gerard@libmng.com) * */ +/* * * */ +/* * The MNG Library is supplied "AS IS". The Contributing Authors * */ +/* * disclaim all warranties, expressed or implied, including, without * */ +/* * limitation, the warranties of merchantability and of fitness for any * */ +/* * purpose. The Contributing Authors assume no liability for direct, * */ +/* * indirect, incidental, special, exemplary, or consequential damages, * */ +/* * which may result from the use of the MNG Library, even if advised of * */ +/* * the possibility of such damage. * */ +/* * * */ +/* * Permission is hereby granted to use, copy, modify, and distribute this * */ +/* * source code, or portions hereof, for any purpose, without fee, subject * */ +/* * to the following restrictions: * */ +/* * * */ +/* * 1. The origin of this source code must not be misrepresented; * */ +/* * you must not claim that you wrote the original software. * */ +/* * * */ +/* * 2. Altered versions must be plainly marked as such and must not be * */ +/* * misrepresented as being the original source. * */ +/* * * */ +/* * 3. This Copyright notice may not be removed or altered from any source * */ +/* * or altered source distribution. * */ +/* * * */ +/* * The Contributing Authors specifically permit, without fee, and * */ +/* * encourage the use of this source code as a component to supporting * */ +/* * the MNG and JNG file format in commercial products. If you use this * */ +/* * source code in a product, acknowledgment would be highly appreciated. * */ +/* * * */ +/* ************************************************************************** */ +/* * * */ +/* * Parts of this software have been adapted from the libpng package. * */ +/* * Although this library supports all features from the PNG specification * */ +/* * (as MNG descends from it) it does not require the libpng package. * */ +/* * It does require the zlib library and optionally the IJG jpeg library, * */ +/* * and/or the "little-cms" library by Marti Maria (depending on the * */ +/* * inclusion of support for JNG and Full-Color-Management respectively. * */ +/* * * */ +/* * This library's function is primarily to read and display MNG * */ +/* * animations. It is not meant as a full-featured image-editing * */ +/* * component! It does however offer creation and editing functionality * */ +/* * at the chunk level. * */ +/* * (future modifications may include some more support for creation * */ +/* * and or editing) * */ +/* * * */ +/* ************************************************************************** */ + +/* ************************************************************************** */ +/* * * */ +/* * Version numbering * */ +/* * * */ +/* * X.Y.Z : X = release (0 = initial build) * */ +/* * Y = major version (uneven = test; even = production) * */ +/* * Z = minor version (bugfixes; 2 is older than 10) * */ +/* * * */ +/* * production versions only appear when a test-version is extensively * */ +/* * tested and found stable or for intermediate bug-fixes (recognized by * */ +/* * a change in the Z number) * */ +/* * * */ +/* * x.1.x = test version * */ +/* * x.2.x = production version * */ +/* * x.3.x = test version * */ +/* * x.4.x = production version * */ +/* * etc. * */ +/* * * */ +/* ************************************************************************** */ +/* * * */ +/* * Identifier naming conventions throughout this library * */ +/* * * */ +/* * iXxxx = an integer * */ +/* * dXxxx = a float * */ +/* * pXxxx = a pointer * */ +/* * bXxxx = a boolean * */ +/* * eXxxx = an enumeration * */ +/* * hXxxx = a handle * */ +/* * zXxxx = a zero-terminated string (pchar) * */ +/* * fXxxx = a pointer to a function (callback) * */ +/* * aXxxx = an array * */ +/* * sXxxx = a structure * */ +/* * * */ +/* * Macros & defines are in all uppercase. * */ +/* * Functions & typedefs in all lowercase. * */ +/* * Exported stuff is prefixed with MNG_ or mng_ respectively. * */ +/* * * */ +/* * (I may have missed a couple; don't hesitate to let me know!) * */ +/* * * */ +/* ************************************************************************** */ + +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : main application interface * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : The main application interface. An application should not * */ +/* * need access to any of the other modules! * */ +/* * * */ +/* * changes : 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - changed chunk iteration function * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - added chunk access functions * */ +/* * - added version control constants & functions * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added set_outputprofile2 & set_srgbprofile2 * */ +/* * - added empty-chunk put-routines * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - added version_dll & VERSION_DLL (for consistency) * */ +/* * - added version control explanatory text & samples * */ +/* * 0.5.1 - 05/15/2000 - G.Juyn * */ +/* * - added getimgdata & putimgdata functions * */ +/* * * */ +/* * 0.5.2 - 05/16/2000 - G.Juyn * */ +/* * - changed the version parameters (obviously) * */ +/* * 0.5.2 - 05/18/2000 - G.Juyn * */ +/* * - complimented constants for chunk-property values * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - fixed MNG_UINT_pHYg value * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added support for get/set default zlib/IJG parms * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - added MNG_BIGENDIAN_SUPPORT (contributed by Tim Rowley) * */ +/* * - separated configuration-options into "mng_conf.h" * */ +/* * - added RGB8_A8 canvasstyle * */ +/* * - added getalphaline callback for RGB8_A8 canvasstyle * */ +/* * 0.5.2 - 06/06/2000 - G.Juyn * */ +/* * - moved errorcodes from "mng_error.h" * */ +/* * - added mng_read_resume function to support * */ +/* * read-suspension * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - changed the version parameters (obviously) * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added get/set for speedtype to facilitate testing * */ +/* * - added get for imagelevel during processtext callback * */ +/* * 0.5.3 - 06/24/2000 - G.Juyn * */ +/* * - fixed inclusion of IJG read/write code * */ +/* * 0.5.3 - 06/26/2000 - G.Juyn * */ +/* * - changed userdata variable to mng_ptr * */ +/* * * */ +/* * 0.9.0 - 06/30/2000 - G.Juyn * */ +/* * - changed refresh parameters to 'x,y,width,height' * */ +/* * * */ +/* * 0.9.1 - 07/06/2000 - G.Juyn * */ +/* * - added MNG_NEEDTIMERWAIT errorcode * */ +/* * - changed comments to indicate modified behavior for * */ +/* * timer & suspension breaks * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - added get routines for internal display variables * */ +/* * - added get/set routines for suspensionmode variable * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added callbacks for SAVE/SEEK processing * */ +/* * - added get/set routines for sectionbreak variable * */ +/* * - added NEEDSECTIONWAIT errorcode * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - added function to set frame-/layer-count & playtime * */ +/* * - added errorcode for updatemngheader if not a MNG * */ +/* * * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - fixed problem with trace-functions improperly wrapped * */ +/* * - added status_xxxx functions * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * - added function to set simplicity field * */ +/* * * */ +/* * 0.9.3 - 08/09/2000 - G.Juyn * */ +/* * - added check for simplicity-bits in MHDR * */ +/* * 0.9.3 - 08/12/2000 - G.Juyn * */ +/* * - added workaround for faulty PhotoShop iCCP chunk * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 10/10/2000 - G.Juyn * */ +/* * - added support for alpha-depth prediction * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - fixed processing of unknown critical chunks * */ +/* * - removed test-MaGN * */ +/* * - added PNG/MNG spec version indicators * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added functions to retrieve PNG/JNG specific header-info * */ +/* * - added JDAA chunk * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * 0.9.3 - 10/20/2000 - G.Juyn * */ +/* * - added errocode for delayed delta-processing * */ +/* * - added get/set for bKGD preference setting * */ +/* * 0.9.3 - 10/21/2000 - G.Juyn * */ +/* * - added get function for interlace/progressive display * */ +/* * * */ +/* * 0.9.4 - 01/18/2001 - G.Juyn * */ +/* * - added errorcode for MAGN methods * */ +/* * - removed test filter-methods 1 & 65 * */ +/* * * */ +/* * 1.0.0 - 02/05/2001 - G.Juyn * */ +/* * - version numbers (obviously) * */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn (code by G.Kelly) * */ +/* * - added BGRA8 canvas with premultiplied alpha * */ +/* * 1.0.1 - 05/02/2001 - G.Juyn * */ +/* * - added "default" sRGB generation (Thanks Marti!) * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * - added processterm callback * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - added late binding errorcode (not used internally) * */ +/* * - added option to turn off progressive refresh * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_h_ +#define _libmng_h_ + +/* ************************************************************************** */ + +#include "libmng_conf.h" /* user-specific configuration options */ + +/* ************************************************************************** */ + +#define MNG_CHECK_BAD_ICCP /* let's catch that sucker !!! */ + +#ifdef MNG_SUPPORT_READ /* dependencies based on user-configuration */ +#define MNG_INCLUDE_READ_PROCS +#endif + +#ifdef MNG_SUPPORT_WRITE +#define MNG_INCLUDE_WRITE_PROCS +#endif + +#ifdef MNG_SUPPORT_DISPLAY +#define MNG_INCLUDE_FILTERS +#define MNG_INCLUDE_INTERLACE +#define MNG_INCLUDE_OBJECTS +#define MNG_INCLUDE_DISPLAY_PROCS +#define MNG_INCLUDE_TIMING_PROCS +#define MNG_INCLUDE_ZLIB +#endif + +#ifdef MNG_STORE_CHUNKS +#define MNG_INCLUDE_ZLIB +#endif + +#ifdef MNG_SUPPORT_IJG6B +#define MNG_INCLUDE_JNG +#define MNG_INCLUDE_IJG6B +#define MNG_USE_SETJMP +#endif + +#ifdef MNG_INCLUDE_JNG +#if defined(MNG_SUPPORT_DISPLAY) || defined(MNG_ACCESS_CHUNKS) +#define MNG_INCLUDE_JNG_READ +#endif +#if defined(MNG_SUPPORT_WRITE) || defined(MNG_ACCESS_CHUNKS) +#define MNG_INCLUDE_JNG_WRITE +#endif +#endif + +#ifdef MNG_FULL_CMS +#define MNG_INCLUDE_LCMS +#endif + +#ifdef MNG_AUTO_DITHER +#define MNG_INCLUDE_DITHERING +#endif + +#ifdef MNG_SUPPORT_TRACE +#define MNG_INCLUDE_TRACE_PROCS +#ifdef MNG_TRACE_TELLTALE +#define MNG_INCLUDE_TRACE_STRINGS +#endif +#endif + +#ifdef MNG_ERROR_TELLTALE +#define MNG_INCLUDE_ERROR_STRINGS +#endif + +/* ************************************************************************** */ + +#include "libmng_types.h" /* platform-specific definitions + and other assorted stuff */ + +/* ************************************************************************** */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ************************************************************************** */ +/* * * */ +/* * Versioning control * */ +/* * * */ +/* * version_so and version_dll will NOT reflect version_major; * */ +/* * these will only change for binary incompatible changes (which will * */ +/* * hopefully never occur) * */ +/* * note: they will be set to 1 on the first public release !!! * */ +/* * * */ +/* * first public release: * */ +/* * #define MNG_VERSION_TEXT "1.0.0" * */ +/* * #define MNG_VERSION_SO 1 eg. libmng.so.1 * */ +/* * #define MNG_VERSION_DLL 1 eg. libmng.dll * */ +/* * #define MNG_VERSION_MAJOR 1 * */ +/* * #define MNG_VERSION_MINOR 0 * */ +/* * #define MNG_VERSION_RELEASE 0 * */ +/* * * */ +/* * bug fix & cosmetics : * */ +/* * #define MNG_VERSION_TEXT "1.0.1" * */ +/* * #define MNG_VERSION_SO 1 eg. libmng.so.1 * */ +/* * #define MNG_VERSION_DLL 1 eg. libmng.dll * */ +/* * #define MNG_VERSION_MAJOR 1 * */ +/* * #define MNG_VERSION_MINOR 0 * */ +/* * #define MNG_VERSION_RELEASE 1 * */ +/* * * */ +/* * feature change : * */ +/* * #define MNG_VERSION_TEXT "1.2.0" * */ +/* * #define MNG_VERSION_SO 1 eg. libmng.so.1 * */ +/* * #define MNG_VERSION_DLL 1 eg. libmng.dll * */ +/* * #define MNG_VERSION_MAJOR 1 * */ +/* * #define MNG_VERSION_MINOR 2 * */ +/* * #define MNG_VERSION_RELEASE 0 * */ +/* * * */ +/* * major rewrite (still binary compatible) : * */ +/* * #define MNG_VERSION_TEXT "2.0.0" * */ +/* * #define MNG_VERSION_SO 1 eg. libmng.so.1 * */ +/* * #define MNG_VERSION_DLL 1 eg. libmng.dll * */ +/* * #define MNG_VERSION_MAJOR 2 * */ +/* * #define MNG_VERSION_MINOR 0 * */ +/* * #define MNG_VERSION_RELEASE 0 * */ +/* * * */ +/* * binary incompatible change: * */ +/* * #define MNG_VERSION_TEXT "13.0.0" * */ +/* * #define MNG_VERSION_SO 2 eg. libmng.so.2 * */ +/* * #define MNG_VERSION_DLL 2 eg. libmng2.dll * */ +/* * #define MNG_VERSION_MAJOR 13 * */ +/* * #define MNG_VERSION_MINOR 0 * */ +/* * #define MNG_VERSION_RELEASE 0 * */ +/* * * */ +/* * note that version_so & version_dll will always remain equal so it * */ +/* * doesn't matter which one is called to do version-checking; they are * */ +/* * just provided for their target platform * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_VERSION_TEXT "1.0.2" +#define MNG_VERSION_SO 1 /* eg. libmng.so.1 */ +#define MNG_VERSION_DLL 1 /* but: libmng.dll (!) */ +#define MNG_VERSION_MAJOR 1 +#define MNG_VERSION_MINOR 0 +#define MNG_VERSION_RELEASE 2 + +MNG_EXT mng_pchar MNG_DECL mng_version_text (void); +MNG_EXT mng_uint8 MNG_DECL mng_version_so (void); +MNG_EXT mng_uint8 MNG_DECL mng_version_dll (void); +MNG_EXT mng_uint8 MNG_DECL mng_version_major (void); +MNG_EXT mng_uint8 MNG_DECL mng_version_minor (void); +MNG_EXT mng_uint8 MNG_DECL mng_version_release (void); + +/* ************************************************************************** */ +/* * * */ +/* * MNG/PNG specification level conformance * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_PNG_VERSION "1.2" +#define MNG_PNG_VERSION_MAJ 1 +#define MNG_PNG_VERSION_MIN 2 + +#define MNG_MNG_VERSION "1.0" +#define MNG_MNG_VERSION_MAJ 1 +#define MNG_MNG_VERSION_MIN 0 +#define MNG_MNG_DRAFT 99 /* deprecated */ + +/* ************************************************************************** */ +/* * * */ +/* * High-level application functions * */ +/* * * */ +/* ************************************************************************** */ + +/* library initialization function */ +/* must be the first called before anything can be done at all */ +/* initializes internal datastructure(s) */ +MNG_EXT mng_handle MNG_DECL mng_initialize (mng_ptr pUserdata, + mng_memalloc fMemalloc, + mng_memfree fMemfree, + mng_traceproc fTraceproc); + +/* library reset function */ +/* can be used to re-initialize the library, so another image can be + processed. there's absolutely no harm in calling it, even when it's not + really necessary */ +MNG_EXT mng_retcode MNG_DECL mng_reset (mng_handle hHandle); + +/* library cleanup function */ +/* must be the last called to clean up internal datastructure(s) */ +MNG_EXT mng_retcode MNG_DECL mng_cleanup (mng_handle* hHandle); + +/* high-level read functions */ +/* use mng_read if you simply want to read a Network Graphic */ +/* mng_read_resume is used in I/O-read-suspension scenarios, where the + "readdata" callback may return FALSE & length=0 indicating it's buffer is + depleted or too short to supply the required bytes, and the buffer needs + to be refilled; libmng will return the errorcode MNG_NEEDMOREDATA telling + the app to refill it's read-buffer after which it must call mng_read_resume + (or mng_display_resume if it also displaying the image simultaneously) */ +#ifdef MNG_SUPPORT_READ +MNG_EXT mng_retcode MNG_DECL mng_read (mng_handle hHandle); +MNG_EXT mng_retcode MNG_DECL mng_read_resume (mng_handle hHandle); +#endif + +/* high-level write & create functions */ +/* use this if you want to write a previously read Network Graphic or + if you want to create a new graphic and write it */ +/* to write a previously read graphic you must have defined MNG_STORE_CHUNKS */ +/* to create a new graphic you'll also need access to the chunks + (eg. #define MNG_ACCESS_CHUNKS !) */ +#ifdef MNG_SUPPORT_WRITE +MNG_EXT mng_retcode MNG_DECL mng_write (mng_handle hHandle); +MNG_EXT mng_retcode MNG_DECL mng_create (mng_handle hHandle); +#endif + +/* high-level display functions */ +/* use these to display a previously read or created graphic or + to read & display a graphic simultaneously */ +/* mng_display_resume should be called after a timer-interval + expires that was set through the settimer-callback, after a + read suspension-break, or, to resume an animation after a call + to mng_display_freeze/mng_display_reset */ +/* mng_display_freeze thru mng_display_gotime can be used to influence + the display of an image, BUT ONLY if it has been completely read! */ +#ifdef MNG_SUPPORT_DISPLAY +#ifdef MNG_SUPPORT_READ +MNG_EXT mng_retcode MNG_DECL mng_readdisplay (mng_handle hHandle); +#endif +MNG_EXT mng_retcode MNG_DECL mng_display (mng_handle hHandle); +MNG_EXT mng_retcode MNG_DECL mng_display_resume (mng_handle hHandle); +MNG_EXT mng_retcode MNG_DECL mng_display_freeze (mng_handle hHandle); +MNG_EXT mng_retcode MNG_DECL mng_display_reset (mng_handle hHandle); +MNG_EXT mng_retcode MNG_DECL mng_display_goframe (mng_handle hHandle, + mng_uint32 iFramenr); +MNG_EXT mng_retcode MNG_DECL mng_display_golayer (mng_handle hHandle, + mng_uint32 iLayernr); +MNG_EXT mng_retcode MNG_DECL mng_display_gotime (mng_handle hHandle, + mng_uint32 iPlaytime); +#endif /* MNG_SUPPORT_DISPLAY */ + +/* error reporting function */ +/* use this if you need more detailed info on the last error */ +/* iExtra1 & iExtra2 may contain errorcodes from zlib, jpeg, etc... */ +/* zErrortext will only be filled if you #define MNG_ERROR_TELLTALE */ +MNG_EXT mng_retcode MNG_DECL mng_getlasterror (mng_handle hHandle, + mng_int8* iSeverity, + mng_chunkid* iChunkname, + mng_uint32* iChunkseq, + mng_int32* iExtra1, + mng_int32* iExtra2, + mng_pchar* zErrortext); + +/* ************************************************************************** */ +/* * * */ +/* * Callback set functions * */ +/* * * */ +/* ************************************************************************** */ + +/* memory callbacks */ +/* called to allocate and release internal datastructures */ +#ifndef MNG_INTERNAL_MEMMNGMT +MNG_EXT mng_retcode MNG_DECL mng_setcb_memalloc (mng_handle hHandle, + mng_memalloc fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_memfree (mng_handle hHandle, + mng_memfree fProc); +#endif /* MNG_INTERNAL_MEMMNGMT */ + +/* open- & close-stream callbacks */ +/* called to open & close streams for input or output */ +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) +MNG_EXT mng_retcode MNG_DECL mng_setcb_openstream (mng_handle hHandle, + mng_openstream fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_closestream (mng_handle hHandle, + mng_closestream fProc); +#endif + +/* read callback */ +/* called to get data from the inputstream */ +#ifdef MNG_SUPPORT_READ +MNG_EXT mng_retcode MNG_DECL mng_setcb_readdata (mng_handle hHandle, + mng_readdata fProc); +#endif + +/* write callback */ +/* called to put data into the outputstream */ +#ifdef MNG_SUPPORT_WRITE +MNG_EXT mng_retcode MNG_DECL mng_setcb_writedata (mng_handle hHandle, + mng_writedata fProc); +#endif + +/* error callback */ +/* called when an error occurs */ +/* the application can determine if the error is recoverable, + and may inform the library by setting specific returncodes */ +MNG_EXT mng_retcode MNG_DECL mng_setcb_errorproc (mng_handle hHandle, + mng_errorproc fProc); + +/* trace callback */ +/* called to show the currently executing function */ +#ifdef MNG_SUPPORT_TRACE +MNG_EXT mng_retcode MNG_DECL mng_setcb_traceproc (mng_handle hHandle, + mng_traceproc fProc); +#endif + +/* callbacks for read processing */ +/* processheader is called when all header information has been gathered + from the inputstream */ +/* processtext is called for every tEXt, zTXt and iTXt chunk in the + inputstream (iType=0 for tEXt, 1 for zTXt and 2 for iTXt); + you can call get_imagelevel to check at what nesting-level the chunk is + encountered (eg. tEXt inside an embedded image inside a MNG -> level == 2; + in most other case -> level == 1) */ +/* processsave & processseek are called for SAVE/SEEK chunks */ +/* processneed is called for the nEED chunk; you should specify a callback + for this as the default behavior will be to abort processing */ +/* processunknown is called after reading each non-critical unknown chunk */ +#ifdef MNG_SUPPORT_READ +MNG_EXT mng_retcode MNG_DECL mng_setcb_processheader (mng_handle hHandle, + mng_processheader fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processtext (mng_handle hHandle, + mng_processtext fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processsave (mng_handle hHandle, + mng_processsave fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processseek (mng_handle hHandle, + mng_processseek fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processneed (mng_handle hHandle, + mng_processneed fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processmend (mng_handle hHandle, + mng_processmend fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processunknown(mng_handle hHandle, + mng_processunknown fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processterm (mng_handle hHandle, + mng_processterm fProc); +#endif + +/* callbacks for display processing */ +/* getcanvasline is called to get an access-pointer to a line on the + drawing-canvas */ +/* getbkgdline is called to get an access-pointer to a line from the + background-canvas */ +/* refresh is called to inform the GUI to redraw the current canvas onto + it's output device (eg. in Win32 this would mean sending an + invalidate message for the specified region */ +/* NOTE that the update-region is specified as x,y,width,height; eg. the + invalidate message for Windows requires left,top,right,bottom parameters + where the bottom-right is exclusive of the region!! + to get these correctly is as simple as: + left = x; + top = y; + right = x + width; + bottom = y + height; + if your implementation requires inclusive points, simply subtract 1 from + both the right & bottom values calculated above. + */ +#ifdef MNG_SUPPORT_DISPLAY +MNG_EXT mng_retcode MNG_DECL mng_setcb_getcanvasline (mng_handle hHandle, + mng_getcanvasline fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_getbkgdline (mng_handle hHandle, + mng_getbkgdline fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_getalphaline (mng_handle hHandle, + mng_getalphaline fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_refresh (mng_handle hHandle, + mng_refresh fProc); + +/* timing callbacks */ +/* gettickcount is called to get the system tickcount (milliseconds); + this is used to determine the remaining interval between frames */ +/* settimer is called to inform the application that it should set a timer; + when the timer is triggered the app must call mng_display_resume */ +MNG_EXT mng_retcode MNG_DECL mng_setcb_gettickcount (mng_handle hHandle, + mng_gettickcount fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_settimer (mng_handle hHandle, + mng_settimer fProc); + +/* color management callbacks */ +/* called to transmit color management information to the application */ +/* these are only used when you #define MNG_APP_CMS */ +#ifdef MNG_APP_CMS +MNG_EXT mng_retcode MNG_DECL mng_setcb_processgamma (mng_handle hHandle, + mng_processgamma fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processchroma (mng_handle hHandle, + mng_processchroma fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processsrgb (mng_handle hHandle, + mng_processsrgb fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processiccp (mng_handle hHandle, + mng_processiccp fProc); +MNG_EXT mng_retcode MNG_DECL mng_setcb_processarow (mng_handle hHandle, + mng_processarow fProc); +#endif /* MNG_APP_CMS */ +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ +/* * * */ +/* * Callback get functions * */ +/* * * */ +/* ************************************************************************** */ + +/* see _setcb_ */ +#ifndef MNG_INTERNAL_MEMMNGMT +MNG_EXT mng_memalloc MNG_DECL mng_getcb_memalloc (mng_handle hHandle); +MNG_EXT mng_memfree MNG_DECL mng_getcb_memfree (mng_handle hHandle); +#endif + +/* see _setcb_ */ +#if defined(MNG_SUPPORT_READ) || defined(MNG_WRITE_SUPPORT) +MNG_EXT mng_openstream MNG_DECL mng_getcb_openstream (mng_handle hHandle); +MNG_EXT mng_closestream MNG_DECL mng_getcb_closestream (mng_handle hHandle); +#endif + +/* see _setcb_ */ +#ifdef MNG_SUPPORT_READ +MNG_EXT mng_readdata MNG_DECL mng_getcb_readdata (mng_handle hHandle); +#endif + +/* see _setcb_ */ +#ifdef MNG_SUPPORT_WRITE +MNG_EXT mng_writedata MNG_DECL mng_getcb_writedata (mng_handle hHandle); +#endif + +/* see _setcb_ */ +MNG_EXT mng_errorproc MNG_DECL mng_getcb_errorproc (mng_handle hHandle); + +/* see _setcb_ */ +#ifdef MNG_SUPPORT_TRACE +MNG_EXT mng_traceproc MNG_DECL mng_getcb_traceproc (mng_handle hHandle); +#endif + +/* see _setcb_ */ +#ifdef MNG_SUPPORT_READ +MNG_EXT mng_processheader MNG_DECL mng_getcb_processheader (mng_handle hHandle); +MNG_EXT mng_processtext MNG_DECL mng_getcb_processtext (mng_handle hHandle); +MNG_EXT mng_processsave MNG_DECL mng_getcb_processsave (mng_handle hHandle); +MNG_EXT mng_processseek MNG_DECL mng_getcb_processseek (mng_handle hHandle); +MNG_EXT mng_processneed MNG_DECL mng_getcb_processneed (mng_handle hHandle); +MNG_EXT mng_processunknown MNG_DECL mng_getcb_processunknown (mng_handle hHandle); +MNG_EXT mng_processterm MNG_DECL mng_getcb_processterm (mng_handle hHandle); +#endif + +/* see _setcb_ */ +#ifdef MNG_SUPPORT_DISPLAY +MNG_EXT mng_getcanvasline MNG_DECL mng_getcb_getcanvasline (mng_handle hHandle); +MNG_EXT mng_getbkgdline MNG_DECL mng_getcb_getbkgdline (mng_handle hHandle); +MNG_EXT mng_getalphaline MNG_DECL mng_getcb_getalphaline (mng_handle hHandle); +MNG_EXT mng_refresh MNG_DECL mng_getcb_refresh (mng_handle hHandle); + +/* see _setcb_ */ +MNG_EXT mng_gettickcount MNG_DECL mng_getcb_gettickcount (mng_handle hHandle); +MNG_EXT mng_settimer MNG_DECL mng_getcb_settimer (mng_handle hHandle); + +/* see _setcb_ */ +#ifdef MNG_APP_CMS +MNG_EXT mng_processgamma MNG_DECL mng_getcb_processgamma (mng_handle hHandle); +MNG_EXT mng_processchroma MNG_DECL mng_getcb_processchroma (mng_handle hHandle); +MNG_EXT mng_processsrgb MNG_DECL mng_getcb_processsrgb (mng_handle hHandle); +MNG_EXT mng_processiccp MNG_DECL mng_getcb_processiccp (mng_handle hHandle); +MNG_EXT mng_processarow MNG_DECL mng_getcb_processarow (mng_handle hHandle); +#endif /* MNG_APP_CMS */ +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ +/* * * */ +/* * Property set functions * */ +/* * * */ +/* ************************************************************************** */ + +/* Application data pointer */ +/* provided for application use; not used by the library */ +MNG_EXT mng_retcode MNG_DECL mng_set_userdata (mng_handle hHandle, + mng_ptr pUserdata); + +/* The style of the drawing- & background-canvas */ +/* only used for displaying images */ +/* both are initially set to 24-bit RGB (eg. 8-bit per channel) */ +MNG_EXT mng_retcode MNG_DECL mng_set_canvasstyle (mng_handle hHandle, + mng_uint32 iStyle); +MNG_EXT mng_retcode MNG_DECL mng_set_bkgdstyle (mng_handle hHandle, + mng_uint32 iStyle); + +/* The default background color */ +/* only used if the getbkgdline callback is not defined */ +/* for initially painting the canvas and restoring (part of) the background */ +MNG_EXT mng_retcode MNG_DECL mng_set_bgcolor (mng_handle hHandle, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue); + +/* Indicates preferred use of the bKGD chunk for PNG images */ +MNG_EXT mng_retcode MNG_DECL mng_set_usebkgd (mng_handle hHandle, + mng_bool bUseBKGD); + +/* Indicates storage of read chunks */ +/* only useful if you #define mng_store_chunks */ +/* can be used to dynamically change storage management */ +MNG_EXT mng_retcode MNG_DECL mng_set_storechunks (mng_handle hHandle, + mng_bool bStorechunks); + +/* Indicates breaks requested when processing SAVE/SEEK */ +/* set this to let the app handle section breaks; the library will return + MNG_NEEDSECTIONWAIT return-codes for each SEEK chunk */ +MNG_EXT mng_retcode MNG_DECL mng_set_sectionbreaks (mng_handle hHandle, + mng_bool bSectionbreaks); + +/* Indicates storage of playback info (ON by default!) */ +/* can be used to turn off caching of playback info; this is useful to + specifically optimize MNG-video playback; note that if caching is turned off + LOOP chunks will be flagged as errors! TERM chunks will be ignored and only + passed to the processterm() callback if it is defined by the app; also, this + feature can only be used with mng_readdisplay(); mng_read(), + mng_display_reset() and mng_display_goxxxx() will return an error; + once this option is turned off it can't be turned on for the same stream!!! */ +MNG_EXT mng_retcode MNG_DECL mng_set_cacheplayback (mng_handle hHandle, + mng_bool bCacheplayback); + +/* Indicates automatic progressive refreshes for large images (ON by default!) */ +/* turn this off if you do not want intermittent painting while a large image + is being read. useful if the input-stream comes from a fast medium, such + as a local harddisk */ +MNG_EXT mng_retcode MNG_DECL mng_set_doprogressive (mng_handle hHandle, + mng_bool bDoProgressive); + +/* Color-management necessaries */ +/* + ************************************************************************* + !!!!!!!! THIS BIT IS IMPORTANT !!!!!!!!! + ************************************************************************* + + If you have defined MNG_FULL_CMS (and are using lcms), you will have to + think hard about the following routines. + + lcms requires 2 profiles to work off the differences in the input-image + and the output-device. The ICC profile for the input-image will be + embedded within it to reflect its color-characteristics, but the output + profile depends on the output-device, which is something only *YOU* know + about. sRGB (standard RGB) is common for x86 compatible environments + (eg. Windows, Linux and some others) + + If you are compiling for a sRGB compliant system you probably won't have + to do anything special. (unless you want to ofcourse) + + If you are compiling for a non-sRGB compliant system + (eg. SGI, Mac, Next, others...) + you *MUST* define a proper ICC profile for the generic output-device + associated with that platform. + + In either event, you may also want to offer an option to your users to + set the profile manually, or, if you know how, set it from a + system-defined default. + + TO RECAP: for sRGB systems (Windows, Linux) no action required! + for non-sRGB systems (SGI, Mac, Next) ACTION REQUIRED! + + Please visit http://www.srgb.com, http://www.color.org and + http://www.littlecms.com for more info. + + ************************************************************************* + !!!!!!!! THIS BIT IS IMPORTANT !!!!!!!!! + ************************************************************************* +*/ +/* mng_set_srgb tells libmng if it's running on a sRGB compliant system or not + the default is already set to MNG_TRUE */ +/* mng_set_outputprofile, mng_set_outputprofile2, mng_set_outputsrgb + are used to set the default profile describing the output-device + by default it is already initialized with an sRGB profile */ +/* mng_set_srgbprofile, mng_set_srgbprofile2, mng_set_srgbimplicit + are used to set the default profile describing a standard sRGB device + this is used when the input-image is tagged only as being sRGB, but the + output-device is defined as not being sRGB compliant + by default it is already initialized with a standard sRGB profile */ +#if defined(MNG_SUPPORT_DISPLAY) +MNG_EXT mng_retcode MNG_DECL mng_set_srgb (mng_handle hHandle, + mng_bool bIssRGB); +MNG_EXT mng_retcode MNG_DECL mng_set_outputprofile (mng_handle hHandle, + mng_pchar zFilename); +MNG_EXT mng_retcode MNG_DECL mng_set_outputprofile2 (mng_handle hHandle, + mng_uint32 iProfilesize, + mng_ptr pProfile); +MNG_EXT mng_retcode MNG_DECL mng_set_outputsrgb (mng_handle hHandle); +MNG_EXT mng_retcode MNG_DECL mng_set_srgbprofile (mng_handle hHandle, + mng_pchar zFilename); +MNG_EXT mng_retcode MNG_DECL mng_set_srgbprofile2 (mng_handle hHandle, + mng_uint32 iProfilesize, + mng_ptr pProfile); +MNG_EXT mng_retcode MNG_DECL mng_set_srgbimplicit (mng_handle hHandle); +#endif + +/* Gamma settings */ +/* only used if you #define MNG_FULL_CMS or #define MNG_GAMMA_ONLY */ +/* ... blabla (explain gamma processing a little; eg. formula & stuff) ... */ +MNG_EXT mng_retcode MNG_DECL mng_set_viewgamma (mng_handle hHandle, + mng_float dGamma); +MNG_EXT mng_retcode MNG_DECL mng_set_displaygamma (mng_handle hHandle, + mng_float dGamma); +MNG_EXT mng_retcode MNG_DECL mng_set_dfltimggamma (mng_handle hHandle, + mng_float dGamma); +MNG_EXT mng_retcode MNG_DECL mng_set_viewgammaint (mng_handle hHandle, + mng_uint32 iGamma); +MNG_EXT mng_retcode MNG_DECL mng_set_displaygammaint (mng_handle hHandle, + mng_uint32 iGamma); +MNG_EXT mng_retcode MNG_DECL mng_set_dfltimggammaint (mng_handle hHandle, + mng_uint32 iGamma); + +/* Ultimate clipping size */ +/* used to limit extreme graphics from overloading the system */ +/* if a graphic exceeds these limits a warning is issued, which can + be ignored by the app (using the errorproc callback). in that case + the library will use these settings to clip the input graphic, and + the app's canvas must account for this */ +MNG_EXT mng_retcode MNG_DECL mng_set_maxcanvaswidth (mng_handle hHandle, + mng_uint32 iMaxwidth); +MNG_EXT mng_retcode MNG_DECL mng_set_maxcanvasheight (mng_handle hHandle, + mng_uint32 iMaxheight); +MNG_EXT mng_retcode MNG_DECL mng_set_maxcanvassize (mng_handle hHandle, + mng_uint32 iMaxwidth, + mng_uint32 iMaxheight); + +/* ZLIB default compression parameters */ +/* these are used when writing out chunks */ +/* they are also used when compressing PNG image-data or JNG alpha-data; + in this case you can set them just before calling mng_putimgdata_ihdr */ +/* set to your liking; usually the defaults will suffice though! */ +/* check the documentation for ZLIB for details on these parameters */ +#ifdef MNG_INCLUDE_ZLIB +MNG_EXT mng_retcode MNG_DECL mng_set_zlib_level (mng_handle hHandle, + mng_int32 iZlevel); +MNG_EXT mng_retcode MNG_DECL mng_set_zlib_method (mng_handle hHandle, + mng_int32 iZmethod); +MNG_EXT mng_retcode MNG_DECL mng_set_zlib_windowbits (mng_handle hHandle, + mng_int32 iZwindowbits); +MNG_EXT mng_retcode MNG_DECL mng_set_zlib_memlevel (mng_handle hHandle, + mng_int32 iZmemlevel); +MNG_EXT mng_retcode MNG_DECL mng_set_zlib_strategy (mng_handle hHandle, + mng_int32 iZstrategy); + +MNG_EXT mng_retcode MNG_DECL mng_set_zlib_maxidat (mng_handle hHandle, + mng_uint32 iMaxIDAT); +#endif /* MNG_INCLUDE_ZLIB */ + +/* JNG default compression parameters (based on IJG code) */ +/* these are used when compressing JNG image-data; so you can set them + just before calling mng_putimgdata_jhdr */ +/* set to your liking; usually the defaults will suffice though! */ +/* check the documentation for IJGSRC6B for details on these parameters */ +#ifdef MNG_INCLUDE_JNG +#ifdef MNG_INCLUDE_IJG6B +MNG_EXT mng_retcode MNG_DECL mng_set_jpeg_dctmethod (mng_handle hHandle, + mngjpeg_dctmethod eJPEGdctmethod); +#endif +MNG_EXT mng_retcode MNG_DECL mng_set_jpeg_quality (mng_handle hHandle, + mng_int32 iJPEGquality); +MNG_EXT mng_retcode MNG_DECL mng_set_jpeg_smoothing (mng_handle hHandle, + mng_int32 iJPEGsmoothing); +MNG_EXT mng_retcode MNG_DECL mng_set_jpeg_progressive(mng_handle hHandle, + mng_bool bJPEGprogressive); +MNG_EXT mng_retcode MNG_DECL mng_set_jpeg_optimized (mng_handle hHandle, + mng_bool bJPEGoptimized); + +MNG_EXT mng_retcode MNG_DECL mng_set_jpeg_maxjdat (mng_handle hHandle, + mng_uint32 iMaxJDAT); +#endif /* MNG_INCLUDE_JNG */ + +/* Suspension-mode setting */ +/* use this to activate the internal suspension-buffer to improve + read-suspension processing */ +/* TODO: write-suspension ??? */ +#if defined(MNG_SUPPORT_READ) +MNG_EXT mng_retcode MNG_DECL mng_set_suspensionmode (mng_handle hHandle, + mng_bool bSuspensionmode); +#endif + +/* Speed setting */ +/* use this to influence the display-speed of animations */ +#if defined(MNG_SUPPORT_DISPLAY) +MNG_EXT mng_retcode MNG_DECL mng_set_speed (mng_handle hHandle, + mng_speedtype iSpeed); +#endif + +/* ************************************************************************** */ +/* * * */ +/* * Property get functions * */ +/* * * */ +/* ************************************************************************** */ + +/* see _set_ */ +MNG_EXT mng_ptr MNG_DECL mng_get_userdata (mng_handle hHandle); + +/* Network Graphic header details */ +/* these get filled once the graphics header is processed, + so they are available in the processheader callback; before that + they are zeroed out and imagetype is set to it_unknown */ +/* this might be a good point for the app to initialize the drawing-canvas! */ +/* note that some fields are only set for the first(!) header-chunk: + MNG/MHDR (imagetype = mng_it_mng) - ticks thru simplicity + PNG/IHDR (imagetype = mng_it_png) - bitdepth thru interlace + JNG/JHDR (imagetype = mng_it_jng) - bitdepth thru compression & + interlace thru alphainterlace */ +MNG_EXT mng_imgtype MNG_DECL mng_get_sigtype (mng_handle hHandle); +MNG_EXT mng_imgtype MNG_DECL mng_get_imagetype (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_imagewidth (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_imageheight (mng_handle hHandle); + +MNG_EXT mng_uint32 MNG_DECL mng_get_ticks (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_framecount (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_layercount (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_playtime (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_simplicity (mng_handle hHandle); + +MNG_EXT mng_uint8 MNG_DECL mng_get_bitdepth (mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_colortype (mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_compression (mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_filter (mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_interlace (mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_alphabitdepth (mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_alphacompression(mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_alphafilter (mng_handle hHandle); +MNG_EXT mng_uint8 MNG_DECL mng_get_alphainterlace (mng_handle hHandle); + +/* indicates the predicted alpha-depth required to properly display the image */ +/* gets set once the graphics header is processed and is available in the + processheader callback for any type of input-image (PNG, JNG or MNG) */ +/* possible values are 0,1,2,4,8,16 + 0 = no transparency required + 1 = on/off transparency required (alpha-values are 0 or 2^bit_depth-1) + 2+ = semi-transparency required (values will be scaled to the bitdepth of the + canvasstyle supplied by the application) */ +MNG_EXT mng_uint8 MNG_DECL mng_get_alphadepth (mng_handle hHandle); + +/* defines whether a refresh() callback is called for an interlace pass (PNG) + or progressive scan (JNG) */ +/* returns the interlace pass number for PNG or a fabricated pass number for JNG; + returns 0 in all other cases */ +/* only useful if the image_type = mng_it_png or mng_it_jng and if the image + is actually interlaced (PNG) or progressive (JNG) */ +MNG_EXT mng_uint8 MNG_DECL mng_get_refreshpass (mng_handle hHandle); + +/* see _set_ */ +MNG_EXT mng_uint32 MNG_DECL mng_get_canvasstyle (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_bkgdstyle (mng_handle hHandle); + +/* see _set_ */ +MNG_EXT mng_retcode MNG_DECL mng_get_bgcolor (mng_handle hHandle, + mng_uint16* iRed, + mng_uint16* iGreen, + mng_uint16* iBlue); + +/* see _set_ */ +MNG_EXT mng_bool MNG_DECL mng_get_usebkgd (mng_handle hHandle); + +/* see _set_ */ +MNG_EXT mng_bool MNG_DECL mng_get_storechunks (mng_handle hHandle); + +/* see _set_ */ +MNG_EXT mng_bool MNG_DECL mng_get_sectionbreaks (mng_handle hHandle); + +/* see _set_ */ +MNG_EXT mng_bool MNG_DECL mng_get_cacheplayback (mng_handle hHandle); + +/* see _set_ */ +MNG_EXT mng_bool MNG_DECL mng_get_doprogressive (mng_handle hHandle); + +/* see _set_ */ +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_FULL_CMS) +MNG_EXT mng_bool MNG_DECL mng_get_srgb (mng_handle hHandle); +#endif + +/* see _set_ */ +MNG_EXT mng_float MNG_DECL mng_get_viewgamma (mng_handle hHandle); +MNG_EXT mng_float MNG_DECL mng_get_displaygamma (mng_handle hHandle); +MNG_EXT mng_float MNG_DECL mng_get_dfltimggamma (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_viewgammaint (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_displaygammaint (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_dfltimggammaint (mng_handle hHandle); + +/* see _set_ */ +MNG_EXT mng_uint32 MNG_DECL mng_get_maxcanvaswidth (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_maxcanvasheight (mng_handle hHandle); + +/* see _set_ */ +#ifdef MNG_INCLUDE_ZLIB +MNG_EXT mng_int32 MNG_DECL mng_get_zlib_level (mng_handle hHandle); +MNG_EXT mng_int32 MNG_DECL mng_get_zlib_method (mng_handle hHandle); +MNG_EXT mng_int32 MNG_DECL mng_get_zlib_windowbits (mng_handle hHandle); +MNG_EXT mng_int32 MNG_DECL mng_get_zlib_memlevel (mng_handle hHandle); +MNG_EXT mng_int32 MNG_DECL mng_get_zlib_strategy (mng_handle hHandle); + +MNG_EXT mng_uint32 MNG_DECL mng_get_zlib_maxidat (mng_handle hHandle); +#endif /* MNG_INCLUDE_ZLIB */ + +/* see _set_ */ +#ifdef MNG_INCLUDE_JNG +#ifdef MNG_INCLUDE_IJG6B +MNG_EXT mngjpeg_dctmethod + MNG_DECL mng_get_jpeg_dctmethod (mng_handle hHandle); +#endif +MNG_EXT mng_int32 MNG_DECL mng_get_jpeg_quality (mng_handle hHandle); +MNG_EXT mng_int32 MNG_DECL mng_get_jpeg_smoothing (mng_handle hHandle); +MNG_EXT mng_bool MNG_DECL mng_get_jpeg_progressive(mng_handle hHandle); +MNG_EXT mng_bool MNG_DECL mng_get_jpeg_optimized (mng_handle hHandle); + +MNG_EXT mng_uint32 MNG_DECL mng_get_jpeg_maxjdat (mng_handle hHandle); +#endif /* MNG_INCLUDE_JNG */ + +/* see _set_ */ +#if defined(MNG_SUPPORT_READ) +MNG_EXT mng_bool MNG_DECL mng_get_suspensionmode (mng_handle hHandle); +#endif + +/* see _set_ */ +#if defined(MNG_SUPPORT_DISPLAY) +MNG_EXT mng_speedtype + MNG_DECL mng_get_speed (mng_handle hHandle); +#endif + +/* Image-level */ +/* this can be used inside the processtext callback to determine the level of + text of the image being processed; the value 1 is returned for top-level + texts, and the value 2 for a text inside an embedded image inside a MNG */ +MNG_EXT mng_uint32 MNG_DECL mng_get_imagelevel (mng_handle hHandle); + +/* Display status variables */ +/* these get filled & updated during display processing */ +/* starttime is the tickcount at the start of displaying the animation */ +/* runtime is the actual number of millisecs since the start of the animation */ +/* currentframe, currentlayer & currentplaytime indicate the current + frame/layer/playtime(msecs) in the animation (these keep increasing; + even after the animation loops back to the TERM chunk) */ +#if defined(MNG_SUPPORT_DISPLAY) +MNG_EXT mng_uint32 MNG_DECL mng_get_starttime (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_runtime (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_currentframe (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_currentlayer (mng_handle hHandle); +MNG_EXT mng_uint32 MNG_DECL mng_get_currentplaytime (mng_handle hHandle); +#endif + +/* Status variables */ +/* these indicate the internal state of the library */ +/* most indicate exactly what you would expect: + status_error returns MNG_TRUE if the last function call returned an errorcode + status_reading returns MNG_TRUE if the library is (still) reading an image + status_suspendbreak returns MNG_TRUE if the library has suspended for "I/O" + status_creating returns MNG_TRUE if the library is in the middle of creating an image + status_writing returns MNG_TRUE if the library is in the middle of writing an image + status_displaying returns MNG_TRUE if the library is displaying an image + status_running returns MNG_TRUE if display processing is active (eg. not frozen or reset) + status_timerbreak returns MNG_TRUE if the library has suspended for a "timer-break" */ +/* eg. mng_readdisplay() will turn the reading, displaying and running status on; + when EOF is reached the reading status will be turned off */ +MNG_EXT mng_bool MNG_DECL mng_status_error (mng_handle hHandle); +#ifdef MNG_SUPPORT_READ +MNG_EXT mng_bool MNG_DECL mng_status_reading (mng_handle hHandle); +MNG_EXT mng_bool MNG_DECL mng_status_suspendbreak (mng_handle hHandle); +#endif +#ifdef MNG_SUPPORT_WRITE +MNG_EXT mng_bool MNG_DECL mng_status_creating (mng_handle hHandle); +MNG_EXT mng_bool MNG_DECL mng_status_writing (mng_handle hHandle); +#endif +#ifdef MNG_SUPPORT_DISPLAY +MNG_EXT mng_bool MNG_DECL mng_status_displaying (mng_handle hHandle); +MNG_EXT mng_bool MNG_DECL mng_status_running (mng_handle hHandle); +MNG_EXT mng_bool MNG_DECL mng_status_timerbreak (mng_handle hHandle); +#endif + +/* ************************************************************************** */ +/* * * */ +/* * Chunk access functions * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_ACCESS_CHUNKS + +/* ************************************************************************** */ + +/* use this to iterate the stored chunks */ +/* requires MNG_ACCESS_CHUNKS & MNG_STORE_CHUNKS */ +/* starts from the supplied chunk-index-nr; the first chunk has index 0!! */ +MNG_EXT mng_retcode MNG_DECL mng_iterate_chunks (mng_handle hHandle, + mng_uint32 iChunkseq, + mng_iteratechunk fProc); + +/* ************************************************************************** */ + +/* use these to get chunk data from within the callback in iterate_chunks */ +MNG_EXT mng_retcode MNG_DECL mng_getchunk_ihdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint8 *iBitdepth, + mng_uint8 *iColortype, + mng_uint8 *iCompression, + mng_uint8 *iFilter, + mng_uint8 *iInterlace); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_plte (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount, + mng_palette8 *aPalette); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_idat (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iRawlen, + mng_ptr *pRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_trns (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_bool *bGlobal, + mng_uint8 *iType, + mng_uint32 *iCount, + mng_uint8arr *aAlphas, + mng_uint16 *iGray, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint32 *iRawlen, + mng_uint8arr *aRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_gama (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iGamma); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_chrm (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iWhitepointx, + mng_uint32 *iWhitepointy, + mng_uint32 *iRedx, + mng_uint32 *iRedy, + mng_uint32 *iGreenx, + mng_uint32 *iGreeny, + mng_uint32 *iBluex, + mng_uint32 *iBluey); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_srgb (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iRenderingintent); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_iccp (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iNamesize, + mng_pchar *zName, + mng_uint8 *iCompression, + mng_uint32 *iProfilesize, + mng_ptr *pProfile); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_text (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordsize, + mng_pchar *zKeyword, + mng_uint32 *iTextsize, + mng_pchar *zText); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_ztxt (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordsize, + mng_pchar *zKeyword, + mng_uint8 *iCompression, + mng_uint32 *iTextsize, + mng_pchar *zText); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_itxt (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordsize, + mng_pchar *zKeyword, + mng_uint8 *iCompressionflag, + mng_uint8 *iCompressionmethod, + mng_uint32 *iLanguagesize, + mng_pchar *zLanguage, + mng_uint32 *iTranslationsize, + mng_pchar *zTranslation, + mng_uint32 *iTextsize, + mng_pchar *zText); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_bkgd (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iType, + mng_uint8 *iIndex, + mng_uint16 *iGray, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_phys (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iSizex, + mng_uint32 *iSizey, + mng_uint8 *iUnit); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_sbit (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iType, + mng_uint8arr4 *aBits); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_splt (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iNamesize, + mng_pchar *zName, + mng_uint8 *iSampledepth, + mng_uint32 *iEntrycount, + mng_ptr *pEntries); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_hist (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iEntrycount, + mng_uint16arr *aEntries); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_time (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iYear, + mng_uint8 *iMonth, + mng_uint8 *iDay, + mng_uint8 *iHour, + mng_uint8 *iMinute, + mng_uint8 *iSecond); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_mhdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint32 *iTicks, + mng_uint32 *iLayercount, + mng_uint32 *iFramecount, + mng_uint32 *iPlaytime, + mng_uint32 *iSimplicity); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_loop (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iLevel, + mng_uint32 *iRepeat, + mng_uint8 *iTermination, + mng_uint32 *iItermin, + mng_uint32 *iItermax, + mng_uint32 *iCount, + mng_uint32p *pSignals); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_endl (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iLevel); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_defi (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iObjectid, + mng_uint8 *iDonotshow, + mng_uint8 *iConcrete, + mng_bool *bHasloca, + mng_int32 *iXlocation, + mng_int32 *iYlocation, + mng_bool *bHasclip, + mng_int32 *iLeftcb, + mng_int32 *iRightcb, + mng_int32 *iTopcb, + mng_int32 *iBottomcb); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_basi (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint8 *iBitdepth, + mng_uint8 *iColortype, + mng_uint8 *iCompression, + mng_uint8 *iFilter, + mng_uint8 *iInterlace, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint16 *iAlpha, + mng_uint8 *iViewable); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_clon (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iSourceid, + mng_uint16 *iCloneid, + mng_uint8 *iClonetype, + mng_uint8 *iDonotshow, + mng_uint8 *iConcrete, + mng_bool *bHasloca, + mng_uint8 *iLocationtype, + mng_int32 *iLocationx, + mng_int32 *iLocationy); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_past (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iDestid, + mng_uint8 *iTargettype, + mng_int32 *iTargetx, + mng_int32 *iTargety, + mng_uint32 *iCount); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_past_src (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_uint16 *iSourceid, + mng_uint8 *iComposition, + mng_uint8 *iOrientation, + mng_uint8 *iOffsettype, + mng_int32 *iOffsetx, + mng_int32 *iOffsety, + mng_uint8 *iBoundarytype, + mng_int32 *iBoundaryl, + mng_int32 *iBoundaryr, + mng_int32 *iBoundaryt, + mng_int32 *iBoundaryb); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_disc (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount, + mng_uint16p *pObjectids); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_back (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint8 *iMandatory, + mng_uint16 *iImageid, + mng_uint8 *iTile); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_fram (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iMode, + mng_uint32 *iNamesize, + mng_pchar *zName, + mng_uint8 *iChangedelay, + mng_uint8 *iChangetimeout, + mng_uint8 *iChangeclipping, + mng_uint8 *iChangesyncid, + mng_uint32 *iDelay, + mng_uint32 *iTimeout, + mng_uint8 *iBoundarytype, + mng_int32 *iBoundaryl, + mng_int32 *iBoundaryr, + mng_int32 *iBoundaryt, + mng_int32 *iBoundaryb, + mng_uint32 *iCount, + mng_uint32p *pSyncids); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_move (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint8 *iMovetype, + mng_int32 *iMovex, + mng_int32 *iMovey); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_clip (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint8 *iCliptype, + mng_int32 *iClipl, + mng_int32 *iClipr, + mng_int32 *iClipt, + mng_int32 *iClipb); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_show (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint8 *iMode); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_term (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iTermaction, + mng_uint8 *iIteraction, + mng_uint32 *iDelay, + mng_uint32 *iItermax); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_save (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iOffsettype, + mng_uint32 *iCount); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_save_entry (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_uint8 *iEntrytype, + mng_uint32arr2 *iOffset, + mng_uint32arr2 *iStarttime, + mng_uint32 *iLayernr, + mng_uint32 *iFramenr, + mng_uint32 *iNamesize, + mng_pchar *zName); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_seek (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iNamesize, + mng_pchar *zName); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_expi (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iSnapshotid, + mng_uint32 *iNamesize, + mng_pchar *zName); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_fpri (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iDeltatype, + mng_uint8 *iPriority); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_need (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordssize, + mng_pchar *zKeywords); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_phyg (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iSizex, + mng_uint32 *iSizey, + mng_uint8 *iUnit); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_jhdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint8 *iColortype, + mng_uint8 *iImagesampledepth, + mng_uint8 *iImagecompression, + mng_uint8 *iImageinterlace, + mng_uint8 *iAlphasampledepth, + mng_uint8 *iAlphacompression, + mng_uint8 *iAlphafilter, + mng_uint8 *iAlphainterlace); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_jdat (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iRawlen, + mng_ptr *pRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_jdaa (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iRawlen, + mng_ptr *pRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_dhdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iObjectid, + mng_uint8 *iImagetype, + mng_uint8 *iDeltatype, + mng_uint32 *iBlockwidth, + mng_uint32 *iBlockheight, + mng_uint32 *iBlockx, + mng_uint32 *iBlocky); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_prom (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iColortype, + mng_uint8 *iSampledepth, + mng_uint8 *iFilltype); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_pplt (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_pplt_entry (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint16 *iAlpha, + mng_bool *bUsed); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_drop (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount, + mng_chunkidp *pChunknames); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_dbyk (mng_handle hHandle, + mng_handle hChunk, + mng_chunkid *iChunkname, + mng_uint8 *iPolarity, + mng_uint32 *iKeywordssize, + mng_pchar *zKeywords); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_ordr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_ordr_entry (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_chunkid *iChunkname, + mng_uint8 *iOrdertype); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_magn (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint16 *iMethodX, + mng_uint16 *iMX, + mng_uint16 *iMY, + mng_uint16 *iML, + mng_uint16 *iMR, + mng_uint16 *iMT, + mng_uint16 *iMB, + mng_uint16 *iMethodY); + +MNG_EXT mng_retcode MNG_DECL mng_getchunk_unknown (mng_handle hHandle, + mng_handle hChunk, + mng_chunkid *iChunkname, + mng_uint32 *iRawlen, + mng_ptr *pRawdata); + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_WRITE_PROCS + +/* use these to create new chunks at the end of the chunk-list */ +/* requires at least MNG_ACCESS_CHUNKS (MNG_SUPPORT_WRITE may be nice too) */ +MNG_EXT mng_retcode MNG_DECL mng_putchunk_ihdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_plte (mng_handle hHandle, + mng_uint32 iCount, + mng_palette8 aPalette); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_idat (mng_handle hHandle, + mng_uint32 iRawlen, + mng_ptr pRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_iend (mng_handle hHandle); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_trns (mng_handle hHandle, + mng_bool bEmpty, + mng_bool bGlobal, + mng_uint8 iType, + mng_uint32 iCount, + mng_uint8arr aAlphas, + mng_uint16 iGray, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint32 iRawlen, + mng_uint8arr aRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_gama (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iGamma); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_chrm (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iWhitepointx, + mng_uint32 iWhitepointy, + mng_uint32 iRedx, + mng_uint32 iRedy, + mng_uint32 iGreenx, + mng_uint32 iGreeny, + mng_uint32 iBluex, + mng_uint32 iBluey); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_srgb (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iRenderingintent); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_iccp (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iNamesize, + mng_pchar zName, + mng_uint8 iCompression, + mng_uint32 iProfilesize, + mng_ptr pProfile); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_text (mng_handle hHandle, + mng_uint32 iKeywordsize, + mng_pchar zKeyword, + mng_uint32 iTextsize, + mng_pchar zText); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_ztxt (mng_handle hHandle, + mng_uint32 iKeywordsize, + mng_pchar zKeyword, + mng_uint8 iCompression, + mng_uint32 iTextsize, + mng_pchar zText); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_itxt (mng_handle hHandle, + mng_uint32 iKeywordsize, + mng_pchar zKeyword, + mng_uint8 iCompressionflag, + mng_uint8 iCompressionmethod, + mng_uint32 iLanguagesize, + mng_pchar zLanguage, + mng_uint32 iTranslationsize, + mng_pchar zTranslation, + mng_uint32 iTextsize, + mng_pchar zText); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_bkgd (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iType, + mng_uint8 iIndex, + mng_uint16 iGray, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_phys (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iSizex, + mng_uint32 iSizey, + mng_uint8 iUnit); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_sbit (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iType, + mng_uint8arr4 aBits); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_splt (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iNamesize, + mng_pchar zName, + mng_uint8 iSampledepth, + mng_uint32 iEntrycount, + mng_ptr pEntries); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_hist (mng_handle hHandle, + mng_uint32 iEntrycount, + mng_uint16arr aEntries); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_time (mng_handle hHandle, + mng_uint16 iYear, + mng_uint8 iMonth, + mng_uint8 iDay, + mng_uint8 iHour, + mng_uint8 iMinute, + mng_uint8 iSecond); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_mhdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint32 iTicks, + mng_uint32 iLayercount, + mng_uint32 iFramecount, + mng_uint32 iPlaytime, + mng_uint32 iSimplicity); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_mend (mng_handle hHandle); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_loop (mng_handle hHandle, + mng_uint8 iLevel, + mng_uint32 iRepeat, + mng_uint8 iTermination, + mng_uint32 iItermin, + mng_uint32 iItermax, + mng_uint32 iCount, + mng_uint32p pSignals); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_endl (mng_handle hHandle, + mng_uint8 iLevel); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_defi (mng_handle hHandle, + mng_uint16 iObjectid, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_int32 iXlocation, + mng_int32 iYlocation, + mng_bool bHasclip, + mng_int32 iLeftcb, + mng_int32 iRightcb, + mng_int32 iTopcb, + mng_int32 iBottomcb); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_basi (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint16 iAlpha, + mng_uint8 iViewable); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_clon (mng_handle hHandle, + mng_uint16 iSourceid, + mng_uint16 iCloneid, + mng_uint8 iClonetype, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_past (mng_handle hHandle, + mng_uint16 iDestid, + mng_uint8 iTargettype, + mng_int32 iTargetx, + mng_int32 iTargety, + mng_uint32 iCount); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_past_src (mng_handle hHandle, + mng_uint32 iEntry, + mng_uint16 iSourceid, + mng_uint8 iComposition, + mng_uint8 iOrientation, + mng_uint8 iOffsettype, + mng_int32 iOffsetx, + mng_int32 iOffsety, + mng_uint8 iBoundarytype, + mng_int32 iBoundaryl, + mng_int32 iBoundaryr, + mng_int32 iBoundaryt, + mng_int32 iBoundaryb); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_disc (mng_handle hHandle, + mng_uint32 iCount, + mng_uint16p pObjectids); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_back (mng_handle hHandle, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint8 iMandatory, + mng_uint16 iImageid, + mng_uint8 iTile); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_fram (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iMode, + mng_uint32 iNamesize, + mng_pchar zName, + mng_uint8 iChangedelay, + mng_uint8 iChangetimeout, + mng_uint8 iChangeclipping, + mng_uint8 iChangesyncid, + mng_uint32 iDelay, + mng_uint32 iTimeout, + mng_uint8 iBoundarytype, + mng_int32 iBoundaryl, + mng_int32 iBoundaryr, + mng_int32 iBoundaryt, + mng_int32 iBoundaryb, + mng_uint32 iCount, + mng_uint32p pSyncids); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_move (mng_handle hHandle, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iMovetype, + mng_int32 iMovex, + mng_int32 iMovey); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_clip (mng_handle hHandle, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_show (mng_handle hHandle, + mng_bool bEmpty, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iMode); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_term (mng_handle hHandle, + mng_uint8 iTermaction, + mng_uint8 iIteraction, + mng_uint32 iDelay, + mng_uint32 iItermax); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_save (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iOffsettype, + mng_uint32 iCount); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_save_entry (mng_handle hHandle, + mng_uint32 iEntry, + mng_uint8 iEntrytype, + mng_uint32arr2 iOffset, + mng_uint32arr2 iStarttime, + mng_uint32 iLayernr, + mng_uint32 iFramenr, + mng_uint32 iNamesize, + mng_pchar zName); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_seek (mng_handle hHandle, + mng_uint32 iNamesize, + mng_pchar zName); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_expi (mng_handle hHandle, + mng_uint16 iSnapshotid, + mng_uint32 iNamesize, + mng_pchar zName); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_fpri (mng_handle hHandle, + mng_uint8 iDeltatype, + mng_uint8 iPriority); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_need (mng_handle hHandle, + mng_uint32 iKeywordssize, + mng_pchar zKeywords); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_phyg (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iSizex, + mng_uint32 iSizey, + mng_uint8 iUnit); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_jhdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iColortype, + mng_uint8 iImagesampledepth, + mng_uint8 iImagecompression, + mng_uint8 iImageinterlace, + mng_uint8 iAlphasampledepth, + mng_uint8 iAlphacompression, + mng_uint8 iAlphafilter, + mng_uint8 iAlphainterlace); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_jdat (mng_handle hHandle, + mng_uint32 iRawlen, + mng_ptr pRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_jdaa (mng_handle hHandle, + mng_uint32 iRawlen, + mng_ptr pRawdata); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_jsep (mng_handle hHandle); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_dhdr (mng_handle hHandle, + mng_uint16 iObjectid, + mng_uint8 iImagetype, + mng_uint8 iDeltatype, + mng_uint32 iBlockwidth, + mng_uint32 iBlockheight, + mng_uint32 iBlockx, + mng_uint32 iBlocky); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_prom (mng_handle hHandle, + mng_uint8 iColortype, + mng_uint8 iSampledepth, + mng_uint8 iFilltype); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_ipng (mng_handle hHandle); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_pplt (mng_handle hHandle, + mng_uint32 iCount); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_pplt_entry (mng_handle hHandle, + mng_uint32 iEntry, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint16 iAlpha, + mng_bool bUsed); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_jpng (mng_handle hHandle); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_drop (mng_handle hHandle, + mng_uint32 iCount, + mng_chunkidp pChunknames); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_dbyk (mng_handle hHandle, + mng_chunkid iChunkname, + mng_uint8 iPolarity, + mng_uint32 iKeywordssize, + mng_pchar zKeywords); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_ordr (mng_handle hHandle, + mng_uint32 iCount); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_ordr_entry (mng_handle hHandle, + mng_uint32 iEntry, + mng_chunkid iChunkname, + mng_uint8 iOrdertype); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_magn (mng_handle hHandle, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint16 iMethodX, + mng_uint16 iMX, + mng_uint16 iMY, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint16 iMT, + mng_uint16 iMB, + mng_uint16 iMethodY); + +MNG_EXT mng_retcode MNG_DECL mng_putchunk_unknown (mng_handle hHandle, + mng_chunkid iChunkname, + mng_uint32 iRawlen, + mng_ptr pRawdata); + +#endif /* MNG_INCLUDE_WRITE_PROCS */ + +/* ************************************************************************** */ + +/* use these functions to access the actual image-data in stored chunks, + as opposed to the IDAT/JDAT data */ +/* to get accurate pixel-data the canvasstyle should seriously reflect the + bitdepth/colortype combination of the preceding IHDR/JHDR/BASI/DHDR; + all input can be converted to rgb(a)8 (rgb(a)16 for 16-bit images), but + there are only limited conversions back (see below for putimgdata) */ + +/* call this function if you want to extract the nth image from the list; + the first image is designated seqnr 0! */ +/* this function finds the IHDR/JHDR/BASI/DHDR with the appropriate seqnr, + starting from the beginning of the chunk-list; this may tend to get a little + slow for animations with a large number of chunks for images near the end */ +/* supplying a seqnr past the last image in the animation will return with + an errorcode */ +MNG_EXT mng_retcode MNG_DECL mng_getimgdata_seq (mng_handle hHandle, + mng_uint32 iSeqnr, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline); + +/* both the following functions will search forward to find the first IDAT/JDAT, + and then traverse back to find the start of the image (IHDR,JHDR,DHDR,BASI); + note that this is very fast compared to decoding the IDAT/JDAT, so there's + not really a need for optimization; either can be called from the + iterate_chunks callback when a IHDR/JHDR is encountered; for BASI/DHDR there + may not be real image-data so it's wisest to keep iterating till the IEND, + and then call either of these functions if necessary (remember the correct seqnr!) */ + +/* call this function if you want to extract the image starting at or after the nth + position in the chunk-list; this number is returned in the iterate_chunks callback */ +MNG_EXT mng_retcode MNG_DECL mng_getimgdata_chunkseq (mng_handle hHandle, + mng_uint32 iSeqnr, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline); + +/* call this function if you want to extract the image starting at or after the + indicated chunk; the handle of a chunk is returned in the iterate_chunks callback */ +MNG_EXT mng_retcode MNG_DECL mng_getimgdata_chunk (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline); + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_WRITE_PROCS + +/* use the following functions to add image-data to the list of stored chunks */ +/* note that this only adds the IDAT or JDAT chunks and no others; you must call + one of these functions after you 'put' the initial chunks of the image and + before you 'put' the closing chunks */ +/* the canvasstyle should seriously reflect the bitdepth/colortype combination; + eg. bitdepth=16 would expect a 16-bit canvasstyle, + colortype=g or ga would expect a gray or gray+alpha style respectively + and so on, and so forth ... + (nb. the number of conversions will be extremely limited for the moment!) */ + +MNG_EXT mng_retcode MNG_DECL mng_putimgdata_ihdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iColortype, + mng_uint8 iBitdepth, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline); + +MNG_EXT mng_retcode MNG_DECL mng_putimgdata_jhdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iColortype, + mng_uint8 iBitdepth, + mng_uint8 iCompression, + mng_uint8 iInterlace, + mng_uint8 iAlphaBitdepth, + mng_uint8 iAlphaCompression, + mng_uint8 iAlphaFilter, + mng_uint8 iAlphaInterlace, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline); + +/* ************************************************************************** */ + +/* use the following functions to set the framecount/layercount/playtime or + simplicity of an animation you are creating; this may be useful if these + variables are calculated during the creation-process */ + +MNG_EXT mng_retcode MNG_DECL mng_updatemngheader (mng_handle hHandle, + mng_uint32 iFramecount, + mng_uint32 iLayercount, + mng_uint32 iPlaytime); + +MNG_EXT mng_retcode MNG_DECL mng_updatemngsimplicity (mng_handle hHandle, + mng_uint32 iSimplicity); + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_WRITE_PROCS */ + +#endif /* MNG_ACCESS_CHUNKS */ + +/* ************************************************************************** */ +/* * * */ +/* * Error-code structure * */ +/* * * */ +/* * 0b0000 00xx xxxx xxxx - basic errors; severity 9 (environment) * */ +/* * 0b0000 01xx xxxx xxxx - chunk errors; severity 9 (image induced) * */ +/* * 0b0000 10xx xxxx xxxx - severity 5 errors (application induced) * */ +/* * 0b0001 00xx xxxx xxxx - severity 2 warnings (recoverable) * */ +/* * 0b0010 00xx xxxx xxxx - severity 1 warnings (recoverable) * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_NOERROR (mng_retcode)0 /* er.. indicates all's well */ + +#define MNG_OUTOFMEMORY (mng_retcode)1 /* oops, buy some megabytes! */ +#define MNG_INVALIDHANDLE (mng_retcode)2 /* call mng_initialize first */ +#define MNG_NOCALLBACK (mng_retcode)3 /* set the callbacks please */ +#define MNG_UNEXPECTEDEOF (mng_retcode)4 /* what'd ya do with the data? */ +#define MNG_ZLIBERROR (mng_retcode)5 /* zlib burped */ +#define MNG_JPEGERROR (mng_retcode)6 /* jpglib complained */ +#define MNG_LCMSERROR (mng_retcode)7 /* little cms stressed out */ +#define MNG_NOOUTPUTPROFILE (mng_retcode)8 /* no output-profile defined */ +#define MNG_NOSRGBPROFILE (mng_retcode)9 /* no sRGB-profile defined */ +#define MNG_BUFOVERFLOW (mng_retcode)10 /* zlib output-buffer overflow */ +#define MNG_FUNCTIONINVALID (mng_retcode)11 /* ay, totally inappropriate */ +#define MNG_OUTPUTERROR (mng_retcode)12 /* disk full ? */ +#define MNG_JPEGBUFTOOSMALL (mng_retcode)13 /* can't handle buffer overflow*/ +#define MNG_NEEDMOREDATA (mng_retcode)14 /* I'm hungry, give me more */ +#define MNG_NEEDTIMERWAIT (mng_retcode)15 /* Sleep a while then wake me */ +#define MNG_NEEDSECTIONWAIT (mng_retcode)16 /* just processed a SEEK */ +#define MNG_LOOPWITHCACHEOFF (mng_retcode)17 /* LOOP when playback info off */ + +#define MNG_DLLNOTLOADED (mng_retcode)99 /* late binding failed */ + +#define MNG_APPIOERROR (mng_retcode)901 /* application I/O error */ +#define MNG_APPTIMERERROR (mng_retcode)902 /* application timing error */ +#define MNG_APPCMSERROR (mng_retcode)903 /* application CMS error */ +#define MNG_APPMISCERROR (mng_retcode)904 /* application other error */ +#define MNG_APPTRACEABORT (mng_retcode)905 /* application aborts on trace */ + +#define MNG_INTERNALERROR (mng_retcode)999 /* internal inconsistancy */ + +#define MNG_INVALIDSIG (mng_retcode)1025 /* invalid graphics file */ +#define MNG_INVALIDCRC (mng_retcode)1027 /* crc check failed */ +#define MNG_INVALIDLENGTH (mng_retcode)1028 /* chunklength mystifies me */ +#define MNG_SEQUENCEERROR (mng_retcode)1029 /* invalid chunk sequence */ +#define MNG_CHUNKNOTALLOWED (mng_retcode)1030 /* completely out-of-place */ +#define MNG_MULTIPLEERROR (mng_retcode)1031 /* only one occurence allowed */ +#define MNG_PLTEMISSING (mng_retcode)1032 /* indexed-color requires PLTE */ +#define MNG_IDATMISSING (mng_retcode)1033 /* IHDR-block requires IDAT */ +#define MNG_CANNOTBEEMPTY (mng_retcode)1034 /* must contain some data */ +#define MNG_GLOBALLENGTHERR (mng_retcode)1035 /* global data incorrect */ +#define MNG_INVALIDBITDEPTH (mng_retcode)1036 /* bitdepth out-of-range */ +#define MNG_INVALIDCOLORTYPE (mng_retcode)1037 /* colortype out-of-range */ +#define MNG_INVALIDCOMPRESS (mng_retcode)1038 /* compression method invalid */ +#define MNG_INVALIDFILTER (mng_retcode)1039 /* filter method invalid */ +#define MNG_INVALIDINTERLACE (mng_retcode)1040 /* interlace method invalid */ +#define MNG_NOTENOUGHIDAT (mng_retcode)1041 /* ran out of compressed data */ +#define MNG_PLTEINDEXERROR (mng_retcode)1042 /* palette-index out-of-range */ +#define MNG_NULLNOTFOUND (mng_retcode)1043 /* couldn't find null-separator*/ +#define MNG_KEYWORDNULL (mng_retcode)1044 /* keyword cannot be empty */ +#define MNG_OBJECTUNKNOWN (mng_retcode)1045 /* the object can't be found */ +#define MNG_OBJECTEXISTS (mng_retcode)1046 /* the object already exists */ +#define MNG_TOOMUCHIDAT (mng_retcode)1047 /* got too much compressed data*/ +#define MNG_INVSAMPLEDEPTH (mng_retcode)1048 /* sampledepth out-of-range */ +#define MNG_INVOFFSETSIZE (mng_retcode)1049 /* invalid offset-size */ +#define MNG_INVENTRYTYPE (mng_retcode)1050 /* invalid entry-type */ +#define MNG_ENDWITHNULL (mng_retcode)1051 /* may not end with NULL */ +#define MNG_INVIMAGETYPE (mng_retcode)1052 /* invalid image_type */ +#define MNG_INVDELTATYPE (mng_retcode)1053 /* invalid delta_type */ +#define MNG_INVALIDINDEX (mng_retcode)1054 /* index-value invalid */ +#define MNG_TOOMUCHJDAT (mng_retcode)1055 /* got too much compressed data*/ +#define MNG_JPEGPARMSERR (mng_retcode)1056 /* JHDR/JPEG parms do not match*/ +#define MNG_INVFILLMETHOD (mng_retcode)1057 /* invalid fill_method */ +#define MNG_OBJNOTCONCRETE (mng_retcode)1058 /* object must be concrete */ +#define MNG_TARGETNOALPHA (mng_retcode)1059 /* object has no alpha-channel */ +#define MNG_MNGTOOCOMPLEX (mng_retcode)1060 /* can't handle complexity */ +#define MNG_UNKNOWNCRITICAL (mng_retcode)1061 /* unknown critical chunk found*/ +#define MNG_UNSUPPORTEDNEED (mng_retcode)1062 /* nEED requirement unsupported*/ +#define MNG_INVALIDDELTA (mng_retcode)1063 /* Delta operation illegal */ +#define MNG_INVALIDMETHOD (mng_retcode)1064 /* invalid MAGN method */ + +#define MNG_INVALIDCNVSTYLE (mng_retcode)2049 /* can't make anything of this */ +#define MNG_WRONGCHUNK (mng_retcode)2050 /* accessing the wrong chunk */ +#define MNG_INVALIDENTRYIX (mng_retcode)2051 /* accessing the wrong entry */ +#define MNG_NOHEADER (mng_retcode)2052 /* must have had header first */ +#define MNG_NOCORRCHUNK (mng_retcode)2053 /* can't find parent chunk */ +#define MNG_NOMHDR (mng_retcode)2054 /* no MNG header available */ + +#define MNG_IMAGETOOLARGE (mng_retcode)4097 /* input-image way too big */ +#define MNG_NOTANANIMATION (mng_retcode)4098 /* file not a MNG */ +#define MNG_FRAMENRTOOHIGH (mng_retcode)4099 /* frame-nr out-of-range */ +#define MNG_LAYERNRTOOHIGH (mng_retcode)4100 /* layer-nr out-of-range */ +#define MNG_PLAYTIMETOOHIGH (mng_retcode)4101 /* playtime out-of-range */ +#define MNG_FNNOTIMPLEMENTED (mng_retcode)4102 /* function not yet available */ + +#define MNG_IMAGEFROZEN (mng_retcode)8193 /* stopped displaying */ + +#define MNG_LCMS_NOHANDLE 1 /* LCMS returned NULL handle */ +#define MNG_LCMS_NOMEM 2 /* LCMS returned NULL gammatab */ +#define MNG_LCMS_NOTRANS 3 /* LCMS returned NULL transform*/ + +/* ************************************************************************** */ +/* * * */ +/* * Canvas styles * */ +/* * * */ +/* * Note that the intentions are pretty darn good, but that the focus * */ +/* * is currently on 8-bit color support * */ +/* * * */ +/* * The RGB8_A8 style is defined for apps that require a separate * */ +/* * canvas for the color-planes and the alpha-plane (eg. mozilla) * */ +/* * This requires for the app to supply the "getalphaline" callback!!! * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_CANVAS_RGB8 0x00000000L +#define MNG_CANVAS_RGBA8 0x00001000L +#define MNG_CANVAS_ARGB8 0x00003000L +#define MNG_CANVAS_RGB8_A8 0x00005000L +#define MNG_CANVAS_BGR8 0x00000001L +#define MNG_CANVAS_BGRA8 0x00001001L +#define MNG_CANVAS_BGRA8PM 0x00009001L +#define MNG_CANVAS_ABGR8 0x00003001L +#define MNG_CANVAS_RGB16 0x00000100L /* not supported yet */ +#define MNG_CANVAS_RGBA16 0x00001100L /* not supported yet */ +#define MNG_CANVAS_ARGB16 0x00003100L /* not supported yet */ +#define MNG_CANVAS_BGR16 0x00000101L /* not supported yet */ +#define MNG_CANVAS_BGRA16 0x00001101L /* not supported yet */ +#define MNG_CANVAS_ABGR16 0x00003101L /* not supported yet */ +#define MNG_CANVAS_GRAY8 0x00000002L /* not supported yet */ +#define MNG_CANVAS_GRAY16 0x00000102L /* not supported yet */ +#define MNG_CANVAS_GRAYA8 0x00001002L /* not supported yet */ +#define MNG_CANVAS_GRAYA16 0x00001102L /* not supported yet */ +#define MNG_CANVAS_AGRAY8 0x00003002L /* not supported yet */ +#define MNG_CANVAS_AGRAY16 0x00003102L /* not supported yet */ +#define MNG_CANVAS_DX15 0x00000003L /* not supported yet */ +#define MNG_CANVAS_DX16 0x00000004L /* not supported yet */ + +#define MNG_CANVAS_PIXELTYPE(C) (C & 0x000000FFL) +#define MNG_CANVAS_BITDEPTH(C) (C & 0x00000100L) +#define MNG_CANVAS_HASALPHA(C) (C & 0x00001000L) +#define MNG_CANVAS_ALPHAFIRST(C) (C & 0x00002000L) +#define MNG_CANVAS_ALPHASEPD(C) (C & 0x00004000L) +#define MNG_CANVAS_ALPHAPM(C) (C & 0x00008000L) + +#define MNG_CANVAS_RGB(C) (MNG_CANVAS_PIXELTYPE (C) == 0) +#define MNG_CANVAS_BGR(C) (MNG_CANVAS_PIXELTYPE (C) == 1) +#define MNG_CANVAS_GRAY(C) (MNG_CANVAS_PIXELTYPE (C) == 2) +#define MNG_CANVAS_DIRECTX15(C) (MNG_CANVAS_PIXELTYPE (C) == 3) +#define MNG_CANVAS_DIRECTX16(C) (MNG_CANVAS_PIXELTYPE (C) == 4) +#define MNG_CANVAS_8BIT(C) (!MNG_CANVAS_BITDEPTH (C)) +#define MNG_CANVAS_16BIT(C) (MNG_CANVAS_BITDEPTH (C)) +#define MNG_CANVAS_PIXELFIRST(C) (!MNG_CANVAS_ALPHAFIRST (C)) + +/* ************************************************************************** */ +/* * * */ +/* * Chunk names (idea adapted from libpng 1.1.0 - png.h) * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_UINT_HUH 0x40404040L + +#define MNG_UINT_BACK 0x4241434bL +#define MNG_UINT_BASI 0x42415349L +#define MNG_UINT_CLIP 0x434c4950L +#define MNG_UINT_CLON 0x434c4f4eL +#define MNG_UINT_DBYK 0x4442594bL +#define MNG_UINT_DEFI 0x44454649L +#define MNG_UINT_DHDR 0x44484452L +#define MNG_UINT_DISC 0x44495343L +#define MNG_UINT_DROP 0x44524f50L +#define MNG_UINT_ENDL 0x454e444cL +#define MNG_UINT_FRAM 0x4652414dL +#define MNG_UINT_IDAT 0x49444154L +#define MNG_UINT_IEND 0x49454e44L +#define MNG_UINT_IHDR 0x49484452L +#define MNG_UINT_IJNG 0x494a4e47L +#define MNG_UINT_IPNG 0x49504e47L +#define MNG_UINT_JDAA 0x4a444141L +#define MNG_UINT_JDAT 0x4a444154L +#define MNG_UINT_JHDR 0x4a484452L +#define MNG_UINT_JSEP 0x4a534550L +#define MNG_UINT_JdAA 0x4a644141L +#define MNG_UINT_LOOP 0x4c4f4f50L +#define MNG_UINT_MAGN 0x4d41474eL +#define MNG_UINT_MEND 0x4d454e44L +#define MNG_UINT_MHDR 0x4d484452L +#define MNG_UINT_MOVE 0x4d4f5645L +#define MNG_UINT_ORDR 0x4f524452L +#define MNG_UINT_PAST 0x50415354L +#define MNG_UINT_PLTE 0x504c5445L +#define MNG_UINT_PPLT 0x50504c54L +#define MNG_UINT_PROM 0x50524f4dL +#define MNG_UINT_SAVE 0x53415645L +#define MNG_UINT_SEEK 0x5345454bL +#define MNG_UINT_SHOW 0x53484f57L +#define MNG_UINT_TERM 0x5445524dL +#define MNG_UINT_bKGD 0x624b4744L +#define MNG_UINT_cHRM 0x6348524dL +#define MNG_UINT_eXPI 0x65585049L +#define MNG_UINT_fPRI 0x66505249L +#define MNG_UINT_gAMA 0x67414d41L +#define MNG_UINT_hIST 0x68495354L +#define MNG_UINT_iCCP 0x69434350L +#define MNG_UINT_iTXt 0x69545874L +#define MNG_UINT_nEED 0x6e454544L +#define MNG_UINT_oFFs 0x6f464673L +#define MNG_UINT_pCAL 0x7043414cL +#define MNG_UINT_pHYg 0x70444167L +#define MNG_UINT_pHYs 0x70485973L +#define MNG_UINT_sBIT 0x73424954L +#define MNG_UINT_sCAL 0x7343414cL +#define MNG_UINT_sPLT 0x73504c54L +#define MNG_UINT_sRGB 0x73524742L +#define MNG_UINT_tEXt 0x74455874L +#define MNG_UINT_tIME 0x74494d45L +#define MNG_UINT_tRNS 0x74524e53L +#define MNG_UINT_zTXt 0x7a545874L + +/* ************************************************************************** */ +/* * * */ +/* * Chunk property values * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_BITDEPTH_1 1 /* IHDR, BASI, JHDR, PROM */ +#define MNG_BITDEPTH_2 2 +#define MNG_BITDEPTH_4 4 +#define MNG_BITDEPTH_8 8 /* sPLT */ +#define MNG_BITDEPTH_16 16 + +#define MNG_COLORTYPE_GRAY 0 /* IHDR, BASI, PROM */ +#define MNG_COLORTYPE_RGB 2 +#define MNG_COLORTYPE_INDEXED 3 +#define MNG_COLORTYPE_GRAYA 4 +#define MNG_COLORTYPE_RGBA 6 + +#define MNG_COMPRESSION_DEFLATE 0 /* IHDR, zTXt, iTXt, iCCP, + BASI, JHDR */ + +#define MNG_FILTER_ADAPTIVE 0 /* IHDR, BASI, JHDR */ +/* #define MNG_FILTER_NO_ADAPTIVE 1 */ +#define MNG_FILTER_NO_DIFFERING 0 +#define MNG_FILTER_DIFFERING 0x40 +/* #define MNG_FILTER_MASK (MNG_FILTER_NO_ADAPTIVE | MNG_FILTER_DIFFERING) */ + +#define MNG_INTERLACE_NONE 0 /* IHDR, BASI, JHDR */ +#define MNG_INTERLACE_ADAM7 1 + +#define MNG_FILTER_NONE 0 /* IDAT */ +#define MNG_FILTER_SUB 1 +#define MNG_FILTER_UP 2 +#define MNG_FILTER_AVERAGE 3 +#define MNG_FILTER_PAETH 4 + +#define MNG_INTENT_PERCEPTUAL 0 /* sRGB */ +#define MNG_INTENT_RELATIVECOLORIMETRIC 1 +#define MNG_INTENT_SATURATION 2 +#define MNG_INTENT_ABSOLUTECOLORIMETRIC 3 + /* tEXt, zTXt, iTXt */ +#define MNG_TEXT_TITLE "Title" +#define MNG_TEXT_AUTHOR "Author" +#define MNG_TEXT_DESCRIPTION "Description" +#define MNG_TEXT_COPYRIGHT "Copyright" +#define MNG_TEXT_CREATIONTIME "Creation Time" +#define MNG_TEXT_SOFTWARE "Software" +#define MNG_TEXT_DISCLAIMER "Disclaimer" +#define MNG_TEXT_WARNING "Warning" +#define MNG_TEXT_SOURCE "Source" +#define MNG_TEXT_COMMENT "Comment" + +#define MNG_FLAG_UNCOMPRESSED 0 /* iTXt */ +#define MNG_FLAG_COMPRESSED 1 + +#define MNG_UNIT_UNKNOWN 0 /* pHYs, pHYg */ +#define MNG_UNIT_METER 1 + /* MHDR */ +#define MNG_SIMPLICITY_VALID 0x00000001 +#define MNG_SIMPLICITY_SIMPLEFEATURES 0x00000002 +#define MNG_SIMPLICITY_COMPLEXFEATURES 0x00000004 +#define MNG_SIMPLICITY_TRANSPARENCY 0x00000008 +#define MNG_SIMPLICITY_JNG 0x00000010 +#define MNG_SIMPLICITY_DELTAPNG 0x00000020 + +#define MNG_TERMINATION_DECODER_NC 0 /* LOOP */ +#define MNG_TERMINATION_USER_NC 1 +#define MNG_TERMINATION_EXTERNAL_NC 2 +#define MNG_TERMINATION_DETERMINISTIC_NC 3 +#define MNG_TERMINATION_DECODER_C 4 +#define MNG_TERMINATION_USER_C 5 +#define MNG_TERMINATION_EXTERNAL_C 6 +#define MNG_TERMINATION_DETERMINISTIC_C 7 + +#define MNG_DONOTSHOW_VISIBLE 0 /* DEFI */ +#define MNG_DONOTSHOW_NOTVISIBLE 1 + +#define MNG_ABSTRACT 0 /* DEFI */ +#define MNG_CONCRETE 1 + +#define MNG_NOTVIEWABLE 0 /* BASI */ +#define MNG_VIEWABLE 1 + +#define MNG_FULL_CLONE 0 /* CLON */ +#define MNG_PARTIAL_CLONE 1 +#define MNG_RENUMBER 2 + +#define MNG_CONCRETE_ASPARENT 0 /* CLON */ +#define MNG_CONCRETE_MAKEABSTRACT 1 + +#define MNG_LOCATION_ABSOLUTE 0 /* CLON, MOVE */ +#define MNG_LOCATION_RELATIVE 1 + +#define MNG_TARGET_ABSOLUTE 0 /* PAST */ +#define MNG_TARGET_RELATIVE_SAMEPAST 1 +#define MNG_TARGET_RELATIVE_PREVPAST 2 + +#define MNG_COMPOSITE_OVER 0 /* PAST */ +#define MNG_COMPOSITE_REPLACE 1 +#define MNG_COMPOSITE_UNDER 2 + +#define MNG_ORIENTATION_SAME 0 /* PAST */ +#define MNG_ORIENTATION_180DEG 2 +#define MNG_ORIENTATION_FLIPHORZ 4 +#define MNG_ORIENTATION_FLIPVERT 6 +#define MNG_ORIENTATION_TILED 8 + +#define MNG_OFFSET_ABSOLUTE 0 /* PAST */ +#define MNG_OFFSET_RELATIVE 1 + +#define MNG_BOUNDARY_ABSOLUTE 0 /* PAST, FRAM */ +#define MNG_BOUNDARY_RELATIVE 1 + +#define MNG_BACKGROUNDCOLOR_MANDATORY 0x01 /* BACK */ +#define MNG_BACKGROUNDIMAGE_MANDATORY 0x02 /* BACK */ + +#define MNG_BACKGROUNDIMAGE_NOTILE 0 /* BACK */ +#define MNG_BACKGROUNDIMAGE_TILE 1 + +#define MNG_FRAMINGMODE_NOCHANGE 0 /* FRAM */ +#define MNG_FRAMINGMODE_1 1 +#define MNG_FRAMINGMODE_2 2 +#define MNG_FRAMINGMODE_3 3 +#define MNG_FRAMINGMODE_4 4 + +#define MNG_CHANGEDELAY_NO 0 /* FRAM */ +#define MNG_CHANGEDELAY_NEXTSUBFRAME 1 +#define MNG_CHANGEDELAY_DEFAULT 2 + +#define MNG_CHANGETIMOUT_NO 0 /* FRAM */ +#define MNG_CHANGETIMOUT_DETERMINISTIC_1 1 +#define MNG_CHANGETIMOUT_DETERMINISTIC_2 2 +#define MNG_CHANGETIMOUT_DECODER_1 3 +#define MNG_CHANGETIMOUT_DECODER_2 4 +#define MNG_CHANGETIMOUT_USER_1 5 +#define MNG_CHANGETIMOUT_USER_2 6 +#define MNG_CHANGETIMOUT_EXTERNAL_1 7 +#define MNG_CHANGETIMOUT_EXTERNAL_2 8 + +#define MNG_CHANGECLIPPING_NO 0 /* FRAM */ +#define MNG_CHANGECLIPPING_NEXTSUBFRAME 1 +#define MNG_CHANGECLIPPING_DEFAULT 2 + +#define MNG_CHANGESYNCID_NO 0 /* FRAM */ +#define MNG_CHANGESYNCID_NEXTSUBFRAME 1 +#define MNG_CHANGESYNCID_DEFAULT 2 + +#define MNG_CLIPPING_ABSOLUTE 0 /* CLIP */ +#define MNG_CLIPPING_RELATIVE 1 + +#define MNG_SHOWMODE_0 0 /* SHOW */ +#define MNG_SHOWMODE_1 1 +#define MNG_SHOWMODE_2 2 +#define MNG_SHOWMODE_3 3 +#define MNG_SHOWMODE_4 4 +#define MNG_SHOWMODE_5 5 +#define MNG_SHOWMODE_6 6 +#define MNG_SHOWMODE_7 7 + +#define MNG_TERMACTION_LASTFRAME 0 /* TERM */ +#define MNG_TERMACTION_CLEAR 1 +#define MNG_TERMACTION_FIRSTFRAME 2 +#define MNG_TERMACTION_REPEAT 3 + +#define MNG_ITERACTION_LASTFRAME 0 /* TERM */ +#define MNG_ITERACTION_CLEAR 1 +#define MNG_ITERACTION_FIRSTFRAME 2 + +#define MNG_SAVEOFFSET_4BYTE 4 /* SAVE */ +#define MNG_SAVEOFFSET_8BYTE 8 + +#define MNG_SAVEENTRY_SEGMENTFULL 0 /* SAVE */ +#define MNG_SAVEENTRY_SEGMENT 1 +#define MNG_SAVEENTRY_SUBFRAME 2 +#define MNG_SAVEENTRY_EXPORTEDIMAGE 3 + +#define MNG_PRIORITY_ABSOLUTE 0 /* fPRI */ +#define MNG_PRIORITY_RELATIVE 1 + +#ifdef MNG_INCLUDE_JNG +#define MNG_COLORTYPE_JPEGGRAY 8 /* JHDR */ +#define MNG_COLORTYPE_JPEGCOLOR 10 +#define MNG_COLORTYPE_JPEGGRAYA 12 +#define MNG_COLORTYPE_JPEGCOLORA 14 + +#define MNG_BITDEPTH_JPEG8 8 /* JHDR */ +#define MNG_BITDEPTH_JPEG12 12 +#define MNG_BITDEPTH_JPEG8AND12 20 + +#define MNG_COMPRESSION_BASELINEJPEG 8 /* JHDR */ + +#define MNG_INTERLACE_SEQUENTIAL 0 /* JHDR */ +#define MNG_INTERLACE_PROGRESSIVE 8 +#endif /* MNG_INCLUDE_JNG */ + +#define MNG_IMAGETYPE_UNKNOWN 0 /* DHDR */ +#define MNG_IMAGETYPE_PNG 1 +#define MNG_IMAGETYPE_JNG 2 + +#define MNG_DELTATYPE_REPLACE 0 /* DHDR */ +#define MNG_DELTATYPE_BLOCKPIXELADD 1 +#define MNG_DELTATYPE_BLOCKALPHAADD 2 +#define MNG_DELTATYPE_BLOCKCOLORADD 3 +#define MNG_DELTATYPE_BLOCKPIXELREPLACE 4 +#define MNG_DELTATYPE_BLOCKALPHAREPLACE 5 +#define MNG_DELTATYPE_BLOCKCOLORREPLACE 6 +#define MNG_DELTATYPE_NOCHANGE 7 + +#define MNG_FILLMETHOD_LEFTBITREPLICATE 0 /* PROM */ +#define MNG_FILLMETHOD_ZEROFILL 1 + +#define MNG_DELTATYPE_REPLACERGB 0 /* PPLT */ +#define MNG_DELTATYPE_DELTARGB 1 +#define MNG_DELTATYPE_REPLACEALPHA 2 +#define MNG_DELTATYPE_DELTAALPHA 3 +#define MNG_DELTATYPE_REPLACERGBA 4 +#define MNG_DELTATYPE_DELTARGBA 5 + +#define MNG_POLARITY_ONLY 0 /* DBYK */ +#define MNG_POLARITY_ALLBUT 1 + +/* ************************************************************************** */ +/* * * */ +/* * Processtext callback types * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_TYPE_TEXT 0 +#define MNG_TYPE_ZTXT 1 +#define MNG_TYPE_ITXT 2 + +/* ************************************************************************** */ + +#ifdef __cplusplus +} +#endif + +#endif /* _libmng_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_callback_xs.c b/freeimage241/Source/LibMNG/libmng_callback_xs.c new file mode 100644 index 0000000..690b3a8 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_callback_xs.c @@ -0,0 +1,1147 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_callback_xs.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : callback get/set interface (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the callback get/set functions * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - fixed calling convention * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - fixed up punctuation (contribution by Tim Rowley) * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - added getalphaline callback for RGB8_A8 canvasstyle * */ +/* * * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added callbacks for SAVE/SEEK processing * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added processterm callback * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ +/* * * */ +/* * Callback set functions * */ +/* * * */ +/* ************************************************************************** */ + +#ifndef MNG_INTERNAL_MEMMNGMT +mng_retcode MNG_DECL mng_setcb_memalloc (mng_handle hHandle, + mng_memalloc fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_MEMALLOC, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fMemalloc = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_MEMALLOC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INTERNAL_MEMMNGMT */ + +/* ************************************************************************** */ + +#ifndef MNG_INTERNAL_MEMMNGMT +mng_retcode MNG_DECL mng_setcb_memfree (mng_handle hHandle, + mng_memfree fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_MEMFREE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fMemfree = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_MEMFREE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INTERNAL_MEMMNGMT */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) +mng_retcode MNG_DECL mng_setcb_openstream (mng_handle hHandle, + mng_openstream fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_OPENSTREAM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fOpenstream = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_OPENSTREAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) +mng_retcode MNG_DECL mng_setcb_closestream (mng_handle hHandle, + mng_closestream fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_CLOSESTREAM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fClosestream = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_CLOSESTREAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_readdata (mng_handle hHandle, + mng_readdata fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_READDATA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fReaddata = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_READDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_WRITE +mng_retcode MNG_DECL mng_setcb_writedata (mng_handle hHandle, + mng_writedata fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_WRITEDATA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fWritedata = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_WRITEDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_setcb_errorproc (mng_handle hHandle, + mng_errorproc fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_ERRORPROC, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fErrorproc = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_ERRORPROC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_TRACE +mng_retcode MNG_DECL mng_setcb_traceproc (mng_handle hHandle, + mng_traceproc fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_TRACEPROC, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fTraceproc = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_TRACEPROC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_TRACE */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processheader (mng_handle hHandle, + mng_processheader fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSHEADER, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessheader = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSHEADER, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processtext (mng_handle hHandle, + mng_processtext fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSTEXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcesstext = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSTEXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processsave (mng_handle hHandle, + mng_processsave fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSSAVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcesssave = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSSAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processseek (mng_handle hHandle, + mng_processseek fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSSEEK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessseek = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSSEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processneed (mng_handle hHandle, + mng_processneed fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSNEED, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessneed = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSNEED, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processmend (mng_handle hHandle, + mng_processmend fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSMEND, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessmend = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSMEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processunknown (mng_handle hHandle, + mng_processunknown fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSUNKNOWN, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessunknown = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSUNKNOWN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_setcb_processterm (mng_handle hHandle, + mng_processterm fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSTERM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessterm = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSTERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_setcb_getcanvasline (mng_handle hHandle, + mng_getcanvasline fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETCANVASLINE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fGetcanvasline = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETCANVASLINE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_setcb_getbkgdline (mng_handle hHandle, + mng_getbkgdline fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETBKGDLINE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fGetbkgdline = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETBKGDLINE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_setcb_getalphaline (mng_handle hHandle, + mng_getalphaline fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETALPHALINE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fGetalphaline = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETALPHALINE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_setcb_refresh (mng_handle hHandle, + mng_refresh fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_REFRESH, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fRefresh = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_REFRESH, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_setcb_gettickcount (mng_handle hHandle, + mng_gettickcount fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETTICKCOUNT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fGettickcount = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_GETTICKCOUNT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_setcb_settimer (mng_handle hHandle, + mng_settimer fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_SETTIMER, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fSettimer = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_SETTIMER, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_retcode MNG_DECL mng_setcb_processgamma (mng_handle hHandle, + mng_processgamma fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSGAMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessgamma = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSGAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_retcode MNG_DECL mng_setcb_processchroma (mng_handle hHandle, + mng_processchroma fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSCHROMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcesschroma = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSCHROMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_retcode MNG_DECL mng_setcb_processsrgb (mng_handle hHandle, + mng_processsrgb fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSSRGB, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcesssrgb = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSSRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_retcode MNG_DECL mng_setcb_processiccp (mng_handle hHandle, + mng_processiccp fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSICCP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessiccp = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_retcode MNG_DECL mng_setcb_processarow (mng_handle hHandle, + mng_processarow fProc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSAROW, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->fProcessarow = fProc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SETCB_PROCESSAROW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ +/* * * */ +/* * Callback get functions * */ +/* * * */ +/* ************************************************************************** */ + +#ifndef MNG_INTERNAL_MEMMNGMT +mng_memalloc MNG_DECL mng_getcb_memalloc (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_MEMALLOC, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_MEMALLOC, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fMemalloc; +} +#endif /* MNG_INTERNAL_MEMMNGMT */ + +/* ************************************************************************** */ + +#ifndef MNG_INTERNAL_MEMMNGMT +mng_memfree MNG_DECL mng_getcb_memfree (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_MEMFREE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_MEMFREE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fMemfree; +} +#endif /* MNG_INTERNAL_MEMMNGMT */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_readdata MNG_DECL mng_getcb_readdata (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_READDATA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_READDATA, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fReaddata; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) +mng_openstream MNG_DECL mng_getcb_openstream (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_OPENSTREAM, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_OPENSTREAM, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fOpenstream; +} +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) +mng_closestream MNG_DECL mng_getcb_closestream (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_CLOSESTREAM, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_CLOSESTREAM, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fClosestream; +} +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_WRITE +mng_writedata MNG_DECL mng_getcb_writedata (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_WRITEDATA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_WRITEDATA, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fWritedata; +} +#endif /* MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +mng_errorproc MNG_DECL mng_getcb_errorproc (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_ERRORPROC, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_ERRORPROC, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fErrorproc; +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_TRACE +mng_traceproc MNG_DECL mng_getcb_traceproc (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_TRACEPROC, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_TRACEPROC, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fTraceproc; +} +#endif /* MNG_SUPPORT_TRACE */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processheader MNG_DECL mng_getcb_processheader (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSHEADER, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSHEADER, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessheader; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processtext MNG_DECL mng_getcb_processtext (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSTEXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSTEXT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcesstext; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processsave MNG_DECL mng_getcb_processsave (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSSAVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSSAVE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcesssave; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processseek MNG_DECL mng_getcb_processseek (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSSEEK, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSSEEK, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessseek; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processneed MNG_DECL mng_getcb_processneed (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSNEED, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSNEED, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessneed; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processmend MNG_DECL mng_getcb_processmend (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSMEND, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSMEND, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessmend; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processunknown MNG_DECL mng_getcb_processunknown (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSUNKNOWN, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSUNKNOWN, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessunknown; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_processterm MNG_DECL mng_getcb_processterm (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSTERM, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSTERM, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessterm; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_getcanvasline MNG_DECL mng_getcb_getcanvasline (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETCANVASLINE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETCANVASLINE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fGetcanvasline; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_getbkgdline MNG_DECL mng_getcb_getbkgdline (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETBKGDLINE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETBKGDLINE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fGetbkgdline; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_getalphaline MNG_DECL mng_getcb_getalphaline (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETALPHALINE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETALPHALINE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fGetalphaline; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_refresh MNG_DECL mng_getcb_refresh (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_REFRESH, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_REFRESH, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fRefresh; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_gettickcount MNG_DECL mng_getcb_gettickcount (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETTICKCOUNT, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_GETTICKCOUNT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fGettickcount; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_settimer MNG_DECL mng_getcb_settimer (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_SETTIMER, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_SETTIMER, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fSettimer; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_processgamma MNG_DECL mng_getcb_processgamma (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSGAMMA, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessgamma; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_processchroma MNG_DECL mng_getcb_processchroma (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSCHROMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSCHROMA, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcesschroma; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_processsrgb MNG_DECL mng_getcb_processsrgb (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSSRGB, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSSRGB, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcesssrgb; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_processiccp MNG_DECL mng_getcb_processiccp (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSICCP, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSICCP, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessiccp; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_APP_CMS) +mng_processarow MNG_DECL mng_getcb_processarow (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSAROW, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GETCB_PROCESSAROW, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->fProcessarow; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_APP_CMS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_chunk_io.c b/freeimage241/Source/LibMNG/libmng_chunk_io.c new file mode 100644 index 0000000..0f61a70 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_chunk_io.c @@ -0,0 +1,8817 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_chunk_io.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : Chunk I/O routines (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of chunk input/output routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/01/2000 - G.Juyn * */ +/* * - cleaned up left-over teststuff in the BACK chunk routine * */ +/* * 0.5.1 - 05/04/2000 - G.Juyn * */ +/* * - changed CRC initialization to use dynamic structure * */ +/* * (wasn't thread-safe the old way !) * */ +/* * 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - filled in many missing sequence&length checks * */ +/* * - filled in many missing chunk-store snippets * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - added checks for running animations * */ +/* * - filled some write routines * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/10/2000 - G.Juyn * */ +/* * - filled some more write routines * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - filled remaining write routines * */ +/* * - fixed read_pplt with regard to deltatype * */ +/* * - added callback error-reporting support * */ +/* * - added pre-draft48 support (short MHDR, frame_mode, LOOP) * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * - fixed chunk-storage bit in several routines * */ +/* * 0.5.1 - 05/13/2000 - G.Juyn * */ +/* * - added eMNGma hack (will be removed in 1.0.0 !!!) * */ +/* * - added TERM animation object pointer (easier reference) * */ +/* * - supplemented the SAVE & SEEK display processing * */ +/* * * */ +/* * 0.5.2 - 05/18/2000 - G.Juyn * */ +/* * - B004 - fixed problem with MNG_SUPPORT_WRITE not defined * */ +/* * also for MNG_SUPPORT_WRITE without MNG_INCLUDE_JNG * */ +/* * 0.5.2 - 05/19/2000 - G.Juyn * */ +/* * - cleaned up some code regarding mixed support * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - implemented JNG support * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added support for global color-chunks in animation * */ +/* * - added support for global PLTE,tRNS,bKGD in animation * */ +/* * - added support for SAVE & SEEK in animation * */ +/* * 0.5.2 - 05/29/2000 - G.Juyn * */ +/* * - changed ani_create calls not returning object pointer * */ +/* * - create ani objects always (not just inside TERM/LOOP) * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added support for delta-image processing * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - fixed up punctuation (contributed by Tim Rowley) * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - changed SWAP_ENDIAN to BIGENDIAN_SUPPORTED * */ +/* * 0.5.2 - 06/03/2000 - G.Juyn * */ +/* * - fixed makeup for Linux gcc compile * */ +/* * * */ +/* * 0.5.3 - 06/12/2000 - G.Juyn * */ +/* * - added processing of color-info on delta-image * */ +/* * 0.5.3 - 06/13/2000 - G.Juyn * */ +/* * - fixed handling of empty SAVE chunk * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - changed to support delta-images * */ +/* * - added extra checks for delta-images * */ +/* * 0.5.3 - 06/20/2000 - G.Juyn * */ +/* * - fixed possible trouble if IEND display-process got * */ +/* * broken up * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added processing of PLTE & tRNS for delta-images * */ +/* * - added administration of imagelevel parameter * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - implemented support for PPLT chunk * */ +/* * 0.5.3 - 06/26/2000 - G.Juyn * */ +/* * - added precaution against faulty iCCP chunks from PS * */ +/* * 0.5.3 - 06/29/2000 - G.Juyn * */ +/* * - fixed some 64-bit warnings * */ +/* * * */ +/* * 0.9.1 - 07/14/2000 - G.Juyn * */ +/* * - changed pre-draft48 frame_mode=3 to frame_mode=1 * */ +/* * 0.9.1 - 07/16/2000 - G.Juyn * */ +/* * - fixed storage of images during mng_read() * */ +/* * - fixed support for mng_display() after mng_read() * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - fixed several chunk-writing routines * */ +/* * 0.9.1 - 07/24/2000 - G.Juyn * */ +/* * - fixed reading of still-images * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/07/2000 - G.Juyn * */ +/* * - B111300 - fixup for improved portability * */ +/* * 0.9.3 - 08/08/2000 - G.Juyn * */ +/* * - fixed compiler-warnings from Mozilla * */ +/* * 0.9.3 - 08/09/2000 - G.Juyn * */ +/* * - added check for simplicity-bits in MHDR * */ +/* * 0.9.3 - 08/12/2000 - G.Juyn * */ +/* * - fixed check for simplicity-bits in MHDR (JNG) * */ +/* * 0.9.3 - 08/12/2000 - G.Juyn * */ +/* * - added workaround for faulty PhotoShop iCCP chunk * */ +/* * 0.9.3 - 08/22/2000 - G.Juyn * */ +/* * - fixed write-code for zTXt & iTXt * */ +/* * - fixed read-code for iTXt * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 09/10/2000 - G.Juyn * */ +/* * - fixed DEFI behavior * */ +/* * 0.9.3 - 10/02/2000 - G.Juyn * */ +/* * - fixed simplicity-check in compliance with draft 81/0.98a * */ +/* * 0.9.3 - 10/10/2000 - G.Juyn * */ +/* * - added support for alpha-depth prediction * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for JDAA * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - fixed support for MAGN * */ +/* * - implemented nEED "xxxx" (where "xxxx" is a chunkid) * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * - fixed support for bKGD * */ +/* * 0.9.3 - 10/23/2000 - G.Juyn * */ +/* * - fixed bug in empty PLTE handling * */ +/* * * */ +/* * 0.9.4 - 11/20/2000 - G.Juyn * */ +/* * - changed IHDR filter_method check for PNGs * */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - added errorchecking for MAGN methods * */ +/* * - removed test filter-methods 1 & 65 * */ +/* * * */ +/* * 0.9.5 - 1/25/2001 - G.Juyn * */ +/* * - fixed some small compiler warnings (thanks Nikki) * */ +/* * * */ +/* * 1.0.2 - 05/05/2000 - G.Juyn * */ +/* * - B421427 - writes wrong format in bKGD and tRNS * */ +/* * 1.0.2 - 06/20/2000 - G.Juyn * */ +/* * - B434583 - compiler-warning if MNG_STORE_CHUNKS undefined * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_objects.h" +#include "libmng_object_prc.h" +#include "libmng_chunks.h" +#ifdef MNG_CHECK_BAD_ICCP +#include "libmng_chunk_prc.h" +#endif +#include "libmng_memory.h" +#include "libmng_display.h" +#include "libmng_zlib.h" +#include "libmng_pixels.h" +#include "libmng_chunk_io.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ +/* * * */ +/* * CRC - Cyclic Redundancy Check * */ +/* * * */ +/* * The code below is taken directly from the sample provided with the * */ +/* * PNG specification. * */ +/* * (it is only adapted to the library's internal data-definitions) * */ +/* * * */ +/* ************************************************************************** */ + +/* Make the table for a fast CRC. */ +void make_crc_table (mng_datap pData) +{ + mng_uint32 iC; + mng_int32 iN, iK; + + for (iN = 0; iN < 256; iN++) + { + iC = (mng_uint32) iN; + + for (iK = 0; iK < 8; iK++) + { + if (iC & 1) + iC = 0xedb88320U ^ (iC >> 1); + else + iC = iC >> 1; + } + + pData->aCRCtable [iN] = iC; + } + + pData->bCRCcomputed = MNG_TRUE; +} + +/* Update a running CRC with the bytes buf[0..len-1]--the CRC + should be initialized to all 1's, and the transmitted value + is the 1's complement of the final running CRC (see the + crc() routine below). */ + +mng_uint32 update_crc (mng_datap pData, + mng_uint32 iCrc, + mng_uint8p pBuf, + mng_int32 iLen) +{ + mng_uint32 iC = iCrc; + mng_int32 iN; + + if (!pData->bCRCcomputed) + make_crc_table (pData); + + for (iN = 0; iN < iLen; iN++) + iC = pData->aCRCtable [(iC ^ pBuf [iN]) & 0xff] ^ (iC >> 8); + + return iC; +} + +/* Return the CRC of the bytes buf[0..len-1]. */ +mng_uint32 crc (mng_datap pData, + mng_uint8p pBuf, + mng_int32 iLen) +{ + return update_crc (pData, 0xffffffffU, pBuf, iLen) ^ 0xffffffffU; +} + +/* ************************************************************************** */ +/* * * */ +/* * Routines for swapping byte-order from and to graphic files * */ +/* * (This code is adapted from the libpng package) * */ +/* * * */ +/* ************************************************************************** */ + +#ifndef MNG_BIGENDIAN_SUPPORTED + +/* ************************************************************************** */ + +mng_uint32 mng_get_uint32 (mng_uint8p pBuf) +{ + mng_uint32 i = ((mng_uint32)(*pBuf) << 24) + + ((mng_uint32)(*(pBuf + 1)) << 16) + + ((mng_uint32)(*(pBuf + 2)) << 8) + + (mng_uint32)(*(pBuf + 3)); + return (i); +} + +/* ************************************************************************** */ + +mng_int32 mng_get_int32 (mng_uint8p pBuf) +{ + mng_int32 i = ((mng_int32)(*pBuf) << 24) + + ((mng_int32)(*(pBuf + 1)) << 16) + + ((mng_int32)(*(pBuf + 2)) << 8) + + (mng_int32)(*(pBuf + 3)); + return (i); +} + +/* ************************************************************************** */ + +mng_uint16 mng_get_uint16 (mng_uint8p pBuf) +{ + mng_uint16 i = (mng_uint16)(((mng_uint16)(*pBuf) << 8) + + (mng_uint16)(*(pBuf + 1))); + return (i); +} + +/* ************************************************************************** */ + +void mng_put_uint32 (mng_uint8p pBuf, + mng_uint32 i) +{ + *pBuf = (mng_uint8)((i >> 24) & 0xff); + *(pBuf+1) = (mng_uint8)((i >> 16) & 0xff); + *(pBuf+2) = (mng_uint8)((i >> 8) & 0xff); + *(pBuf+3) = (mng_uint8)(i & 0xff); +} + +/* ************************************************************************** */ + +void mng_put_int32 (mng_uint8p pBuf, + mng_int32 i) +{ + *pBuf = (mng_uint8)((i >> 24) & 0xff); + *(pBuf+1) = (mng_uint8)((i >> 16) & 0xff); + *(pBuf+2) = (mng_uint8)((i >> 8) & 0xff); + *(pBuf+3) = (mng_uint8)(i & 0xff); +} + +/* ************************************************************************** */ + +void mng_put_uint16 (mng_uint8p pBuf, + mng_uint16 i) +{ + *pBuf = (mng_uint8)((i >> 8) & 0xff); + *(pBuf+1) = (mng_uint8)(i & 0xff); +} + +/* ************************************************************************** */ + +#endif /* !MNG_BIGENDIAN_SUPPORTED */ + +/* ************************************************************************** */ +/* * * */ +/* * Helper routines to simplify chunk-data extraction * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_READ_PROCS + +/* ************************************************************************** */ + +mng_uint8p find_null (mng_uint8p pIn) +{ + mng_uint8p pOut = pIn; + + while (*pOut) /* the read_graphic routine has made sure there's */ + pOut++; /* always at least 1 zero-byte in the buffer */ + + return pOut; +} + +/* ************************************************************************** */ + +mng_retcode inflate_buffer (mng_datap pData, + mng_uint8p pInbuf, + mng_uint32 iInsize, + mng_uint8p *pOutbuf, + mng_uint32 *iOutsize, + mng_uint32 *iRealsize) +{ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INFLATE_BUFFER, MNG_LC_START) +#endif + + if (iInsize) /* anything to do ? */ + { + *iOutsize = iInsize * 3; /* estimate uncompressed size */ + /* and allocate a temporary buffer */ + MNG_ALLOC (pData, *pOutbuf, *iOutsize) + + do + { + mngzlib_inflateinit (pData); /* initialize zlib */ + /* let zlib know where to store the output */ + pData->sZlib.next_out = *pOutbuf; + /* "size - 1" so we've got space for the + zero-termination of a possible string */ + pData->sZlib.avail_out = *iOutsize - 1; + /* ok; let's inflate... */ + iRetcode = mngzlib_inflatedata (pData, iInsize, pInbuf); + /* determine actual output size */ + *iRealsize = (mng_uint32)pData->sZlib.total_out; + + mngzlib_inflatefree (pData); /* zlib's done */ + + if (iRetcode == MNG_BUFOVERFLOW) /* not enough space ? */ + { /* then get some more */ + MNG_FREEX (pData, *pOutbuf, *iOutsize) + *iOutsize = *iOutsize + iInsize; + MNG_ALLOC (pData, *pOutbuf, *iOutsize) + } + } /* repeat if we didn't have enough space */ + while ((iRetcode == MNG_BUFOVERFLOW) && + (*iOutsize < 20 * iInsize)); + + if (!iRetcode) /* if oke ? */ + *((*pOutbuf) + *iRealsize) = 0; /* then put terminator zero */ + + } + else + { + *pOutbuf = 0; /* nothing to do; then there's no output */ + *iOutsize = 0; + *iRealsize = 0; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INFLATE_BUFFER, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_READ_PROCS */ + +/* ************************************************************************** */ +/* * * */ +/* * Helper routines to simplify chunk writing * */ +/* * * */ +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_WRITE_PROCS +/* B004 */ +/* ************************************************************************** */ + +mng_retcode deflate_buffer (mng_datap pData, + mng_uint8p pInbuf, + mng_uint32 iInsize, + mng_uint8p *pOutbuf, + mng_uint32 *iOutsize, + mng_uint32 *iRealsize) +{ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DEFLATE_BUFFER, MNG_LC_START) +#endif + + if (iInsize) /* anything to do ? */ + { + *iOutsize = (iInsize * 5) >> 2; /* estimate compressed size */ + /* and allocate a temporary buffer */ + MNG_ALLOC (pData, *pOutbuf, *iOutsize) + + do + { + mngzlib_deflateinit (pData); /* initialize zlib */ + /* let zlib know where to store the output */ + pData->sZlib.next_out = *pOutbuf; + pData->sZlib.avail_out = *iOutsize; + /* ok; let's deflate... */ + iRetcode = mngzlib_deflatedata (pData, iInsize, pInbuf); + /* determine actual output size */ + *iRealsize = pData->sZlib.total_out; + + mngzlib_deflatefree (pData); /* zlib's done */ + + if (iRetcode == MNG_BUFOVERFLOW) /* not enough space ? */ + { /* then get some more */ + MNG_FREEX (pData, *pOutbuf, *iOutsize) + *iOutsize = *iOutsize + (iInsize >> 1); + MNG_ALLOC (pData, *pOutbuf, *iOutsize) + } + } /* repeat if we didn't have enough space */ + while (iRetcode == MNG_BUFOVERFLOW); + } + else + { + *pOutbuf = 0; /* nothing to do; then there's no output */ + *iOutsize = 0; + *iRealsize = 0; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DEFLATE_BUFFER, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +mng_retcode write_raw_chunk (mng_datap pData, + mng_chunkid iChunkname, + mng_uint32 iRawlen, + mng_uint8p pRawdata) +{ + mng_uint32 iCrc; + mng_uint32 iWritten; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_RAW_CHUNK, MNG_LC_START) +#endif + /* temporary buffer ? */ + if ((pRawdata != 0) && (pRawdata != pData->pWritebuf+8)) + { /* store length & chunktype in default buffer */ + mng_put_uint32 (pData->pWritebuf, iRawlen); + mng_put_uint32 (pData->pWritebuf+4, (mng_uint32)iChunkname); + /* calculate the crc */ + iCrc = update_crc (pData, 0xffffffffL, pData->pWritebuf+4, 4); + iCrc = update_crc (pData, iCrc, pRawdata, iRawlen) ^ 0xffffffffL; + /* store crc in default buffer */ + mng_put_uint32 (pData->pWritebuf+8, iCrc); + /* write the length & chunktype */ + if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, 8, &iWritten)) + MNG_ERROR (pData, MNG_APPIOERROR) + + if (iWritten != 8) /* disk full ? */ + MNG_ERROR (pData, MNG_OUTPUTERROR) + /* write the temporary buffer */ + if (!pData->fWritedata ((mng_handle)pData, pRawdata, iRawlen, &iWritten)) + MNG_ERROR (pData, MNG_APPIOERROR) + + if (iWritten != iRawlen) /* disk full ? */ + MNG_ERROR (pData, MNG_OUTPUTERROR) + + /* write the crc */ + if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf+8, 4, &iWritten)) + MNG_ERROR (pData, MNG_APPIOERROR) + + if (iWritten != 4) /* disk full ? */ + MNG_ERROR (pData, MNG_OUTPUTERROR) + + } + else + { /* prefix with length & chunktype */ + mng_put_uint32 (pData->pWritebuf, iRawlen); + mng_put_uint32 (pData->pWritebuf+4, (mng_uint32)iChunkname); + /* calculate the crc */ + iCrc = crc (pData, pData->pWritebuf+4, iRawlen + 4); + /* add it to the buffer */ + mng_put_uint32 (pData->pWritebuf + iRawlen + 8, iCrc); + /* write it in a single pass */ + if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, iRawlen + 12, &iWritten)) + MNG_ERROR (pData, MNG_APPIOERROR) + + if (iWritten != iRawlen + 12) /* disk full ? */ + MNG_ERROR (pData, MNG_OUTPUTERROR) + + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_RAW_CHUNK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* B004 */ +#endif /* MNG_INCLUDE_WRITE_PROCS */ +/* B004 */ +/* ************************************************************************** */ +/* * * */ +/* * chunk read functions * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_READ_PROCS + +/* ************************************************************************** */ + +READ_CHUNK (read_ihdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IHDR, MNG_LC_START) +#endif + + if (iRawlen != 13) /* length oke ? */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + /* only allowed inside PNG or MNG */ + if ((pData->eSigtype != mng_it_png) && (pData->eSigtype != mng_it_mng)) + MNG_ERROR (pData, MNG_CHUNKNOTALLOWED) + /* sequence checks */ + if ((pData->eSigtype == mng_it_png) && (pData->iChunkseq > 1)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasIDAT) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasIDAT)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + pData->bHasIHDR = MNG_TRUE; /* indicate IHDR is present */ + /* and store interesting fields */ + if ((!pData->bHasDHDR) || (pData->iDeltatype == MNG_DELTATYPE_NOCHANGE)) + { + pData->iDatawidth = mng_get_uint32 (pRawdata); + pData->iDataheight = mng_get_uint32 (pRawdata+4); + } + + pData->iBitdepth = *(pRawdata+8); + pData->iColortype = *(pRawdata+9); + pData->iCompression = *(pRawdata+10); + pData->iFilter = *(pRawdata+11); + pData->iInterlace = *(pRawdata+12); + + if ((pData->iBitdepth != 1) && /* parameter validity checks */ + (pData->iBitdepth != 2) && + (pData->iBitdepth != 4) && + (pData->iBitdepth != 8) && + (pData->iBitdepth != 16) ) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if ((pData->iColortype != MNG_COLORTYPE_GRAY ) && + (pData->iColortype != MNG_COLORTYPE_RGB ) && + (pData->iColortype != MNG_COLORTYPE_INDEXED) && + (pData->iColortype != MNG_COLORTYPE_GRAYA ) && + (pData->iColortype != MNG_COLORTYPE_RGBA ) ) + MNG_ERROR (pData, MNG_INVALIDCOLORTYPE) + + if ((pData->iColortype == MNG_COLORTYPE_INDEXED) && (pData->iBitdepth > 8)) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if (((pData->iColortype == MNG_COLORTYPE_RGB ) || + (pData->iColortype == MNG_COLORTYPE_GRAYA ) || + (pData->iColortype == MNG_COLORTYPE_RGBA ) ) && + (pData->iBitdepth < 8 ) ) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if (pData->iCompression != MNG_COMPRESSION_DEFLATE) + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + if ((pData->eSigtype == mng_it_png) && (pData->iFilter)) + MNG_ERROR (pData, MNG_INVALIDFILTER) + else + if (pData->iFilter & (~MNG_FILTER_DIFFERING)) + MNG_ERROR (pData, MNG_INVALIDFILTER) + + if ((pData->iInterlace != MNG_INTERLACE_NONE ) && + (pData->iInterlace != MNG_INTERLACE_ADAM7) ) + MNG_ERROR (pData, MNG_INVALIDINTERLACE) + + if (pData->bHasDHDR) /* check the colortype for delta-images ! */ + { + mng_imagedatap pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + + if (pData->iColortype != pBuf->iColortype) + { + if ( ( (pData->iColortype != MNG_COLORTYPE_INDEXED) || + (pBuf->iColortype == MNG_COLORTYPE_GRAY ) ) && + ( (pData->iColortype != MNG_COLORTYPE_GRAY ) || + (pBuf->iColortype == MNG_COLORTYPE_INDEXED) ) ) + MNG_ERROR (pData, MNG_INVALIDCOLORTYPE) + } + } + + if (!pData->bHasheader) /* first chunk ? */ + { + pData->bHasheader = MNG_TRUE; /* we've got a header */ + pData->eImagetype = mng_it_png; /* then this must be a PNG */ + pData->iWidth = pData->iDatawidth; + pData->iHeight = pData->iDataheight; + /* predict alpha-depth ! */ + if ((pData->iColortype == MNG_COLORTYPE_GRAYA ) || + (pData->iColortype == MNG_COLORTYPE_RGBA ) ) + pData->iAlphadepth = pData->iBitdepth; + else + if (pData->iColortype == MNG_COLORTYPE_INDEXED) + pData->iAlphadepth = 8; /* worst case scenario */ + else + pData->iAlphadepth = 0; + /* fits on maximum canvas ? */ + if ((pData->iWidth > pData->iMaxwidth) || (pData->iHeight > pData->iMaxheight)) + MNG_WARNING (pData, MNG_IMAGETOOLARGE) + + if (pData->fProcessheader) /* inform the app ? */ + if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight)) + MNG_ERROR (pData, MNG_APPMISCERROR) + } + + if (!pData->bHasDHDR) + pData->iImagelevel++; /* one level deeper */ + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode = process_display_ihdr (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the fields */ + ((mng_ihdrp)*ppChunk)->iWidth = mng_get_uint32 (pRawdata); + ((mng_ihdrp)*ppChunk)->iHeight = mng_get_uint32 (pRawdata+4); + ((mng_ihdrp)*ppChunk)->iBitdepth = pData->iBitdepth; + ((mng_ihdrp)*ppChunk)->iColortype = pData->iColortype; + ((mng_ihdrp)*ppChunk)->iCompression = pData->iCompression; + ((mng_ihdrp)*ppChunk)->iFilter = pData->iFilter; + ((mng_ihdrp)*ppChunk)->iInterlace = pData->iInterlace; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_plte) +{ +#if defined(MNG_SUPPORT_DISPLAY) || defined(MNG_STORE_CHUNKS) + mng_uint32 iX; + mng_uint8p pRawdata2; +#endif +#ifdef MNG_SUPPORT_DISPLAY + mng_uint32 iRawlen2; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PLTE, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasJHDR)) +#else + if (pData->bHasIDAT) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* multiple PLTE only inside BASI */ + if ((pData->bHasPLTE) && (!pData->bHasBASI)) + MNG_ERROR (pData, MNG_MULTIPLEERROR) + /* length must be multiple of 3 */ + if (((iRawlen % 3) != 0) || (iRawlen > 768)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { /* only allowed for indexed-color or + rgb(a)-color! */ + if ((pData->iColortype != 2) && (pData->iColortype != 3) && (pData->iColortype != 6)) + MNG_ERROR (pData, MNG_CHUNKNOTALLOWED) + /* empty only allowed if global present */ + if ((iRawlen == 0) && (!pData->bHasglobalPLTE)) + MNG_ERROR (pData, MNG_CANNOTBEEMPTY) + } + else + { + if (iRawlen == 0) /* cannot be empty as global! */ + MNG_ERROR (pData, MNG_CANNOTBEEMPTY) + } + + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + pData->bHasPLTE = MNG_TRUE; /* got it! */ + else + pData->bHasglobalPLTE = MNG_TRUE; + + pData->iPLTEcount = iRawlen / 3; + +#ifdef MNG_SUPPORT_DISPLAY + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { + mng_imagep pImage; + mng_imagedatap pBuf; + + if (pData->bHasDHDR) /* processing delta-image ? */ + { /* store in object 0 !!! */ + pImage = (mng_imagep)pData->pObjzero; + pBuf = pImage->pImgbuf; + pBuf->bHasPLTE = MNG_TRUE; /* it's definitely got a PLTE now */ + pBuf->iPLTEcount = iRawlen / 3; /* this is the exact length */ + pRawdata2 = pRawdata; /* copy the entries */ + + for (iX = 0; iX < iRawlen / 3; iX++) + { + pBuf->aPLTEentries[iX].iRed = *pRawdata2; + pBuf->aPLTEentries[iX].iGreen = *(pRawdata2+1); + pBuf->aPLTEentries[iX].iBlue = *(pRawdata2+2); + + pRawdata2 += 3; + } + } + else + { /* get the current object */ + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* no object then dump it in obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address the object buffer */ + pBuf->bHasPLTE = MNG_TRUE; /* and tell it it's got a PLTE now */ + + if (!iRawlen) /* if empty, inherit from global */ + { + pBuf->iPLTEcount = pData->iGlobalPLTEcount; + MNG_COPY (pBuf->aPLTEentries, pData->aGlobalPLTEentries, + sizeof (pBuf->aPLTEentries)) + + if (pData->bHasglobalTRNS) /* also copy global tRNS ? */ + { /* indicate tRNS available */ + pBuf->bHasTRNS = MNG_TRUE; + + iRawlen2 = pData->iGlobalTRNSrawlen; + pRawdata2 = (mng_uint8p)(pData->aGlobalTRNSrawdata); + /* global length oke ? */ + if ((iRawlen2 == 0) || (iRawlen2 > pBuf->iPLTEcount)) + MNG_ERROR (pData, MNG_GLOBALLENGTHERR) + /* copy it */ + pBuf->iTRNScount = iRawlen2; + MNG_COPY (pBuf->aTRNSentries, pRawdata2, iRawlen2) + } + } + else + { /* store fields for future reference */ + pBuf->iPLTEcount = iRawlen / 3; + pRawdata2 = pRawdata; + + for (iX = 0; iX < pBuf->iPLTEcount; iX++) + { + pBuf->aPLTEentries[iX].iRed = *pRawdata2; + pBuf->aPLTEentries[iX].iGreen = *(pRawdata2+1); + pBuf->aPLTEentries[iX].iBlue = *(pRawdata2+2); + + pRawdata2 += 3; + } + } + } + } + else /* store as global */ + { + pData->iGlobalPLTEcount = iRawlen / 3; + pRawdata2 = pRawdata; + + for (iX = 0; iX < pData->iGlobalPLTEcount; iX++) + { + pData->aGlobalPLTEentries[iX].iRed = *pRawdata2; + pData->aGlobalPLTEentries[iX].iGreen = *(pRawdata2+1); + pData->aGlobalPLTEentries[iX].iBlue = *(pRawdata2+2); + + pRawdata2 += 3; + } + + { /* create an animation object */ + mng_retcode iRetcode = create_ani_plte (pData, pData->iGlobalPLTEcount, + pData->aGlobalPLTEentries); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_pltep)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + ((mng_pltep)*ppChunk)->iEntrycount = iRawlen / 3; + pRawdata2 = pRawdata; + + for (iX = 0; iX < ((mng_pltep)*ppChunk)->iEntrycount; iX++) + { + ((mng_pltep)*ppChunk)->aEntries[iX].iRed = *pRawdata2; + ((mng_pltep)*ppChunk)->aEntries[iX].iGreen = *(pRawdata2+1); + ((mng_pltep)*ppChunk)->aEntries[iX].iBlue = *(pRawdata2+2); + + pRawdata2 += 3; + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_idat) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IDAT, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_JNG /* sequence checks */ + if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasJHDR) && + (pData->iJHDRalphacompression != MNG_COMPRESSION_DEFLATE)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (pData->bHasJSEP) + MNG_ERROR (pData, MNG_SEQUENCEERROR) +#endif + /* not allowed for for deltatype NO_CHANGE */ + if ((pData->bHasDHDR) && ((pData->iDeltatype == MNG_DELTATYPE_NOCHANGE))) + MNG_ERROR (pData, MNG_CHUNKNOTALLOWED) + /* can only be empty in BASI-block! */ + if ((iRawlen == 0) && (!pData->bHasBASI)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + /* indexed-color requires PLTE */ + if ((pData->bHasIHDR) && (pData->iColortype == 3) && (!pData->bHasPLTE)) + MNG_ERROR (pData, MNG_PLTEMISSING) + + pData->bHasIDAT = MNG_TRUE; /* got some IDAT now, don't we */ + +#ifdef MNG_SUPPORT_DISPLAY + if (iRawlen) + { /* display processing */ + mng_retcode iRetcode = process_display_idat (pData, iRawlen, pRawdata); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_idatp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + ((mng_idatp)*ppChunk)->iDatasize = iRawlen; + + if (iRawlen != 0) /* is there any data ? */ + { + MNG_ALLOC (pData, ((mng_idatp)*ppChunk)->pData, iRawlen) + MNG_COPY (((mng_idatp)*ppChunk)->pData, pRawdata, iRawlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_iend) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IEND, MNG_LC_START) +#endif + + if (iRawlen > 0) /* must not contain data! */ + MNG_ERROR (pData, MNG_INVALIDLENGTH); + +#ifdef MNG_INCLUDE_JNG /* sequence checks */ + if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* IHDR-block requires IDAT */ + if ((pData->bHasIHDR) && (!pData->bHasIDAT)) + MNG_ERROR (pData, MNG_IDATMISSING) + + pData->iImagelevel--; /* one level up */ + +#ifdef MNG_SUPPORT_DISPLAY + { /* create an animation object */ + mng_retcode iRetcode = create_ani_image (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* display processing */ + iRetcode = process_display_iend (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_SUPPORT_DISPLAY + if (!pData->bTimerset) /* reset only if not broken !!! */ + { +#endif + /* IEND signals the end for most ... */ + pData->bHasIHDR = MNG_FALSE; + pData->bHasBASI = MNG_FALSE; + pData->bHasDHDR = MNG_FALSE; +#ifdef MNG_INCLUDE_JNG + pData->bHasJHDR = MNG_FALSE; + pData->bHasJSEP = MNG_FALSE; + pData->bHasJDAA = MNG_FALSE; + pData->bHasJDAT = MNG_FALSE; +#endif + pData->bHasPLTE = MNG_FALSE; + pData->bHasTRNS = MNG_FALSE; + pData->bHasGAMA = MNG_FALSE; + pData->bHasCHRM = MNG_FALSE; + pData->bHasSRGB = MNG_FALSE; + pData->bHasICCP = MNG_FALSE; + pData->bHasBKGD = MNG_FALSE; + pData->bHasIDAT = MNG_FALSE; +#ifdef MNG_SUPPORT_DISPLAY + } +#endif + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IEND, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_trns) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TRNS, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasJHDR)) +#else + if (pData->bHasIDAT) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* multiple tRNS only inside BASI */ + if ((pData->bHasTRNS) && (!pData->bHasBASI)) + MNG_ERROR (pData, MNG_MULTIPLEERROR) + + if (iRawlen > 256) /* it just can't be bigger than that! */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { /* not allowed with full alpha-channel */ + if ((pData->iColortype == 4) || (pData->iColortype == 6)) + MNG_ERROR (pData, MNG_CHUNKNOTALLOWED) + + if (iRawlen != 0) /* filled ? */ + { /* length checks */ + if ((pData->iColortype == 0) && (iRawlen != 2)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iColortype == 2) && (iRawlen != 6)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + if (pData->iColortype == 3) + { + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + mng_imagedatap pBuf; + + if (!pImage) /* no object then check obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address object buffer */ + + if ((iRawlen == 0) || (iRawlen > pBuf->iPLTEcount)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } +#endif + } + else /* if empty there must be global stuff! */ + { + if (!pData->bHasglobalTRNS) + MNG_ERROR (pData, MNG_CANNOTBEEMPTY) + } + } + + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + pData->bHasTRNS = MNG_TRUE; /* indicate tRNS available */ + else + pData->bHasglobalTRNS = MNG_TRUE; + +#ifdef MNG_SUPPORT_DISPLAY + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { + mng_imagep pImage; + mng_imagedatap pBuf; + mng_uint8p pRawdata2; + mng_uint32 iRawlen2; + + if (pData->bHasDHDR) /* processing delta-image ? */ + { /* store in object 0 !!! */ + pImage = (mng_imagep)pData->pObjzero; + pBuf = pImage->pImgbuf; /* address object buffer */ + + switch (pData->iColortype) /* store fields for future reference */ + { + case 0: { /* gray */ + pBuf->iTRNSgray = mng_get_uint16 (pRawdata); + pBuf->iTRNSred = 0; + pBuf->iTRNSgreen = 0; + pBuf->iTRNSblue = 0; + pBuf->iTRNScount = 0; + break; + } + case 2: { /* rgb */ + pBuf->iTRNSgray = 0; + pBuf->iTRNSred = mng_get_uint16 (pRawdata); + pBuf->iTRNSgreen = mng_get_uint16 (pRawdata+2); + pBuf->iTRNSblue = mng_get_uint16 (pRawdata+4); + pBuf->iTRNScount = 0; + break; + } + case 3: { /* indexed */ + pBuf->iTRNSgray = 0; + pBuf->iTRNSred = 0; + pBuf->iTRNSgreen = 0; + pBuf->iTRNSblue = 0; + pBuf->iTRNScount = iRawlen; + MNG_COPY (pBuf->aTRNSentries, pRawdata, iRawlen) + break; + } + } + + pBuf->bHasTRNS = MNG_TRUE; /* tell it it's got a tRNS now */ + } + else + { /* address current object */ + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* no object then dump it in obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address object buffer */ + pBuf->bHasTRNS = MNG_TRUE; /* and tell it it's got a tRNS now */ + + if (iRawlen == 0) /* if empty, inherit from global */ + { + iRawlen2 = pData->iGlobalTRNSrawlen; + pRawdata2 = (mng_ptr)(pData->aGlobalTRNSrawdata); + /* global length oke ? */ + if ((pData->iColortype == 0) && (iRawlen2 != 2)) + MNG_ERROR (pData, MNG_GLOBALLENGTHERR) + + if ((pData->iColortype == 2) && (iRawlen2 != 6)) + MNG_ERROR (pData, MNG_GLOBALLENGTHERR) + + if ((pData->iColortype == 3) && ((iRawlen2 == 0) || (iRawlen2 > pBuf->iPLTEcount))) + MNG_ERROR (pData, MNG_GLOBALLENGTHERR) + } + else + { + iRawlen2 = iRawlen; + pRawdata2 = pRawdata; + } + + switch (pData->iColortype) /* store fields for future reference */ + { + case 0: { /* gray */ + pBuf->iTRNSgray = mng_get_uint16 (pRawdata2); + pBuf->iTRNSred = 0; + pBuf->iTRNSgreen = 0; + pBuf->iTRNSblue = 0; + pBuf->iTRNScount = 0; + break; + } + case 2: { /* rgb */ + pBuf->iTRNSgray = 0; + pBuf->iTRNSred = mng_get_uint16 (pRawdata2); + pBuf->iTRNSgreen = mng_get_uint16 (pRawdata2+2); + pBuf->iTRNSblue = mng_get_uint16 (pRawdata2+4); + pBuf->iTRNScount = 0; + break; + } + case 3: { /* indexed */ + pBuf->iTRNSgray = 0; + pBuf->iTRNSred = 0; + pBuf->iTRNSgreen = 0; + pBuf->iTRNSblue = 0; + pBuf->iTRNScount = iRawlen2; + MNG_COPY (pBuf->aTRNSentries, pRawdata2, iRawlen2) + break; + } + } + } + } + else /* store as global */ + { + pData->iGlobalTRNSrawlen = iRawlen; + MNG_COPY (pData->aGlobalTRNSrawdata, pRawdata, iRawlen) + + { /* create an animation object */ + mng_retcode iRetcode = create_ani_trns (pData, pData->iGlobalTRNSrawlen, + pData->aGlobalTRNSrawdata); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { /* not global! */ + ((mng_trnsp)*ppChunk)->bGlobal = MNG_FALSE; + ((mng_trnsp)*ppChunk)->iType = pData->iColortype; + + if (iRawlen == 0) /* if empty, indicate so */ + ((mng_trnsp)*ppChunk)->bEmpty = MNG_TRUE; + else + { + ((mng_trnsp)*ppChunk)->bEmpty = MNG_FALSE; + + switch (pData->iColortype) /* store fields */ + { + case 0: { /* gray */ + ((mng_trnsp)*ppChunk)->iGray = mng_get_uint16 (pRawdata); + break; + } + case 2: { /* rgb */ + ((mng_trnsp)*ppChunk)->iRed = mng_get_uint16 (pRawdata); + ((mng_trnsp)*ppChunk)->iGreen = mng_get_uint16 (pRawdata+2); + ((mng_trnsp)*ppChunk)->iBlue = mng_get_uint16 (pRawdata+4); + break; + } + case 3: { /* indexed */ + ((mng_trnsp)*ppChunk)->iCount = iRawlen; + MNG_COPY (((mng_trnsp)*ppChunk)->aEntries, pRawdata, iRawlen) + break; + } + } + } + } + else /* it's global! */ + { + ((mng_trnsp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + ((mng_trnsp)*ppChunk)->bGlobal = MNG_TRUE; + ((mng_trnsp)*ppChunk)->iType = 0; + ((mng_trnsp)*ppChunk)->iRawlen = iRawlen; + + MNG_COPY (((mng_trnsp)*ppChunk)->aRawdata, pRawdata, iRawlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_gama) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_GAMA, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA)) +#else + if ((pData->bHasIDAT) || (pData->bHasPLTE)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { /* length must be exactly 4 */ + if (iRawlen != 4) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else + { /* length must be empty or exactly 4 */ + if ((iRawlen != 0) && (iRawlen != 4)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + pData->bHasGAMA = MNG_TRUE; /* indicate we've got it */ + else + pData->bHasglobalGAMA = (mng_bool)(iRawlen != 0); + +#ifdef MNG_SUPPORT_DISPLAY +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { + mng_imagep pImage; + + if (pData->bHasDHDR) /* update delta image ? */ + { /* store in object 0 ! */ + pImage = (mng_imagep)pData->pObjzero; + /* store for color-processing routines */ + pImage->pImgbuf->iGamma = mng_get_uint32 (pRawdata); + pImage->pImgbuf->bHasGAMA = MNG_TRUE; + } + else + { + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* no object then dump it in obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + /* store for color-processing routines */ + pImage->pImgbuf->iGamma = mng_get_uint32 (pRawdata); + pImage->pImgbuf->bHasGAMA = MNG_TRUE; + } + } + else + { /* store as global */ + if (iRawlen != 0) + pData->iGlobalGamma = mng_get_uint32 (pRawdata); + + { /* create an animation object */ + mng_retcode iRetcode = create_ani_gama (pData, (mng_bool)(iRawlen == 0), + pData->iGlobalGamma); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_gamap)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + ((mng_gamap)*ppChunk)->iGamma = mng_get_uint32 (pRawdata); + + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_chrm) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CHRM, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA)) +#else + if ((pData->bHasIDAT) || (pData->bHasPLTE)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { /* length must be exactly 32 */ + if (iRawlen != 32) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else + { /* length must be empty or exactly 32 */ + if ((iRawlen != 0) && (iRawlen != 32)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + pData->bHasCHRM = MNG_TRUE; /* indicate we've got it */ + else + pData->bHasglobalCHRM = (mng_bool)(iRawlen != 0); + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_uint32 iWhitepointx, iWhitepointy; + mng_uint32 iPrimaryredx, iPrimaryredy; + mng_uint32 iPrimarygreenx, iPrimarygreeny; + mng_uint32 iPrimarybluex, iPrimarybluey; + + iWhitepointx = mng_get_uint32 (pRawdata); + iWhitepointy = mng_get_uint32 (pRawdata+4); + iPrimaryredx = mng_get_uint32 (pRawdata+8); + iPrimaryredy = mng_get_uint32 (pRawdata+12); + iPrimarygreenx = mng_get_uint32 (pRawdata+16); + iPrimarygreeny = mng_get_uint32 (pRawdata+20); + iPrimarybluex = mng_get_uint32 (pRawdata+24); + iPrimarybluey = mng_get_uint32 (pRawdata+28); + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { + mng_imagep pImage; + mng_imagedatap pBuf; + + if (pData->bHasDHDR) /* update delta image ? */ + { /* store it in object 0 ! */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address object buffer */ + pBuf->bHasCHRM = MNG_TRUE; /* and tell it it's got a CHRM now */ + /* store for color-processing routines */ + pBuf->iWhitepointx = iWhitepointx; + pBuf->iWhitepointy = iWhitepointy; + pBuf->iPrimaryredx = iPrimaryredx; + pBuf->iPrimaryredy = iPrimaryredy; + pBuf->iPrimarygreenx = iPrimarygreenx; + pBuf->iPrimarygreeny = iPrimarygreeny; + pBuf->iPrimarybluex = iPrimarybluex; + pBuf->iPrimarybluey = iPrimarybluey; + } + else + { + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* no object then dump it in obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address object buffer */ + pBuf->bHasCHRM = MNG_TRUE; /* and tell it it's got a CHRM now */ + /* store for color-processing routines */ + pBuf->iWhitepointx = iWhitepointx; + pBuf->iWhitepointy = iWhitepointy; + pBuf->iPrimaryredx = iPrimaryredx; + pBuf->iPrimaryredy = iPrimaryredy; + pBuf->iPrimarygreenx = iPrimarygreenx; + pBuf->iPrimarygreeny = iPrimarygreeny; + pBuf->iPrimarybluex = iPrimarybluex; + pBuf->iPrimarybluey = iPrimarybluey; + } + } + else + { /* store as global */ + if (iRawlen != 0) + { + pData->iGlobalWhitepointx = iWhitepointx; + pData->iGlobalWhitepointy = iWhitepointy; + pData->iGlobalPrimaryredx = iPrimaryredx; + pData->iGlobalPrimaryredy = iPrimaryredy; + pData->iGlobalPrimarygreenx = iPrimarygreenx; + pData->iGlobalPrimarygreeny = iPrimarygreeny; + pData->iGlobalPrimarybluex = iPrimarybluex; + pData->iGlobalPrimarybluey = iPrimarybluey; + } + + { /* create an animation object */ + mng_retcode iRetcode = create_ani_chrm (pData, (mng_bool)(iRawlen == 0), + iWhitepointx, iWhitepointy, + iPrimaryredx, iPrimaryredy, + iPrimarygreenx, iPrimarygreeny, + iPrimarybluex, iPrimarybluey); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_chrmp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + { + ((mng_chrmp)*ppChunk)->iWhitepointx = mng_get_uint32 (pRawdata); + ((mng_chrmp)*ppChunk)->iWhitepointy = mng_get_uint32 (pRawdata+4); + ((mng_chrmp)*ppChunk)->iRedx = mng_get_uint32 (pRawdata+8); + ((mng_chrmp)*ppChunk)->iRedy = mng_get_uint32 (pRawdata+12); + ((mng_chrmp)*ppChunk)->iGreenx = mng_get_uint32 (pRawdata+16); + ((mng_chrmp)*ppChunk)->iGreeny = mng_get_uint32 (pRawdata+20); + ((mng_chrmp)*ppChunk)->iBluex = mng_get_uint32 (pRawdata+24); + ((mng_chrmp)*ppChunk)->iBluey = mng_get_uint32 (pRawdata+28); + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_srgb) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SRGB, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA)) +#else + if ((pData->bHasIDAT) || (pData->bHasPLTE)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { /* length must be exactly 1 */ + if (iRawlen != 1) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else + { /* length must be empty or exactly 1 */ + if ((iRawlen != 0) && (iRawlen != 1)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + pData->bHasSRGB = MNG_TRUE; /* indicate we've got it */ + else + pData->bHasglobalSRGB = (mng_bool)(iRawlen != 0); + +#ifdef MNG_SUPPORT_DISPLAY +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { + mng_imagep pImage; + + if (pData->bHasDHDR) /* update delta image ? */ + { /* store in object 0 ! */ + pImage = (mng_imagep)pData->pObjzero; + /* store for color-processing routines */ + pImage->pImgbuf->iRenderingintent = *pRawdata; + pImage->pImgbuf->bHasSRGB = MNG_TRUE; + } + else + { + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* no object then dump it in obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + /* store for color-processing routines */ + pImage->pImgbuf->iRenderingintent = *pRawdata; + pImage->pImgbuf->bHasSRGB = MNG_TRUE; + } + } + else + { /* store as global */ + if (iRawlen != 0) + pData->iGlobalRendintent = *pRawdata; + + { /* create an animation object */ + mng_retcode iRetcode = create_ani_srgb (pData, (mng_bool)(iRawlen == 0), + pData->iGlobalRendintent); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_srgbp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + ((mng_srgbp)*ppChunk)->iRenderingintent = *pRawdata; + + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_iccp) +{ + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint32 iCompressedsize; + mng_uint32 iProfilesize; + mng_uint32 iBufsize = 0; + mng_uint8p pBuf = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ICCP, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasPLTE) || (pData->bHasJDAT) || (pData->bHasJDAA)) +#else + if ((pData->bHasIDAT) || (pData->bHasPLTE)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { /* length must be at least 2 */ + if (iRawlen < 2) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else + { /* length must be empty or at least 2 */ + if ((iRawlen != 0) && (iRawlen < 2)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + + pTemp = find_null (pRawdata); /* find null-separator */ + /* not found inside input-data ? */ + if ((pTemp - pRawdata) > (mng_int32)iRawlen) + MNG_ERROR (pData, MNG_NULLNOTFOUND) + /* determine size of compressed profile */ + iCompressedsize = (mng_uint32)(iRawlen - (pTemp - pRawdata) - 2); + /* decompress the profile */ + iRetcode = inflate_buffer (pData, pTemp+2, iCompressedsize, + &pBuf, &iBufsize, &iProfilesize); + +#ifdef MNG_CHECK_BAD_ICCP /* Check for bad iCCP chunk */ + if ((iRetcode) && (!strncmp ((char *)pRawdata, "Photoshop ICC profile", 21))) + { + if (iRawlen == 2615) /* is it the sRGB profile ? */ + { + mng_chunk_header chunk_srgb = {MNG_UINT_sRGB, init_srgb, free_srgb, + read_srgb, write_srgb, 0, 0}; + /* pretend it's an sRGB chunk then ! */ + iRetcode = read_srgb (pData, &chunk_srgb, 1, (mng_ptr)"0", ppChunk); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffer */ + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + } + } + else + { +#endif /* MNG_CHECK_BAD_ICCP */ + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffer */ + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + pData->bHasICCP = MNG_TRUE; /* indicate we've got it */ + else + pData->bHasglobalICCP = (mng_bool)(iRawlen != 0); + +#ifdef MNG_SUPPORT_DISPLAY +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + { + mng_imagep pImage; + + if (pData->bHasDHDR) /* update delta image ? */ + { /* store in object 0 ! */ + pImage = (mng_imagep)pData->pObjzero; + + if (pImage->pImgbuf->pProfile) /* profile existed ? */ + MNG_FREEX (pData, pImage->pImgbuf->pProfile, pImage->pImgbuf->iProfilesize) + /* allocate a buffer & copy it */ + MNG_ALLOC (pData, pImage->pImgbuf->pProfile, iProfilesize) + MNG_COPY (pImage->pImgbuf->pProfile, pBuf, iProfilesize) + /* store it's length as well */ + pImage->pImgbuf->iProfilesize = iProfilesize; + pImage->pImgbuf->bHasICCP = MNG_TRUE; + } + else + { + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* no object then dump it in obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + + if (pImage->pImgbuf->pProfile) /* profile existed ? */ + MNG_FREEX (pData, pImage->pImgbuf->pProfile, pImage->pImgbuf->iProfilesize) + /* allocate a buffer & copy it */ + MNG_ALLOC (pData, pImage->pImgbuf->pProfile, iProfilesize) + MNG_COPY (pImage->pImgbuf->pProfile, pBuf, iProfilesize) + /* store it's length as well */ + pImage->pImgbuf->iProfilesize = iProfilesize; + pImage->pImgbuf->bHasICCP = MNG_TRUE; + } + } + else + { /* store as global */ + if (iRawlen == 0) /* empty chunk ? */ + { + if (pData->pGlobalProfile) /* did we have a global profile ? */ + MNG_FREEX (pData, pData->pGlobalProfile, pData->iGlobalProfilesize) + + pData->iGlobalProfilesize = 0; /* reset to null */ + pData->pGlobalProfile = MNG_NULL; + } + else + { /* allocate a global buffer & copy it */ + MNG_ALLOC (pData, pData->pGlobalProfile, iProfilesize) + MNG_COPY (pData->pGlobalProfile, pBuf, iProfilesize) + /* store it's length as well */ + pData->iGlobalProfilesize = iProfilesize; + } + + /* create an animation object */ + iRetcode = create_ani_iccp (pData, (mng_bool)(iRawlen == 0), + pData->iGlobalProfilesize, + pData->pGlobalProfile); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffer */ + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + /* store the fields */ + ((mng_iccpp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) /* not empty ? */ + { + if (!pBuf) /* hasn't been unpuzzled it yet ? */ + { /* find null-separator */ + pTemp = find_null (pRawdata); + /* not found inside input-data ? */ + if ((pTemp - pRawdata) > (mng_int32)iRawlen) + MNG_ERROR (pData, MNG_NULLNOTFOUND) + /* determine size of compressed profile */ + iCompressedsize = iRawlen - (pTemp - pRawdata) - 2; + /* decompress the profile */ + iRetcode = inflate_buffer (pData, pTemp+2, iCompressedsize, + &pBuf, &iBufsize, &iProfilesize); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffer */ + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + } + + ((mng_iccpp)*ppChunk)->iNamesize = (mng_uint32)(pTemp - pRawdata); + + if (((mng_iccpp)*ppChunk)->iNamesize) + { + MNG_ALLOC (pData, ((mng_iccpp)*ppChunk)->zName, + ((mng_iccpp)*ppChunk)->iNamesize + 1) + MNG_COPY (((mng_iccpp)*ppChunk)->zName, pRawdata, + ((mng_iccpp)*ppChunk)->iNamesize) + } + + ((mng_iccpp)*ppChunk)->iCompression = *(pTemp+1); + ((mng_iccpp)*ppChunk)->iProfilesize = iProfilesize; + + MNG_ALLOC (pData, ((mng_iccpp)*ppChunk)->pProfile, iProfilesize) + MNG_COPY (((mng_iccpp)*ppChunk)->pProfile, pBuf, iProfilesize) + } + } +#endif /* MNG_STORE_CHUNKS */ + + if (pBuf) /* free the temporary buffer */ + MNG_FREEX (pData, pBuf, iBufsize) + +#ifdef MNG_CHECK_BAD_ICCP + } +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_text) +{ + mng_uint32 iKeywordlen, iTextlen; + mng_pchar zKeyword, zText; + mng_uint8p pTemp; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TEXT, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen < 2) /* length must be at least 2 */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pTemp = find_null (pRawdata); /* find the null separator */ + /* not found inside input-data ? */ + if ((pTemp - pRawdata) > (mng_int32)iRawlen) + MNG_ERROR (pData, MNG_NULLNOTFOUND) + + if (pTemp == pRawdata) /* there must be at least 1 char for keyword */ + MNG_ERROR (pData, MNG_KEYWORDNULL) + + iKeywordlen = (mng_uint32)(pTemp - pRawdata); + iTextlen = iRawlen - iKeywordlen - 1; + + if (pData->fProcesstext) /* inform the application ? */ + { + mng_bool bOke; + + MNG_ALLOC (pData, zKeyword, iKeywordlen + 1) + MNG_COPY (zKeyword, pRawdata, iKeywordlen) + + MNG_ALLOCX (pData, zText, iTextlen + 1) + + if (!zText) /* on error bail out */ + { + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + + if (iTextlen) + MNG_COPY (zText, pTemp+1, iTextlen) + + bOke = pData->fProcesstext ((mng_handle)pData, MNG_TYPE_TEXT, zKeyword, zText, 0, 0); + + MNG_FREEX (pData, zText, iTextlen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + + if (!bOke) + MNG_ERROR (pData, MNG_APPMISCERROR) + + } + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_textp)*ppChunk)->iKeywordsize = iKeywordlen; + ((mng_textp)*ppChunk)->iTextsize = iTextlen; + + if (iKeywordlen) + { + MNG_ALLOC (pData, ((mng_textp)*ppChunk)->zKeyword, iKeywordlen+1) + MNG_COPY (((mng_textp)*ppChunk)->zKeyword, pRawdata, iKeywordlen) + } + + if (iTextlen) + { + MNG_ALLOC (pData, ((mng_textp)*ppChunk)->zText, iTextlen+1) + MNG_COPY (((mng_textp)*ppChunk)->zText, pTemp+1, iTextlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TEXT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_ztxt) +{ + mng_retcode iRetcode; + mng_uint32 iKeywordlen, iTextlen; + mng_pchar zKeyword; + mng_uint8p pTemp; + mng_uint32 iCompressedsize; + mng_uint32 iBufsize; + mng_uint8p pBuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ZTXT, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen < 3) /* length must be at least 3 */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pTemp = find_null (pRawdata); /* find the null separator */ + /* not found inside input-data ? */ + if ((pTemp - pRawdata) > (mng_int32)iRawlen) + MNG_ERROR (pData, MNG_NULLNOTFOUND) + + if (pTemp == pRawdata) /* there must be at least 1 char for keyword */ + MNG_ERROR (pData, MNG_KEYWORDNULL) + + if (*(pTemp+1) != 0) /* only deflate compression-method allowed */ + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + iKeywordlen = (mng_uint32)(pTemp - pRawdata); + iCompressedsize = (mng_uint32)(iRawlen - iKeywordlen - 2); + + zKeyword = 0; /* there's no keyword buffer yet */ + pBuf = 0; /* or a temporary buffer ! */ + + if (pData->fProcesstext) /* inform the application ? */ + { /* decompress the text */ + iRetcode = inflate_buffer (pData, pTemp+2, iCompressedsize, + &pBuf, &iBufsize, &iTextlen); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + + MNG_ALLOCX (pData, zKeyword, iKeywordlen+1) + + if (!zKeyword) /* on error bail out */ + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, pBuf, iBufsize) + MNG_ERROR (pData, MNG_OUTOFMEMORY); + } + + MNG_COPY (zKeyword, pRawdata, iKeywordlen) + + if (!pData->fProcesstext ((mng_handle)pData, MNG_TYPE_ZTXT, zKeyword, (mng_pchar)pBuf, 0, 0)) + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, pBuf, iBufsize) + MNG_FREEX (pData, zKeyword, iKeywordlen+1) + MNG_ERROR (pData, MNG_APPMISCERROR) + } + } + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, pBuf, iBufsize) + MNG_FREEX (pData, zKeyword, iKeywordlen+1) + return iRetcode; + } + /* store the fields */ + ((mng_ztxtp)*ppChunk)->iKeywordsize = iKeywordlen; + ((mng_ztxtp)*ppChunk)->iCompression = *(pTemp+1); + + if ((!pBuf) && (iCompressedsize)) /* did we not get a text-buffer yet ? */ + { /* decompress the text */ + iRetcode = inflate_buffer (pData, pTemp+2, iCompressedsize, + &pBuf, &iBufsize, &iTextlen); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, pBuf, iBufsize) + MNG_FREEX (pData, zKeyword, iKeywordlen+1) + return iRetcode; + } + } + + MNG_ALLOCX (pData, ((mng_ztxtp)*ppChunk)->zKeyword, iKeywordlen + 1) + /* on error bail out */ + if (!((mng_ztxtp)*ppChunk)->zKeyword) + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, pBuf, iBufsize) + MNG_FREEX (pData, zKeyword, iKeywordlen+1) + MNG_ERROR (pData, MNG_OUTOFMEMORY); + } + + MNG_COPY (((mng_ztxtp)*ppChunk)->zKeyword, pRawdata, iKeywordlen) + + ((mng_ztxtp)*ppChunk)->iTextsize = iTextlen; + + if (iCompressedsize) + { + MNG_ALLOCX (pData, ((mng_ztxtp)*ppChunk)->zText, iTextlen + 1) + /* on error bail out */ + if (!((mng_ztxtp)*ppChunk)->zText) + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, pBuf, iBufsize) + MNG_FREEX (pData, zKeyword, iKeywordlen+1) + MNG_ERROR (pData, MNG_OUTOFMEMORY); + } + + MNG_COPY (((mng_ztxtp)*ppChunk)->zText, pBuf, iTextlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + + MNG_FREEX (pData, pBuf, iBufsize) /* free the temporary buffers */ + MNG_FREEX (pData, zKeyword, iKeywordlen+1) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ZTXT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_itxt) +{ + mng_retcode iRetcode; + mng_uint32 iKeywordlen, iTextlen, iLanguagelen, iTranslationlen; + mng_pchar zKeyword, zLanguage, zTranslation; + mng_uint8p pNull1, pNull2, pNull3; + mng_uint32 iCompressedsize; + mng_uint8 iCompressionflag; + mng_uint32 iBufsize; + mng_uint8p pBuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ITXT, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen < 6) /* length must be at least 6 */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pNull1 = find_null (pRawdata); /* find the null separators */ + pNull2 = find_null (pNull1+3); + pNull3 = find_null (pNull2+1); + /* not found inside input-data ? */ + if (((pNull1 - pRawdata) > (mng_int32)iRawlen) || + ((pNull2 - pRawdata) > (mng_int32)iRawlen) || + ((pNull3 - pRawdata) > (mng_int32)iRawlen) ) + MNG_ERROR (pData, MNG_NULLNOTFOUND) + + if (pNull1 == pRawdata) /* there must be at least 1 char for keyword */ + MNG_ERROR (pData, MNG_KEYWORDNULL) + /* compression or not ? */ + if ((*(pNull1+1) != 0) && (*(pNull1+1) != 1)) + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + if (*(pNull1+2) != 0) /* only deflate compression-method allowed */ + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + iKeywordlen = (mng_uint32)(pNull1 - pRawdata); + iLanguagelen = (mng_uint32)(pNull2 - pNull1 - 3); + iTranslationlen = (mng_uint32)(pNull3 - pNull2 - 1); + iCompressedsize = (mng_uint32)(iRawlen - iKeywordlen - iLanguagelen - iTranslationlen - 5); + iCompressionflag = *(pNull1+1); + + zKeyword = 0; /* no buffers acquired yet */ + zLanguage = 0; + zTranslation = 0; + pBuf = 0; + iTextlen = 0; + + if (pData->fProcesstext) /* inform the application ? */ + { + if (iCompressionflag) /* decompress the text ? */ + { + iRetcode = inflate_buffer (pData, pNull3+1, iCompressedsize, + &pBuf, &iBufsize, &iTextlen); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffer */ + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + } + else + { + iTextlen = iCompressedsize; + iBufsize = iTextlen+1; /* plus 1 for terminator byte!!! */ + + MNG_ALLOCX (pData, pBuf, iBufsize); + MNG_COPY (pBuf, pNull3+1, iTextlen); + } + + MNG_ALLOCX (pData, zKeyword, iKeywordlen + 1) + MNG_ALLOCX (pData, zLanguage, iLanguagelen + 1) + MNG_ALLOCX (pData, zTranslation, iTranslationlen + 1) + /* on error bail out */ + if ((!zKeyword) || (!zLanguage) || (!zTranslation)) + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, zTranslation, iTranslationlen + 1) + MNG_FREEX (pData, zLanguage, iLanguagelen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_FREEX (pData, pBuf, iBufsize) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + + MNG_COPY (zKeyword, pRawdata, iKeywordlen) + MNG_COPY (zLanguage, pNull1+3, iLanguagelen) + MNG_COPY (zTranslation, pNull2+1, iTranslationlen) + + if (!pData->fProcesstext ((mng_handle)pData, MNG_TYPE_ITXT, zKeyword, (mng_pchar)pBuf, + zLanguage, zTranslation)) + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, zTranslation, iTranslationlen + 1) + MNG_FREEX (pData, zLanguage, iLanguagelen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_FREEX (pData, pBuf, iBufsize) + + MNG_ERROR (pData, MNG_APPMISCERROR) + } + } + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, zTranslation, iTranslationlen + 1) + MNG_FREEX (pData, zLanguage, iLanguagelen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + /* store the fields */ + ((mng_itxtp)*ppChunk)->iKeywordsize = iKeywordlen; + ((mng_itxtp)*ppChunk)->iLanguagesize = iLanguagelen; + ((mng_itxtp)*ppChunk)->iTranslationsize = iTranslationlen; + ((mng_itxtp)*ppChunk)->iCompressionflag = *(pNull1+1); + ((mng_itxtp)*ppChunk)->iCompressionmethod = *(pNull1+2); + + if ((!pBuf) && (iCompressedsize)) /* did we not get a text-buffer yet ? */ + { + if (iCompressionflag) /* decompress the text ? */ + { + iRetcode = inflate_buffer (pData, pNull3+1, iCompressedsize, + &pBuf, &iBufsize, &iTextlen); + + if (iRetcode) /* on error bail out */ + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, zTranslation, iTranslationlen + 1) + MNG_FREEX (pData, zLanguage, iLanguagelen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_FREEX (pData, pBuf, iBufsize) + return iRetcode; + } + } + else + { + iTextlen = iCompressedsize; + iBufsize = iTextlen+1; /* plus 1 for terminator byte!!! */ + + MNG_ALLOCX (pData, pBuf, iBufsize); + MNG_COPY (pBuf, pNull3+1, iTextlen); + } + } + + MNG_ALLOCX (pData, ((mng_itxtp)*ppChunk)->zKeyword, iKeywordlen + 1) + MNG_ALLOCX (pData, ((mng_itxtp)*ppChunk)->zLanguage, iLanguagelen + 1) + MNG_ALLOCX (pData, ((mng_itxtp)*ppChunk)->zTranslation, iTranslationlen + 1) + /* on error bail out */ + if ((!((mng_itxtp)*ppChunk)->zKeyword ) || + (!((mng_itxtp)*ppChunk)->zLanguage ) || + (!((mng_itxtp)*ppChunk)->zTranslation) ) + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, zTranslation, iTranslationlen + 1) + MNG_FREEX (pData, zLanguage, iLanguagelen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_FREEX (pData, pBuf, iBufsize) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + + MNG_COPY (((mng_itxtp)*ppChunk)->zKeyword, pRawdata, iKeywordlen) + MNG_COPY (((mng_itxtp)*ppChunk)->zLanguage, pNull1+3, iLanguagelen) + MNG_COPY (((mng_itxtp)*ppChunk)->zTranslation, pNull2+1, iTranslationlen) + + ((mng_itxtp)*ppChunk)->iTextsize = iTextlen; + + if (iTextlen) + { + MNG_ALLOCX (pData, ((mng_itxtp)*ppChunk)->zText, iTextlen + 1) + + if (!((mng_itxtp)*ppChunk)->zText) + { /* don't forget to drop the temp buffers */ + MNG_FREEX (pData, zTranslation, iTranslationlen + 1) + MNG_FREEX (pData, zLanguage, iLanguagelen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_FREEX (pData, pBuf, iBufsize) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + + MNG_COPY (((mng_itxtp)*ppChunk)->zText, pBuf, iTextlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + /* free the temporary buffers */ + MNG_FREEX (pData, zTranslation, iTranslationlen + 1) + MNG_FREEX (pData, zLanguage, iLanguagelen + 1) + MNG_FREEX (pData, zKeyword, iKeywordlen + 1) + MNG_FREEX (pData, pBuf, iBufsize) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ITXT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_bkgd) +{ +#ifdef MNG_SUPPORT_DISPLAY + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + mng_imagedatap pBuf; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_BKGD, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasJDAT) || (pData->bHasJDAA)) +#else + if (pData->bHasIDAT) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen > 6) /* it just can't be bigger than that! */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_INCLUDE_JNG /* length checks */ + if (pData->bHasJHDR) + { + if (((pData->iJHDRcolortype == 8) || (pData->iJHDRcolortype == 12)) && (iRawlen != 2)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if (((pData->iJHDRcolortype == 10) || (pData->iJHDRcolortype == 14)) && (iRawlen != 6)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else +#endif /* MNG_INCLUDE_JNG */ + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { + if (((pData->iColortype == 0) || (pData->iColortype == 4)) && (iRawlen != 2)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if (((pData->iColortype == 2) || (pData->iColortype == 6)) && (iRawlen != 6)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iColortype == 3) && (iRawlen != 1)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else + { + if (iRawlen != 6) /* global is always 16-bit RGB ! */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + pData->bHasBKGD = MNG_TRUE; /* indicate bKGD available */ + else + pData->bHasglobalBKGD = (mng_bool)(iRawlen != 0); + +#ifdef MNG_SUPPORT_DISPLAY + if (!pImage) /* if no object dump it in obj 0 */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address object buffer */ + +#ifdef MNG_INCLUDE_JNG + if (pData->bHasJHDR) + { + pBuf->bHasBKGD = MNG_TRUE; /* tell the object it's got bKGD now */ + + switch (pData->iJHDRcolortype) /* store fields for future reference */ + { + case 8 : ; /* gray */ + case 12 : { /* graya */ + pBuf->iBKGDgray = mng_get_uint16 (pRawdata); + break; + } + case 10 : ; /* rgb */ + case 14 : { /* rgba */ + pBuf->iBKGDred = mng_get_uint16 (pRawdata); + pBuf->iBKGDgreen = mng_get_uint16 (pRawdata+2); + pBuf->iBKGDblue = mng_get_uint16 (pRawdata+4); + break; + } + } + } + else +#endif /* MNG_INCLUDE_JNG */ + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { + pBuf->bHasBKGD = MNG_TRUE; /* tell the object it's got bKGD now */ + + switch (pData->iColortype) /* store fields for future reference */ + { + case 0 : ; /* gray */ + case 4 : { /* graya */ + pBuf->iBKGDgray = mng_get_uint16 (pRawdata); + break; + } + case 2 : ; /* rgb */ + case 6 : { /* rgba */ + pBuf->iBKGDred = mng_get_uint16 (pRawdata); + pBuf->iBKGDgreen = mng_get_uint16 (pRawdata+2); + pBuf->iBKGDblue = mng_get_uint16 (pRawdata+4); + break; + } + case 3 : { /* indexed */ + pBuf->iBKGDindex = *pRawdata; + break; + } + } + } + else /* store as global */ + { + if (iRawlen) + { + pData->iGlobalBKGDred = mng_get_uint16 (pRawdata); + pData->iGlobalBKGDgreen = mng_get_uint16 (pRawdata+2); + pData->iGlobalBKGDblue = mng_get_uint16 (pRawdata+4); + } + + { /* create an animation object */ + mng_retcode iRetcode = create_ani_bkgd (pData, pData->iGlobalBKGDred, + pData->iGlobalBKGDgreen, + pData->iGlobalBKGDblue); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_bkgdp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + ((mng_bkgdp)*ppChunk)->iType = pData->iColortype; + + if (iRawlen) + { + switch (iRawlen) /* guess from length */ + { + case 1 : { /* indexed */ + ((mng_bkgdp)*ppChunk)->iType = 3; + ((mng_bkgdp)*ppChunk)->iIndex = *pRawdata; + break; + } + case 2 : { /* gray */ + ((mng_bkgdp)*ppChunk)->iType = 0; + ((mng_bkgdp)*ppChunk)->iGray = mng_get_uint16 (pRawdata); + break; + } + case 6 : { /* rgb */ + ((mng_bkgdp)*ppChunk)->iType = 2; + ((mng_bkgdp)*ppChunk)->iRed = mng_get_uint16 (pRawdata); + ((mng_bkgdp)*ppChunk)->iGreen = mng_get_uint16 (pRawdata+2); + ((mng_bkgdp)*ppChunk)->iBlue = mng_get_uint16 (pRawdata+4); + break; + } + } + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_phys) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PHYS, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIDAT) || (pData->bHasJDAT) || (pData->bHasJDAA)) +#else + if (pData->bHasIDAT) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* it's 9 bytes or empty; no more, no less! */ + if ((iRawlen != 9) && (iRawlen != 0)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_physp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + { + ((mng_physp)*ppChunk)->iSizex = mng_get_uint32 (pRawdata); + ((mng_physp)*ppChunk)->iSizey = mng_get_uint32 (pRawdata+4); + ((mng_physp)*ppChunk)->iUnit = *(pRawdata+8); + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PHYS, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_sbit) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SBIT, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasPLTE) || (pData->bHasIDAT) || (pData->bHasJDAT) || (pData->bHasJDAA)) +#else + if ((pData->bHasPLTE) || (pData->bHasIDAT)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen > 4) /* it just can't be bigger than that! */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_INCLUDE_JNG /* length checks */ + if (pData->bHasJHDR) + { + if ((pData->iJHDRcolortype == 8) && (iRawlen != 1)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iJHDRcolortype == 10) && (iRawlen != 3)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iJHDRcolortype == 12) && (iRawlen != 2)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iJHDRcolortype == 14) && (iRawlen != 4)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else +#endif /* MNG_INCLUDE_JNG */ + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) + { + if ((pData->iColortype == 0) && (iRawlen != 1)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iColortype == 2) && (iRawlen != 3)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iColortype == 3) && (iRawlen != 3)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iColortype == 4) && (iRawlen != 2)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((pData->iColortype == 6) && (iRawlen != 4)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else + { /* global = empty or RGBA */ + if ((iRawlen != 0) && (iRawlen != 4)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_sbitp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + { +#ifdef MNG_INCLUDE_JNG + if (pData->bHasJHDR) + ((mng_sbitp)*ppChunk)->iType = pData->iJHDRcolortype; + else +#endif + if (pData->bHasIHDR) + ((mng_sbitp)*ppChunk)->iType = pData->iColortype; + else /* global ! */ + ((mng_sbitp)*ppChunk)->iType = 6; + + if (iRawlen > 0) + ((mng_sbitp)*ppChunk)->aBits [0] = *pRawdata; + if (iRawlen > 1) + ((mng_sbitp)*ppChunk)->aBits [1] = *(pRawdata+1); + if (iRawlen > 2) + ((mng_sbitp)*ppChunk)->aBits [2] = *(pRawdata+2); + if (iRawlen > 3) + ((mng_sbitp)*ppChunk)->aBits [3] = *(pRawdata+3); + + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SBIT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_splt) +{ + mng_uint8p pTemp; + mng_uint32 iNamelen; + mng_uint8 iSampledepth; + mng_uint32 iRemain; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SPLT, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (pData->bHasIDAT) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen) + { + pTemp = find_null (pRawdata); /* find null-separator */ + /* not found inside input-data ? */ + if ((pTemp - pRawdata) > (mng_int32)iRawlen) + MNG_ERROR (pData, MNG_NULLNOTFOUND) + + iNamelen = (mng_uint32)(pTemp - pRawdata); + iSampledepth = *(pTemp+1); + iRemain = (iRawlen - 2 - iNamelen); + + if ((iSampledepth != 1) && (iSampledepth != 2)) + MNG_ERROR (pData, MNG_INVSAMPLEDEPTH) + /* check remaining length */ + if ( ((iSampledepth == 1) && (iRemain % 6 != 0)) || + ((iSampledepth == 2) && (iRemain % 10 != 0)) ) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + } + else + { + pTemp = MNG_NULL; + iNamelen = 0; + iSampledepth = 0; + iRemain = 0; + } + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_spltp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + { + ((mng_spltp)*ppChunk)->iNamesize = iNamelen; + ((mng_spltp)*ppChunk)->iSampledepth = iSampledepth; + + if (iSampledepth == 1) + ((mng_spltp)*ppChunk)->iEntrycount = iRemain / 6; + else + ((mng_spltp)*ppChunk)->iEntrycount = iRemain / 10; + + if (iNamelen) + { + MNG_ALLOC (pData, ((mng_spltp)*ppChunk)->zName, iNamelen+1) + MNG_COPY (((mng_spltp)*ppChunk)->zName, pRawdata, iNamelen) + } + + if (iRemain) + { + MNG_ALLOC (pData, ((mng_spltp)*ppChunk)->pEntries, iRemain) + MNG_COPY (((mng_spltp)*ppChunk)->pEntries, pTemp+2, iRemain) + } + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_hist) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_HIST, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasIHDR) && (!pData->bHasBASI) && (!pData->bHasDHDR) ) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if ((!pData->bHasPLTE) || (pData->bHasIDAT)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* length oke ? */ + if ( ((iRawlen & 0x01) != 0) || ((iRawlen >> 1) != pData->iPLTEcount) ) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { + mng_uint32 iX; + /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_histp)*ppChunk)->iEntrycount = iRawlen >> 1; + + for (iX = 0; iX < (iRawlen >> 1); iX++) + { + ((mng_histp)*ppChunk)->aEntries [iX] = mng_get_uint16 (pRawdata); + pRawdata += 2; + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_HIST, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_time) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TIME, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 7) /* length must be exactly 7 */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +/* if (pData->fProcesstime) */ /* inform the application ? */ +/* { + + pData->fProcesstime ((mng_handle)pData, ); + } */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_timep)*ppChunk)->iYear = mng_get_uint16 (pRawdata); + ((mng_timep)*ppChunk)->iMonth = *(pRawdata+2); + ((mng_timep)*ppChunk)->iDay = *(pRawdata+3); + ((mng_timep)*ppChunk)->iHour = *(pRawdata+4); + ((mng_timep)*ppChunk)->iMinute = *(pRawdata+5); + ((mng_timep)*ppChunk)->iSecond = *(pRawdata+6); + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TIME, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_mhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MHDR, MNG_LC_START) +#endif + + if (pData->eSigtype != mng_it_mng) /* sequence checks */ + MNG_ERROR (pData, MNG_CHUNKNOTALLOWED) + + if (pData->bHasheader) /* can only be the first chunk! */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* correct length ? */ + if ((iRawlen != 28) && (iRawlen != 12)) + MNG_ERROR (pData, MNG_INVALIDLENGTH); + + pData->bHasMHDR = MNG_TRUE; /* oh boy, a real MNG */ + pData->bHasheader = MNG_TRUE; /* we've got a header */ + pData->eImagetype = mng_it_mng; /* fill header fields */ + pData->iWidth = mng_get_uint32 (pRawdata); + pData->iHeight = mng_get_uint32 (pRawdata+4); + pData->iTicks = mng_get_uint32 (pRawdata+8); + + if (iRawlen == 28) /* proper MHDR ? */ + { + pData->iLayercount = mng_get_uint32 (pRawdata+12); + pData->iFramecount = mng_get_uint32 (pRawdata+16); + pData->iPlaytime = mng_get_uint32 (pRawdata+20); + pData->iSimplicity = mng_get_uint32 (pRawdata+24); + + pData->bPreDraft48 = MNG_FALSE; + } + else /* probably pre-draft48 then */ + { + pData->iLayercount = 0; + pData->iFramecount = 0; + pData->iPlaytime = 0; + pData->iSimplicity = 0; + + pData->bPreDraft48 = MNG_TRUE; + } + /* predict alpha-depth */ + if ((pData->iSimplicity & 0x00000001) == 0) + pData->iAlphadepth = 16; /* no indicators = assume the worst */ + else + if ((pData->iSimplicity & 0x00000008) == 0) + pData->iAlphadepth = 0; /* no transparency at all */ + else + if ((pData->iSimplicity & 0x00000140) == 0x00000040) + pData->iAlphadepth = 1; /* no semi-transparency guaranteed */ + else + pData->iAlphadepth = 16; /* anything else = assume the worst */ + +#ifdef MNG_INCLUDE_JNG /* can we handle the complexity ? */ + if (pData->iSimplicity & 0x0000FC00) +#else + if (pData->iSimplicity & 0x0000FC10) +#endif + MNG_ERROR (pData, MNG_MNGTOOCOMPLEX) + /* fits on maximum canvas ? */ + if ((pData->iWidth > pData->iMaxwidth) || (pData->iHeight > pData->iMaxheight)) + MNG_WARNING (pData, MNG_IMAGETOOLARGE) + + if (pData->fProcessheader) /* inform the app ? */ + if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight)) + MNG_ERROR (pData, MNG_APPMISCERROR) + + pData->iImagelevel++; /* one level deeper */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_mhdrp)*ppChunk)->iWidth = pData->iWidth; + ((mng_mhdrp)*ppChunk)->iHeight = pData->iHeight; + ((mng_mhdrp)*ppChunk)->iTicks = pData->iTicks; + ((mng_mhdrp)*ppChunk)->iLayercount = pData->iLayercount; + ((mng_mhdrp)*ppChunk)->iFramecount = pData->iFramecount; + ((mng_mhdrp)*ppChunk)->iPlaytime = pData->iPlaytime; + ((mng_mhdrp)*ppChunk)->iSimplicity = pData->iSimplicity; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_mend) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MEND, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen > 0) /* must not contain data! */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { /* do something */ + mng_retcode iRetcode = process_display_mend (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + + pData->bHasMHDR = MNG_FALSE; /* end of the line, bro! */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MEND, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_loop) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_LOOP, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (!pData->bCacheplayback) /* must store playback info to work!! */ + MNG_ERROR (pData, MNG_LOOPWITHCACHEOFF) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen >= 5) /* length checks */ + { + if (iRawlen >= 6) + { + if ((iRawlen - 6) % 4 != 0) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + } + else + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_uint8 iLevel; + mng_uint32 iRepeat; + mng_uint8 iTermination = 0; + mng_uint32 iItermin = 1; + mng_uint32 iItermax = 0x7fffffffL; + mng_retcode iRetcode; + + pData->bHasLOOP = MNG_TRUE; /* indicate we're inside a loop */ + + iLevel = *pRawdata; /* determine the fields for processing */ + + if (pData->bPreDraft48) + { + iTermination = *(pRawdata+1); + + iRepeat = mng_get_uint32 (pRawdata+2); + } + else + iRepeat = mng_get_uint32 (pRawdata+1); + + if (iRawlen >= 6) + { + if (!pData->bPreDraft48) + iTermination = *(pRawdata+5); + + if (iRawlen >= 10) + { + iItermin = mng_get_uint32 (pRawdata+6); + + if (iRawlen >= 14) + { + iItermax = mng_get_uint32 (pRawdata+10); + + /* TODO: process signals */ + + } + } + } + + /* create the LOOP ani-object */ + iRetcode = create_ani_loop (pData, iLevel, iRepeat, iTermination, + iItermin, iItermax, 0, 0); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (iRawlen >= 5) /* store the fields */ + { + ((mng_loopp)*ppChunk)->iLevel = *pRawdata; + + if (pData->bPreDraft48) + { + ((mng_loopp)*ppChunk)->iTermination = *(pRawdata+1); + ((mng_loopp)*ppChunk)->iRepeat = mng_get_uint32 (pRawdata+2); + } + else + { + ((mng_loopp)*ppChunk)->iRepeat = mng_get_uint32 (pRawdata+1); + } + + if (iRawlen >= 6) + { + if (!pData->bPreDraft48) + ((mng_loopp)*ppChunk)->iTermination = *(pRawdata+5); + + if (iRawlen >= 10) + { + ((mng_loopp)*ppChunk)->iItermin = mng_get_uint32 (pRawdata+6); + + if (iRawlen >= 14) + { + ((mng_loopp)*ppChunk)->iItermax = mng_get_uint32 (pRawdata+10); + ((mng_loopp)*ppChunk)->iCount = (iRawlen - 14) / 4; + + if (((mng_loopp)*ppChunk)->iCount) + { + MNG_ALLOC (pData, ((mng_loopp)*ppChunk)->pSignals, + ((mng_loopp)*ppChunk)->iCount << 2) + +#ifndef MNG_BIGENDIAN_SUPPORTED + { + mng_uint32 iX; + mng_uint8p pIn = pRawdata + 14; + mng_uint32p pOut = (mng_uint32p)((mng_loopp)*ppChunk)->pSignals; + + for (iX = 0; iX < ((mng_loopp)*ppChunk)->iCount; iX++) + { + *pOut++ = mng_get_uint32 (pIn); + pIn += 4; + } + } +#else + MNG_COPY (((mng_loopp)*ppChunk)->pSignals, pRawdata + 14, + ((mng_loopp)*ppChunk)->iCount << 2) +#endif /* !MNG_BIGENDIAN_SUPPORTED */ + } + } + } + } + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_endl) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ENDL, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 1) /* length must be exactly 1 */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + if (pData->bHasLOOP) /* are we really processing a loop ? */ + { + mng_uint8 iLevel = *pRawdata; /* get the nest level */ + /* create an ENDL animation object */ + mng_retcode iRetcode = create_ani_endl (pData, iLevel); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + { /* process it */ + mng_ani_endlp pENDL = (mng_ani_endlp)pData->pLastaniobj; + + iRetcode = pENDL->sHeader.fProcess (pData, pENDL); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + else + { + + /* TODO: error abort ??? */ + + } + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_endlp)*ppChunk)->iLevel = *pRawdata; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_defi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DEFI, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check the length */ + if ((iRawlen != 2) && (iRawlen != 3) && (iRawlen != 4) && + (iRawlen != 12) && (iRawlen != 28)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + + pData->iDEFIobjectid = mng_get_uint16 (pRawdata); + + if (iRawlen > 2) + { + pData->bDEFIhasdonotshow = MNG_TRUE; + pData->iDEFIdonotshow = *(pRawdata+2); + } + else + { + pData->bDEFIhasdonotshow = MNG_FALSE; + pData->iDEFIdonotshow = 0; + } + + if (iRawlen > 3) + { + pData->bDEFIhasconcrete = MNG_TRUE; + pData->iDEFIconcrete = *(pRawdata+3); + } + else + { + pData->bDEFIhasconcrete = MNG_FALSE; + pData->iDEFIconcrete = 0; + } + + if (iRawlen > 4) + { + pData->bDEFIhasloca = MNG_TRUE; + pData->iDEFIlocax = mng_get_int32 (pRawdata+4); + pData->iDEFIlocay = mng_get_int32 (pRawdata+8); + } + else + { + pData->bDEFIhasloca = MNG_FALSE; + pData->iDEFIlocax = 0; + pData->iDEFIlocay = 0; + } + + if (iRawlen > 12) + { + pData->bDEFIhasclip = MNG_TRUE; + pData->iDEFIclipl = mng_get_int32 (pRawdata+12); + pData->iDEFIclipr = mng_get_int32 (pRawdata+16); + pData->iDEFIclipt = mng_get_int32 (pRawdata+20); + pData->iDEFIclipb = mng_get_int32 (pRawdata+24); + } + else + { + pData->bDEFIhasclip = MNG_FALSE; + pData->iDEFIclipl = 0; + pData->iDEFIclipr = 0; + pData->iDEFIclipt = 0; + pData->iDEFIclipb = 0; + } + /* create an animation object */ + iRetcode = create_ani_defi (pData); + + if (!iRetcode) /* do display processing */ + iRetcode = process_display_defi (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_defip)*ppChunk)->iObjectid = mng_get_uint16 (pRawdata); + + if (iRawlen > 2) + { + ((mng_defip)*ppChunk)->bHasdonotshow = MNG_TRUE; + ((mng_defip)*ppChunk)->iDonotshow = *(pRawdata+2); + } + else + ((mng_defip)*ppChunk)->bHasdonotshow = MNG_FALSE; + + if (iRawlen > 3) + { + ((mng_defip)*ppChunk)->bHasconcrete = MNG_TRUE; + ((mng_defip)*ppChunk)->iConcrete = *(pRawdata+3); + } + else + ((mng_defip)*ppChunk)->bHasconcrete = MNG_FALSE; + + if (iRawlen > 4) + { + ((mng_defip)*ppChunk)->bHasloca = MNG_TRUE; + ((mng_defip)*ppChunk)->iXlocation = mng_get_int32 (pRawdata+4); + ((mng_defip)*ppChunk)->iYlocation = mng_get_int32 (pRawdata+8); + } + else + ((mng_defip)*ppChunk)->bHasloca = MNG_FALSE; + + if (iRawlen > 12) + { + ((mng_defip)*ppChunk)->bHasclip = MNG_TRUE; + ((mng_defip)*ppChunk)->iLeftcb = mng_get_int32 (pRawdata+12); + ((mng_defip)*ppChunk)->iRightcb = mng_get_int32 (pRawdata+16); + ((mng_defip)*ppChunk)->iTopcb = mng_get_int32 (pRawdata+20); + ((mng_defip)*ppChunk)->iBottomcb = mng_get_int32 (pRawdata+24); + } + else + ((mng_defip)*ppChunk)->bHasclip = MNG_FALSE; + + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_basi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_BASI, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check the length */ + if ((iRawlen != 13) && (iRawlen != 19) && (iRawlen != 21) && (iRawlen != 22)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pData->bHasBASI = MNG_TRUE; /* inside a BASI-IEND block now */ + /* store interesting fields */ + pData->iDatawidth = mng_get_uint32 (pRawdata); + pData->iDataheight = mng_get_uint32 (pRawdata+4); + pData->iBitdepth = *(pRawdata+8); + pData->iColortype = *(pRawdata+9); + pData->iCompression = *(pRawdata+10); + pData->iFilter = *(pRawdata+11); + pData->iInterlace = *(pRawdata+12); + + if ((pData->iBitdepth != 1) && /* parameter validity checks */ + (pData->iBitdepth != 2) && + (pData->iBitdepth != 4) && + (pData->iBitdepth != 8) && + (pData->iBitdepth != 16) ) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if ((pData->iColortype != MNG_COLORTYPE_GRAY ) && + (pData->iColortype != MNG_COLORTYPE_RGB ) && + (pData->iColortype != MNG_COLORTYPE_INDEXED) && + (pData->iColortype != MNG_COLORTYPE_GRAYA ) && + (pData->iColortype != MNG_COLORTYPE_RGBA ) ) + MNG_ERROR (pData, MNG_INVALIDCOLORTYPE) + + if ((pData->iColortype == MNG_COLORTYPE_INDEXED) && (pData->iBitdepth > 8)) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if (((pData->iColortype == MNG_COLORTYPE_RGB ) || + (pData->iColortype == MNG_COLORTYPE_GRAYA ) || + (pData->iColortype == MNG_COLORTYPE_RGBA ) ) && + (pData->iBitdepth < 8 ) ) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if (pData->iCompression != MNG_COMPRESSION_DEFLATE) + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + if (pData->iFilter & (~MNG_FILTER_DIFFERING)) + MNG_ERROR (pData, MNG_INVALIDFILTER) + + if ((pData->iInterlace != MNG_INTERLACE_NONE ) && + (pData->iInterlace != MNG_INTERLACE_ADAM7) ) + MNG_ERROR (pData, MNG_INVALIDINTERLACE) + + pData->iImagelevel++; /* one level deeper */ + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_uint16 iRed = 0; + mng_uint16 iGreen = 0; + mng_uint16 iBlue = 0; + mng_bool bHasalpha = MNG_FALSE; + mng_uint16 iAlpha = 0xFFFF; + mng_uint8 iViewable = 0; + mng_retcode iRetcode; + + if (iRawlen > 13) /* get remaining fields, if any */ + { + iRed = mng_get_uint16 (pRawdata+13); + iGreen = mng_get_uint16 (pRawdata+15); + iBlue = mng_get_uint16 (pRawdata+17); + } + + if (iRawlen > 19) + { + bHasalpha = MNG_TRUE; + iAlpha = mng_get_uint16 (pRawdata+19); + } + + if (iRawlen > 21) + iViewable = *(pRawdata+21); + /* create an animation object */ + iRetcode = create_ani_basi (pData, iRed, iGreen, iBlue, + bHasalpha, iAlpha, iViewable); + + if (!iRetcode) /* display-processing... */ + iRetcode = process_display_basi (pData, iRed, iGreen, iBlue, + bHasalpha, iAlpha, iViewable); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_basip)*ppChunk)->iWidth = mng_get_uint32 (pRawdata); + ((mng_basip)*ppChunk)->iHeight = mng_get_uint32 (pRawdata+4); + ((mng_basip)*ppChunk)->iBitdepth = *(pRawdata+8); + ((mng_basip)*ppChunk)->iColortype = *(pRawdata+9); + ((mng_basip)*ppChunk)->iCompression = *(pRawdata+10); + ((mng_basip)*ppChunk)->iFilter = *(pRawdata+11); + ((mng_basip)*ppChunk)->iInterlace = *(pRawdata+12); + + if (iRawlen > 13) + { + ((mng_basip)*ppChunk)->iRed = mng_get_uint16 (pRawdata+13); + ((mng_basip)*ppChunk)->iGreen = mng_get_uint16 (pRawdata+15); + ((mng_basip)*ppChunk)->iBlue = mng_get_uint16 (pRawdata+17); + } + + if (iRawlen > 19) + ((mng_basip)*ppChunk)->iAlpha = mng_get_uint16 (pRawdata+19); + + if (iRawlen > 21) + ((mng_basip)*ppChunk)->iViewable = *(pRawdata+21); + + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_clon) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CLON, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check the length */ + if ((iRawlen != 4) && (iRawlen != 5) && (iRawlen != 6) && + (iRawlen != 7) && (iRawlen != 16)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_uint16 iSourceid, iCloneid; + mng_uint8 iClonetype = 0; + mng_bool bHasdonotshow = MNG_FALSE; + mng_uint8 iDonotshow = 0; + mng_uint8 iConcrete = 0; + mng_bool bHasloca = MNG_FALSE; + mng_uint8 iLocationtype = 0; + mng_int32 iLocationx = 0; + mng_int32 iLocationy = 0; + mng_retcode iRetcode; + + iSourceid = mng_get_uint16 (pRawdata); + iCloneid = mng_get_uint16 (pRawdata+2); + + if (iRawlen > 4) + iClonetype = *(pRawdata+4); + + if (iRawlen > 5) + { + bHasdonotshow = MNG_TRUE; + iDonotshow = *(pRawdata+5); + } + + if (iRawlen > 6) + iConcrete = *(pRawdata+6); + + if (iRawlen > 7) + { + bHasloca = MNG_TRUE; + iLocationtype = *(pRawdata+7); + iLocationx = mng_get_int32 (pRawdata+8); + iLocationy = mng_get_int32 (pRawdata+12); + } + + iRetcode = create_ani_clon (pData, iSourceid, iCloneid, iClonetype, + bHasdonotshow, iDonotshow, iConcrete, + bHasloca, iLocationtype, iLocationx, iLocationy); + + if (!iRetcode) /* do display processing */ + iRetcode = process_display_clon (pData, iSourceid, iCloneid, iClonetype, + bHasdonotshow, iDonotshow, iConcrete, + bHasloca, iLocationtype, iLocationx, iLocationy); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_clonp)*ppChunk)->iSourceid = mng_get_uint16 (pRawdata); + ((mng_clonp)*ppChunk)->iCloneid = mng_get_uint16 (pRawdata+2); + + if (iRawlen > 4) + ((mng_clonp)*ppChunk)->iClonetype = *(pRawdata+4); + + if (iRawlen > 5) + ((mng_clonp)*ppChunk)->iDonotshow = *(pRawdata+5); + + if (iRawlen > 6) + ((mng_clonp)*ppChunk)->iConcrete = *(pRawdata+6); + + if (iRawlen > 7) + { + ((mng_clonp)*ppChunk)->bHasloca = MNG_TRUE; + ((mng_clonp)*ppChunk)->iLocationtype = *(pRawdata+7); + ((mng_clonp)*ppChunk)->iLocationx = mng_get_int32 (pRawdata+8); + ((mng_clonp)*ppChunk)->iLocationy = mng_get_int32 (pRawdata+12); + } + else + { + ((mng_clonp)*ppChunk)->bHasloca = MNG_FALSE; + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_past) +{ +#ifdef MNG_STORE_CHUNKS + mng_uint32 iCount; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PAST, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + /* check the length */ + if ((iRawlen < 41) || (((iRawlen - 11) % 30) != 0)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_STORE_CHUNKS + iCount = ((iRawlen - 11) / 30); /* how many entries again */ +#endif + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { + mng_uint32 iX; + mng_past_sourcep pSource; + /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_pastp)*ppChunk)->iDestid = mng_get_uint16 (pRawdata); + ((mng_pastp)*ppChunk)->iTargettype = *(pRawdata+2); + ((mng_pastp)*ppChunk)->iTargetx = mng_get_int32 (pRawdata+3); + ((mng_pastp)*ppChunk)->iTargety = mng_get_int32 (pRawdata+7); + ((mng_pastp)*ppChunk)->iCount = iCount; + + pRawdata += 11; + /* get a buffer for all the source blocks */ + MNG_ALLOC (pData, ((mng_pastp)*ppChunk)->pSources, (iCount * sizeof (mng_past_source))) + + pSource = ((mng_pastp)*ppChunk)->pSources; + + for (iX = 0; iX < iCount; iX++) /* now copy the source blocks */ + { + pSource->iSourceid = mng_get_uint16 (pRawdata); + pSource->iComposition = *(pRawdata+2); + pSource->iOrientation = *(pRawdata+3); + pSource->iOffsettype = *(pRawdata+4); + pSource->iOffsetx = mng_get_int32 (pRawdata+5); + pSource->iOffsety = mng_get_int32 (pRawdata+9); + pSource->iBoundarytype = *(pRawdata+13); + pSource->iBoundaryl = mng_get_int32 (pRawdata+14); + pSource->iBoundaryr = mng_get_int32 (pRawdata+18); + pSource->iBoundaryt = mng_get_int32 (pRawdata+22); + pSource->iBoundaryb = mng_get_int32 (pRawdata+26); + + pSource += sizeof (mng_past_source); + pRawdata += 30; + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PAST, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_disc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DISC, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if ((iRawlen % 2) != 0) /* check the length */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { /* process it */ + mng_retcode iRetcode = process_display_disc (pData, (iRawlen / 2), + (mng_uint16p)pRawdata); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_discp)*ppChunk)->iCount = iRawlen / 2; + + MNG_ALLOC (pData, ((mng_discp)*ppChunk)->pObjectids, iRawlen) + +#ifndef MNG_BIGENDIAN_SUPPORTED + { + mng_uint32 iX; + mng_uint8p pIn = pRawdata; + mng_uint16p pOut = ((mng_discp)*ppChunk)->pObjectids; + + for (iX = 0; iX < ((mng_discp)*ppChunk)->iCount; iX++) + { + *pOut++ = mng_get_uint16 (pIn); + pIn += 2; + } + } +#else + MNG_COPY (((mng_discp)*ppChunk)->pObjectids, pRawdata, iRawlen) +#endif /* !MNG_BIGENDIAN_SUPPORTED */ + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DISC, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_back) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_BACK, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check the length */ + if ((iRawlen != 6) && (iRawlen != 7) && (iRawlen != 9) && (iRawlen != 10)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + /* retrieve the fields */ + pData->bHasBACK = MNG_TRUE; + pData->iBACKred = mng_get_uint16 (pRawdata); + pData->iBACKgreen = mng_get_uint16 (pRawdata+2); + pData->iBACKblue = mng_get_uint16 (pRawdata+4); + + if (iRawlen > 6) + pData->iBACKmandatory = *(pRawdata+6); + else + pData->iBACKmandatory = 0; + + if (iRawlen > 7) + pData->iBACKimageid = mng_get_uint16 (pRawdata+7); + else + pData->iBACKimageid = 0; + + if (iRawlen > 9) + pData->iBACKtile = *(pRawdata+9); + else + pData->iBACKtile = 0; + + iRetcode = create_ani_back (pData, pData->iBACKred, pData->iBACKgreen, + pData->iBACKblue, pData->iBACKmandatory, + pData->iBACKimageid, pData->iBACKtile); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_backp)*ppChunk)->iRed = mng_get_uint16 (pRawdata); + ((mng_backp)*ppChunk)->iGreen = mng_get_uint16 (pRawdata+2); + ((mng_backp)*ppChunk)->iBlue = mng_get_uint16 (pRawdata+4); + + if (iRawlen > 6) + ((mng_backp)*ppChunk)->iMandatory = *(pRawdata+6); + + if (iRawlen > 7) + ((mng_backp)*ppChunk)->iImageid = mng_get_uint16 (pRawdata+7); + + if (iRawlen > 9) + ((mng_backp)*ppChunk)->iTile = *(pRawdata+9); + + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_fram) +{ + mng_uint8p pTemp; +#ifdef MNG_STORE_CHUNKS + mng_uint32 iNamelen; +#endif + mng_uint32 iRemain; + mng_uint32 iRequired = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_FRAM, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen <= 1) /* only framing-mode ? */ + { +#ifdef MNG_STORE_CHUNKS + iNamelen = 0; /* indicate so */ +#endif + iRemain = 0; + pTemp = MNG_NULL; + } + else + { + pTemp = find_null (pRawdata+1); /* find null-separator */ + /* not found inside input-data ? */ + if ((pTemp - pRawdata) > (mng_int32)iRawlen) + MNG_ERROR (pData, MNG_NULLNOTFOUND) + +#ifdef MNG_STORE_CHUNKS + iNamelen = (mng_uint32)((pTemp - pRawdata) - 1); +#endif + iRemain = (mng_uint32)(iRawlen - (pTemp - pRawdata) - 1); + /* remains must be empty or at least 4 bytes */ + if ((iRemain != 0) && (iRemain < 4)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if (iRemain) + { + iRequired = 4; /* calculate and check required remaining length */ + + if (*(pTemp+1)) { iRequired += 4; } + if (*(pTemp+2)) { iRequired += 4; } + if (*(pTemp+3)) { iRequired += 17; } + + if (*(pTemp+4)) + { + if ((iRemain - iRequired) % 4 != 0) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + else + { + if (iRemain != iRequired) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + } + } + } + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_uint8p pWork = pTemp; + mng_uint8 iFramemode = 0; + mng_uint8 iChangedelay = 0; + mng_uint32 iDelay = 0; + mng_uint8 iChangetimeout = 0; + mng_uint32 iTimeout = 0; + mng_uint8 iChangeclipping = 0; + mng_uint8 iCliptype = 0; + mng_int32 iClipl = 0; + mng_int32 iClipr = 0; + mng_int32 iClipt = 0; + mng_int32 iClipb = 0; + mng_retcode iRetcode; + + if (iRawlen) /* any data specified ? */ + { + if (*(pRawdata)) /* save the new framing mode ? */ + { + iFramemode = *(pRawdata); + + if (pData->bPreDraft48) /* old style input-stream ? */ + { + switch (iFramemode) + { + case 0: { break; } + case 1: { iFramemode = 3; break; } + case 2: { iFramemode = 4; break; } + case 3: { iFramemode = 1; break; } + case 4: { iFramemode = 1; break; } + case 5: { iFramemode = 2; break; } + default: { iFramemode = 1; break; } + } + } + } + + if (iRemain) + { + iChangedelay = *(pWork+1); + iChangetimeout = *(pWork+2); + iChangeclipping = *(pWork+3); + pWork += 5; + + if (iChangedelay) /* delay changed ? */ + { + iDelay = mng_get_uint32 (pWork); + pWork += 4; + } + + if (iChangetimeout) /* timeout changed ? */ + { + iTimeout = mng_get_uint32 (pWork); + pWork += 4; + } + + if (iChangeclipping) /* clipping changed ? */ + { + iCliptype = *pWork; + iClipl = mng_get_int32 (pWork+1); + iClipr = mng_get_int32 (pWork+5); + iClipt = mng_get_int32 (pWork+9); + iClipb = mng_get_int32 (pWork+13); + } + } + } + + iRetcode = create_ani_fram (pData, iFramemode, iChangedelay, iDelay, + iChangetimeout, iTimeout, + iChangeclipping, iCliptype, + iClipl, iClipr, iClipt, iClipb); + + if (!iRetcode) /* now go and do something */ + iRetcode = process_display_fram (pData, iFramemode, iChangedelay, iDelay, + iChangetimeout, iTimeout, + iChangeclipping, iCliptype, + iClipl, iClipr, iClipt, iClipb); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_framp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + { + mng_uint8 iFramemode = *(pRawdata); + + if (pData->bPreDraft48) /* old style input-stream ? */ + { + switch (iFramemode) + { + case 1: { iFramemode = 3; break; } + case 2: { iFramemode = 4; break; } + case 3: { iFramemode = 5; break; } /* TODO: provision for mode=5 ??? */ + case 4: { iFramemode = 1; break; } + case 5: { iFramemode = 2; break; } + default: { iFramemode = 1; break; } + } + } + + ((mng_framp)*ppChunk)->iMode = iFramemode; + ((mng_framp)*ppChunk)->iNamesize = iNamelen; + + if (iNamelen) + { + MNG_ALLOC (pData, ((mng_framp)*ppChunk)->zName, iNamelen+1) + MNG_COPY (((mng_framp)*ppChunk)->zName, pRawdata+1, iNamelen) + } + + if (iRemain) + { + ((mng_framp)*ppChunk)->iChangedelay = *(pTemp+1); + ((mng_framp)*ppChunk)->iChangetimeout = *(pTemp+2); + ((mng_framp)*ppChunk)->iChangeclipping = *(pTemp+3); + ((mng_framp)*ppChunk)->iChangesyncid = *(pTemp+4); + + pTemp += 5; + + if (((mng_framp)*ppChunk)->iChangedelay) + { + ((mng_framp)*ppChunk)->iDelay = mng_get_uint32 (pTemp); + pTemp += 4; + } + + if (((mng_framp)*ppChunk)->iChangetimeout) + { + ((mng_framp)*ppChunk)->iTimeout = mng_get_uint32 (pTemp); + pTemp += 4; + } + + if (((mng_framp)*ppChunk)->iChangeclipping) + { + ((mng_framp)*ppChunk)->iBoundarytype = *pTemp; + ((mng_framp)*ppChunk)->iBoundaryl = mng_get_int32 (pTemp+1); + ((mng_framp)*ppChunk)->iBoundaryr = mng_get_int32 (pTemp+5); + ((mng_framp)*ppChunk)->iBoundaryt = mng_get_int32 (pTemp+9); + ((mng_framp)*ppChunk)->iBoundaryb = mng_get_int32 (pTemp+13); + pTemp += 17; + } + + if (((mng_framp)*ppChunk)->iChangesyncid) + { + ((mng_framp)*ppChunk)->iCount = (iRemain - iRequired) / 4; + + if (((mng_framp)*ppChunk)->iCount) + { + MNG_ALLOC (pData, ((mng_framp)*ppChunk)->pSyncids, + ((mng_framp)*ppChunk)->iCount * 4); + +#ifndef MNG_BIGENDIAN_SUPPORTED + { + mng_uint32 iX; + mng_uint32p pOut = ((mng_framp)*ppChunk)->pSyncids; + + for (iX = 0; iX < ((mng_framp)*ppChunk)->iCount; iX++) + { + *pOut++ = mng_get_uint32 (pTemp); + pTemp += 4; + } + } +#else + MNG_COPY (((mng_framp)*ppChunk)->pSyncids, pTemp, + ((mng_framp)*ppChunk)->iCount * 4) +#endif /* !MNG_BIGENDIAN_SUPPORTED */ + } + } + } + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_FRAM, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_move) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MOVE, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 13) /* check the length */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + /* create a MOVE animation object */ + iRetcode = create_ani_move (pData, mng_get_uint16 (pRawdata), + mng_get_uint16 (pRawdata+2), + *(pRawdata+4), + mng_get_int32 (pRawdata+5), + mng_get_int32 (pRawdata+9)); + + if (!iRetcode) /* process the move */ + iRetcode = process_display_move (pData, + mng_get_uint16 (pRawdata), + mng_get_uint16 (pRawdata+2), + *(pRawdata+4), + mng_get_int32 (pRawdata+5), + mng_get_int32 (pRawdata+9)); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_movep)*ppChunk)->iFirstid = mng_get_uint16 (pRawdata); + ((mng_movep)*ppChunk)->iLastid = mng_get_uint16 (pRawdata+2); + ((mng_movep)*ppChunk)->iMovetype = *(pRawdata+4); + ((mng_movep)*ppChunk)->iMovex = mng_get_int32 (pRawdata+5); + ((mng_movep)*ppChunk)->iMovey = mng_get_int32 (pRawdata+9); + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_clip) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CLIP, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 21) /* check the length */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + /* create a CLIP animation object */ + iRetcode = create_ani_clip (pData, mng_get_uint16 (pRawdata), + mng_get_uint16 (pRawdata+2), + *(pRawdata+4), + mng_get_int32 (pRawdata+5), + mng_get_int32 (pRawdata+9), + mng_get_int32 (pRawdata+13), + mng_get_int32 (pRawdata+17)); + + if (!iRetcode) /* process the clipping */ + iRetcode = process_display_clip (pData, + mng_get_uint16 (pRawdata), + mng_get_uint16 (pRawdata+2), + *(pRawdata+4), + mng_get_int32 (pRawdata+5), + mng_get_int32 (pRawdata+9), + mng_get_int32 (pRawdata+13), + mng_get_int32 (pRawdata+17)); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_clipp)*ppChunk)->iFirstid = mng_get_uint16 (pRawdata); + ((mng_clipp)*ppChunk)->iLastid = mng_get_uint16 (pRawdata+2); + ((mng_clipp)*ppChunk)->iCliptype = *(pRawdata+4); + ((mng_clipp)*ppChunk)->iClipl = mng_get_int32 (pRawdata+5); + ((mng_clipp)*ppChunk)->iClipr = mng_get_int32 (pRawdata+9); + ((mng_clipp)*ppChunk)->iClipt = mng_get_int32 (pRawdata+13); + ((mng_clipp)*ppChunk)->iClipb = mng_get_int32 (pRawdata+17); + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_show) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SHOW, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check the length */ + if ((iRawlen != 0) && (iRawlen != 2) && (iRawlen != 4) && (iRawlen != 5)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + + if (iRawlen) /* determine parameters if any */ + { + pData->iSHOWfromid = mng_get_uint16 (pRawdata); + + if (iRawlen > 2) + pData->iSHOWtoid = mng_get_uint16 (pRawdata+2); + else + pData->iSHOWtoid = pData->iSHOWfromid; + + if (iRawlen > 4) + pData->iSHOWmode = *(pRawdata+4); + else + pData->iSHOWmode = 0; + } + else /* use defaults then */ + { + pData->iSHOWmode = 2; + pData->iSHOWfromid = 1; + pData->iSHOWtoid = 65535; + } + /* create a SHOW animation object */ + iRetcode = create_ani_show (pData, pData->iSHOWfromid, pData->iSHOWtoid, + pData->iSHOWmode); + + if (!iRetcode) /* go and do it! */ + iRetcode = process_display_show (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_showp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + { + ((mng_showp)*ppChunk)->iFirstid = mng_get_uint16 (pRawdata); + + if (iRawlen > 2) + ((mng_showp)*ppChunk)->iLastid = mng_get_uint16 (pRawdata+2); + + if (iRawlen > 4) + ((mng_showp)*ppChunk)->iMode = *(pRawdata+4); + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_term) +{ + mng_uint8 iTermaction; + mng_uint8 iIteraction = 0; + mng_uint32 iDelay = 0; + mng_uint32 iItermax = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TERM, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (pData->bHasLOOP) /* no way, jose! */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (pData->bHasTERM) /* only 1 allowed! */ + MNG_ERROR (pData, MNG_MULTIPLEERROR) + /* check the length */ + if ((iRawlen != 1) && (iRawlen != 10)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pData->bHasTERM = MNG_TRUE; + /* TODO: remove in 1.0.0 !!! */ + if ((!pData->bHasSAVE) && (pData->iChunkseq > 2)) + pData->bEMNGMAhack = MNG_TRUE; + + iTermaction = *pRawdata; /* get the fields */ + + if (iRawlen > 1) + { + iIteraction = *(pRawdata+1); + iDelay = mng_get_uint32 (pRawdata+2); + iItermax = mng_get_uint32 (pRawdata+6); + } + + if (pData->fProcessterm) /* inform the app ? */ + if (!pData->fProcessterm (((mng_handle)pData), iTermaction, iIteraction, + iDelay, iItermax)) + MNG_ERROR (pData, MNG_APPMISCERROR) + +#ifdef MNG_SUPPORT_DISPLAY + { /* create the TERM ani-object */ + mng_retcode iRetcode = create_ani_term (pData, iTermaction, iIteraction, + iDelay, iItermax); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* save for future reference */ + pData->pTermaniobj = pData->pLastaniobj; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_termp)*ppChunk)->iTermaction = iTermaction; + ((mng_termp)*ppChunk)->iIteraction = iIteraction; + ((mng_termp)*ppChunk)->iDelay = iDelay; + ((mng_termp)*ppChunk)->iItermax = iItermax; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_save) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SAVE, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (pData->bHasSAVE)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + pData->bHasSAVE = MNG_TRUE; + + if (pData->fProcesssave) /* inform the application ? */ + { + mng_bool bOke = pData->fProcesssave ((mng_handle)pData); + + if (!bOke) + MNG_ERROR (pData, MNG_APPMISCERROR) + } + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + + + /* TODO: something with the parameters */ + + + /* create a SAVE animation object */ + iRetcode = create_ani_save (pData); + + if (!iRetcode) /* process it */ + iRetcode = process_display_save (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_savep)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) /* not empty ? */ + { + mng_uint8 iOtype = *pRawdata; + mng_uint8 iEtype; + mng_uint32 iCount = 0; + mng_uint8p pTemp; + mng_uint8p pNull; + mng_uint32 iLen; + mng_uint32 iOffset[2]; + mng_uint32 iStarttime[2]; + mng_uint32 iFramenr; + mng_uint32 iLayernr; + mng_uint32 iX; + mng_save_entryp pEntry = MNG_NULL; + mng_uint32 iNamesize; + + if ((iOtype != 4) && (iOtype != 8)) + MNG_ERROR (pData, MNG_INVOFFSETSIZE); + + ((mng_savep)*ppChunk)->iOffsettype = iOtype; + + for (iX = 0; iX < 2; iX++) /* do this twice to get the count first ! */ + { + pTemp = pRawdata + 1; + iLen = iRawlen - 1; + + if (iX) /* second run ? */ + { + MNG_ALLOC (pData, pEntry, (iCount * sizeof (mng_save_entry))) + + ((mng_savep)*ppChunk)->iCount = iCount; + ((mng_savep)*ppChunk)->pEntries = pEntry; + } + + while (iLen) /* anything left ? */ + { + iEtype = *pTemp; /* entrytype */ + + if ((iEtype != 0) && (iEtype != 1) && (iEtype != 2) && (iEtype != 3)) + MNG_ERROR (pData, MNG_INVENTRYTYPE); + + pTemp++; + + if (iEtype > 1) + { + iOffset [0] = 0; + iOffset [1] = 0; + iStarttime [0] = 0; + iStarttime [1] = 0; + iLayernr = 0; + iFramenr = 0; + } + else + { + if (iOtype == 4) + { + iOffset [0] = 0; + iOffset [1] = mng_get_uint32 (pTemp); + + pTemp += 4; + } + else + { + iOffset [0] = mng_get_uint32 (pTemp); + iOffset [1] = mng_get_uint32 (pTemp+4); + + pTemp += 8; + } + + if (iEtype > 0) + { + iStarttime [0] = 0; + iStarttime [1] = 0; + iLayernr = 0; + iFramenr = 0; + } + else + { + if (iOtype == 4) + { + iStarttime [0] = 0; + iStarttime [1] = mng_get_uint32 (pTemp+0); + iLayernr = mng_get_uint32 (pTemp+4); + iFramenr = mng_get_uint32 (pTemp+8); + + pTemp += 12; + } + else + { + iStarttime [0] = mng_get_uint32 (pTemp+0); + iStarttime [1] = mng_get_uint32 (pTemp+4); + iLayernr = mng_get_uint32 (pTemp+8); + iFramenr = mng_get_uint32 (pTemp+12); + + pTemp += 16; + } + } + } + + pNull = find_null (pTemp); /* get the name length */ + + if ((pNull - pRawdata) > (mng_int32)iRawlen) + { + iNamesize = iLen; /* no null found; so end of SAVE */ + iLen = 0; + } + else + { + iNamesize = pNull - pTemp; /* should be another entry */ + iLen -= iNamesize; + + if (!iLen) /* must not end with a null ! */ + MNG_ERROR (pData, MNG_ENDWITHNULL) + } + + if (!pEntry) + { + iCount++; + } + else + { + pEntry->iEntrytype = iEtype; + pEntry->iOffset [0] = iOffset [0]; + pEntry->iOffset [1] = iOffset [1]; + pEntry->iStarttime [0] = iStarttime [0]; + pEntry->iStarttime [1] = iStarttime [1]; + pEntry->iLayernr = iLayernr; + pEntry->iFramenr = iFramenr; + pEntry->iNamesize = iNamesize; + + if (iNamesize) + { + MNG_ALLOC (pData, pEntry->zName, iNamesize+1) + MNG_COPY (pEntry->zName, pTemp, iNamesize) + } + + pEntry++; + } + + pTemp += iNamesize; + } + } + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_seek) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SEEK, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (!pData->bHasSAVE)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (pData->fProcessseek) /* inform the app ? */ + { + mng_bool bOke; + mng_pchar zName; + + MNG_ALLOC (pData, zName, iRawlen + 1) + + if (iRawlen) + MNG_COPY (zName, pRawdata, iRawlen) + + bOke = pData->fProcessseek ((mng_handle)pData, zName); + + MNG_FREEX (pData, zName, iRawlen + 1) + + if (!bOke) + MNG_ERROR (pData, MNG_APPMISCERROR) + } + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + + + /* TODO: something with the name ??? */ + + + + /* create a SEEK animation object */ + iRetcode = create_ani_seek (pData); + + if (!iRetcode) /* process it */ + iRetcode = process_display_seek (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_seekp)*ppChunk)->iNamesize = iRawlen; + + if (iRawlen) + { + MNG_ALLOC (pData, ((mng_seekp)*ppChunk)->zName, iRawlen+1) + MNG_COPY (((mng_seekp)*ppChunk)->zName, pRawdata, iRawlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_expi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_EXPI, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen < 3) /* check the length */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_expip)*ppChunk)->iSnapshotid = mng_get_uint16 (pRawdata); + ((mng_expip)*ppChunk)->iNamesize = iRawlen - 2; + + if (((mng_expip)*ppChunk)->iNamesize) + { + MNG_ALLOC (pData, ((mng_expip)*ppChunk)->zName, + ((mng_expip)*ppChunk)->iNamesize + 1) + MNG_COPY (((mng_expip)*ppChunk)->zName, pRawdata+2, + ((mng_expip)*ppChunk)->iNamesize) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_EXPI, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_fpri) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_FPRI, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 2) /* must be two bytes long */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_fprip)*ppChunk)->iDeltatype = *pRawdata; + ((mng_fprip)*ppChunk)->iPriority = *(pRawdata+1); + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_FPRI, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +mng_bool CheckKeyword (mng_datap pData, + mng_uint8p pKeyword) +{ + mng_chunkid handled_chunks [] = + { + MNG_UINT_BACK, + MNG_UINT_BASI, + MNG_UINT_CLIP, + MNG_UINT_CLON, +/* TODO: MNG_UINT_DBYK, */ + MNG_UINT_DEFI, + MNG_UINT_DHDR, + MNG_UINT_DISC, +/* TODO: MNG_UINT_DROP, */ + MNG_UINT_ENDL, + MNG_UINT_FRAM, + MNG_UINT_IDAT, + MNG_UINT_IEND, + MNG_UINT_IHDR, + MNG_UINT_IJNG, + MNG_UINT_IPNG, +#ifdef MNG_INCLUDE_JNG + MNG_UINT_JDAA, + MNG_UINT_JDAT, + MNG_UINT_JHDR, +/* TODO: MNG_UINT_JSEP, */ + MNG_UINT_JdAA, +#endif + MNG_UINT_LOOP, + MNG_UINT_MAGN, + MNG_UINT_MEND, + MNG_UINT_MHDR, + MNG_UINT_MOVE, +/* TODO: MNG_UINT_ORDR, */ +/* TODO: MNG_UINT_PAST, */ + MNG_UINT_PLTE, + MNG_UINT_PPLT, + MNG_UINT_PROM, + MNG_UINT_SAVE, + MNG_UINT_SEEK, + MNG_UINT_SHOW, + MNG_UINT_TERM, + MNG_UINT_bKGD, + MNG_UINT_cHRM, +/* TODO: MNG_UINT_eXPI, */ +/* TODO: MNG_UINT_fPRI, */ + MNG_UINT_gAMA, +/* TODO: MNG_UINT_hIST, */ + MNG_UINT_iCCP, + MNG_UINT_iTXt, + MNG_UINT_nEED, +/* TODO: MNG_UINT_oFFs, */ +/* TODO: MNG_UINT_pCAL, */ +/* TODO: MNG_UINT_pHYg, */ +/* TODO: MNG_UINT_pHYs, */ +/* TODO: MNG_UINT_sBIT, */ +/* TODO: MNG_UINT_sCAL, */ +/* TODO: MNG_UINT_sPLT, */ + MNG_UINT_sRGB, + MNG_UINT_tEXt, + MNG_UINT_tIME, + MNG_UINT_tRNS, + MNG_UINT_zTXt, + }; + + mng_bool bOke = MNG_FALSE; + + if (pData->fProcessneed) /* does the app handle it ? */ + bOke = pData->fProcessneed ((mng_handle)pData, (mng_pchar)pKeyword); + + if (!bOke) + { /* find the keyword length */ + mng_uint8p pNull = find_null (pKeyword); + + if (pNull - pKeyword == 4) /* test a chunk ? */ + { /* get the chunk-id */ + mng_chunkid iChunkid = (*pKeyword << 24) + (*(pKeyword+1) << 16) + + (*(pKeyword+2) << 8) + (*(pKeyword+3) ); + /* binary search variables */ + mng_int32 iTop, iLower, iUpper, iMiddle; + /* determine max index of table */ + iTop = (sizeof (handled_chunks) / sizeof (handled_chunks [0])) - 1; + + /* binary search; with 52 chunks, worst-case is 7 comparisons */ + iLower = 0; + iMiddle = iTop >> 1; + iUpper = iTop; + + do /* the binary search itself */ + { + if (handled_chunks [iMiddle] < iChunkid) + iLower = iMiddle + 1; + else if (handled_chunks [iMiddle] > iChunkid) + iUpper = iMiddle - 1; + else + { + bOke = MNG_TRUE; + break; + } + + iMiddle = (iLower + iUpper) >> 1; + } + while (iLower <= iUpper); + } + /* test draft ? */ + if ((!bOke) && (pNull - pKeyword == 8) && + (*pKeyword == 'd') && (*(pKeyword+1) == 'r') && + (*(pKeyword+2) == 'a') && (*(pKeyword+3) == 'f') && + (*(pKeyword+4) == 't') && (*(pKeyword+5) == ' ')) + { + mng_uint32 iDraft; + + iDraft = (*(pKeyword+6) - '0') * 10 + (*(pKeyword+7) - '0'); + bOke = (mng_bool)(iDraft <= MNG_MNG_DRAFT); + } + /* test MNG 1.0 ? */ + if ((!bOke) && (pNull - pKeyword == 7) && + (*pKeyword == 'M') && (*(pKeyword+1) == 'N') && + (*(pKeyword+2) == 'G') && (*(pKeyword+3) == '-') && + (*(pKeyword+4) == '1') && (*(pKeyword+5) == '.') && + (*(pKeyword+6) == '0')) + bOke = MNG_TRUE; + + } + + return bOke; +} + +/* ************************************************************************** */ + +READ_CHUNK (read_need) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_NEED, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen < 1) /* check the length */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + { /* let's check it */ + mng_bool bOke = MNG_TRUE; + mng_pchar zKeywords; + mng_uint8p pNull, pTemp; + + MNG_ALLOC (pData, zKeywords, iRawlen + 1) + + if (iRawlen) + MNG_COPY (zKeywords, pRawdata, iRawlen) + + pTemp = (mng_uint8p)zKeywords; + pNull = find_null (pTemp); + + while ((bOke) && (pNull < (mng_uint8p)zKeywords + iRawlen)) + { + bOke = CheckKeyword (pData, pTemp); + pTemp = pNull + 1; + pNull = find_null (pTemp); + } + + if (bOke) + bOke = CheckKeyword (pData, pTemp); + + MNG_FREEX (pData, zKeywords, iRawlen + 1) + + if (!bOke) + MNG_ERROR (pData, MNG_UNSUPPORTEDNEED) + } + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_needp)*ppChunk)->iKeywordssize = iRawlen; + + if (iRawlen) + { + MNG_ALLOC (pData, ((mng_needp)*ppChunk)->zKeywords, iRawlen+1) + MNG_COPY (((mng_needp)*ppChunk)->zKeywords, pRawdata, iRawlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_NEED, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_phyg) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PHYG, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* it's 9 bytes or empty; no more, no less! */ + if ((iRawlen != 9) && (iRawlen != 0)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_phygp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + + if (iRawlen) + { + ((mng_phygp)*ppChunk)->iSizex = mng_get_uint32 (pRawdata); + ((mng_phygp)*ppChunk)->iSizey = mng_get_uint32 (pRawdata+4); + ((mng_phygp)*ppChunk)->iUnit = *(pRawdata+8); + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PHYG, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +READ_CHUNK (read_jhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JHDR, MNG_LC_START) +#endif + /* sequence checks */ + if ((pData->eSigtype != mng_it_jng) && (pData->eSigtype != mng_it_mng)) + MNG_ERROR (pData, MNG_CHUNKNOTALLOWED) + + if ((pData->eSigtype == mng_it_jng) && (pData->iChunkseq > 1)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 16) /* length oke ? */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + /* inside a JHDR-IEND block now */ + pData->bHasJHDR = MNG_TRUE; + /* and store interesting fields */ + pData->iDatawidth = mng_get_uint32 (pRawdata); + pData->iDataheight = mng_get_uint32 (pRawdata+4); + pData->iJHDRcolortype = *(pRawdata+8); + pData->iJHDRimgbitdepth = *(pRawdata+9); + pData->iJHDRimgcompression = *(pRawdata+10); + pData->iJHDRimginterlace = *(pRawdata+11); + pData->iJHDRalphabitdepth = *(pRawdata+12); + pData->iJHDRalphacompression = *(pRawdata+13); + pData->iJHDRalphafilter = *(pRawdata+14); + pData->iJHDRalphainterlace = *(pRawdata+15); + /* parameter validity checks */ + if ((pData->iJHDRcolortype != MNG_COLORTYPE_JPEGGRAY ) && + (pData->iJHDRcolortype != MNG_COLORTYPE_JPEGCOLOR ) && + (pData->iJHDRcolortype != MNG_COLORTYPE_JPEGGRAYA ) && + (pData->iJHDRcolortype != MNG_COLORTYPE_JPEGCOLORA) ) + MNG_ERROR (pData, MNG_INVALIDCOLORTYPE) + + if ((pData->iJHDRimgbitdepth != 8) && + (pData->iJHDRimgbitdepth != 12) && + (pData->iJHDRimgbitdepth != 20) ) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if (pData->iJHDRimgcompression != MNG_COMPRESSION_BASELINEJPEG) + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + if ((pData->iJHDRimginterlace != MNG_INTERLACE_SEQUENTIAL ) && + (pData->iJHDRimginterlace != MNG_INTERLACE_PROGRESSIVE) ) + MNG_ERROR (pData, MNG_INVALIDINTERLACE) + + if ((pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) ) + { + if ((pData->iJHDRalphabitdepth != 1) && + (pData->iJHDRalphabitdepth != 2) && + (pData->iJHDRalphabitdepth != 4) && + (pData->iJHDRalphabitdepth != 8) && + (pData->iJHDRalphabitdepth != 16) ) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if ((pData->iJHDRalphacompression != MNG_COMPRESSION_DEFLATE ) && + (pData->iJHDRalphacompression != MNG_COMPRESSION_BASELINEJPEG) ) + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + if ((pData->iJHDRalphacompression == MNG_COMPRESSION_BASELINEJPEG) && + (pData->iJHDRalphabitdepth != 8 ) ) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if (pData->iJHDRalphafilter & (~MNG_FILTER_DIFFERING)) + MNG_ERROR (pData, MNG_INVALIDFILTER) + + if ((pData->iJHDRalphainterlace != MNG_INTERLACE_NONE ) && + (pData->iJHDRalphainterlace != MNG_INTERLACE_ADAM7) ) + MNG_ERROR (pData, MNG_INVALIDINTERLACE) + + } + else + { + if (pData->iJHDRalphabitdepth != 0) + MNG_ERROR (pData, MNG_INVALIDBITDEPTH) + + if (pData->iJHDRalphacompression != 0) + MNG_ERROR (pData, MNG_INVALIDCOMPRESS) + + if (pData->iJHDRalphafilter != 0) + MNG_ERROR (pData, MNG_INVALIDFILTER) + + if (pData->iJHDRalphainterlace != 0) + MNG_ERROR (pData, MNG_INVALIDINTERLACE) + + } + + if (!pData->bHasheader) /* first chunk ? */ + { + pData->bHasheader = MNG_TRUE; /* we've got a header */ + pData->eImagetype = mng_it_jng; /* then this must be a JNG */ + pData->iWidth = mng_get_uint32 (pRawdata); + pData->iHeight = mng_get_uint32 (pRawdata+4); + /* predict alpha-depth ! */ + if ((pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) ) + pData->iAlphadepth = pData->iJHDRalphabitdepth; + else + pData->iAlphadepth = 0; + /* fits on maximum canvas ? */ + if ((pData->iWidth > pData->iMaxwidth) || (pData->iHeight > pData->iMaxheight)) + MNG_WARNING (pData, MNG_IMAGETOOLARGE) + + if (pData->fProcessheader) /* inform the app ? */ + if (!pData->fProcessheader (((mng_handle)pData), pData->iWidth, pData->iHeight)) + MNG_ERROR (pData, MNG_APPMISCERROR) + + } + + pData->iColortype = 0; /* fake grayscale for other routines */ + pData->iImagelevel++; /* one level deeper */ + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode = process_display_jhdr (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_jhdrp)*ppChunk)->iWidth = mng_get_uint32 (pRawdata); + ((mng_jhdrp)*ppChunk)->iHeight = mng_get_uint32 (pRawdata+4); + ((mng_jhdrp)*ppChunk)->iColortype = *(pRawdata+8); + ((mng_jhdrp)*ppChunk)->iImagesampledepth = *(pRawdata+9); + ((mng_jhdrp)*ppChunk)->iImagecompression = *(pRawdata+10); + ((mng_jhdrp)*ppChunk)->iImageinterlace = *(pRawdata+11); + ((mng_jhdrp)*ppChunk)->iAlphasampledepth = *(pRawdata+12); + ((mng_jhdrp)*ppChunk)->iAlphacompression = *(pRawdata+13); + ((mng_jhdrp)*ppChunk)->iAlphafilter = *(pRawdata+14); + ((mng_jhdrp)*ppChunk)->iAlphainterlace = *(pRawdata+15); + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} +#else +#define read_jhdr 0 +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +READ_CHUNK (read_jdaa) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JDAA, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasJHDR) && (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (pData->bHasJSEP) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (pData->iJHDRalphacompression != MNG_COMPRESSION_BASELINEJPEG) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen == 0) /* can never be empty */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pData->bHasJDAA = MNG_TRUE; /* got some JDAA now, don't we */ + +#ifdef MNG_SUPPORT_DISPLAY + if (iRawlen) + { /* display processing for non-empty chunks */ + mng_retcode iRetcode = process_display_jdaa (pData, iRawlen, pRawdata); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_jdaap)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + ((mng_jdaap)*ppChunk)->iDatasize = iRawlen; + + if (iRawlen != 0) /* is there any data ? */ + { + MNG_ALLOC (pData, ((mng_jdaap)*ppChunk)->pData, iRawlen) + MNG_COPY (((mng_jdaap)*ppChunk)->pData, pRawdata, iRawlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JDAA, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} +#else +#define read_jdaa 0 +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +READ_CHUNK (read_jdat) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JDAT, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasJHDR) && (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen == 0) /* can never be empty */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pData->bHasJDAT = MNG_TRUE; /* got some JDAT now, don't we */ + +#ifdef MNG_SUPPORT_DISPLAY + if (iRawlen) + { /* display processing for non-empty chunks */ + mng_retcode iRetcode = process_display_jdat (pData, iRawlen, pRawdata); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_jdatp)*ppChunk)->bEmpty = (mng_bool)(iRawlen == 0); + ((mng_jdatp)*ppChunk)->iDatasize = iRawlen; + + if (iRawlen != 0) /* is there any data ? */ + { + MNG_ALLOC (pData, ((mng_jdatp)*ppChunk)->pData, iRawlen) + MNG_COPY (((mng_jdatp)*ppChunk)->pData, pRawdata, iRawlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} +#else +#define read_jdat 0 +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +READ_CHUNK (read_jsep) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JSEP, MNG_LC_START) +#endif + + if (!pData->bHasJHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 0) /* must be empty ! */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pData->bHasJSEP = MNG_TRUE; /* indicate we've had the 8-/12-bit separator */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_JSEP, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} +#else +#define read_jsep 0 +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +READ_CHUNK (read_dhdr) +{ + mng_uint8 iImagetype, iDeltatype; +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DHDR, MNG_LC_START) +#endif + + if (!pData->bHasMHDR) /* sequence checks */ + MNG_ERROR (pData, MNG_SEQUENCEERROR) + +#ifdef MNG_INCLUDE_JNG + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((pData->bHasIHDR) || (pData->bHasBASI) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check for valid length */ + if ((iRawlen != 4) && (iRawlen != 12) && (iRawlen != 20)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + iImagetype = *(pRawdata+2); /* check fields for validity */ + iDeltatype = *(pRawdata+3); + + if (iImagetype > MNG_IMAGETYPE_JNG) + MNG_ERROR (pData, MNG_INVIMAGETYPE) + + if (iDeltatype > MNG_DELTATYPE_NOCHANGE) + MNG_ERROR (pData, MNG_INVDELTATYPE) + + if ((iDeltatype == MNG_DELTATYPE_REPLACE) && (iRawlen > 12)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((iDeltatype == MNG_DELTATYPE_NOCHANGE) && (iRawlen > 4)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + pData->bHasDHDR = MNG_TRUE; /* inside a DHDR-IEND block now */ + + pData->iImagelevel++; /* one level deeper */ + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_uint16 iObjectid = mng_get_uint16 (pRawdata); + mng_uint32 iBlockwidth = 0; + mng_uint32 iBlockheight = 0; + mng_uint32 iBlockx = 0; + mng_uint32 iBlocky = 0; + mng_retcode iRetcode; + + if (iRawlen > 4) + { + iBlockwidth = mng_get_uint32 (pRawdata+4); + iBlockheight = mng_get_uint32 (pRawdata+8); + } + + if (iRawlen > 12) + { + iBlockx = mng_get_uint32 (pRawdata+12); + iBlocky = mng_get_uint32 (pRawdata+16); + } + + iRetcode = create_ani_dhdr (pData, iObjectid, iImagetype, iDeltatype, + iBlockwidth, iBlockheight, iBlockx, iBlocky); + + if (!iRetcode) /* display processing ? */ + iRetcode = process_display_dhdr (pData, iObjectid, iImagetype, iDeltatype, + iBlockwidth, iBlockheight, iBlockx, iBlocky); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_dhdrp)*ppChunk)->iObjectid = mng_get_uint16 (pRawdata); + ((mng_dhdrp)*ppChunk)->iImagetype = iImagetype; + ((mng_dhdrp)*ppChunk)->iDeltatype = iDeltatype; + + if (iRawlen > 4) + { + ((mng_dhdrp)*ppChunk)->iBlockwidth = mng_get_uint32 (pRawdata+4); + ((mng_dhdrp)*ppChunk)->iBlockheight = mng_get_uint32 (pRawdata+8); + } + + if (iRawlen > 12) + { + ((mng_dhdrp)*ppChunk)->iBlockx = mng_get_uint32 (pRawdata+12); + ((mng_dhdrp)*ppChunk)->iBlocky = mng_get_uint32 (pRawdata+16); + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_prom) +{ + mng_uint8 iColortype; + mng_uint8 iSampledepth; + mng_uint8 iFilltype; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PROM, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 3) /* gotta be exactly 3 bytes */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + iColortype = *pRawdata; /* check fields for validity */ + iSampledepth = *(pRawdata+1); + iFilltype = *(pRawdata+2); + + if ((iColortype != MNG_COLORTYPE_GRAY ) && + (iColortype != MNG_COLORTYPE_RGB ) && + (iColortype != MNG_COLORTYPE_INDEXED) && + (iColortype != MNG_COLORTYPE_GRAYA ) && + (iColortype != MNG_COLORTYPE_RGBA ) ) + MNG_ERROR (pData, MNG_INVALIDCOLORTYPE) + + if ((iSampledepth != MNG_BITDEPTH_1 ) && + (iSampledepth != MNG_BITDEPTH_2 ) && + (iSampledepth != MNG_BITDEPTH_4 ) && + (iSampledepth != MNG_BITDEPTH_8 ) && + (iSampledepth != MNG_BITDEPTH_16) ) + MNG_ERROR (pData, MNG_INVSAMPLEDEPTH) + + if ((iFilltype != MNG_FILLMETHOD_LEFTBITREPLICATE) && + (iFilltype != MNG_FILLMETHOD_ZEROFILL ) ) + MNG_ERROR (pData, MNG_INVFILLMETHOD) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode = create_ani_prom (pData, iSampledepth, iColortype, iFilltype); + + if (!iRetcode) /* display processing ? */ + iRetcode = process_display_prom (pData, iSampledepth, + iColortype, iFilltype); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_promp)*ppChunk)->iColortype = iColortype; + ((mng_promp)*ppChunk)->iSampledepth = iSampledepth; + ((mng_promp)*ppChunk)->iFilltype = iFilltype; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_ipng) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IPNG, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 0) /* gotta be empty */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode = create_ani_ipng (pData); + + if (!iRetcode) /* process it */ + iRetcode = process_display_ipng (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_pplt) +{ + mng_uint8 iDeltatype; + mng_uint8p pTemp; + mng_uint32 iLen; + mng_uint8 iX, iM; + mng_uint32 iY; + mng_uint32 iMax; + mng_rgbpaltab aIndexentries; + mng_uint8arr aAlphaentries; + mng_uint8arr aUsedentries; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PPLT, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) && (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen < 1) /* must have at least 1 byte */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + iDeltatype = *pRawdata; + /* valid ? */ + if (iDeltatype > MNG_DELTATYPE_DELTARGBA) + MNG_ERROR (pData, MNG_INVDELTATYPE) + /* must be indexed color ! */ + if (pData->iColortype != MNG_COLORTYPE_INDEXED) + MNG_ERROR (pData, MNG_INVALIDCOLORTYPE) + + pTemp = pRawdata + 1; + iLen = iRawlen - 1; + iMax = 0; + + for (iY = 0; iY < 256; iY++) /* reset arrays */ + { + aIndexentries [iY].iRed = 0; + aIndexentries [iY].iGreen = 0; + aIndexentries [iY].iBlue = 0; + aAlphaentries [iY] = 255; + aUsedentries [iY] = 0; + } + + while (iLen) /* as long as there are entries left ... */ + { + mng_uint32 iDiff; + + if (iLen < 2) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + iX = *pTemp; /* get start and end index */ + iM = *(pTemp+1); + + if (iM < iX) + MNG_ERROR (pData, MNG_INVALIDINDEX) + + if ((mng_uint32)iM >= iMax) /* determine highest used index */ + iMax = (mng_uint32)iM + 1; + + pTemp += 2; + iLen -= 2; + + if ((iDeltatype == MNG_DELTATYPE_REPLACERGB ) || + (iDeltatype == MNG_DELTATYPE_DELTARGB ) ) + iDiff = (iM - iX + 1) * 3; + else + if ((iDeltatype == MNG_DELTATYPE_REPLACEALPHA) || + (iDeltatype == MNG_DELTATYPE_DELTAALPHA ) ) + iDiff = (iM - iX + 1); + else + iDiff = (iM - iX + 1) * 4; + + if (iLen < iDiff) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if ((iDeltatype == MNG_DELTATYPE_REPLACERGB ) || + (iDeltatype == MNG_DELTATYPE_DELTARGB ) ) + { + for (iY = (mng_uint32)iX; iY <= (mng_uint32)iM; iY++) + { + aIndexentries [iY].iRed = *pTemp; + aIndexentries [iY].iGreen = *(pTemp+1); + aIndexentries [iY].iBlue = *(pTemp+2); + aUsedentries [iY] = 1; + + pTemp += 3; + iLen -= 3; + } + } + else + if ((iDeltatype == MNG_DELTATYPE_REPLACEALPHA) || + (iDeltatype == MNG_DELTATYPE_DELTAALPHA ) ) + { + for (iY = (mng_uint32)iX; iY <= (mng_uint32)iM; iY++) + { + aAlphaentries [iY] = *pTemp; + aUsedentries [iY] = 1; + + pTemp++; + iLen--; + } + } + else + { + for (iY = (mng_uint32)iX; iY <= (mng_uint32)iM; iY++) + { + aIndexentries [iY].iRed = *pTemp; + aIndexentries [iY].iGreen = *(pTemp+1); + aIndexentries [iY].iBlue = *(pTemp+2); + aAlphaentries [iY] = *(pTemp+3); + aUsedentries [iY] = 1; + + pTemp += 4; + iLen -= 4; + } + } + } + + switch (pData->iBitdepth) /* check maximum allowed entries for bitdepth */ + { + case MNG_BITDEPTH_1 : { + if (iMax > 2) + MNG_ERROR (pData, MNG_INVALIDINDEX) + break; + } + case MNG_BITDEPTH_2 : { + if (iMax > 4) + MNG_ERROR (pData, MNG_INVALIDINDEX) + break; + } + case MNG_BITDEPTH_4 : { + if (iMax > 16) + MNG_ERROR (pData, MNG_INVALIDINDEX) + break; + } + } + +#ifdef MNG_SUPPORT_DISPLAY + { /* create animation object */ + mng_retcode iRetcode = create_ani_pplt (pData, iDeltatype, iMax, + aIndexentries, aAlphaentries, + aUsedentries); + + if (!iRetcode) /* execute it now ? */ + iRetcode = process_display_pplt (pData, iDeltatype, iMax, aIndexentries, + aAlphaentries, aUsedentries); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_ppltp)*ppChunk)->iDeltatype = iDeltatype; + ((mng_ppltp)*ppChunk)->iCount = iMax; + + for (iY = 0; iY < 256; iY++) + { + ((mng_ppltp)*ppChunk)->aEntries [iY].iRed = aIndexentries [iY].iRed; + ((mng_ppltp)*ppChunk)->aEntries [iY].iGreen = aIndexentries [iY].iGreen; + ((mng_ppltp)*ppChunk)->aEntries [iY].iBlue = aIndexentries [iY].iBlue; + ((mng_ppltp)*ppChunk)->aEntries [iY].iAlpha = aAlphaentries [iY]; + ((mng_ppltp)*ppChunk)->aEntries [iY].bUsed = (mng_bool)(aUsedentries [iY]); + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_ijng) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IJNG, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen != 0) /* gotta be empty */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode = create_ani_ijng (pData); + + if (!iRetcode) /* process it */ + iRetcode = process_display_ijng (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_drop) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DROP, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check length */ + if ((iRawlen < 4) || ((iRawlen % 4) != 0)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_dropp)*ppChunk)->iCount = iRawlen / 4; + + if (iRawlen) + { + mng_uint32 iX; + mng_uint8p pTemp = pRawdata; + mng_uint32p pEntry; + + MNG_ALLOC (pData, pEntry, iRawlen) + + ((mng_dropp)*ppChunk)->pChunknames = (mng_ptr)pEntry; + + for (iX = 0; iX < iRawlen / 4; iX++) + { + *pEntry = mng_get_uint32 (pTemp); + + pTemp += 4; + pEntry++; + } + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DROP, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_dbyk) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DBYK, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + + if (iRawlen < 6) /* must be at least 6 long */ + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_dbykp)*ppChunk)->iChunkname = mng_get_uint32 (pRawdata); + ((mng_dbykp)*ppChunk)->iPolarity = *(pRawdata+4); + ((mng_dbykp)*ppChunk)->iKeywordssize = iRawlen - 5; + + if (iRawlen > 5) + { + MNG_ALLOC (pData, ((mng_dbykp)*ppChunk)->zKeywords, iRawlen-4) + MNG_COPY (((mng_dbykp)*ppChunk)->zKeywords, pRawdata+5, iRawlen-5) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DBYK, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_ordr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ORDR, MNG_LC_START) +#endif + /* sequence checks */ + if ((!pData->bHasMHDR) || (!pData->bHasDHDR)) + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check length */ + if ((iRawlen < 5) || ((iRawlen % 5) != 0)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + +#ifdef MNG_SUPPORT_DISPLAY + { + + + /* TODO: something !!! */ + + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_ordrp)*ppChunk)->iCount = iRawlen / 5; + + if (iRawlen) + { + mng_uint32 iX; + mng_ordr_entryp pEntry; + mng_uint8p pTemp = pRawdata; + + MNG_ALLOC (pData, pEntry, iRawlen) + + ((mng_ordrp)*ppChunk)->pEntries = pEntry; + + for (iX = 0; iX < iRawlen / 5; iX++) + { + pEntry->iChunkname = mng_get_uint32 (pTemp); + pEntry->iOrdertype = *(pTemp+4); + + pTemp += 5; + pEntry++; + } + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_ORDR, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_magn) +{ + mng_uint16 iFirstid, iLastid; + mng_uint16 iMethodX, iMethodY; + mng_uint16 iMX, iMY, iML, iMR, iMT, iMB; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MAGN, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_SUPPORT_JNG + if ((!pData->bHasMHDR) || (pData->bHasIHDR) || (pData->bHasDHDR) || (pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) || (pData->bHasIHDR) || (pData->bHasDHDR)) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* check length */ + if ((iRawlen > 20) || ((iRawlen & 0x01) != 0)) + MNG_ERROR (pData, MNG_INVALIDLENGTH) + + if (iRawlen > 0) /* get the fields */ + iFirstid = mng_get_uint16 (pRawdata); + else + iFirstid = 0; + + if (iRawlen > 2) + iLastid = mng_get_uint16 (pRawdata+2); + else + iLastid = iFirstid; + + if (iRawlen > 4) + iMethodX = mng_get_uint16 (pRawdata+4); + else + iMethodX = 0; + + if (iRawlen > 6) + iMX = mng_get_uint16 (pRawdata+6); + else + iMX = 1; + + if (iRawlen > 8) + iMY = mng_get_uint16 (pRawdata+8); + else + iMY = iMX; + + if (iRawlen > 10) + iML = mng_get_uint16 (pRawdata+10); + else + iML = iMX; + + if (iRawlen > 12) + iMR = mng_get_uint16 (pRawdata+12); + else + iMR = iMX; + + if (iRawlen > 14) + iMT = mng_get_uint16 (pRawdata+14); + else + iMT = iMY; + + if (iRawlen > 16) + iMB = mng_get_uint16 (pRawdata+16); + else + iMB = iMY; + + if (iRawlen > 18) + iMethodY = mng_get_uint16 (pRawdata+18); + else + iMethodY = iMethodX; + /* check field validity */ + if ((iMethodX > 5) || (iMethodY > 5)) + MNG_ERROR (pData, MNG_INVALIDMETHOD) + +#ifdef MNG_SUPPORT_DISPLAY + { + mng_retcode iRetcode; + + iRetcode = create_ani_magn (pData, iFirstid, iLastid, iMethodX, + iMX, iMY, iML, iMR, iMT, iMB, iMethodY); + + if (!iRetcode) /* display processing ? */ + iRetcode = process_display_magn (pData, iFirstid, iLastid, iMethodX, + iMX, iMY, iML, iMR, iMT, iMB, iMethodY); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the fields */ + ((mng_magnp)*ppChunk)->iFirstid = iFirstid; + ((mng_magnp)*ppChunk)->iLastid = iLastid; + ((mng_magnp)*ppChunk)->iMethodX = iMethodX; + ((mng_magnp)*ppChunk)->iMX = iMX; + ((mng_magnp)*ppChunk)->iMY = iMY; + ((mng_magnp)*ppChunk)->iML = iML; + ((mng_magnp)*ppChunk)->iMR = iMR; + ((mng_magnp)*ppChunk)->iMT = iMT; + ((mng_magnp)*ppChunk)->iMB = iMB; + ((mng_magnp)*ppChunk)->iMethodY = iMethodY; + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +READ_CHUNK (read_unknown) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_UNKNOWN, MNG_LC_START) +#endif + /* sequence checks */ +#ifdef MNG_INCLUDE_JNG + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && + (!pData->bHasBASI) && (!pData->bHasDHDR) ) +#endif + MNG_ERROR (pData, MNG_SEQUENCEERROR) + /* critical chunk ? */ + if (((mng_uint32)pData->iChunkname & 0x20000000) == 0) + MNG_ERROR (pData, MNG_UNKNOWNCRITICAL) + + if (pData->fProcessunknown) /* let the app handle it ? */ + { + mng_bool bOke = pData->fProcessunknown ((mng_handle)pData, pData->iChunkname, + iRawlen, (mng_ptr)pRawdata); + + if (!bOke) + MNG_ERROR (pData, MNG_APPMISCERROR) + } + +#ifdef MNG_STORE_CHUNKS + if (pData->bStorechunks) + { /* initialize storage */ + mng_retcode iRetcode = ((mng_chunk_headerp)pHeader)->fCreate (pData, pHeader, ppChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* store the length */ + ((mng_chunk_headerp)*ppChunk)->iChunkname = pData->iChunkname; + ((mng_unknown_chunkp)*ppChunk)->iDatasize = iRawlen; + + if (iRawlen == 0) /* any data at all ? */ + ((mng_unknown_chunkp)*ppChunk)->pData = 0; + else + { /* then store it */ + MNG_ALLOC (pData, ((mng_unknown_chunkp)*ppChunk)->pData, iRawlen) + MNG_COPY (((mng_unknown_chunkp)*ppChunk)->pData, pRawdata, iRawlen) + } + } +#endif /* MNG_STORE_CHUNKS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_UNKNOWN, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_READ_PROCS */ + +/* ************************************************************************** */ +/* * * */ +/* * chunk write functions * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_WRITE_PROCS + +/* ************************************************************************** */ + +WRITE_CHUNK (write_ihdr) +{ + mng_ihdrp pIHDR; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IHDR, MNG_LC_START) +#endif + + pIHDR = (mng_ihdrp)pChunk; /* address the proper chunk */ + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 13; + /* fill the output buffer */ + mng_put_uint32 (pRawdata, pIHDR->iWidth); + mng_put_uint32 (pRawdata+4, pIHDR->iHeight); + + *(pRawdata+8) = pIHDR->iBitdepth; + *(pRawdata+9) = pIHDR->iColortype; + *(pRawdata+10) = pIHDR->iCompression; + *(pRawdata+11) = pIHDR->iFilter; + *(pRawdata+12) = pIHDR->iInterlace; + /* and write it */ + iRetcode = write_raw_chunk (pData, pIHDR->sHeader.iChunkname, iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IHDR, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_plte) +{ + mng_pltep pPLTE; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PLTE, MNG_LC_START) +#endif + + pPLTE = (mng_pltep)pChunk; /* address the proper chunk */ + + if (pPLTE->bEmpty) /* write empty chunk ? */ + iRetcode = write_raw_chunk (pData, pPLTE->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pPLTE->iEntrycount * 3; + /* fill the output buffer */ + pTemp = pRawdata; + + for (iX = 0; iX < pPLTE->iEntrycount; iX++) + { + *pTemp = pPLTE->aEntries [iX].iRed; + *(pTemp+1) = pPLTE->aEntries [iX].iGreen; + *(pTemp+2) = pPLTE->aEntries [iX].iBlue; + + pTemp += 3; + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pPLTE->sHeader.iChunkname, iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PLTE, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_idat) +{ + mng_idatp pIDAT; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IDAT, MNG_LC_START) +#endif + + pIDAT = (mng_idatp)pChunk; /* address the proper chunk */ + + if (pIDAT->bEmpty) /* and write it */ + iRetcode = write_raw_chunk (pData, pIDAT->sHeader.iChunkname, 0, 0); + else + iRetcode = write_raw_chunk (pData, pIDAT->sHeader.iChunkname, + pIDAT->iDatasize, pIDAT->pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IDAT, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_iend) +{ + mng_iendp pIEND; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IEND, MNG_LC_START) +#endif + + pIEND = (mng_iendp)pChunk; /* address the proper chunk */ + /* and write it */ + iRetcode = write_raw_chunk (pData, pIEND->sHeader.iChunkname, 0, 0); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IEND, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_trns) +{ + mng_trnsp pTRNS; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TRNS, MNG_LC_START) +#endif + + pTRNS = (mng_trnsp)pChunk; /* address the proper chunk */ + + if (pTRNS->bEmpty) /* write empty chunk ? */ + iRetcode = write_raw_chunk (pData, pTRNS->sHeader.iChunkname, 0, 0); + else + if (pTRNS->bGlobal) /* write global chunk ? */ + iRetcode = write_raw_chunk (pData, pTRNS->sHeader.iChunkname, + pTRNS->iRawlen, (mng_uint8p)pTRNS->aRawdata); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer */ + iRawlen = 0; /* and default size */ + + switch (pTRNS->iType) + { + case 0: { + iRawlen = 2; /* fill the size & output buffer */ + mng_put_uint16 (pRawdata, pTRNS->iGray); + + break; + } + case 2: { + iRawlen = 6; /* fill the size & output buffer */ + mng_put_uint16 (pRawdata, pTRNS->iRed); + mng_put_uint16 (pRawdata+2, pTRNS->iGreen); + mng_put_uint16 (pRawdata+4, pTRNS->iBlue); + + break; + } + case 3: { /* init output buffer size */ + iRawlen = pTRNS->iCount; + + pTemp = pRawdata; /* fill the output buffer */ + + for (iX = 0; iX < pTRNS->iCount; iX++) + { + *pTemp = pTRNS->aEntries[iX]; + pTemp++; + } + + break; + } + } + /* write the chunk */ + iRetcode = write_raw_chunk (pData, pTRNS->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TRNS, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_gama) +{ + mng_gamap pGAMA; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_GAMA, MNG_LC_START) +#endif + + pGAMA = (mng_gamap)pChunk; /* address the proper chunk */ + + if (pGAMA->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pGAMA->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 4; + /* fill the buffer */ + mng_put_uint32 (pRawdata, pGAMA->iGamma); + /* and write it */ + iRetcode = write_raw_chunk (pData, pGAMA->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_GAMA, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_chrm) +{ + mng_chrmp pCHRM; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_CHRM, MNG_LC_START) +#endif + + pCHRM = (mng_chrmp)pChunk; /* address the proper chunk */ + + if (pCHRM->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pCHRM->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 32; + /* fill the buffer */ + mng_put_uint32 (pRawdata, pCHRM->iWhitepointx); + mng_put_uint32 (pRawdata+4, pCHRM->iWhitepointy); + mng_put_uint32 (pRawdata+8, pCHRM->iRedx); + mng_put_uint32 (pRawdata+12, pCHRM->iRedy); + mng_put_uint32 (pRawdata+16, pCHRM->iGreenx); + mng_put_uint32 (pRawdata+20, pCHRM->iGreeny); + mng_put_uint32 (pRawdata+24, pCHRM->iBluex); + mng_put_uint32 (pRawdata+28, pCHRM->iBluey); + /* and write it */ + iRetcode = write_raw_chunk (pData, pCHRM->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_CHRM, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_srgb) +{ + mng_srgbp pSRGB; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SRGB, MNG_LC_START) +#endif + + pSRGB = (mng_srgbp)pChunk; /* address the proper chunk */ + + if (pSRGB->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pSRGB->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 1; + /* fill the buffer */ + *pRawdata = pSRGB->iRenderingintent; + /* and write it */ + iRetcode = write_raw_chunk (pData, pSRGB->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SRGB, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_iccp) +{ + mng_iccpp pICCP; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint8p pBuf = 0; + mng_uint32 iBuflen; + mng_uint32 iReallen; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ICCP, MNG_LC_START) +#endif + + pICCP = (mng_iccpp)pChunk; /* address the proper chunk */ + + if (pICCP->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pICCP->sHeader.iChunkname, 0, 0); + else + { /* compress the profile */ + iRetcode = deflate_buffer (pData, pICCP->pProfile, pICCP->iProfilesize, + &pBuf, &iBuflen, &iReallen); + + if (!iRetcode) /* still oke ? */ + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pICCP->iNamesize + 2 + iReallen; + /* requires large buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_ALLOC (pData, pRawdata, iRawlen) + + pTemp = pRawdata; /* fill the buffer */ + + if (pICCP->iNamesize) + { + MNG_COPY (pTemp, pICCP->zName, pICCP->iNamesize) + pTemp += pICCP->iNamesize; + } + + *pTemp = 0; + *(pTemp+1) = pICCP->iCompression; + pTemp += 2; + + if (iReallen) + MNG_COPY (pTemp, pBuf, iReallen) + /* and write it */ + iRetcode = write_raw_chunk (pData, pICCP->sHeader.iChunkname, + iRawlen, pRawdata); + /* drop the temp buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_FREEX (pData, pRawdata, iRawlen) + + } + + MNG_FREEX (pData, pBuf, iBuflen) /* always drop the extra buffer */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ICCP, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_text) +{ + mng_textp pTEXT; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TEXT, MNG_LC_START) +#endif + + pTEXT = (mng_textp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pTEXT->iKeywordsize + 1 + pTEXT->iTextsize; + /* requires large buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_ALLOC (pData, pRawdata, iRawlen) + + pTemp = pRawdata; /* fill the buffer */ + + if (pTEXT->iKeywordsize) + { + MNG_COPY (pTemp, pTEXT->zKeyword, pTEXT->iKeywordsize) + pTemp += pTEXT->iKeywordsize; + } + + *pTemp = 0; + pTemp += 1; + + if (pTEXT->iTextsize) + MNG_COPY (pTemp, pTEXT->zText, pTEXT->iTextsize) + /* and write it */ + iRetcode = write_raw_chunk (pData, pTEXT->sHeader.iChunkname, + iRawlen, pRawdata); + + if (iRawlen > pData->iWritebufsize) /* drop the temp buffer ? */ + MNG_FREEX (pData, pRawdata, iRawlen) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TEXT, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_ztxt) +{ + mng_ztxtp pZTXT; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint8p pBuf = 0; + mng_uint32 iBuflen; + mng_uint32 iReallen; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ZTXT, MNG_LC_START) +#endif + + pZTXT = (mng_ztxtp)pChunk; /* address the proper chunk */ + /* compress the text */ + iRetcode = deflate_buffer (pData, (mng_uint8p)pZTXT->zText, pZTXT->iTextsize, + &pBuf, &iBuflen, &iReallen); + + if (!iRetcode) /* all ok ? */ + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pZTXT->iKeywordsize + 2 + iReallen; + /* requires large buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_ALLOC (pData, pRawdata, iRawlen) + + pTemp = pRawdata; /* fill the buffer */ + + if (pZTXT->iKeywordsize) + { + MNG_COPY (pTemp, pZTXT->zKeyword, pZTXT->iKeywordsize) + pTemp += pZTXT->iKeywordsize; + } + + *pTemp = 0; /* terminator zero */ + pTemp++; + *pTemp = 0; /* compression type */ + pTemp++; + + if (iReallen) + MNG_COPY (pTemp, pBuf, iReallen) + /* and write it */ + iRetcode = write_raw_chunk (pData, pZTXT->sHeader.iChunkname, + iRawlen, pRawdata); + /* drop the temp buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_FREEX (pData, pRawdata, iRawlen) + + } + + MNG_FREEX (pData, pBuf, iBuflen); /* always drop the compression buffer */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ZTXT, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_itxt) +{ + mng_itxtp pITXT; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint8p pBuf = 0; + mng_uint32 iBuflen; + mng_uint32 iReallen; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ITXT, MNG_LC_START) +#endif + + pITXT = (mng_itxtp)pChunk; /* address the proper chunk */ + + if (pITXT->iCompressionflag) /* compress the text */ + iRetcode = deflate_buffer (pData, (mng_uint8p)pITXT->zText, pITXT->iTextsize, + &pBuf, &iBuflen, &iReallen); + else + iRetcode = MNG_NOERROR; + + if (!iRetcode) /* all ok ? */ + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pITXT->iKeywordsize + pITXT->iLanguagesize + + pITXT->iTranslationsize + 5; + + if (pITXT->iCompressionflag) + iRawlen = iRawlen + iReallen; + else + iRawlen = iRawlen + pITXT->iTextsize; + /* requires large buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_ALLOC (pData, pRawdata, iRawlen) + + pTemp = pRawdata; /* fill the buffer */ + + if (pITXT->iKeywordsize) + { + MNG_COPY (pTemp, pITXT->zKeyword, pITXT->iKeywordsize) + pTemp += pITXT->iKeywordsize; + } + + *pTemp = 0; + pTemp++; + *pTemp = pITXT->iCompressionflag; + pTemp++; + *pTemp = pITXT->iCompressionmethod; + pTemp++; + + if (pITXT->iLanguagesize) + { + MNG_COPY (pTemp, pITXT->zLanguage, pITXT->iLanguagesize) + pTemp += pITXT->iLanguagesize; + } + + *pTemp = 0; + pTemp++; + + if (pITXT->iTranslationsize) + { + MNG_COPY (pTemp, pITXT->zTranslation, pITXT->iTranslationsize) + pTemp += pITXT->iTranslationsize; + } + + *pTemp = 0; + pTemp++; + + if (pITXT->iCompressionflag) + { + if (iReallen) + MNG_COPY (pTemp, pBuf, iReallen) + } + else + { + if (pITXT->iTextsize) + MNG_COPY (pTemp, pITXT->zText, pITXT->iTextsize) + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pITXT->sHeader.iChunkname, + iRawlen, pRawdata); + /* drop the temp buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_FREEX (pData, pRawdata, iRawlen) + + } + + MNG_FREEX (pData, pBuf, iBuflen); /* always drop the compression buffer */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ITXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_bkgd) +{ + mng_bkgdp pBKGD; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_BKGD, MNG_LC_START) +#endif + + pBKGD = (mng_bkgdp)pChunk; /* address the proper chunk */ + + if (pBKGD->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pBKGD->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 0; /* and default size */ + + switch (pBKGD->iType) + { + case 0: { /* gray */ + iRawlen = 2; /* fill the size & output buffer */ + mng_put_uint16 (pRawdata, pBKGD->iGray); + + break; + } + case 2: { /* rgb */ + iRawlen = 6; /* fill the size & output buffer */ + mng_put_uint16 (pRawdata, pBKGD->iRed); + mng_put_uint16 (pRawdata+2, pBKGD->iGreen); + mng_put_uint16 (pRawdata+4, pBKGD->iBlue); + + break; + } + case 3: { /* indexed */ + iRawlen = 1; /* fill the size & output buffer */ + *pRawdata = pBKGD->iIndex; + + break; + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pBKGD->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_BKGD, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_phys) +{ + mng_physp pPHYS; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PHYS, MNG_LC_START) +#endif + + pPHYS = (mng_physp)pChunk; /* address the proper chunk */ + + if (pPHYS->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pPHYS->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 9; + /* fill the output buffer */ + mng_put_uint32 (pRawdata, pPHYS->iSizex); + mng_put_uint32 (pRawdata+4, pPHYS->iSizey); + + *(pRawdata+8) = pPHYS->iUnit; + /* and write it */ + iRetcode = write_raw_chunk (pData, pPHYS->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PHYS, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_sbit) +{ + mng_sbitp pSBIT; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SBIT, MNG_LC_START) +#endif + + pSBIT = (mng_sbitp)pChunk; /* address the proper chunk */ + + if (pSBIT->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pSBIT->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 0; /* and default size */ + + switch (pSBIT->iType) + { + case 0: { /* gray */ + iRawlen = 1; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + + break; + } + case 2: { /* rgb */ + iRawlen = 3; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + *(pRawdata+1) = pSBIT->aBits[1]; + *(pRawdata+2) = pSBIT->aBits[2]; + + break; + } + case 3: { /* indexed */ + iRawlen = 1; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + + break; + } + case 4: { /* gray + alpha */ + iRawlen = 2; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + *(pRawdata+1) = pSBIT->aBits[1]; + + break; + } + case 6: { /* rgb + alpha */ + iRawlen = 4; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + *(pRawdata+1) = pSBIT->aBits[1]; + *(pRawdata+2) = pSBIT->aBits[2]; + *(pRawdata+3) = pSBIT->aBits[3]; + + break; + } + case 10: { /* jpeg gray */ + iRawlen = 1; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + + break; + } + case 12: { /* jpeg rgb */ + iRawlen = 3; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + *(pRawdata+1) = pSBIT->aBits[1]; + *(pRawdata+2) = pSBIT->aBits[2]; + + break; + } + case 14: { /* jpeg gray + alpha */ + iRawlen = 2; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + *(pRawdata+1) = pSBIT->aBits[1]; + + break; + } + case 16: { /* jpeg rgb + alpha */ + iRawlen = 4; /* fill the size & output buffer */ + *pRawdata = pSBIT->aBits[0]; + *(pRawdata+1) = pSBIT->aBits[1]; + *(pRawdata+2) = pSBIT->aBits[2]; + *(pRawdata+3) = pSBIT->aBits[3]; + + break; + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pSBIT->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SBIT, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_splt) +{ + mng_spltp pSPLT; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint32 iEntrieslen; + mng_uint8p pTemp; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SPLT, MNG_LC_START) +#endif + + pSPLT = (mng_spltp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iEntrieslen = ((pSPLT->iSampledepth >> 3) * 4 + 2) * pSPLT->iEntrycount; + iRawlen = pSPLT->iNamesize + 2 + iEntrieslen; + /* requires large buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_ALLOC (pData, pRawdata, iRawlen) + + pTemp = pRawdata; /* fill the buffer */ + + if (pSPLT->iNamesize) + { + MNG_COPY (pTemp, pSPLT->zName, pSPLT->iNamesize) + pTemp += pSPLT->iNamesize; + } + + *pTemp = 0; + *(pTemp+1) = pSPLT->iSampledepth; + pTemp += 2; + + if (pSPLT->iEntrycount) + MNG_COPY (pTemp, pSPLT->pEntries, iEntrieslen) + /* and write it */ + iRetcode = write_raw_chunk (pData, pSPLT->sHeader.iChunkname, + iRawlen, pRawdata); + + if (iRawlen > pData->iWritebufsize) /* drop the temp buffer ? */ + MNG_FREEX (pData, pRawdata, iRawlen) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SPLT, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_hist) +{ + mng_histp pHIST; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_HIST, MNG_LC_START) +#endif + + pHIST = (mng_histp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pHIST->iEntrycount << 1; + + pTemp = pRawdata; /* fill the output buffer */ + + for (iX = 0; iX < pHIST->iEntrycount; iX++) + { + mng_put_uint16 (pTemp, pHIST->aEntries [iX]); + pTemp += 2; + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pHIST->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_HIST, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_time) +{ + mng_timep pTIME; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TIME, MNG_LC_START) +#endif + + pTIME = (mng_timep)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 7; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pTIME->iYear); + + *(pRawdata+2) = pTIME->iMonth; + *(pRawdata+3) = pTIME->iDay; + *(pRawdata+4) = pTIME->iHour; + *(pRawdata+5) = pTIME->iMinute; + *(pRawdata+6) = pTIME->iSecond; + /* and write it */ + iRetcode = write_raw_chunk (pData, pTIME->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TIME, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_mhdr) +{ + mng_mhdrp pMHDR; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MHDR, MNG_LC_START) +#endif + + pMHDR = (mng_mhdrp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 28; + /* fill the output buffer */ + mng_put_uint32 (pRawdata, pMHDR->iWidth); + mng_put_uint32 (pRawdata+4, pMHDR->iHeight); + mng_put_uint32 (pRawdata+8, pMHDR->iTicks); + mng_put_uint32 (pRawdata+12, pMHDR->iLayercount); + mng_put_uint32 (pRawdata+16, pMHDR->iFramecount); + mng_put_uint32 (pRawdata+20, pMHDR->iPlaytime); + mng_put_uint32 (pRawdata+24, pMHDR->iSimplicity); + + /* and write it */ + iRetcode = write_raw_chunk (pData, pMHDR->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MHDR, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_mend) +{ + mng_mendp pMEND; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MEND, MNG_LC_START) +#endif + + pMEND = (mng_mendp)pChunk; /* address the proper chunk */ + /* and write it */ + iRetcode = write_raw_chunk (pData, pMEND->sHeader.iChunkname, 0, 0); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MEND, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_loop) +{ + mng_loopp pLOOP; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp1; + mng_uint32p pTemp2; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_LOOP, MNG_LC_START) +#endif + + pLOOP = (mng_loopp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 5; + /* fill the output buffer */ + *pRawdata = pLOOP->iLevel; + mng_put_uint32 (pRawdata+1, pLOOP->iRepeat); + + if (pLOOP->iTermination) + { + iRawlen++; + *(pRawdata+5) = pLOOP->iTermination; + + if ((pLOOP->iCount) || + (pLOOP->iItermin != 1) || (pLOOP->iItermax != 0x7FFFFFFFL)) + { + iRawlen += 8; + + mng_put_uint32 (pRawdata+6, pLOOP->iItermin); + mng_put_uint32 (pRawdata+10, pLOOP->iItermax); + + if (pLOOP->iCount) + { + iRawlen += pLOOP->iCount * 4; + + pTemp1 = pRawdata+14; + pTemp2 = pLOOP->pSignals; + + for (iX = 0; iX < pLOOP->iCount; iX++) + { + mng_put_uint32 (pTemp1, *pTemp2); + + pTemp1 += 4; + pTemp2++; + } + } + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pLOOP->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_LOOP, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_endl) +{ + mng_endlp pENDL; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ENDL, MNG_LC_START) +#endif + + pENDL = (mng_endlp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 1; + + *pRawdata = pENDL->iLevel; /* fill the output buffer */ + /* and write it */ + iRetcode = write_raw_chunk (pData, pENDL->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ENDL, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_defi) +{ + mng_defip pDEFI; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DEFI, MNG_LC_START) +#endif + + pDEFI = (mng_defip)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 2; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pDEFI->iObjectid); + + if ((pDEFI->iDonotshow) || (pDEFI->iConcrete) || (pDEFI->bHasloca) || (pDEFI->bHasclip)) + { + iRawlen++; + *(pRawdata+2) = pDEFI->iDonotshow; + + if ((pDEFI->iConcrete) || (pDEFI->bHasloca) || (pDEFI->bHasclip)) + { + iRawlen++; + *(pRawdata+3) = pDEFI->iConcrete; + + if ((pDEFI->bHasloca) || (pDEFI->bHasclip)) + { + iRawlen += 8; + + mng_put_uint32 (pRawdata+4, pDEFI->iXlocation); + mng_put_uint32 (pRawdata+8, pDEFI->iYlocation); + + if (pDEFI->bHasclip) + { + iRawlen += 16; + + mng_put_uint32 (pRawdata+12, pDEFI->iLeftcb); + mng_put_uint32 (pRawdata+16, pDEFI->iRightcb); + mng_put_uint32 (pRawdata+20, pDEFI->iTopcb); + mng_put_uint32 (pRawdata+24, pDEFI->iBottomcb); + } + } + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pDEFI->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DEFI, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_basi) +{ + mng_basip pBASI; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_bool bOpaque; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_BASI, MNG_LC_START) +#endif + + pBASI = (mng_basip)pChunk; /* address the proper chunk */ + + if (pBASI->iBitdepth <= 8) /* determine opacity alpha-field */ + bOpaque = (mng_bool)(pBASI->iAlpha == 0xFF); + else + bOpaque = (mng_bool)(pBASI->iAlpha == 0xFFFF); + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 13; + /* fill the output buffer */ + mng_put_uint32 (pRawdata, pBASI->iWidth); + mng_put_uint32 (pRawdata+4, pBASI->iHeight); + + *(pRawdata+8) = pBASI->iBitdepth; + *(pRawdata+9) = pBASI->iColortype; + *(pRawdata+10) = pBASI->iCompression; + *(pRawdata+11) = pBASI->iFilter; + *(pRawdata+12) = pBASI->iInterlace; + + if ((pBASI->iRed) || (pBASI->iGreen) || (pBASI->iBlue) || + (!bOpaque) || (pBASI->iViewable)) + { + iRawlen += 6; + mng_put_uint16 (pRawdata+13, pBASI->iRed); + mng_put_uint16 (pRawdata+15, pBASI->iGreen); + mng_put_uint16 (pRawdata+17, pBASI->iBlue); + + if ((!bOpaque) || (pBASI->iViewable)) + { + iRawlen += 2; + mng_put_uint16 (pRawdata+19, pBASI->iAlpha); + + if (pBASI->iViewable) + { + iRawlen++; + *(pRawdata+21) = pBASI->iViewable; + } + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pBASI->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_BASI, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_clon) +{ + mng_clonp pCLON; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_CLON, MNG_LC_START) +#endif + + pCLON = (mng_clonp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 4; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pCLON->iSourceid); + mng_put_uint16 (pRawdata+2, pCLON->iCloneid); + + if ((pCLON->iClonetype) || (pCLON->iDonotshow) || (pCLON->iConcrete) || (pCLON->bHasloca)) + { + iRawlen++; + *(pRawdata+4) = pCLON->iClonetype; + + if ((pCLON->iDonotshow) || (pCLON->iConcrete) || (pCLON->bHasloca)) + { + iRawlen++; + *(pRawdata+5) = pCLON->iDonotshow; + + if ((pCLON->iConcrete) || (pCLON->bHasloca)) + { + iRawlen++; + *(pRawdata+6) = pCLON->iConcrete; + + if (pCLON->bHasloca) + { + iRawlen += 9; + *(pRawdata+7) = pCLON->iLocationtype; + mng_put_int32 (pRawdata+8, pCLON->iLocationx); + mng_put_int32 (pRawdata+12, pCLON->iLocationy); + } + } + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pCLON->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_CLON, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_past) +{ + mng_pastp pPAST; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_past_sourcep pSource; + mng_uint32 iX; + mng_uint8p pTemp; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PAST, MNG_LC_START) +#endif + + pPAST = (mng_pastp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 11 + (30 * pPAST->iCount); + /* requires large buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_ALLOC (pData, pRawdata, iRawlen) + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pPAST->iDestid); + + *(pRawdata+2) = pPAST->iTargettype; + + mng_put_int32 (pRawdata+3, pPAST->iTargetx); + mng_put_int32 (pRawdata+7, pPAST->iTargety); + + pTemp = pRawdata+11; + pSource = pPAST->pSources; + + for (iX = 0; iX < pPAST->iCount; iX++) + { + mng_put_uint16 (pTemp, pSource->iSourceid); + + *(pTemp+2) = pSource->iComposition; + *(pTemp+3) = pSource->iOrientation; + *(pTemp+4) = pSource->iOffsettype; + + mng_put_int32 (pTemp+5, pSource->iOffsetx); + mng_put_int32 (pTemp+9, pSource->iOffsety); + + *(pTemp+13) = pSource->iBoundarytype; + + mng_put_int32 (pTemp+14, pSource->iBoundaryl); + mng_put_int32 (pTemp+18, pSource->iBoundaryr); + mng_put_int32 (pTemp+22, pSource->iBoundaryt); + mng_put_int32 (pTemp+26, pSource->iBoundaryb); + + pSource++; + pTemp += 30; + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pPAST->sHeader.iChunkname, + iRawlen, pRawdata); + /* free temporary buffer ? */ + if (iRawlen > pData->iWritebufsize) + MNG_FREEX (pData, pRawdata, iRawlen) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PAST, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_disc) +{ + mng_discp pDISC; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint32 iX; + mng_uint8p pTemp1; + mng_uint16p pTemp2; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DISC, MNG_LC_START) +#endif + + pDISC = (mng_discp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pDISC->iCount << 1; + + pTemp1 = pRawdata; /* fill the output buffer */ + pTemp2 = pDISC->pObjectids; + + for (iX = 0; iX < pDISC->iCount; iX++) + { + mng_put_uint16 (pTemp1, *pTemp2); + + pTemp2++; + pTemp1 += 2; + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pDISC->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DISC, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_back) +{ + mng_backp pBACK; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_BACK, MNG_LC_START) +#endif + + pBACK = (mng_backp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 6; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pBACK->iRed); + mng_put_uint16 (pRawdata+2, pBACK->iGreen); + mng_put_uint16 (pRawdata+4, pBACK->iBlue); + + if ((pBACK->iMandatory) || (pBACK->iImageid) || (pBACK->iTile)) + { + iRawlen++; + *(pRawdata+6) = pBACK->iMandatory; + + if ((pBACK->iImageid) || (pBACK->iTile)) + { + iRawlen += 2; + mng_put_uint16 (pRawdata+7, pBACK->iImageid); + + if (pBACK->iTile) + { + iRawlen++; + *(pRawdata+9) = pBACK->iTile; + } + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pBACK->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_BACK, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_fram) +{ + mng_framp pFRAM; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_uint32p pTemp2; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_FRAM, MNG_LC_START) +#endif + + pFRAM = (mng_framp)pChunk; /* address the proper chunk */ + + if (pFRAM->bEmpty) /* empty ? */ + iRetcode = write_raw_chunk (pData, pFRAM->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 1; + /* fill the output buffer */ + *pRawdata = pFRAM->iMode; + + if ((pFRAM->iNamesize ) || + (pFRAM->iChangedelay ) || (pFRAM->iChangetimeout) || + (pFRAM->iChangeclipping) || (pFRAM->iChangesyncid ) ) + { + if (pFRAM->iNamesize) + MNG_COPY (pRawdata+1, pFRAM->zName, pFRAM->iNamesize) + + iRawlen += pFRAM->iNamesize; + pTemp = pRawdata + pFRAM->iNamesize + 1; + + if ((pFRAM->iChangedelay ) || (pFRAM->iChangetimeout) || + (pFRAM->iChangeclipping) || (pFRAM->iChangesyncid ) ) + { + *pTemp = 0; + *(pTemp+1) = pFRAM->iChangedelay; + *(pTemp+2) = pFRAM->iChangetimeout; + *(pTemp+3) = pFRAM->iChangeclipping; + *(pTemp+4) = pFRAM->iChangesyncid; + + iRawlen += 5; + pTemp += 5; + + if (pFRAM->iChangedelay) + { + mng_put_uint32 (pTemp, pFRAM->iDelay); + iRawlen += 4; + pTemp += 4; + } + + if (pFRAM->iChangetimeout) + { + mng_put_uint32 (pTemp, pFRAM->iTimeout); + iRawlen += 4; + pTemp += 4; + } + + if (pFRAM->iChangeclipping) + { + *pTemp = pFRAM->iBoundarytype; + + mng_put_uint32 (pTemp+1, pFRAM->iBoundaryl); + mng_put_uint32 (pTemp+5, pFRAM->iBoundaryr); + mng_put_uint32 (pTemp+9, pFRAM->iBoundaryt); + mng_put_uint32 (pTemp+13, pFRAM->iBoundaryb); + + iRawlen += 17; + pTemp += 17; + } + + if (pFRAM->iChangesyncid) + { + iRawlen += pFRAM->iCount * 4; + pTemp2 = pFRAM->pSyncids; + + for (iX = 0; iX < pFRAM->iCount; iX++) + { + mng_put_uint32 (pTemp, *pTemp2); + + pTemp2++; + pTemp += 4; + } + } + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pFRAM->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_FRAM, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_move) +{ + mng_movep pMOVE; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MOVE, MNG_LC_START) +#endif + + pMOVE = (mng_movep)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 13; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pMOVE->iFirstid); + mng_put_uint16 (pRawdata+2, pMOVE->iLastid); + + *(pRawdata+4) = pMOVE->iMovetype; + + mng_put_int32 (pRawdata+5, pMOVE->iMovex); + mng_put_int32 (pRawdata+9, pMOVE->iMovey); + /* and write it */ + iRetcode = write_raw_chunk (pData, pMOVE->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MOVE, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_clip) +{ + mng_clipp pCLIP; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_CLIP, MNG_LC_START) +#endif + + pCLIP = (mng_clipp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 21; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pCLIP->iFirstid); + mng_put_uint16 (pRawdata+2, pCLIP->iLastid); + + *(pRawdata+4) = pCLIP->iCliptype; + + mng_put_int32 (pRawdata+5, pCLIP->iClipl); + mng_put_int32 (pRawdata+9, pCLIP->iClipr); + mng_put_int32 (pRawdata+13, pCLIP->iClipt); + mng_put_int32 (pRawdata+17, pCLIP->iClipb); + /* and write it */ + iRetcode = write_raw_chunk (pData, pCLIP->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_CLIP, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_show) +{ + mng_showp pSHOW; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SHOW, MNG_LC_START) +#endif + + pSHOW = (mng_showp)pChunk; /* address the proper chunk */ + + if (pSHOW->bEmpty) /* empty ? */ + iRetcode = write_raw_chunk (pData, pSHOW->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 2; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pSHOW->iFirstid); + + if ((pSHOW->iLastid != pSHOW->iFirstid) || (pSHOW->iMode)) + { + iRawlen += 2; + mng_put_uint16 (pRawdata+2, pSHOW->iLastid); + + if (pSHOW->iMode) + { + iRawlen++; + *(pRawdata+4) = pSHOW->iMode; + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pSHOW->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SHOW, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_term) +{ + mng_termp pTERM; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TERM, MNG_LC_START) +#endif + + pTERM = (mng_termp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 1; + + *pRawdata = pTERM->iTermaction; /* fill the output buffer */ + + if (pTERM->iTermaction == 3) + { + iRawlen = 10; + *(pRawdata+1) = pTERM->iIteraction; + + mng_put_uint32 (pRawdata+2, pTERM->iDelay); + mng_put_uint32 (pRawdata+6, pTERM->iItermax); + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pTERM->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_TERM, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_save) +{ + mng_savep pSAVE; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_save_entryp pEntry; + mng_uint32 iEntrysize; + mng_uint8p pTemp; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SAVE, MNG_LC_START) +#endif + + pSAVE = (mng_savep)pChunk; /* address the proper chunk */ + + if (pSAVE->bEmpty) /* empty ? */ + iRetcode = write_raw_chunk (pData, pSAVE->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 1; + + *pRawdata = pSAVE->iOffsettype; /* fill the output buffer */ + + if (pSAVE->iOffsettype == 16) + iEntrysize = 25; + else + iEntrysize = 17; + + pTemp = pRawdata+1; + pEntry = pSAVE->pEntries; + + for (iX = 0; iX < pSAVE->iCount; iX++) + { + if (iX) /* put separator null-byte, except the first */ + { + *pTemp = 0; + pTemp++; + iRawlen++; + } + + iRawlen += iEntrysize + pEntry->iNamesize; + *pTemp = pEntry->iEntrytype; + + if (pSAVE->iOffsettype == 16) + { + mng_put_uint32 (pTemp+1, pEntry->iOffset[0]); + mng_put_uint32 (pTemp+5, pEntry->iOffset[1]); + mng_put_uint32 (pTemp+9, pEntry->iStarttime[0]); + mng_put_uint32 (pTemp+13, pEntry->iStarttime[1]); + mng_put_uint32 (pTemp+17, pEntry->iLayernr); + mng_put_uint32 (pTemp+21, pEntry->iFramenr); + + pTemp += 25; + } + else + { + mng_put_uint32 (pTemp+1, pEntry->iOffset[1]); + mng_put_uint32 (pTemp+5, pEntry->iStarttime[1]); + mng_put_uint32 (pTemp+9, pEntry->iLayernr); + mng_put_uint32 (pTemp+13, pEntry->iFramenr); + + pTemp += 17; + } + + if (pEntry->iNamesize) + { + MNG_COPY (pTemp, pEntry->zName, pEntry->iNamesize); + pTemp += pEntry->iNamesize; + } + + pEntry++; + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pSAVE->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SAVE, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_seek) +{ + mng_seekp pSEEK; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SEEK, MNG_LC_START) +#endif + + pSEEK = (mng_seekp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pSEEK->iNamesize; + + if (iRawlen) /* fill the output buffer */ + MNG_COPY (pRawdata, pSEEK->zName, iRawlen) + /* and write it */ + iRetcode = write_raw_chunk (pData, pSEEK->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_SEEK, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_expi) +{ + mng_expip pEXPI; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_EXPI, MNG_LC_START) +#endif + + pEXPI = (mng_expip)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 2 + pEXPI->iNamesize; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pEXPI->iSnapshotid); + + if (pEXPI->iNamesize) + MNG_COPY (pRawdata+2, pEXPI->zName, pEXPI->iNamesize) + /* and write it */ + iRetcode = write_raw_chunk (pData, pEXPI->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_EXPI, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_fpri) +{ + mng_fprip pFPRI; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_FPRI, MNG_LC_START) +#endif + + pFPRI = (mng_fprip)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 2; + + *pRawdata = pFPRI->iDeltatype; /* fill the output buffer */ + *(pRawdata+1) = pFPRI->iPriority; + /* and write it */ + iRetcode = write_raw_chunk (pData, pFPRI->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_FPRI, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_need) +{ + mng_needp pNEED; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_NEED, MNG_LC_START) +#endif + + pNEED = (mng_needp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pNEED->iKeywordssize; + /* fill the output buffer */ + if (pNEED->iKeywordssize) + MNG_COPY (pRawdata, pNEED->zKeywords, pNEED->iKeywordssize) + /* and write it */ + iRetcode = write_raw_chunk (pData, pNEED->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_NEED, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_phyg) +{ + mng_phygp pPHYG; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PHYG, MNG_LC_START) +#endif + + pPHYG = (mng_phygp)pChunk; /* address the proper chunk */ + + if (pPHYG->bEmpty) /* write empty ? */ + iRetcode = write_raw_chunk (pData, pPHYG->sHeader.iChunkname, 0, 0); + else + { + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 9; + /* fill the output buffer */ + mng_put_uint32 (pRawdata, pPHYG->iSizex); + mng_put_uint32 (pRawdata+4, pPHYG->iSizey); + + *(pRawdata+8) = pPHYG->iUnit; + /* and write it */ + iRetcode = write_raw_chunk (pData, pPHYG->sHeader.iChunkname, + iRawlen, pRawdata); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PHYG, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +WRITE_CHUNK (write_jhdr) +{ + mng_jhdrp pJHDR; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JHDR, MNG_LC_START) +#endif + + pJHDR = (mng_jhdrp)pChunk; /* address the proper chunk */ + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 16; + /* fill the output buffer */ + mng_put_uint32 (pRawdata, pJHDR->iWidth); + mng_put_uint32 (pRawdata+4, pJHDR->iHeight); + + *(pRawdata+8) = pJHDR->iColortype; + *(pRawdata+9) = pJHDR->iImagesampledepth; + *(pRawdata+10) = pJHDR->iImagecompression; + *(pRawdata+11) = pJHDR->iImageinterlace; + *(pRawdata+12) = pJHDR->iAlphasampledepth; + *(pRawdata+13) = pJHDR->iAlphacompression; + *(pRawdata+14) = pJHDR->iAlphafilter; + *(pRawdata+15) = pJHDR->iAlphainterlace; + /* and write it */ + iRetcode = write_raw_chunk (pData, pJHDR->sHeader.iChunkname, iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JHDR, MNG_LC_END) +#endif + + return iRetcode; +} +#else +#define write_jhdr 0 +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +WRITE_CHUNK (write_jdaa) +{ + mng_jdatp pJDAA; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JDAA, MNG_LC_START) +#endif + + pJDAA = (mng_jdaap)pChunk; /* address the proper chunk */ + + if (pJDAA->bEmpty) /* and write it */ + iRetcode = write_raw_chunk (pData, pJDAA->sHeader.iChunkname, 0, 0); + else + iRetcode = write_raw_chunk (pData, pJDAA->sHeader.iChunkname, + pJDAA->iDatasize, pJDAA->pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JDAA, MNG_LC_END) +#endif + + return iRetcode; +} +#else +#define write_jdaa 0 +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +WRITE_CHUNK (write_jdat) +{ + mng_jdatp pJDAT; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JDAT, MNG_LC_START) +#endif + + pJDAT = (mng_jdatp)pChunk; /* address the proper chunk */ + + if (pJDAT->bEmpty) /* and write it */ + iRetcode = write_raw_chunk (pData, pJDAT->sHeader.iChunkname, 0, 0); + else + iRetcode = write_raw_chunk (pData, pJDAT->sHeader.iChunkname, + pJDAT->iDatasize, pJDAT->pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JDAT, MNG_LC_END) +#endif + + return iRetcode; +} +#else +#define write_jdat 0 +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ + +/* ************************************************************************** */ + +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +WRITE_CHUNK (write_jsep) +{ + mng_jsepp pJSEP; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JSEP, MNG_LC_START) +#endif + + pJSEP = (mng_jsepp)pChunk; /* address the proper chunk */ + /* and write it */ + iRetcode = write_raw_chunk (pData, pJSEP->sHeader.iChunkname, 0, 0); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_JSEP, MNG_LC_END) +#endif + + return iRetcode; +} +#else +#define write_jsep 0 +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ + +/* ************************************************************************** */ + +WRITE_CHUNK (write_dhdr) +{ + mng_dhdrp pDHDR; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DHDR, MNG_LC_START) +#endif + + pDHDR = (mng_dhdrp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 4; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pDHDR->iObjectid); + + *(pRawdata+2) = pDHDR->iImagetype; + *(pRawdata+3) = pDHDR->iDeltatype; + + if (pDHDR->iDeltatype != 7) + { + iRawlen += 8; + mng_put_uint32 (pRawdata+4, pDHDR->iBlockwidth); + mng_put_uint32 (pRawdata+8, pDHDR->iBlockheight); + + if (pDHDR->iDeltatype != 0) + { + iRawlen += 8; + mng_put_uint32 (pRawdata+12, pDHDR->iBlockx); + mng_put_uint32 (pRawdata+16, pDHDR->iBlocky); + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pDHDR->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DHDR, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_prom) +{ + mng_promp pPROM; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PROM, MNG_LC_START) +#endif + + pPROM = (mng_promp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 3; + + *pRawdata = pPROM->iColortype; /* fill the output buffer */ + *(pRawdata+1) = pPROM->iSampledepth; + *(pRawdata+2) = pPROM->iFilltype; + /* and write it */ + iRetcode = write_raw_chunk (pData, pPROM->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PROM, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_ipng) +{ + mng_ipngp pIPNG; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IPNG, MNG_LC_START) +#endif + + pIPNG = (mng_ipngp)pChunk; /* address the proper chunk */ + /* and write it */ + iRetcode = write_raw_chunk (pData, pIPNG->sHeader.iChunkname, 0, 0); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IPNG, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_pplt) +{ + mng_ppltp pPPLT; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_pplt_entryp pEntry; + mng_uint8p pTemp; + mng_uint32 iX; + mng_bool bHasgroup; + mng_uint8p pLastid = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PPLT, MNG_LC_START) +#endif + + pPPLT = (mng_ppltp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 1; + + *pRawdata = pPPLT->iDeltatype; /* fill the output buffer */ + + pTemp = pRawdata+1; + bHasgroup = MNG_FALSE; + + for (iX = 0; iX < pPPLT->iCount; iX++) + { + pEntry = &pPPLT->aEntries[iX]; + + if (pEntry->bUsed) /* valid entry ? */ + { + if (!bHasgroup) /* start a new group ? */ + { + bHasgroup = MNG_TRUE; + pLastid = pTemp+1; + + *pTemp = (mng_uint8)iX; + *(pTemp+1) = 0; + + pTemp += 2; + } + + switch (pPPLT->iDeltatype) /* add group-entry depending on type */ + { + case 0: ; + case 1: { + *pTemp = pEntry->iRed; + *(pTemp+1) = pEntry->iGreen; + *(pTemp+2) = pEntry->iBlue; + + pTemp += 3; + + break; + } + + case 2: ; + case 3: { + *pTemp = pEntry->iAlpha; + + pTemp++; + + break; + } + + case 4: ; + case 5: { + *pTemp = pEntry->iRed; + *(pTemp+1) = pEntry->iGreen; + *(pTemp+2) = pEntry->iBlue; + *(pTemp+3) = pEntry->iAlpha; + + pTemp += 4; + + break; + } + + } + } + else + { + if (bHasgroup) /* finish off a group ? */ + *pLastid = (mng_uint8)(iX-1); + + bHasgroup = MNG_FALSE; + } + } + + if (bHasgroup) /* last group unfinished ? */ + *pLastid = (mng_uint8)(pPPLT->iCount-1); + /* write the output buffer */ + iRetcode = write_raw_chunk (pData, pPPLT->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_PPLT, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_ijng) +{ + mng_ijngp pIJNG; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IJNG, MNG_LC_START) +#endif + + pIJNG = (mng_ijngp)pChunk; /* address the proper chunk */ + /* and write it */ + iRetcode = write_raw_chunk (pData, pIJNG->sHeader.iChunkname, 0, 0); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_IJNG, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_drop) +{ + mng_dropp pDROP; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint32 iX; + mng_uint8p pTemp1; + mng_chunkidp pTemp2; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DROP, MNG_LC_START) +#endif + + pDROP = (mng_dropp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pDROP->iCount << 2; + + pTemp1 = pRawdata; /* fill the output buffer */ + pTemp2 = pDROP->pChunknames; + + for (iX = 0; iX < pDROP->iCount; iX++) + { + mng_put_uint32 (pTemp1, (mng_uint32)*pTemp2); + + pTemp2++; + pTemp1 += 4; + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pDROP->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DROP, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_dbyk) +{ + mng_dbykp pDBYK; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DBYK, MNG_LC_START) +#endif + + pDBYK = (mng_dbykp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 5 + pDBYK->iKeywordssize; + /* fill the output buffer */ + mng_put_uint32 (pRawdata, pDBYK->iChunkname); + *(pRawdata+4) = pDBYK->iPolarity; + + if (pDBYK->iKeywordssize) + MNG_COPY (pRawdata+5, pDBYK->zKeywords, pDBYK->iKeywordssize) + /* and write it */ + iRetcode = write_raw_chunk (pData, pDBYK->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_DBYK, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_ordr) +{ + mng_ordrp pORDR; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + mng_uint8p pTemp; + mng_ordr_entryp pEntry; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ORDR, MNG_LC_START) +#endif + + pORDR = (mng_ordrp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = pORDR->iCount * 5; + + pTemp = pRawdata; /* fill the output buffer */ + pEntry = pORDR->pEntries; + + for (iX = 0; iX < pORDR->iCount; iX++) + { + mng_put_uint32 (pTemp, pEntry->iChunkname); + *(pTemp+4) = pEntry->iOrdertype; + pTemp += 5; + pEntry++; + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pORDR->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_ORDR, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_magn) +{ + mng_magnp pMAGN; + mng_uint8p pRawdata; + mng_uint32 iRawlen; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MAGN, MNG_LC_START) +#endif + + pMAGN = (mng_magnp)pChunk; /* address the proper chunk */ + + pRawdata = pData->pWritebuf+8; /* init output buffer & size */ + iRawlen = 20; + /* fill the output buffer */ + mng_put_uint16 (pRawdata, pMAGN->iFirstid); + mng_put_uint16 (pRawdata+2, pMAGN->iLastid); + mng_put_uint16 (pRawdata+4, pMAGN->iMethodX); + mng_put_uint16 (pRawdata+6, pMAGN->iMX); + mng_put_uint16 (pRawdata+8, pMAGN->iMY); + mng_put_uint16 (pRawdata+10, pMAGN->iML); + mng_put_uint16 (pRawdata+12, pMAGN->iMR); + mng_put_uint16 (pRawdata+14, pMAGN->iMT); + mng_put_uint16 (pRawdata+16, pMAGN->iMB); + mng_put_uint16 (pRawdata+18, pMAGN->iMethodY); + /* optimize length */ + if (pMAGN->iMethodY == pMAGN->iMethodX) + { + iRawlen -= 2; + + if (pMAGN->iMB == pMAGN->iMY) + { + iRawlen -= 2; + + if (pMAGN->iMT == pMAGN->iMY) + { + iRawlen -= 2; + + if (pMAGN->iMR == pMAGN->iMX) + { + iRawlen -= 2; + + if (pMAGN->iML == pMAGN->iMX) + { + iRawlen -= 2; + + if (pMAGN->iMY == pMAGN->iMX) + { + iRawlen -= 2; + + if (pMAGN->iMX == 1) + { + iRawlen -= 2; + + if (pMAGN->iMethodX == 0) + { + iRawlen -= 2; + + if (pMAGN->iLastid == pMAGN->iFirstid) + { + iRawlen -= 2; + + if (pMAGN->iFirstid == 0) + iRawlen = 0; + + } + } + } + } + } + } + } + } + } + /* and write it */ + iRetcode = write_raw_chunk (pData, pMAGN->sHeader.iChunkname, + iRawlen, pRawdata); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_MAGN, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +WRITE_CHUNK (write_unknown) +{ + mng_unknown_chunkp pUnknown; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_UNKNOWN, MNG_LC_START) +#endif + /* address the proper chunk */ + pUnknown = (mng_unknown_chunkp)pChunk; + /* and write it */ + iRetcode = write_raw_chunk (pData, pUnknown->sHeader.iChunkname, + pUnknown->iDatasize, pUnknown->pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_UNKNOWN, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_WRITE_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + + + + + diff --git a/freeimage241/Source/LibMNG/libmng_chunk_io.h b/freeimage241/Source/LibMNG/libmng_chunk_io.h new file mode 100644 index 0000000..d905601 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_chunk_io.h @@ -0,0 +1,295 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_chunk_io.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Chunk I/O routines (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the chunk input/output routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/04/2000 - G.Juyn * */ +/* * - changed CRC initializtion to use dynamic structure * */ +/* * (wasn't thread-safe the old way !) * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed write routines definition * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for JDAA * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_chunk_io_h_ +#define _libmng_chunk_io_h_ + +/* ************************************************************************** */ + +mng_uint32 crc (mng_datap pData, + mng_uint8p buf, + mng_int32 len); + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_READ_PROCS + +#define READ_CHUNK(n) mng_retcode n (mng_datap pData, \ + mng_chunkp pHeader, \ + mng_uint32 iRawlen, \ + mng_uint8p pRawdata, \ + mng_chunkp* ppChunk) + +READ_CHUNK (read_ihdr) ; +READ_CHUNK (read_plte) ; +READ_CHUNK (read_idat) ; +READ_CHUNK (read_iend) ; +READ_CHUNK (read_trns) ; +READ_CHUNK (read_gama) ; +READ_CHUNK (read_chrm) ; +READ_CHUNK (read_srgb) ; +READ_CHUNK (read_iccp) ; +READ_CHUNK (read_text) ; +READ_CHUNK (read_ztxt) ; +READ_CHUNK (read_itxt) ; +READ_CHUNK (read_bkgd) ; +READ_CHUNK (read_phys) ; +READ_CHUNK (read_sbit) ; +READ_CHUNK (read_splt) ; +READ_CHUNK (read_hist) ; +READ_CHUNK (read_time) ; +READ_CHUNK (read_mhdr) ; +READ_CHUNK (read_mend) ; +READ_CHUNK (read_loop) ; +READ_CHUNK (read_endl) ; +READ_CHUNK (read_defi) ; +READ_CHUNK (read_basi) ; +READ_CHUNK (read_clon) ; +READ_CHUNK (read_past) ; +READ_CHUNK (read_disc) ; +READ_CHUNK (read_back) ; +READ_CHUNK (read_fram) ; +READ_CHUNK (read_move) ; +READ_CHUNK (read_clip) ; +READ_CHUNK (read_show) ; +READ_CHUNK (read_term) ; +READ_CHUNK (read_save) ; +READ_CHUNK (read_seek) ; +READ_CHUNK (read_expi) ; +READ_CHUNK (read_fpri) ; +READ_CHUNK (read_phyg) ; +READ_CHUNK (read_jhdr) ; +READ_CHUNK (read_jdaa) ; +READ_CHUNK (read_jdat) ; +READ_CHUNK (read_jsep) ; +READ_CHUNK (read_dhdr) ; +READ_CHUNK (read_prom) ; +READ_CHUNK (read_ipng) ; +READ_CHUNK (read_pplt) ; +READ_CHUNK (read_ijng) ; +READ_CHUNK (read_drop) ; +READ_CHUNK (read_dbyk) ; +READ_CHUNK (read_ordr) ; +READ_CHUNK (read_magn) ; +READ_CHUNK (read_need) ; +READ_CHUNK (read_unknown) ; + +/* ************************************************************************** */ + +#else /* MNG_INCLUDE_READ_PROCS */ +#define read_ihdr 0 +#define read_plte 0 +#define read_idat 0 +#define read_iend 0 +#define read_trns 0 +#define read_gama 0 +#define read_chrm 0 +#define read_srgb 0 +#define read_iccp 0 +#define read_text 0 +#define read_ztxt 0 +#define read_itxt 0 +#define read_bkgd 0 +#define read_phys 0 +#define read_sbit 0 +#define read_splt 0 +#define read_hist 0 +#define read_time 0 +#define read_mhdr 0 +#define read_mend 0 +#define read_loop 0 +#define read_endl 0 +#define read_defi 0 +#define read_basi 0 +#define read_clon 0 +#define read_past 0 +#define read_disc 0 +#define read_back 0 +#define read_fram 0 +#define read_move 0 +#define read_clip 0 +#define read_show 0 +#define read_term 0 +#define read_save 0 +#define read_seek 0 +#define read_expi 0 +#define read_fpri 0 +#define read_phyg 0 +#define read_jhdr 0 +#define read_jdaa 0 +#define read_jdat 0 +#define read_jsep 0 +#define read_dhdr 0 +#define read_prom 0 +#define read_ipng 0 +#define read_pplt 0 +#define read_ijng 0 +#define read_drop 0 +#define read_dbyk 0 +#define read_ordr 0 +#define read_magn 0 +#define read_need 0 +#define read_unknown 0 +#endif /* MNG_INCLUDE_READ_PROCS */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_WRITE_PROCS + +#define WRITE_CHUNK(n) mng_retcode n (mng_datap pData, \ + mng_chunkp pChunk) + +WRITE_CHUNK (write_ihdr) ; +WRITE_CHUNK (write_plte) ; +WRITE_CHUNK (write_idat) ; +WRITE_CHUNK (write_iend) ; +WRITE_CHUNK (write_trns) ; +WRITE_CHUNK (write_gama) ; +WRITE_CHUNK (write_chrm) ; +WRITE_CHUNK (write_srgb) ; +WRITE_CHUNK (write_iccp) ; +WRITE_CHUNK (write_text) ; +WRITE_CHUNK (write_ztxt) ; +WRITE_CHUNK (write_itxt) ; +WRITE_CHUNK (write_bkgd) ; +WRITE_CHUNK (write_phys) ; +WRITE_CHUNK (write_sbit) ; +WRITE_CHUNK (write_splt) ; +WRITE_CHUNK (write_hist) ; +WRITE_CHUNK (write_time) ; +WRITE_CHUNK (write_mhdr) ; +WRITE_CHUNK (write_mend) ; +WRITE_CHUNK (write_loop) ; +WRITE_CHUNK (write_endl) ; +WRITE_CHUNK (write_defi) ; +WRITE_CHUNK (write_basi) ; +WRITE_CHUNK (write_clon) ; +WRITE_CHUNK (write_past) ; +WRITE_CHUNK (write_disc) ; +WRITE_CHUNK (write_back) ; +WRITE_CHUNK (write_fram) ; +WRITE_CHUNK (write_move) ; +WRITE_CHUNK (write_clip) ; +WRITE_CHUNK (write_show) ; +WRITE_CHUNK (write_term) ; +WRITE_CHUNK (write_save) ; +WRITE_CHUNK (write_seek) ; +WRITE_CHUNK (write_expi) ; +WRITE_CHUNK (write_fpri) ; +WRITE_CHUNK (write_phyg) ; +WRITE_CHUNK (write_jhdr) ; +WRITE_CHUNK (write_jdaa) ; +WRITE_CHUNK (write_jdat) ; +WRITE_CHUNK (write_jsep) ; +WRITE_CHUNK (write_dhdr) ; +WRITE_CHUNK (write_prom) ; +WRITE_CHUNK (write_ipng) ; +WRITE_CHUNK (write_pplt) ; +WRITE_CHUNK (write_ijng) ; +WRITE_CHUNK (write_drop) ; +WRITE_CHUNK (write_dbyk) ; +WRITE_CHUNK (write_ordr) ; +WRITE_CHUNK (write_magn) ; +WRITE_CHUNK (write_need) ; +WRITE_CHUNK (write_unknown) ; + +/* ************************************************************************** */ + +#else /* MNG_INCLUDE_WRITE_PROCS */ +#define write_ihdr 0 +#define write_plte 0 +#define write_idat 0 +#define write_iend 0 +#define write_trns 0 +#define write_gama 0 +#define write_chrm 0 +#define write_srgb 0 +#define write_iccp 0 +#define write_text 0 +#define write_ztxt 0 +#define write_itxt 0 +#define write_bkgd 0 +#define write_phys 0 +#define write_sbit 0 +#define write_splt 0 +#define write_hist 0 +#define write_time 0 +#define write_mhdr 0 +#define write_mend 0 +#define write_loop 0 +#define write_endl 0 +#define write_defi 0 +#define write_basi 0 +#define write_clon 0 +#define write_past 0 +#define write_disc 0 +#define write_back 0 +#define write_fram 0 +#define write_move 0 +#define write_clip 0 +#define write_show 0 +#define write_term 0 +#define write_save 0 +#define write_seek 0 +#define write_expi 0 +#define write_fpri 0 +#define write_phyg 0 +#define write_jhdr 0 +#define write_jdaa 0 +#define write_jdat 0 +#define write_jsep 0 +#define write_dhdr 0 +#define write_prom 0 +#define write_ipng 0 +#define write_pplt 0 +#define write_ijng 0 +#define write_drop 0 +#define write_dbyk 0 +#define write_ordr 0 +#define write_magn 0 +#define write_need 0 +#define write_unknown 0 +#endif /* MNG_INCLUDE_WRITE_PROCS */ + +/* ************************************************************************** */ + +#endif /* _libmng_chunk_io_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_chunk_prc.c b/freeimage241/Source/LibMNG/libmng_chunk_prc.c new file mode 100644 index 0000000..f3c27f4 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_chunk_prc.c @@ -0,0 +1,2102 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_chunk_prc.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Chunk initialization & cleanup (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the chunk initialization & cleanup * */ +/* * routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - fixed creation-code * */ +/* * * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - put add_chunk() inside MNG_INCLUDE_WRITE_PROCS wrapper * */ +/* * 0.9.2 - 08/01/2000 - G.Juyn * */ +/* * - wrapper for add_chunk() changed * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for JDAA * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_memory.h" +#include "libmng_chunks.h" +#include "libmng_chunk_prc.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ +/* * * */ +/* * General chunk routines * */ +/* * * */ +/* ************************************************************************** */ + +void add_chunk (mng_datap pData, + mng_chunkp pChunk) +{ + if (!pData->pFirstchunk) /* list is still empty ? */ + { + pData->pFirstchunk = pChunk; /* then this becomes the first */ + +#ifdef MNG_SUPPORT_WRITE + pData->iFirstchunkadded = ((mng_chunk_headerp)pChunk)->iChunkname; +#endif + + if (((mng_chunk_headerp)pChunk)->iChunkname == MNG_UINT_IHDR) + pData->eImagetype = mng_it_png; + else +#ifdef MNG_INCLUDE_JNG + if (((mng_chunk_headerp)pChunk)->iChunkname == MNG_UINT_JHDR) + pData->eImagetype = mng_it_jng; + else +#endif + pData->eImagetype = mng_it_mng; + + pData->eSigtype = pData->eImagetype; + } + else + { /* else we make appropriate links */ + ((mng_chunk_headerp)pChunk)->pPrev = pData->pLastchunk; + ((mng_chunk_headerp)pData->pLastchunk)->pNext = pChunk; + } + + pData->pLastchunk = pChunk; /* and it's always the last */ + + return; +} + +/* ************************************************************************** */ +/* * * */ +/* * Chunk specific initialization routines * */ +/* * * */ +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_ihdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IHDR, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_ihdr)) + ((mng_ihdrp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_plte) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PLTE, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_plte)) + ((mng_pltep)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_idat) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDAT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_idat)) + ((mng_idatp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_iend) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IEND, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_iend)) + ((mng_iendp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_trns) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TRNS, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_trns)) + ((mng_trnsp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_gama) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GAMA, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_gama)) + ((mng_gamap)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_chrm) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_CHRM, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_chrm)) + ((mng_chrmp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_srgb) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SRGB, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_srgb)) + ((mng_srgbp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_iccp) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ICCP, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_iccp)) + ((mng_iccpp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_text) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TEXT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_text)) + ((mng_textp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TEXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_ztxt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ZTXT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_ztxt)) + ((mng_ztxtp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ZTXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_itxt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ITXT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_itxt)) + ((mng_itxtp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ITXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_bkgd) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_BKGD, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_bkgd)) + ((mng_bkgdp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_phys) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PHYS, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_phys)) + ((mng_physp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PHYS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_sbit) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SBIT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_sbit)) + ((mng_sbitp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SBIT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_splt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SPLT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_splt)) + ((mng_spltp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_hist) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_HIST, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_hist)) + ((mng_histp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_HIST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_time) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TIME, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_time)) + ((mng_timep)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TIME, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_mhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MHDR, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_mhdr)) + ((mng_mhdrp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_mend) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MEND, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_mend)) + ((mng_mendp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_loop) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_LOOP, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_loop)) + ((mng_loopp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_endl) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ENDL, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_endl)) + ((mng_endlp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_defi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DEFI, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_defi)) + ((mng_defip)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_basi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_BASI, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_basi)) + ((mng_basip)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_clon) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_CLON, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_clon)) + ((mng_clonp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_past) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PAST, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_past)) + ((mng_pastp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PAST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_disc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DISC, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_disc)) + ((mng_discp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DISC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_back) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_BACK, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_back)) + ((mng_backp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_fram) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FRAM, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_fram)) + ((mng_framp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FRAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_move) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MOVE, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_move)) + ((mng_movep)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_clip) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_CLIP, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_clip)) + ((mng_clipp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_show) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SHOW, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_show)) + ((mng_showp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_term) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TERM, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_term)) + ((mng_termp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_save) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SAVE, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_save)) + ((mng_savep)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_seek) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SEEK, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_seek)) + ((mng_seekp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_expi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_EXPI, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_expi)) + ((mng_expip)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_EXPI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_fpri) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FPRI, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_fpri)) + ((mng_fprip)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FPRI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_need) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_NEED, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_need)) + ((mng_needp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_NEED, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_phyg) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PHYG, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_phyg)) + ((mng_phygp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PHYG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +INIT_CHUNK_HDR (init_jhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JHDR, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_jhdr)) + ((mng_jhdrp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +INIT_CHUNK_HDR (init_jdaa) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JDAA, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_jdaa)) + ((mng_jdaap)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JDAA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +INIT_CHUNK_HDR (init_jdat) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JDAT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_jdat)) + ((mng_jdatp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +INIT_CHUNK_HDR (init_jsep) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JSEP, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_jsep)) + ((mng_jsepp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JSEP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_dhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DHDR, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_dhdr)) + ((mng_dhdrp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_prom) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PROM, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_prom)) + ((mng_promp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_ipng) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IPNG, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_ipng)) + ((mng_ipngp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_pplt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PPLT, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_pplt)) + ((mng_ppltp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_ijng) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IJNG, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_ijng)) + ((mng_ijngp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_drop) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DROP, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_drop)) + ((mng_dropp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DROP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_dbyk) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DBYK, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_dbyk)) + ((mng_dbykp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_DBYK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_ordr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ORDR, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_ordr)) + ((mng_ordrp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ORDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_magn) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MAGN, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_magn)) + ((mng_magnp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +INIT_CHUNK_HDR (init_unknown) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_UNKNOWN, MNG_LC_START) +#endif + + MNG_ALLOC (pData, *ppChunk, sizeof (mng_unknown_chunk)) + ((mng_unknown_chunkp)*ppChunk)->sHeader = *((mng_chunk_headerp)pHeader); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_UNKNOWN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Chunk specific cleanup routines * */ +/* * * */ +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_ihdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IHDR, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_ihdr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_plte) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PLTE, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_plte)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_idat) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IDAT, MNG_LC_START) +#endif + + if (((mng_idatp)pHeader)->iDatasize) + MNG_FREEX (pData, ((mng_idatp)pHeader)->pData, + ((mng_idatp)pHeader)->iDatasize) + + MNG_FREEX (pData, pHeader, sizeof (mng_idat)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_iend) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IEND, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_iend)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_trns) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TRNS, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_trns)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_gama) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_GAMA, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_gama)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_chrm) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_CHRM, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_chrm)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_srgb) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SRGB, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_srgb)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_iccp) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ICCP, MNG_LC_START) +#endif + + if (((mng_iccpp)pHeader)->iNamesize) + MNG_FREEX (pData, ((mng_iccpp)pHeader)->zName, + ((mng_iccpp)pHeader)->iNamesize + 1) + + if (((mng_iccpp)pHeader)->iProfilesize) + MNG_FREEX (pData, ((mng_iccpp)pHeader)->pProfile, + ((mng_iccpp)pHeader)->iProfilesize) + + MNG_FREEX (pData, pHeader, sizeof (mng_iccp)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_text) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TEXT, MNG_LC_START) +#endif + + if (((mng_textp)pHeader)->iKeywordsize) + MNG_FREEX (pData, ((mng_textp)pHeader)->zKeyword, + ((mng_textp)pHeader)->iKeywordsize + 1) + + if (((mng_textp)pHeader)->iTextsize) + MNG_FREEX (pData, ((mng_textp)pHeader)->zText, + ((mng_textp)pHeader)->iTextsize + 1) + + MNG_FREEX (pData, pHeader, sizeof (mng_text)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TEXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_ztxt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ZTXT, MNG_LC_START) +#endif + + if (((mng_ztxtp)pHeader)->iKeywordsize) + MNG_FREEX (pData, ((mng_ztxtp)pHeader)->zKeyword, + ((mng_ztxtp)pHeader)->iKeywordsize + 1) + + if (((mng_ztxtp)pHeader)->iTextsize) + MNG_FREEX (pData, ((mng_ztxtp)pHeader)->zText, + ((mng_ztxtp)pHeader)->iTextsize) + + MNG_FREEX (pData, pHeader, sizeof (mng_ztxt)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ZTXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_itxt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ITXT, MNG_LC_START) +#endif + + if (((mng_itxtp)pHeader)->iKeywordsize) + MNG_FREEX (pData, ((mng_itxtp)pHeader)->zKeyword, + ((mng_itxtp)pHeader)->iKeywordsize + 1) + + if (((mng_itxtp)pHeader)->iLanguagesize) + MNG_FREEX (pData, ((mng_itxtp)pHeader)->zLanguage, + ((mng_itxtp)pHeader)->iLanguagesize + 1) + + if (((mng_itxtp)pHeader)->iTranslationsize) + MNG_FREEX (pData, ((mng_itxtp)pHeader)->zTranslation, + ((mng_itxtp)pHeader)->iTranslationsize + 1) + + if (((mng_itxtp)pHeader)->iTextsize) + MNG_FREEX (pData, ((mng_itxtp)pHeader)->zText, + ((mng_itxtp)pHeader)->iTextsize) + + MNG_FREEX (pData, pHeader, sizeof (mng_itxt)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ITXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_bkgd) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_BKGD, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_bkgd)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_phys) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PHYS, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_phys)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PHYS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_sbit) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SBIT, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_sbit)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SBIT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_splt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SPLT, MNG_LC_START) +#endif + + if (((mng_spltp)pHeader)->iNamesize) + MNG_FREEX (pData, ((mng_spltp)pHeader)->zName, + ((mng_spltp)pHeader)->iNamesize + 1) + + if (((mng_spltp)pHeader)->iEntrycount) + MNG_FREEX (pData, ((mng_spltp)pHeader)->pEntries, + ((mng_spltp)pHeader)->iEntrycount * + (((mng_spltp)pHeader)->iSampledepth * 3 + sizeof (mng_uint16)) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_splt)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_hist) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_HIST, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_hist)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_HIST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_time) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TIME, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_time)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TIME, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_mhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MHDR, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_mhdr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_mend) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MEND, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_mend)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_loop) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_LOOP, MNG_LC_START) +#endif + + if (((mng_loopp)pHeader)->iCount) + MNG_FREEX (pData, ((mng_loopp)pHeader)->pSignals, + ((mng_loopp)pHeader)->iCount * sizeof (mng_uint32) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_loop)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_endl) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ENDL, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_endl)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_defi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DEFI, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_defi)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_basi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_BASI, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_basi)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_clon) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_CLON, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_clon)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_past) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PAST, MNG_LC_START) +#endif + + if (((mng_pastp)pHeader)->iCount) + MNG_FREEX (pData, ((mng_pastp)pHeader)->pSources, + ((mng_pastp)pHeader)->iCount * sizeof (mng_past_source) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_past)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PAST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_disc) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DISC, MNG_LC_START) +#endif + + if (((mng_discp)pHeader)->iCount) + MNG_FREEX (pData, ((mng_discp)pHeader)->pObjectids, + ((mng_discp)pHeader)->iCount * sizeof (mng_uint16) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_disc)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DISC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_back) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_BACK, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_back)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_fram) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_FRAM, MNG_LC_START) +#endif + + if (((mng_framp)pHeader)->iNamesize) + MNG_FREEX (pData, ((mng_framp)pHeader)->zName, + ((mng_framp)pHeader)->iNamesize + 1) + + if (((mng_framp)pHeader)->iCount) + MNG_FREEX (pData, ((mng_framp)pHeader)->pSyncids, + ((mng_framp)pHeader)->iCount * sizeof (mng_uint32) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_fram)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_FRAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_move) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MOVE, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_move)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_clip) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_CLIP, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_clip)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_show) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SHOW, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_show)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_term) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TERM, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_term)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_save) +{ + mng_save_entryp pEntry = ((mng_savep)pHeader)->pEntries; + mng_uint32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SAVE, MNG_LC_START) +#endif + + for (iX = 0; iX < ((mng_savep)pHeader)->iCount; iX++) + { + if (pEntry->iNamesize) + MNG_FREEX (pData, pEntry->zName, pEntry->iNamesize) + + pEntry = pEntry + sizeof (mng_save_entry); + } + + if (((mng_savep)pHeader)->iCount) + MNG_FREEX (pData, ((mng_savep)pHeader)->pEntries, + ((mng_savep)pHeader)->iCount * sizeof (mng_save_entry) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_save)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_seek) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SEEK, MNG_LC_START) +#endif + + if (((mng_seekp)pHeader)->iNamesize) + MNG_FREEX (pData, ((mng_seekp)pHeader)->zName, + ((mng_seekp)pHeader)->iNamesize + 1) + + MNG_FREEX (pData, pHeader, sizeof (mng_seek)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_expi) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_EXPI, MNG_LC_START) +#endif + + if (((mng_expip)pHeader)->iNamesize) + MNG_FREEX (pData, ((mng_expip)pHeader)->zName, + ((mng_expip)pHeader)->iNamesize + 1) + + MNG_FREEX (pData, pHeader, sizeof (mng_expi)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_EXPI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_fpri) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_FPRI, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_fpri)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_FPRI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_need) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_NEED, MNG_LC_START) +#endif + + if (((mng_needp)pHeader)->iKeywordssize) + MNG_FREEX (pData, ((mng_needp)pHeader)->zKeywords, + ((mng_needp)pHeader)->iKeywordssize + 1) + + MNG_FREEX (pData, pHeader, sizeof (mng_need)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_NEED, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_phyg) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PHYG, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_phyg)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PHYG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +FREE_CHUNK_HDR (free_jhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JHDR, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_jhdr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +FREE_CHUNK_HDR (free_jdaa) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JDAA, MNG_LC_START) +#endif + + if (((mng_jdaap)pHeader)->iDatasize) + MNG_FREEX (pData, ((mng_jdaap)pHeader)->pData, + ((mng_jdaap)pHeader)->iDatasize) + + MNG_FREEX (pData, pHeader, sizeof (mng_jdaa)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JDAA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +FREE_CHUNK_HDR (free_jdat) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JDAT, MNG_LC_START) +#endif + + if (((mng_jdatp)pHeader)->iDatasize) + MNG_FREEX (pData, ((mng_jdatp)pHeader)->pData, + ((mng_jdatp)pHeader)->iDatasize) + + MNG_FREEX (pData, pHeader, sizeof (mng_jdat)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +FREE_CHUNK_HDR (free_jsep) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JSEP, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_jsep)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_JSEP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_dhdr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DHDR, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_dhdr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_prom) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PROM, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_prom)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_ipng) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IPNG, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_ipng)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_pplt) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PPLT, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_pplt)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_ijng) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IJNG, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_ijng)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_drop) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DROP, MNG_LC_START) +#endif + + if (((mng_dropp)pHeader)->iCount) + MNG_FREEX (pData, ((mng_dropp)pHeader)->pChunknames, + ((mng_dropp)pHeader)->iCount * sizeof (mng_chunkid) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_drop)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DROP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_dbyk) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DBYK, MNG_LC_START) +#endif + + if (((mng_dbykp)pHeader)->iKeywordssize) + MNG_FREEX (pData, ((mng_dbykp)pHeader)->zKeywords, + ((mng_dbykp)pHeader)->iKeywordssize) + + MNG_FREEX (pData, pHeader, sizeof (mng_dbyk)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_DBYK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_ordr) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ORDR, MNG_LC_START) +#endif + + if (((mng_ordrp)pHeader)->iCount) + MNG_FREEX (pData, ((mng_ordrp)pHeader)->pEntries, + ((mng_ordrp)pHeader)->iCount * sizeof (mng_ordr_entry) ) + + MNG_FREEX (pData, pHeader, sizeof (mng_ordr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ORDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_magn) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MAGN, MNG_LC_START) +#endif + + MNG_FREEX (pData, pHeader, sizeof (mng_magn)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +FREE_CHUNK_HDR (free_unknown) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_UNKNOWN, MNG_LC_START) +#endif + + if (((mng_unknown_chunkp)pHeader)->iDatasize) + MNG_FREEX (pData, ((mng_unknown_chunkp)pHeader)->pData, + ((mng_unknown_chunkp)pHeader)->iDatasize) + + MNG_FREEX (pData, pHeader, sizeof (mng_unknown_chunk)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_UNKNOWN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_chunk_prc.h b/freeimage241/Source/LibMNG/libmng_chunk_prc.h new file mode 100644 index 0000000..a1054d4 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_chunk_prc.h @@ -0,0 +1,168 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_chunk_prc.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Chunk initialization & cleanup (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : definition of the chunk initialization & cleanup routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for JDAA * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_chunk_prc_h_ +#define _libmng_chunk_prc_h_ + +/* ************************************************************************** */ + +void add_chunk (mng_datap pData, + mng_chunkp pChunk); + +/* ************************************************************************** */ + +#define INIT_CHUNK_HDR(n) mng_retcode n (mng_datap pData, \ + mng_chunkp pHeader, \ + mng_chunkp* ppChunk) + +INIT_CHUNK_HDR (init_ihdr) ; +INIT_CHUNK_HDR (init_plte) ; +INIT_CHUNK_HDR (init_idat) ; +INIT_CHUNK_HDR (init_iend) ; +INIT_CHUNK_HDR (init_trns) ; +INIT_CHUNK_HDR (init_gama) ; +INIT_CHUNK_HDR (init_chrm) ; +INIT_CHUNK_HDR (init_srgb) ; +INIT_CHUNK_HDR (init_iccp) ; +INIT_CHUNK_HDR (init_text) ; +INIT_CHUNK_HDR (init_ztxt) ; +INIT_CHUNK_HDR (init_itxt) ; +INIT_CHUNK_HDR (init_bkgd) ; +INIT_CHUNK_HDR (init_phys) ; +INIT_CHUNK_HDR (init_sbit) ; +INIT_CHUNK_HDR (init_splt) ; +INIT_CHUNK_HDR (init_hist) ; +INIT_CHUNK_HDR (init_time) ; +INIT_CHUNK_HDR (init_mhdr) ; +INIT_CHUNK_HDR (init_mend) ; +INIT_CHUNK_HDR (init_loop) ; +INIT_CHUNK_HDR (init_endl) ; +INIT_CHUNK_HDR (init_defi) ; +INIT_CHUNK_HDR (init_basi) ; +INIT_CHUNK_HDR (init_clon) ; +INIT_CHUNK_HDR (init_past) ; +INIT_CHUNK_HDR (init_disc) ; +INIT_CHUNK_HDR (init_back) ; +INIT_CHUNK_HDR (init_fram) ; +INIT_CHUNK_HDR (init_move) ; +INIT_CHUNK_HDR (init_clip) ; +INIT_CHUNK_HDR (init_show) ; +INIT_CHUNK_HDR (init_term) ; +INIT_CHUNK_HDR (init_save) ; +INIT_CHUNK_HDR (init_seek) ; +INIT_CHUNK_HDR (init_expi) ; +INIT_CHUNK_HDR (init_fpri) ; +INIT_CHUNK_HDR (init_need) ; +INIT_CHUNK_HDR (init_phyg) ; +INIT_CHUNK_HDR (init_jhdr) ; +INIT_CHUNK_HDR (init_jdaa) ; +INIT_CHUNK_HDR (init_jdat) ; +INIT_CHUNK_HDR (init_jsep) ; +INIT_CHUNK_HDR (init_dhdr) ; +INIT_CHUNK_HDR (init_prom) ; +INIT_CHUNK_HDR (init_ipng) ; +INIT_CHUNK_HDR (init_pplt) ; +INIT_CHUNK_HDR (init_ijng) ; +INIT_CHUNK_HDR (init_drop) ; +INIT_CHUNK_HDR (init_dbyk) ; +INIT_CHUNK_HDR (init_ordr) ; +INIT_CHUNK_HDR (init_magn) ; +INIT_CHUNK_HDR (init_unknown) ; + +/* ************************************************************************** */ + +#define FREE_CHUNK_HDR(n) mng_retcode n (mng_datap pData, \ + mng_chunkp pHeader) + +FREE_CHUNK_HDR (free_ihdr) ; +FREE_CHUNK_HDR (free_plte) ; +FREE_CHUNK_HDR (free_idat) ; +FREE_CHUNK_HDR (free_iend) ; +FREE_CHUNK_HDR (free_trns) ; +FREE_CHUNK_HDR (free_gama) ; +FREE_CHUNK_HDR (free_chrm) ; +FREE_CHUNK_HDR (free_srgb) ; +FREE_CHUNK_HDR (free_iccp) ; +FREE_CHUNK_HDR (free_text) ; +FREE_CHUNK_HDR (free_ztxt) ; +FREE_CHUNK_HDR (free_itxt) ; +FREE_CHUNK_HDR (free_bkgd) ; +FREE_CHUNK_HDR (free_phys) ; +FREE_CHUNK_HDR (free_sbit) ; +FREE_CHUNK_HDR (free_splt) ; +FREE_CHUNK_HDR (free_hist) ; +FREE_CHUNK_HDR (free_time) ; +FREE_CHUNK_HDR (free_mhdr) ; +FREE_CHUNK_HDR (free_mend) ; +FREE_CHUNK_HDR (free_loop) ; +FREE_CHUNK_HDR (free_endl) ; +FREE_CHUNK_HDR (free_defi) ; +FREE_CHUNK_HDR (free_basi) ; +FREE_CHUNK_HDR (free_clon) ; +FREE_CHUNK_HDR (free_past) ; +FREE_CHUNK_HDR (free_disc) ; +FREE_CHUNK_HDR (free_back) ; +FREE_CHUNK_HDR (free_fram) ; +FREE_CHUNK_HDR (free_move) ; +FREE_CHUNK_HDR (free_clip) ; +FREE_CHUNK_HDR (free_show) ; +FREE_CHUNK_HDR (free_term) ; +FREE_CHUNK_HDR (free_save) ; +FREE_CHUNK_HDR (free_seek) ; +FREE_CHUNK_HDR (free_expi) ; +FREE_CHUNK_HDR (free_fpri) ; +FREE_CHUNK_HDR (free_need) ; +FREE_CHUNK_HDR (free_phyg) ; +FREE_CHUNK_HDR (free_jhdr) ; +FREE_CHUNK_HDR (free_jdaa) ; +FREE_CHUNK_HDR (free_jdat) ; +FREE_CHUNK_HDR (free_jsep) ; +FREE_CHUNK_HDR (free_dhdr) ; +FREE_CHUNK_HDR (free_prom) ; +FREE_CHUNK_HDR (free_ipng) ; +FREE_CHUNK_HDR (free_pplt) ; +FREE_CHUNK_HDR (free_ijng) ; +FREE_CHUNK_HDR (free_drop) ; +FREE_CHUNK_HDR (free_dbyk) ; +FREE_CHUNK_HDR (free_ordr) ; +FREE_CHUNK_HDR (free_magn) ; +FREE_CHUNK_HDR (free_unknown) ; + +/* ************************************************************************** */ + +#endif /* _libmng_chunk_prc_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_chunk_xs.c b/freeimage241/Source/LibMNG/libmng_chunk_xs.c new file mode 100644 index 0000000..8ca3f47 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_chunk_xs.c @@ -0,0 +1,5119 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_chunk_xs.c copyright (c) 2000 G. Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : chunk access functions (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the chunk access functions * */ +/* * * */ +/* * changes : 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - changed and filled iterate-chunk function * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - fixed calling convention * */ +/* * - added getchunk functions * */ +/* * - added putchunk functions * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added empty-chunk put-routines * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * 0.5.1 - 05/15/2000 - G.Juyn * */ +/* * - added getimgdata & putimgdata functions * */ +/* * * */ +/* * 0.5.2 - 05/19/2000 - G.Juyn * */ +/* * - B004 - fixed problem with MNG_SUPPORT_WRITE not defined * */ +/* * also for MNG_SUPPORT_WRITE without MNG_INCLUDE_JNG * */ +/* * - Cleaned up some code regarding mixed support * */ +/* * * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - fixed creation-code * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * - added function to set simplicity field * */ +/* * - fixed putchunk_unknown() function * */ +/* * * */ +/* * 0.9.3 - 08/07/2000 - G.Juyn * */ +/* * - B111300 - fixup for improved portability * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 10/20/2000 - G.Juyn * */ +/* * - fixed putchunk_plte() to set bEmpty parameter * */ +/* * * */ +/* * 0.9.5 - 1/25/2001 - G.Juyn * */ +/* * - fixed some small compiler warnings (thanks Nikki) * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_memory.h" +#include "libmng_chunks.h" +#include "libmng_chunk_prc.h" +#include "libmng_chunk_io.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_ACCESS_CHUNKS + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_iterate_chunks (mng_handle hHandle, + mng_uint32 iChunkseq, + mng_iteratechunk fProc) +{ + mng_uint32 iSeq; + mng_chunkid iChunkname; + mng_datap pData; + mng_chunkp pChunk; + mng_bool bCont; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_ITERATE_CHUNKS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + + iSeq = 0; + bCont = MNG_TRUE; + pChunk = pData->pFirstchunk; /* get the first chunk */ + /* as long as there are some more */ + while ((pChunk) && (bCont)) /* and the app didn't signal a stop */ + { + if (iSeq >= iChunkseq) /* reached the first target ? */ + { /* then call this and next ones back in... */ + iChunkname = ((mng_chunk_headerp)pChunk)->iChunkname; + bCont = fProc (hHandle, (mng_handle)pChunk, iChunkname, iSeq); + } + + iSeq++; /* next one */ + pChunk = ((mng_chunk_headerp)pChunk)->pNext; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_ITERATE_CHUNKS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_ihdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint8 *iBitdepth, + mng_uint8 *iColortype, + mng_uint8 *iCompression, + mng_uint8 *iFilter, + mng_uint8 *iInterlace) +{ + mng_datap pData; + mng_ihdrp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_IHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_ihdrp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_IHDR) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iWidth = pChunk->iWidth; /* fill the fields */ + *iHeight = pChunk->iHeight; + *iBitdepth = pChunk->iBitdepth; + *iColortype = pChunk->iColortype; + *iCompression = pChunk->iCompression; + *iFilter = pChunk->iFilter; + *iInterlace = pChunk->iInterlace; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_IHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_plte (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount, + mng_palette8 *aPalette) +{ + mng_datap pData; + mng_pltep pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PLTE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_pltep)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_PLTE) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iCount = pChunk->iEntrycount; /* fill the fields */ + + MNG_COPY (*aPalette, pChunk->aEntries, sizeof (mng_palette8)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_idat (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iRawlen, + mng_ptr *pRawdata) +{ + mng_datap pData; + mng_idatp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_IDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_idatp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_IDAT) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iRawlen = pChunk->iDatasize; /* fill the fields */ + *pRawdata = pChunk->pData; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_IDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_trns (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_bool *bGlobal, + mng_uint8 *iType, + mng_uint32 *iCount, + mng_uint8arr *aAlphas, + mng_uint16 *iGray, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint32 *iRawlen, + mng_uint8arr *aRawdata) +{ + mng_datap pData; + mng_trnsp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TRNS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_trnsp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_tRNS) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *bGlobal = pChunk->bGlobal; + *iType = pChunk->iType; + *iCount = pChunk->iCount; + *iGray = pChunk->iGray; + *iRed = pChunk->iRed; + *iGreen = pChunk->iGreen; + *iBlue = pChunk->iBlue; + *iRawlen = pChunk->iRawlen; + + MNG_COPY (*aAlphas, pChunk->aEntries, sizeof (mng_uint8arr)) + MNG_COPY (*aRawdata, pChunk->aRawdata, sizeof (mng_uint8arr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_gama (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iGamma) +{ + mng_datap pData; + mng_gamap pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_GAMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_gamap)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_gAMA) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iGamma = pChunk->iGamma; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_chrm (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iWhitepointx, + mng_uint32 *iWhitepointy, + mng_uint32 *iRedx, + mng_uint32 *iRedy, + mng_uint32 *iGreenx, + mng_uint32 *iGreeny, + mng_uint32 *iBluex, + mng_uint32 *iBluey) +{ + mng_datap pData; + mng_chrmp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_CHRM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_chrmp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_cHRM) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iWhitepointx = pChunk->iWhitepointx; + *iWhitepointy = pChunk->iWhitepointy; + *iRedx = pChunk->iRedx; + *iRedy = pChunk->iRedy; + *iGreenx = pChunk->iGreenx; + *iGreeny = pChunk->iGreeny; + *iBluex = pChunk->iBluex; + *iBluey = pChunk->iBluey; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_srgb (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iRenderingintent) +{ + mng_datap pData; + mng_srgbp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SRGB, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_srgbp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_sRGB) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iRenderingintent = pChunk->iRenderingintent; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_iccp (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iNamesize, + mng_pchar *zName, + mng_uint8 *iCompression, + mng_uint32 *iProfilesize, + mng_ptr *pProfile) +{ + mng_datap pData; + mng_iccpp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ICCP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_iccpp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_iCCP) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iNamesize = pChunk->iNamesize; + *zName = pChunk->zName; + *iCompression = pChunk->iCompression; + *iProfilesize = pChunk->iProfilesize; + *pProfile = pChunk->pProfile; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_text (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordsize, + mng_pchar *zKeyword, + mng_uint32 *iTextsize, + mng_pchar *zText) +{ + mng_datap pData; + mng_textp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TEXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_textp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_tEXt) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + /* fill the fields */ + *iKeywordsize = pChunk->iKeywordsize; + *zKeyword = pChunk->zKeyword; + *iTextsize = pChunk->iTextsize; + *zText = pChunk->zText; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TEXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_ztxt (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordsize, + mng_pchar *zKeyword, + mng_uint8 *iCompression, + mng_uint32 *iTextsize, + mng_pchar *zText) +{ + mng_datap pData; + mng_ztxtp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ZTXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_ztxtp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_zTXt) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + /* fill the fields */ + *iKeywordsize = pChunk->iKeywordsize; + *zKeyword = pChunk->zKeyword; + *iCompression = pChunk->iCompression; + *iTextsize = pChunk->iTextsize; + *zText = pChunk->zText; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ZTXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_itxt (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordsize, + mng_pchar *zKeyword, + mng_uint8 *iCompressionflag, + mng_uint8 *iCompressionmethod, + mng_uint32 *iLanguagesize, + mng_pchar *zLanguage, + mng_uint32 *iTranslationsize, + mng_pchar *zTranslation, + mng_uint32 *iTextsize, + mng_pchar *zText) +{ + mng_datap pData; + mng_itxtp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ITXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_itxtp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_iTXt) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + /* fill the fields */ + *iKeywordsize = pChunk->iKeywordsize; + *zKeyword = pChunk->zKeyword; + *iCompressionflag = pChunk->iCompressionflag; + *iCompressionmethod = pChunk->iCompressionmethod; + *iLanguagesize = pChunk->iLanguagesize; + *zLanguage = pChunk->zLanguage; + *iTranslationsize = pChunk->iTranslationsize; + *zTranslation = pChunk->zTranslation; + *iTextsize = pChunk->iTextsize; + *zText = pChunk->zText; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ITXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_bkgd (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iType, + mng_uint8 *iIndex, + mng_uint16 *iGray, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue) +{ + mng_datap pData; + mng_bkgdp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_BKGD, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_bkgdp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_bKGD) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iType = pChunk->iType; + *iIndex = pChunk->iIndex; + *iGray = pChunk->iGray; + *iRed = pChunk->iRed; + *iGreen = pChunk->iGreen; + *iBlue = pChunk->iBlue; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_phys (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iSizex, + mng_uint32 *iSizey, + mng_uint8 *iUnit) +{ + mng_datap pData; + mng_physp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PHYS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_physp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_pHYs) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iSizex = pChunk->iSizex; + *iSizey = pChunk->iSizey; + *iUnit = pChunk->iUnit; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PHYS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_sbit (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iType, + mng_uint8arr4 *aBits) +{ + mng_datap pData; + mng_sbitp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SBIT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_sbitp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_sBIT) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; + *iType = pChunk->iType; + (*aBits)[0] = pChunk->aBits[0]; + (*aBits)[1] = pChunk->aBits[1]; + (*aBits)[2] = pChunk->aBits[2]; + (*aBits)[3] = pChunk->aBits[3]; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SBIT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_splt (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iNamesize, + mng_pchar *zName, + mng_uint8 *iSampledepth, + mng_uint32 *iEntrycount, + mng_ptr *pEntries) +{ + mng_datap pData; + mng_spltp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SPLT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_spltp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_sPLT) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iNamesize = pChunk->iNamesize; + *zName = pChunk->zName; + *iSampledepth = pChunk->iSampledepth; + *iEntrycount = pChunk->iEntrycount; + *pEntries = pChunk->pEntries; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_hist (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iEntrycount, + mng_uint16arr *aEntries) +{ + mng_datap pData; + mng_histp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_HIST, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_histp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_hIST) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iEntrycount = pChunk->iEntrycount; /* fill the fields */ + + MNG_COPY (*aEntries, pChunk->aEntries, sizeof (mng_uint16arr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_HIST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_time (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iYear, + mng_uint8 *iMonth, + mng_uint8 *iDay, + mng_uint8 *iHour, + mng_uint8 *iMinute, + mng_uint8 *iSecond) +{ + mng_datap pData; + mng_timep pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TIME, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_timep)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_tIME) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iYear = pChunk->iYear; /* fill the fields */ + *iMonth = pChunk->iMonth; + *iDay = pChunk->iDay; + *iHour = pChunk->iHour; + *iMinute = pChunk->iMinute; + *iSecond = pChunk->iSecond; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TIME, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_mhdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint32 *iTicks, + mng_uint32 *iLayercount, + mng_uint32 *iFramecount, + mng_uint32 *iPlaytime, + mng_uint32 *iSimplicity) +{ + mng_datap pData; + mng_mhdrp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_MHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_mhdrp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iWidth = pChunk->iWidth; /* fill the fields */ + *iHeight = pChunk->iHeight; + *iTicks = pChunk->iTicks; + *iLayercount = pChunk->iLayercount; + *iFramecount = pChunk->iFramecount; + *iPlaytime = pChunk->iPlaytime; + *iSimplicity = pChunk->iSimplicity; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_MHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_loop (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iLevel, + mng_uint32 *iRepeat, + mng_uint8 *iTermination, + mng_uint32 *iItermin, + mng_uint32 *iItermax, + mng_uint32 *iCount, + mng_uint32p *pSignals) +{ + mng_datap pData; + mng_loopp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_LOOP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_loopp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_LOOP) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iLevel = pChunk->iLevel; /* fill teh fields */ + *iRepeat = pChunk->iRepeat; + *iTermination = pChunk->iTermination; + *iItermin = pChunk->iItermin; + *iItermax = pChunk->iItermax; + *iCount = pChunk->iCount; + *pSignals = pChunk->pSignals; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_endl (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iLevel) +{ + mng_datap pData; + mng_endlp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ENDL, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_endlp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_ENDL) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iLevel = pChunk->iLevel; /* fill the field */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_defi (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iObjectid, + mng_uint8 *iDonotshow, + mng_uint8 *iConcrete, + mng_bool *bHasloca, + mng_int32 *iXlocation, + mng_int32 *iYlocation, + mng_bool *bHasclip, + mng_int32 *iLeftcb, + mng_int32 *iRightcb, + mng_int32 *iTopcb, + mng_int32 *iBottomcb) +{ + mng_datap pData; + mng_defip pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DEFI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_defip)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_DEFI) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iObjectid = pChunk->iObjectid; /* fill the fields */ + *iDonotshow = pChunk->iDonotshow; + *iConcrete = pChunk->iConcrete; + *bHasloca = pChunk->bHasloca; + *iXlocation = pChunk->iXlocation; + *iYlocation = pChunk->iYlocation; + *bHasclip = pChunk->bHasclip; + *iLeftcb = pChunk->iLeftcb; + *iRightcb = pChunk->iRightcb; + *iTopcb = pChunk->iTopcb; + *iBottomcb = pChunk->iBottomcb; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_basi (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint8 *iBitdepth, + mng_uint8 *iColortype, + mng_uint8 *iCompression, + mng_uint8 *iFilter, + mng_uint8 *iInterlace, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint16 *iAlpha, + mng_uint8 *iViewable) +{ + mng_datap pData; + mng_basip pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_BASI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_basip)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_BASI) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iWidth = pChunk->iWidth; /* fill the fields */ + *iHeight = pChunk->iHeight; + *iBitdepth = pChunk->iBitdepth; + *iColortype = pChunk->iColortype; + *iCompression = pChunk->iCompression; + *iFilter = pChunk->iFilter; + *iInterlace = pChunk->iInterlace; + *iRed = pChunk->iRed; + *iGreen = pChunk->iGreen; + *iBlue = pChunk->iBlue; + *iAlpha = pChunk->iAlpha; + *iViewable = pChunk->iViewable; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_clon (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iSourceid, + mng_uint16 *iCloneid, + mng_uint8 *iClonetype, + mng_uint8 *iDonotshow, + mng_uint8 *iConcrete, + mng_bool *bHasloca, + mng_uint8 *iLocationtype, + mng_int32 *iLocationx, + mng_int32 *iLocationy) +{ + mng_datap pData; + mng_clonp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_CLON, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_clonp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_CLON) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iSourceid = pChunk->iSourceid; /* fill the fields */ + *iCloneid = pChunk->iCloneid; + *iClonetype = pChunk->iClonetype; + *iDonotshow = pChunk->iDonotshow; + *iConcrete = pChunk->iConcrete; + *bHasloca = pChunk->bHasloca; + *iLocationtype = pChunk->iLocationtype; + *iLocationx = pChunk->iLocationx; + *iLocationy = pChunk->iLocationy; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_past (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iDestid, + mng_uint8 *iTargettype, + mng_int32 *iTargetx, + mng_int32 *iTargety, + mng_uint32 *iCount) +{ + mng_datap pData; + mng_pastp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PAST, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_pastp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_PAST) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iDestid = pChunk->iDestid; /* fill the fields */ + *iTargettype = pChunk->iTargettype; + *iTargetx = pChunk->iTargetx; + *iTargety = pChunk->iTargety; + *iCount = pChunk->iCount; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PAST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_past_src (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_uint16 *iSourceid, + mng_uint8 *iComposition, + mng_uint8 *iOrientation, + mng_uint8 *iOffsettype, + mng_int32 *iOffsetx, + mng_int32 *iOffsety, + mng_uint8 *iBoundarytype, + mng_int32 *iBoundaryl, + mng_int32 *iBoundaryr, + mng_int32 *iBoundaryt, + mng_int32 *iBoundaryb) +{ + mng_datap pData; + mng_pastp pChunk; + mng_past_sourcep pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PAST_SRC, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_pastp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_PAST) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + if (iEntry >= pChunk->iCount) /* valid index ? */ + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + /* address the entry */ + pEntry = pChunk->pSources + iEntry; + + *iSourceid = pEntry->iSourceid; /* fill the fields */ + *iComposition = pEntry->iComposition; + *iOrientation = pEntry->iOrientation; + *iOffsettype = pEntry->iOffsettype; + *iOffsetx = pEntry->iOffsetx; + *iOffsety = pEntry->iOffsety; + *iBoundarytype = pEntry->iBoundarytype; + *iBoundaryl = pEntry->iBoundaryl; + *iBoundaryr = pEntry->iBoundaryr; + *iBoundaryt = pEntry->iBoundaryt; + *iBoundaryb = pEntry->iBoundaryb; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PAST_SRC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_disc (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount, + mng_uint16p *pObjectids) +{ + mng_datap pData; + mng_discp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DISC, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_discp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_DISC) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iCount = pChunk->iCount; /* fill the fields */ + *pObjectids = pChunk->pObjectids; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DISC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_back (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint8 *iMandatory, + mng_uint16 *iImageid, + mng_uint8 *iTile) +{ + mng_datap pData; + mng_backp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_BACK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_backp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_BACK) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iRed = pChunk->iRed; /* fill the fields */ + *iGreen = pChunk->iGreen; + *iBlue = pChunk->iBlue; + *iMandatory = pChunk->iMandatory; + *iImageid = pChunk->iImageid; + *iTile = pChunk->iTile; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_fram (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iMode, + mng_uint32 *iNamesize, + mng_pchar *zName, + mng_uint8 *iChangedelay, + mng_uint8 *iChangetimeout, + mng_uint8 *iChangeclipping, + mng_uint8 *iChangesyncid, + mng_uint32 *iDelay, + mng_uint32 *iTimeout, + mng_uint8 *iBoundarytype, + mng_int32 *iBoundaryl, + mng_int32 *iBoundaryr, + mng_int32 *iBoundaryt, + mng_int32 *iBoundaryb, + mng_uint32 *iCount, + mng_uint32p *pSyncids) +{ + mng_datap pData; + mng_framp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_FRAM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_framp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_FRAM) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iMode = pChunk->iMode; + *iNamesize = pChunk->iNamesize; + *zName = pChunk->zName; + *iChangedelay = pChunk->iChangedelay; + *iChangetimeout = pChunk->iChangetimeout; + *iChangeclipping = pChunk->iChangeclipping; + *iChangesyncid = pChunk->iChangesyncid; + *iDelay = pChunk->iDelay; + *iTimeout = pChunk->iTimeout; + *iBoundarytype = pChunk->iBoundarytype; + *iBoundaryl = pChunk->iBoundaryl; + *iBoundaryr = pChunk->iBoundaryr; + *iBoundaryt = pChunk->iBoundaryt; + *iBoundaryb = pChunk->iBoundaryb; + *iCount = pChunk->iCount; + *pSyncids = pChunk->pSyncids; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_FRAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_move (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint8 *iMovetype, + mng_int32 *iMovex, + mng_int32 *iMovey) +{ + mng_datap pData; + mng_movep pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_MOVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_movep)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_MOVE) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iFirstid = pChunk->iFirstid; /* fill the fields */ + *iLastid = pChunk->iLastid; + *iMovetype = pChunk->iMovetype; + *iMovex = pChunk->iMovex; + *iMovey = pChunk->iMovey; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_clip (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint8 *iCliptype, + mng_int32 *iClipl, + mng_int32 *iClipr, + mng_int32 *iClipt, + mng_int32 *iClipb) +{ + mng_datap pData; + mng_clipp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_CLIP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_clipp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_CLIP) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iFirstid = pChunk->iFirstid; /* fill the fields */ + *iLastid = pChunk->iLastid; + *iCliptype = pChunk->iCliptype; + *iClipl = pChunk->iClipl; + *iClipr = pChunk->iClipr; + *iClipt = pChunk->iClipt; + *iClipb = pChunk->iClipb; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_show (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint8 *iMode) +{ + mng_datap pData; + mng_showp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SHOW, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_showp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_SHOW) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iFirstid = pChunk->iFirstid; + *iLastid = pChunk->iLastid; + *iMode = pChunk->iMode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_term (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iTermaction, + mng_uint8 *iIteraction, + mng_uint32 *iDelay, + mng_uint32 *iItermax) +{ + mng_datap pData; + mng_termp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TERM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_termp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_TERM) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iTermaction = pChunk->iTermaction; /* fill the fields */ + *iIteraction = pChunk->iIteraction; + *iDelay = pChunk->iDelay; + *iItermax = pChunk->iItermax; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_save (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint8 *iOffsettype, + mng_uint32 *iCount) +{ + mng_datap pData; + mng_savep pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SAVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_savep)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_SAVE) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iOffsettype = pChunk->iOffsettype; + *iCount = pChunk->iCount; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_save_entry (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_uint8 *iEntrytype, + mng_uint32arr2 *iOffset, + mng_uint32arr2 *iStarttime, + mng_uint32 *iLayernr, + mng_uint32 *iFramenr, + mng_uint32 *iNamesize, + mng_pchar *zName) +{ + mng_datap pData; + mng_savep pChunk; + mng_save_entryp pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SAVE_ENTRY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_savep)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_SAVE) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + if (iEntry >= pChunk->iCount) /* valid index ? */ + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + + pEntry = pChunk->pEntries + iEntry; /* address the entry */ + /* fill the fields */ + *iEntrytype = pEntry->iEntrytype; + (*iOffset)[0] = pEntry->iOffset[0]; + (*iOffset)[1] = pEntry->iOffset[1]; + (*iStarttime)[0] = pEntry->iStarttime[0]; + (*iStarttime)[1] = pEntry->iStarttime[1]; + *iLayernr = pEntry->iLayernr; + *iFramenr = pEntry->iFramenr; + *iNamesize = pEntry->iNamesize; + *zName = pEntry->zName; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SAVE_ENTRY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_seek (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iNamesize, + mng_pchar *zName) +{ + mng_datap pData; + mng_seekp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SEEK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_seekp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_SEEK) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iNamesize = pChunk->iNamesize; /* fill the fields */ + *zName = pChunk->zName; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_expi (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iSnapshotid, + mng_uint32 *iNamesize, + mng_pchar *zName) +{ + mng_datap pData; + mng_expip pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_EXPI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_expip)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_eXPI) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iSnapshotid = pChunk->iSnapshotid; /* fill the fields */ + *iNamesize = pChunk->iNamesize; + *zName = pChunk->zName; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_EXPI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_fpri (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iDeltatype, + mng_uint8 *iPriority) +{ + mng_datap pData; + mng_fprip pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_FPRI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_fprip)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_fPRI) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iDeltatype = pChunk->iDeltatype; /* fill the fields */ + *iPriority = pChunk->iPriority; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_FPRI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_need (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iKeywordssize, + mng_pchar *zKeywords) +{ + mng_datap pData; + mng_needp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_NEED, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_needp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_nEED) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + /* fill the fields */ + *iKeywordssize = pChunk->iKeywordssize; + *zKeywords = pChunk->zKeywords; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_NEED, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_phyg (mng_handle hHandle, + mng_handle hChunk, + mng_bool *bEmpty, + mng_uint32 *iSizex, + mng_uint32 *iSizey, + mng_uint8 *iUnit) +{ + mng_datap pData; + mng_phygp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PHYG, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_phygp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_pHYg) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *bEmpty = pChunk->bEmpty; /* fill the fields */ + *iSizex = pChunk->iSizex; + *iSizey = pChunk->iSizey; + *iUnit = pChunk->iUnit; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PHYG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +mng_retcode MNG_DECL mng_getchunk_jhdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iWidth, + mng_uint32 *iHeight, + mng_uint8 *iColortype, + mng_uint8 *iImagesampledepth, + mng_uint8 *iImagecompression, + mng_uint8 *iImageinterlace, + mng_uint8 *iAlphasampledepth, + mng_uint8 *iAlphacompression, + mng_uint8 *iAlphafilter, + mng_uint8 *iAlphainterlace) +{ + mng_datap pData; + mng_jhdrp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_JHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_jhdrp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_JHDR) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iWidth = pChunk->iWidth; /* fill the fields */ + *iHeight = pChunk->iHeight; + *iColortype = pChunk->iColortype; + *iImagesampledepth = pChunk->iImagesampledepth; + *iImagecompression = pChunk->iImagecompression; + *iImageinterlace = pChunk->iImageinterlace; + *iAlphasampledepth = pChunk->iAlphasampledepth; + *iAlphacompression = pChunk->iAlphacompression; + *iAlphafilter = pChunk->iAlphafilter; + *iAlphainterlace = pChunk->iAlphainterlace; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_JHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +mng_retcode MNG_DECL mng_getchunk_jdat (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iRawlen, + mng_ptr *pRawdata) +{ + mng_datap pData; + mng_jdatp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_JDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_jdatp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_JDAT) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iRawlen = pChunk->iDatasize; /* fill the fields */ + *pRawdata = pChunk->pData; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_JDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_dhdr (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iObjectid, + mng_uint8 *iImagetype, + mng_uint8 *iDeltatype, + mng_uint32 *iBlockwidth, + mng_uint32 *iBlockheight, + mng_uint32 *iBlockx, + mng_uint32 *iBlocky) +{ + mng_datap pData; + mng_dhdrp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_dhdrp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_DHDR) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iObjectid = pChunk->iObjectid; /* fill the fields */ + *iImagetype = pChunk->iImagetype; + *iDeltatype = pChunk->iDeltatype; + *iBlockwidth = pChunk->iBlockwidth; + *iBlockheight = pChunk->iBlockheight; + *iBlockx = pChunk->iBlockx; + *iBlocky = pChunk->iBlocky; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_prom (mng_handle hHandle, + mng_handle hChunk, + mng_uint8 *iColortype, + mng_uint8 *iSampledepth, + mng_uint8 *iFilltype) +{ + mng_datap pData; + mng_promp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PROM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_promp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_PROM) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iColortype = pChunk->iColortype; /* fill the fields */ + *iSampledepth = pChunk->iSampledepth; + *iFilltype = pChunk->iFilltype; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_pplt (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount) +{ + mng_datap pData; + mng_ppltp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PPLT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_ppltp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_PPLT) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iCount = pChunk->iCount; /* fill the field */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_pplt_entry (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_uint16 *iRed, + mng_uint16 *iGreen, + mng_uint16 *iBlue, + mng_uint16 *iAlpha, + mng_bool *bUsed) +{ + mng_datap pData; + mng_ppltp pChunk; + mng_pplt_entryp pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PPLT_ENTRY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_ppltp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_PPLT) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + if (iEntry >= pChunk->iCount) /* valid index ? */ + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + + pEntry = &pChunk->aEntries[iEntry]; /* address the entry */ + + *iRed = pEntry->iRed; /* fill the fields */ + *iGreen = pEntry->iGreen; + *iBlue = pEntry->iBlue; + *iAlpha = pEntry->iAlpha; + *bUsed = pEntry->bUsed; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_PPLT_ENTRY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_drop (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount, + mng_chunkidp *pChunknames) +{ + mng_datap pData; + mng_dropp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DROP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_dropp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_DROP) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iCount = pChunk->iCount; /* fill the fields */ + *pChunknames = pChunk->pChunknames; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DROP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_dbyk (mng_handle hHandle, + mng_handle hChunk, + mng_chunkid *iChunkname, + mng_uint8 *iPolarity, + mng_uint32 *iKeywordssize, + mng_pchar *zKeywords) +{ + mng_datap pData; + mng_dbykp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DBYK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_dbykp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_DBYK) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iChunkname = pChunk->iChunkname; /* fill the fields */ + *iPolarity = pChunk->iPolarity; + *iKeywordssize = pChunk->iKeywordssize; + *zKeywords = pChunk->zKeywords; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_DBYK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_ordr (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 *iCount) +{ + mng_datap pData; + mng_ordrp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ORDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_ordrp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_ORDR) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iCount = pChunk->iCount; /* fill the field */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ORDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_ordr_entry (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iEntry, + mng_chunkid *iChunkname, + mng_uint8 *iOrdertype) +{ + mng_datap pData; + mng_ordrp pChunk; + mng_ordr_entryp pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ORDR_ENTRY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_ordrp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_ORDR) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + if (iEntry >= pChunk->iCount) /* valid index ? */ + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + + pEntry = pChunk->pEntries + iEntry; /* address the proper entry */ + + *iChunkname = pEntry->iChunkname; /* fill the fields */ + *iOrdertype = pEntry->iOrdertype; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_ORDR_ENTRY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_magn (mng_handle hHandle, + mng_handle hChunk, + mng_uint16 *iFirstid, + mng_uint16 *iLastid, + mng_uint16 *iMethodX, + mng_uint16 *iMX, + mng_uint16 *iMY, + mng_uint16 *iML, + mng_uint16 *iMR, + mng_uint16 *iMT, + mng_uint16 *iMB, + mng_uint16 *iMethodY) +{ + mng_datap pData; + mng_magnp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_MAGN, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_magnp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.iChunkname != MNG_UINT_MAGN) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + + *iFirstid = pChunk->iFirstid; /* fill the fields */ + *iLastid = pChunk->iLastid; + *iMethodX = pChunk->iMethodX; + *iMX = pChunk->iMX; + *iMY = pChunk->iMY; + *iML = pChunk->iML; + *iMR = pChunk->iMR; + *iMT = pChunk->iMT; + *iMB = pChunk->iMB; + *iMethodY = pChunk->iMethodY; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getchunk_unknown (mng_handle hHandle, + mng_handle hChunk, + mng_chunkid *iChunkname, + mng_uint32 *iRawlen, + mng_ptr *pRawdata) +{ + mng_datap pData; + mng_unknown_chunkp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_UNKNOWN, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + pChunk = (mng_unknown_chunkp)hChunk; /* address the chunk */ + + if (pChunk->sHeader.fCreate != init_unknown) + MNG_ERROR (pData, MNG_WRONGCHUNK) /* ouch */ + /* fill the fields */ + *iChunkname = pChunk->sHeader.iChunkname; + *iRawlen = pChunk->iDatasize; + *pRawdata = pChunk->pData; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETCHUNK_UNKNOWN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_WRITE_PROCS +/* B004 */ +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_ihdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_IHDR, init_ihdr, free_ihdr, read_ihdr, write_ihdr, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* create the chunk */ + iRetcode = init_ihdr (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_ihdrp)pChunk)->iWidth = iWidth; + ((mng_ihdrp)pChunk)->iHeight = iHeight; + ((mng_ihdrp)pChunk)->iBitdepth = iBitdepth; + ((mng_ihdrp)pChunk)->iColortype = iColortype; + ((mng_ihdrp)pChunk)->iCompression = iCompression; + ((mng_ihdrp)pChunk)->iFilter = iFilter; + ((mng_ihdrp)pChunk)->iInterlace = iInterlace; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_plte (mng_handle hHandle, + mng_uint32 iCount, + mng_palette8 aPalette) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_PLTE, init_plte, free_plte, read_plte, write_plte, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PLTE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_plte (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_pltep)pChunk)->iEntrycount = iCount; + ((mng_pltep)pChunk)->bEmpty = (mng_bool)(iCount == 0); + + MNG_COPY (((mng_pltep)pChunk)->aEntries, aPalette, sizeof (mng_palette8)) + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_idat (mng_handle hHandle, + mng_uint32 iRawlen, + mng_ptr pRawdata) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_IDAT, init_idat, free_idat, read_idat, write_idat, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_idat (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_idatp)pChunk)->bEmpty = (mng_bool)(iRawlen == 0); + ((mng_idatp)pChunk)->iDatasize = iRawlen; + + if (iRawlen) + { + MNG_ALLOC (pData, ((mng_idatp)pChunk)->pData, iRawlen) + MNG_COPY (((mng_idatp)pChunk)->pData, pRawdata, iRawlen) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_iend (mng_handle hHandle) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_IEND, init_iend, free_iend, read_iend, write_iend, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IEND, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_iend (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_INCLUDE_JNG + if ((pData->iFirstchunkadded == MNG_UINT_IHDR) || + (pData->iFirstchunkadded == MNG_UINT_JHDR) ) +#else + if (pData->iFirstchunkadded == MNG_UINT_IHDR) +#endif + pData->bCreating = MNG_FALSE; /* should be last chunk !!! */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_trns (mng_handle hHandle, + mng_bool bEmpty, + mng_bool bGlobal, + mng_uint8 iType, + mng_uint32 iCount, + mng_uint8arr aAlphas, + mng_uint16 iGray, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint32 iRawlen, + mng_uint8arr aRawdata) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_tRNS, init_trns, free_trns, read_trns, write_trns, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TRNS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_trns (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_trnsp)pChunk)->bEmpty = bEmpty; + ((mng_trnsp)pChunk)->bGlobal = bGlobal; + ((mng_trnsp)pChunk)->iType = iType; + ((mng_trnsp)pChunk)->iCount = iCount; + ((mng_trnsp)pChunk)->iGray = iGray; + ((mng_trnsp)pChunk)->iRed = iRed; + ((mng_trnsp)pChunk)->iGreen = iGreen; + ((mng_trnsp)pChunk)->iBlue = iBlue; + ((mng_trnsp)pChunk)->iRawlen = iRawlen; + + MNG_COPY (((mng_trnsp)pChunk)->aEntries, aAlphas, sizeof (mng_uint8arr)) + MNG_COPY (((mng_trnsp)pChunk)->aRawdata, aRawdata, sizeof (mng_uint8arr)) + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_gama (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iGamma) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_gAMA, init_gama, free_gama, read_gama, write_gama, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_GAMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_gama (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_gamap)pChunk)->bEmpty = bEmpty; + ((mng_gamap)pChunk)->iGamma = iGamma; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_chrm (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iWhitepointx, + mng_uint32 iWhitepointy, + mng_uint32 iRedx, + mng_uint32 iRedy, + mng_uint32 iGreenx, + mng_uint32 iGreeny, + mng_uint32 iBluex, + mng_uint32 iBluey) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_cHRM, init_chrm, free_chrm, read_chrm, write_chrm, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_CHRM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_chrm (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_chrmp)pChunk)->bEmpty = bEmpty; + ((mng_chrmp)pChunk)->iWhitepointx = iWhitepointx; + ((mng_chrmp)pChunk)->iWhitepointy = iWhitepointy; + ((mng_chrmp)pChunk)->iRedx = iRedx; + ((mng_chrmp)pChunk)->iRedy = iRedy; + ((mng_chrmp)pChunk)->iGreenx = iGreenx; + ((mng_chrmp)pChunk)->iGreeny = iGreeny; + ((mng_chrmp)pChunk)->iBluex = iBluex; + ((mng_chrmp)pChunk)->iBluey = iBluey; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_srgb (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iRenderingintent) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_sRGB, init_srgb, free_srgb, read_srgb, write_srgb, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SRGB, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_srgb (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_srgbp)pChunk)->bEmpty = bEmpty; + ((mng_srgbp)pChunk)->iRenderingintent = iRenderingintent; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_iccp (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iNamesize, + mng_pchar zName, + mng_uint8 iCompression, + mng_uint32 iProfilesize, + mng_ptr pProfile) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_iCCP, init_iccp, free_iccp, read_iccp, write_iccp, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ICCP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_iccp (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_iccpp)pChunk)->bEmpty = bEmpty; + ((mng_iccpp)pChunk)->iNamesize = iNamesize; + ((mng_iccpp)pChunk)->iCompression = iCompression; + ((mng_iccpp)pChunk)->iProfilesize = iProfilesize; + + if (iNamesize) + { + MNG_ALLOC (pData, ((mng_iccpp)pChunk)->zName, iNamesize + 1) + MNG_COPY (((mng_iccpp)pChunk)->zName, zName, iNamesize) + } + + if (iProfilesize) + { + MNG_ALLOC (pData, ((mng_iccpp)pChunk)->pProfile, iProfilesize) + MNG_COPY (((mng_iccpp)pChunk)->pProfile, pProfile, iProfilesize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_text (mng_handle hHandle, + mng_uint32 iKeywordsize, + mng_pchar zKeyword, + mng_uint32 iTextsize, + mng_pchar zText) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_tEXt, init_text, free_text, read_text, write_text, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TEXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_text (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_textp)pChunk)->iKeywordsize = iKeywordsize; + ((mng_textp)pChunk)->iTextsize = iTextsize; + + if (iKeywordsize) + { + MNG_ALLOC (pData, ((mng_textp)pChunk)->zKeyword, iKeywordsize + 1) + MNG_COPY (((mng_textp)pChunk)->zKeyword, zKeyword, iKeywordsize) + } + + if (iTextsize) + { + MNG_ALLOC (pData, ((mng_textp)pChunk)->zText, iTextsize + 1) + MNG_COPY (((mng_textp)pChunk)->zText, zText, iTextsize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TEXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_ztxt (mng_handle hHandle, + mng_uint32 iKeywordsize, + mng_pchar zKeyword, + mng_uint8 iCompression, + mng_uint32 iTextsize, + mng_pchar zText) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_zTXt, init_ztxt, free_ztxt, read_ztxt, write_ztxt, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ZTXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_ztxt (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_ztxtp)pChunk)->iKeywordsize = iKeywordsize; + ((mng_ztxtp)pChunk)->iCompression = iCompression; + ((mng_ztxtp)pChunk)->iTextsize = iTextsize; + + if (iKeywordsize) + { + MNG_ALLOC (pData, ((mng_ztxtp)pChunk)->zKeyword, iKeywordsize + 1) + MNG_COPY (((mng_ztxtp)pChunk)->zKeyword, zKeyword, iKeywordsize) + } + + if (iTextsize) + { + MNG_ALLOC (pData, ((mng_ztxtp)pChunk)->zText, iTextsize + 1) + MNG_COPY (((mng_ztxtp)pChunk)->zText, zText, iTextsize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ZTXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_itxt (mng_handle hHandle, + mng_uint32 iKeywordsize, + mng_pchar zKeyword, + mng_uint8 iCompressionflag, + mng_uint8 iCompressionmethod, + mng_uint32 iLanguagesize, + mng_pchar zLanguage, + mng_uint32 iTranslationsize, + mng_pchar zTranslation, + mng_uint32 iTextsize, + mng_pchar zText) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_iTXt, init_itxt, free_itxt, read_itxt, write_itxt, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ITXT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_itxt (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_itxtp)pChunk)->iKeywordsize = iKeywordsize; + ((mng_itxtp)pChunk)->iCompressionflag = iCompressionflag; + ((mng_itxtp)pChunk)->iCompressionmethod = iCompressionmethod; + ((mng_itxtp)pChunk)->iLanguagesize = iLanguagesize; + ((mng_itxtp)pChunk)->iTranslationsize = iTranslationsize; + ((mng_itxtp)pChunk)->iTextsize = iTextsize; + + if (iKeywordsize) + { + MNG_ALLOC (pData, ((mng_itxtp)pChunk)->zKeyword, iKeywordsize + 1) + MNG_COPY (((mng_itxtp)pChunk)->zKeyword, zKeyword, iKeywordsize) + } + + if (iLanguagesize) + { + MNG_ALLOC (pData, ((mng_itxtp)pChunk)->zLanguage, iLanguagesize + 1) + MNG_COPY (((mng_itxtp)pChunk)->zLanguage, zLanguage, iLanguagesize) + } + + if (iTranslationsize) + { + MNG_ALLOC (pData, ((mng_itxtp)pChunk)->zTranslation, iTranslationsize + 1) + MNG_COPY (((mng_itxtp)pChunk)->zTranslation, zTranslation, iTranslationsize) + } + + if (iTextsize) + { + MNG_ALLOC (pData, ((mng_itxtp)pChunk)->zText, iTextsize + 1) + MNG_COPY (((mng_itxtp)pChunk)->zText, zText, iTextsize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ITXT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_bkgd (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iType, + mng_uint8 iIndex, + mng_uint16 iGray, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_bKGD, init_bkgd, free_bkgd, read_bkgd, write_bkgd, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_BKGD, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_bkgd (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_bkgdp)pChunk)->bEmpty = bEmpty; + ((mng_bkgdp)pChunk)->iType = iType; + ((mng_bkgdp)pChunk)->iIndex = iIndex; + ((mng_bkgdp)pChunk)->iGray = iGray; + ((mng_bkgdp)pChunk)->iRed = iRed; + ((mng_bkgdp)pChunk)->iGreen = iGreen; + ((mng_bkgdp)pChunk)->iBlue = iBlue; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_phys (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iSizex, + mng_uint32 iSizey, + mng_uint8 iUnit) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_pHYs, init_phys, free_phys, read_phys, write_phys, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PHYS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_phys (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_physp)pChunk)->bEmpty = bEmpty; + ((mng_physp)pChunk)->iSizex = iSizex; + ((mng_physp)pChunk)->iSizey = iSizey; + ((mng_physp)pChunk)->iUnit = iUnit; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PHYS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_sbit (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iType, + mng_uint8arr4 aBits) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_sBIT, init_sbit, free_sbit, read_sbit, write_sbit, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SBIT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_sbit (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_sbitp)pChunk)->bEmpty = bEmpty; + ((mng_sbitp)pChunk)->iType = iType; + ((mng_sbitp)pChunk)->aBits[0] = aBits[0]; + ((mng_sbitp)pChunk)->aBits[1] = aBits[1]; + ((mng_sbitp)pChunk)->aBits[2] = aBits[2]; + ((mng_sbitp)pChunk)->aBits[3] = aBits[3]; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SBIT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_splt (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iNamesize, + mng_pchar zName, + mng_uint8 iSampledepth, + mng_uint32 iEntrycount, + mng_ptr pEntries) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_sPLT, init_splt, free_splt, read_splt, write_splt, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SPLT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_splt (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_spltp)pChunk)->bEmpty = bEmpty; + ((mng_spltp)pChunk)->iNamesize = iNamesize; + ((mng_spltp)pChunk)->iSampledepth = iSampledepth; + ((mng_spltp)pChunk)->iEntrycount = iEntrycount; + + if (iNamesize) + { + MNG_ALLOC (pData, ((mng_spltp)pChunk)->zName, iNamesize + 1) + MNG_COPY (((mng_spltp)pChunk)->zName, zName, iNamesize) + } + + if (iEntrycount) + { + mng_uint32 iSize = iEntrycount * ((iSampledepth >> 1) + 2); + + MNG_ALLOC (pData, ((mng_spltp)pChunk)->pEntries, iSize) + MNG_COPY (((mng_spltp)pChunk)->pEntries, pEntries, iSize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_hist (mng_handle hHandle, + mng_uint32 iEntrycount, + mng_uint16arr aEntries) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_hIST, init_hist, free_hist, read_hist, write_hist, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_HIST, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_hist (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_histp)pChunk)->iEntrycount = iEntrycount; + + MNG_COPY (((mng_histp)pChunk)->aEntries, aEntries, sizeof (mng_uint16arr)) + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_HIST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_time (mng_handle hHandle, + mng_uint16 iYear, + mng_uint8 iMonth, + mng_uint8 iDay, + mng_uint8 iHour, + mng_uint8 iMinute, + mng_uint8 iSecond) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_tIME, init_time, free_time, read_time, write_time, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TIME, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_time (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_timep)pChunk)->iYear = iYear; + ((mng_timep)pChunk)->iMonth = iMonth; + ((mng_timep)pChunk)->iDay = iDay; + ((mng_timep)pChunk)->iHour = iHour; + ((mng_timep)pChunk)->iMinute = iMinute; + ((mng_timep)pChunk)->iSecond = iSecond; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TIME, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_mhdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint32 iTicks, + mng_uint32 iLayercount, + mng_uint32 iFramecount, + mng_uint32 iPlaytime, + mng_uint32 iSimplicity) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_MHDR, init_mhdr, free_mhdr, read_mhdr, write_mhdr, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* create the chunk */ + iRetcode = init_mhdr (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_mhdrp)pChunk)->iWidth = iWidth; + ((mng_mhdrp)pChunk)->iHeight = iHeight; + ((mng_mhdrp)pChunk)->iTicks = iTicks; + ((mng_mhdrp)pChunk)->iLayercount = iLayercount; + ((mng_mhdrp)pChunk)->iFramecount = iFramecount; + ((mng_mhdrp)pChunk)->iPlaytime = iPlaytime; + ((mng_mhdrp)pChunk)->iSimplicity = iSimplicity; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_mend (mng_handle hHandle) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_MEND, init_mend, free_mend, read_mend, write_mend, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MEND, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_mend (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + add_chunk (pData, pChunk); /* add it to the list */ + + pData->bCreating = MNG_FALSE; /* should be last chunk !!! */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_loop (mng_handle hHandle, + mng_uint8 iLevel, + mng_uint32 iRepeat, + mng_uint8 iTermination, + mng_uint32 iItermin, + mng_uint32 iItermax, + mng_uint32 iCount, + mng_uint32p pSignals) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_LOOP, init_loop, free_loop, read_loop, write_loop, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_LOOP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_loop (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_loopp)pChunk)->iLevel = iLevel; + ((mng_loopp)pChunk)->iRepeat = iRepeat; + ((mng_loopp)pChunk)->iTermination = iTermination; + ((mng_loopp)pChunk)->iItermin = iItermin; + ((mng_loopp)pChunk)->iItermax = iItermax; + ((mng_loopp)pChunk)->iCount = iCount; + ((mng_loopp)pChunk)->pSignals = pSignals; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_endl (mng_handle hHandle, + mng_uint8 iLevel) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_ENDL, init_endl, free_endl, read_endl, write_endl, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ENDL, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_endl (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_endlp)pChunk)->iLevel = iLevel; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_defi (mng_handle hHandle, + mng_uint16 iObjectid, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_int32 iXlocation, + mng_int32 iYlocation, + mng_bool bHasclip, + mng_int32 iLeftcb, + mng_int32 iRightcb, + mng_int32 iTopcb, + mng_int32 iBottomcb) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_DEFI, init_defi, free_defi, read_defi, write_defi, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DEFI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_defi (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_defip)pChunk)->iObjectid = iObjectid; + ((mng_defip)pChunk)->iDonotshow = iDonotshow; + ((mng_defip)pChunk)->iConcrete = iConcrete; + ((mng_defip)pChunk)->bHasloca = bHasloca; + ((mng_defip)pChunk)->iXlocation = iXlocation; + ((mng_defip)pChunk)->iYlocation = iYlocation; + ((mng_defip)pChunk)->bHasclip = bHasclip; + ((mng_defip)pChunk)->iLeftcb = iLeftcb; + ((mng_defip)pChunk)->iRightcb = iRightcb; + ((mng_defip)pChunk)->iTopcb = iTopcb; + ((mng_defip)pChunk)->iBottomcb = iBottomcb; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_basi (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint16 iAlpha, + mng_uint8 iViewable) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_BASI, init_basi, free_basi, read_basi, write_basi, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_BASI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_basi (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_basip)pChunk)->iWidth = iWidth; + ((mng_basip)pChunk)->iHeight = iHeight; + ((mng_basip)pChunk)->iBitdepth = iBitdepth; + ((mng_basip)pChunk)->iColortype = iColortype; + ((mng_basip)pChunk)->iCompression = iCompression; + ((mng_basip)pChunk)->iFilter = iFilter; + ((mng_basip)pChunk)->iInterlace = iInterlace; + ((mng_basip)pChunk)->iRed = iRed; + ((mng_basip)pChunk)->iGreen = iGreen; + ((mng_basip)pChunk)->iBlue = iBlue; + ((mng_basip)pChunk)->iAlpha = iAlpha; + ((mng_basip)pChunk)->iViewable = iViewable; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_clon (mng_handle hHandle, + mng_uint16 iSourceid, + mng_uint16 iCloneid, + mng_uint8 iClonetype, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_CLON, init_clon, free_clon, read_clon, write_clon, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_CLON, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_clon (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_clonp)pChunk)->iSourceid = iSourceid; + ((mng_clonp)pChunk)->iCloneid = iCloneid; + ((mng_clonp)pChunk)->iClonetype = iClonetype; + ((mng_clonp)pChunk)->iDonotshow = iDonotshow; + ((mng_clonp)pChunk)->iConcrete = iConcrete; + ((mng_clonp)pChunk)->bHasloca = bHasloca; + ((mng_clonp)pChunk)->iLocationtype = iLocationtype; + ((mng_clonp)pChunk)->iLocationx = iLocationx; + ((mng_clonp)pChunk)->iLocationy = iLocationy; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_past (mng_handle hHandle, + mng_uint16 iDestid, + mng_uint8 iTargettype, + mng_int32 iTargetx, + mng_int32 iTargety, + mng_uint32 iCount) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_PAST, init_past, free_past, read_past, write_past, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PAST, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_past (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_pastp)pChunk)->iDestid = iDestid; + ((mng_pastp)pChunk)->iTargettype = iTargettype; + ((mng_pastp)pChunk)->iTargetx = iTargetx; + ((mng_pastp)pChunk)->iTargety = iTargety; + ((mng_pastp)pChunk)->iCount = iCount; + + if (iCount) + MNG_ALLOC (pData, ((mng_pastp)pChunk)->pSources, iCount * sizeof (mng_past_source)) + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PAST, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_past_src (mng_handle hHandle, + mng_uint32 iEntry, + mng_uint16 iSourceid, + mng_uint8 iComposition, + mng_uint8 iOrientation, + mng_uint8 iOffsettype, + mng_int32 iOffsetx, + mng_int32 iOffsety, + mng_uint8 iBoundarytype, + mng_int32 iBoundaryl, + mng_int32 iBoundaryr, + mng_int32 iBoundaryt, + mng_int32 iBoundaryb) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_past_sourcep pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PAST_SRC, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + + pChunk = pData->pLastchunk; /* last one must have been PAST ! */ + + if (((mng_chunk_headerp)pChunk)->iChunkname != MNG_UINT_PAST) + MNG_ERROR (pData, MNG_NOCORRCHUNK) + /* index out of bounds ? */ + if (iEntry >= ((mng_pastp)pChunk)->iCount) + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + /* address proper entry */ + pEntry = ((mng_pastp)pChunk)->pSources + iEntry; + + pEntry->iSourceid = iSourceid; /* fill entry */ + pEntry->iComposition = iComposition; + pEntry->iOrientation = iOrientation; + pEntry->iOffsettype = iOffsettype; + pEntry->iOffsetx = iOffsetx; + pEntry->iOffsety = iOffsety; + pEntry->iBoundarytype = iBoundarytype; + pEntry->iBoundaryl = iBoundaryl; + pEntry->iBoundaryr = iBoundaryr; + pEntry->iBoundaryt = iBoundaryt; + pEntry->iBoundaryb = iBoundaryb; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PAST_SRC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_disc (mng_handle hHandle, + mng_uint32 iCount, + mng_uint16p pObjectids) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_DISC, init_disc, free_disc, read_disc, write_disc, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DISC, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_disc (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_discp)pChunk)->iCount = iCount; + + if (iCount) + { + mng_uint32 iSize = iCount * sizeof (mng_uint32); + + MNG_ALLOC (pData, ((mng_discp)pChunk)->pObjectids, iSize); + MNG_COPY (((mng_discp)pChunk)->pObjectids, pObjectids, iSize); + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DISC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_back (mng_handle hHandle, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint8 iMandatory, + mng_uint16 iImageid, + mng_uint8 iTile) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_BACK, init_back, free_back, read_back, write_back, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_BACK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_back (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_backp)pChunk)->iRed = iRed; + ((mng_backp)pChunk)->iGreen = iGreen; + ((mng_backp)pChunk)->iBlue = iBlue; + ((mng_backp)pChunk)->iMandatory = iMandatory; + ((mng_backp)pChunk)->iImageid = iImageid; + ((mng_backp)pChunk)->iTile = iTile; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_fram (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iMode, + mng_uint32 iNamesize, + mng_pchar zName, + mng_uint8 iChangedelay, + mng_uint8 iChangetimeout, + mng_uint8 iChangeclipping, + mng_uint8 iChangesyncid, + mng_uint32 iDelay, + mng_uint32 iTimeout, + mng_uint8 iBoundarytype, + mng_int32 iBoundaryl, + mng_int32 iBoundaryr, + mng_int32 iBoundaryt, + mng_int32 iBoundaryb, + mng_uint32 iCount, + mng_uint32p pSyncids) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_FRAM, init_fram, free_fram, read_fram, write_fram, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_FRAM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_fram (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_framp)pChunk)->bEmpty = bEmpty; + ((mng_framp)pChunk)->iMode = iMode; + ((mng_framp)pChunk)->iNamesize = iNamesize; + ((mng_framp)pChunk)->iChangedelay = iChangedelay; + ((mng_framp)pChunk)->iChangetimeout = iChangetimeout; + ((mng_framp)pChunk)->iChangeclipping = iChangeclipping; + ((mng_framp)pChunk)->iChangesyncid = iChangesyncid; + ((mng_framp)pChunk)->iDelay = iDelay; + ((mng_framp)pChunk)->iTimeout = iTimeout; + ((mng_framp)pChunk)->iBoundarytype = iBoundarytype; + ((mng_framp)pChunk)->iBoundaryl = iBoundaryl; + ((mng_framp)pChunk)->iBoundaryr = iBoundaryr; + ((mng_framp)pChunk)->iBoundaryt = iBoundaryt; + ((mng_framp)pChunk)->iBoundaryb = iBoundaryb; + ((mng_framp)pChunk)->iCount = iCount; + + if (iNamesize) + { + MNG_ALLOC (pData, ((mng_framp)pChunk)->zName, iNamesize + 1) + MNG_COPY (((mng_framp)pChunk)->zName, zName, iNamesize) + } + + if (iCount) + { + mng_uint32 iSize = iCount * sizeof (mng_uint32); + + MNG_ALLOC (pData, ((mng_framp)pChunk)->pSyncids, iSize) + MNG_COPY (((mng_framp)pChunk)->pSyncids, pSyncids, iSize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_FRAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_move (mng_handle hHandle, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iMovetype, + mng_int32 iMovex, + mng_int32 iMovey) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_MOVE, init_move, free_move, read_move, write_move, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MOVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_move (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_movep)pChunk)->iFirstid = iFirstid; + ((mng_movep)pChunk)->iLastid = iLastid; + ((mng_movep)pChunk)->iMovetype = iMovetype; + ((mng_movep)pChunk)->iMovex = iMovex; + ((mng_movep)pChunk)->iMovey = iMovey; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_clip (mng_handle hHandle, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_CLIP, init_clip, free_clip, read_clip, write_clip, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_CLIP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_clip (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_clipp)pChunk)->iFirstid = iFirstid; + ((mng_clipp)pChunk)->iLastid = iLastid; + ((mng_clipp)pChunk)->iCliptype = iCliptype; + ((mng_clipp)pChunk)->iClipl = iClipl; + ((mng_clipp)pChunk)->iClipr = iClipr; + ((mng_clipp)pChunk)->iClipt = iClipt; + ((mng_clipp)pChunk)->iClipb = iClipb; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_show (mng_handle hHandle, + mng_bool bEmpty, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iMode) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_SHOW, init_show, free_show, read_show, write_show, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SHOW, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_show (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_showp)pChunk)->bEmpty = bEmpty; + ((mng_showp)pChunk)->iFirstid = iFirstid; + ((mng_showp)pChunk)->iLastid = iLastid; + ((mng_showp)pChunk)->iMode = iMode; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_term (mng_handle hHandle, + mng_uint8 iTermaction, + mng_uint8 iIteraction, + mng_uint32 iDelay, + mng_uint32 iItermax) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_TERM, init_term, free_term, read_term, write_term, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TERM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_term (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_termp)pChunk)->iTermaction = iTermaction; + ((mng_termp)pChunk)->iIteraction = iIteraction; + ((mng_termp)pChunk)->iDelay = iDelay; + ((mng_termp)pChunk)->iItermax = iItermax; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_save (mng_handle hHandle, + mng_bool bEmpty, + mng_uint8 iOffsettype, + mng_uint32 iCount) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_SAVE, init_save, free_save, read_save, write_save, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SAVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_save (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_savep)pChunk)->bEmpty = bEmpty; + ((mng_savep)pChunk)->iOffsettype = iOffsettype; + ((mng_savep)pChunk)->iCount = iCount; + + if (iCount) + MNG_ALLOC (pData, ((mng_savep)pChunk)->pEntries, iCount * sizeof (mng_save_entry)) + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_save_entry (mng_handle hHandle, + mng_uint32 iEntry, + mng_uint8 iEntrytype, + mng_uint32arr2 iOffset, + mng_uint32arr2 iStarttime, + mng_uint32 iLayernr, + mng_uint32 iFramenr, + mng_uint32 iNamesize, + mng_pchar zName) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_save_entryp pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SAVE_ENTRY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + + pChunk = pData->pLastchunk; /* last one must have been SAVE ! */ + + if (((mng_chunk_headerp)pChunk)->iChunkname != MNG_UINT_SAVE) + MNG_ERROR (pData, MNG_NOCORRCHUNK) + /* index out of bounds ? */ + if (iEntry >= ((mng_savep)pChunk)->iCount) + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + /* address proper entry */ + pEntry = ((mng_savep)pChunk)->pEntries + iEntry; + + pEntry->iEntrytype = iEntrytype; /* fill entry */ + pEntry->iOffset[0] = iOffset[0]; + pEntry->iOffset[1] = iOffset[1]; + pEntry->iStarttime[0] = iStarttime[0]; + pEntry->iStarttime[1] = iStarttime[1]; + pEntry->iLayernr = iLayernr; + pEntry->iFramenr = iFramenr; + pEntry->iNamesize = iNamesize; + + if (iNamesize) + { + MNG_ALLOC (pData, pEntry->zName, iNamesize + 1) + MNG_COPY (pEntry->zName, zName, iNamesize) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SAVE_ENTRY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_seek (mng_handle hHandle, + mng_uint32 iNamesize, + mng_pchar zName) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_SEEK, init_seek, free_seek, read_seek, write_seek, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SEEK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_seek (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_seekp)pChunk)->iNamesize = iNamesize; + + if (iNamesize) + { + MNG_ALLOC (pData, ((mng_seekp)pChunk)->zName, iNamesize + 1) + MNG_COPY (((mng_seekp)pChunk)->zName, zName, iNamesize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_expi (mng_handle hHandle, + mng_uint16 iSnapshotid, + mng_uint32 iNamesize, + mng_pchar zName) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_eXPI, init_expi, free_expi, read_expi, write_expi, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_EXPI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_expi (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_expip)pChunk)->iSnapshotid = iSnapshotid; + ((mng_expip)pChunk)->iNamesize = iNamesize; + + if (iNamesize) + { + MNG_ALLOC (pData, ((mng_expip)pChunk)->zName, iNamesize + 1) + MNG_COPY (((mng_expip)pChunk)->zName, zName, iNamesize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_EXPI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_fpri (mng_handle hHandle, + mng_uint8 iDeltatype, + mng_uint8 iPriority) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_fPRI, init_fpri, free_fpri, read_fpri, write_fpri, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_FPRI, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_fpri (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_fprip)pChunk)->iDeltatype = iDeltatype; + ((mng_fprip)pChunk)->iPriority = iPriority; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_FPRI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_need (mng_handle hHandle, + mng_uint32 iKeywordssize, + mng_pchar zKeywords) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_nEED, init_need, free_need, read_need, write_need, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_NEED, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_need (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_needp)pChunk)->iKeywordssize = iKeywordssize; + + if (iKeywordssize) + { + MNG_ALLOC (pData, ((mng_needp)pChunk)->zKeywords, iKeywordssize + 1) + MNG_COPY (((mng_needp)pChunk)->zKeywords, zKeywords, iKeywordssize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_NEED, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_phyg (mng_handle hHandle, + mng_bool bEmpty, + mng_uint32 iSizex, + mng_uint32 iSizey, + mng_uint8 iUnit) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_pHYg, init_phyg, free_phyg, read_phyg, write_phyg, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PHYG, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_phyg (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_phygp)pChunk)->bEmpty = bEmpty; + ((mng_phygp)pChunk)->iSizex = iSizex; + ((mng_phygp)pChunk)->iSizey = iSizey; + ((mng_phygp)pChunk)->iUnit = iUnit; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PHYG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +mng_retcode MNG_DECL mng_putchunk_jhdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iColortype, + mng_uint8 iImagesampledepth, + mng_uint8 iImagecompression, + mng_uint8 iImageinterlace, + mng_uint8 iAlphasampledepth, + mng_uint8 iAlphacompression, + mng_uint8 iAlphafilter, + mng_uint8 iAlphainterlace) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_JHDR, init_jhdr, free_jhdr, read_jhdr, write_jhdr, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_JHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* create the chunk */ + iRetcode = init_jhdr (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_jhdrp)pChunk)->iWidth = iWidth; + ((mng_jhdrp)pChunk)->iHeight = iHeight; + ((mng_jhdrp)pChunk)->iColortype = iColortype; + ((mng_jhdrp)pChunk)->iImagesampledepth = iImagesampledepth; + ((mng_jhdrp)pChunk)->iImagecompression = iImagecompression; + ((mng_jhdrp)pChunk)->iImageinterlace = iImageinterlace; + ((mng_jhdrp)pChunk)->iAlphasampledepth = iAlphasampledepth; + ((mng_jhdrp)pChunk)->iAlphacompression = iAlphacompression; + ((mng_jhdrp)pChunk)->iAlphafilter = iAlphafilter; + ((mng_jhdrp)pChunk)->iAlphainterlace = iAlphainterlace; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_JHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +mng_retcode MNG_DECL mng_putchunk_jdat (mng_handle hHandle, + mng_uint32 iRawlen, + mng_ptr pRawdata) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_JDAT, init_jdat, free_jdat, read_jdat, write_jdat, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_JDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR or JHDR first! */ + if ((pData->iFirstchunkadded != MNG_UINT_MHDR) && + (pData->iFirstchunkadded != MNG_UINT_JHDR) ) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_jdat (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_jdatp)pChunk)->iDatasize = iRawlen; + + if (iRawlen) + { + MNG_ALLOC (pData, ((mng_jdatp)pChunk)->pData, iRawlen) + MNG_COPY (((mng_jdatp)pChunk)->pData, pRawdata, iRawlen) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_JDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_JNG +/* B004 */ +mng_retcode MNG_DECL mng_putchunk_jsep (mng_handle hHandle) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_JSEP, init_jsep, free_jsep, read_jsep, write_jsep, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_JSEP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR or JHDR first! */ + if ((pData->iFirstchunkadded != MNG_UINT_MHDR) && + (pData->iFirstchunkadded != MNG_UINT_JHDR) ) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_jsep (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_JSEP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +/* B004 */ +#endif /* MNG_INCLUDE_JNG */ +/* B004 */ +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_dhdr (mng_handle hHandle, + mng_uint16 iObjectid, + mng_uint8 iImagetype, + mng_uint8 iDeltatype, + mng_uint32 iBlockwidth, + mng_uint32 iBlockheight, + mng_uint32 iBlockx, + mng_uint32 iBlocky) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_DHDR, init_dhdr, free_dhdr, read_dhdr, write_dhdr, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DHDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_dhdr (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_dhdrp)pChunk)->iObjectid = iObjectid; + ((mng_dhdrp)pChunk)->iImagetype = iImagetype; + ((mng_dhdrp)pChunk)->iDeltatype = iDeltatype; + ((mng_dhdrp)pChunk)->iBlockwidth = iBlockwidth; + ((mng_dhdrp)pChunk)->iBlockheight = iBlockheight; + ((mng_dhdrp)pChunk)->iBlockx = iBlockx; + ((mng_dhdrp)pChunk)->iBlocky = iBlocky; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_prom (mng_handle hHandle, + mng_uint8 iColortype, + mng_uint8 iSampledepth, + mng_uint8 iFilltype) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_PROM, init_prom, free_prom, read_prom, write_prom, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PROM, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_prom (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_promp)pChunk)->iColortype = iColortype; + ((mng_promp)pChunk)->iSampledepth = iSampledepth; + ((mng_promp)pChunk)->iFilltype = iFilltype; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_ipng (mng_handle hHandle) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_IPNG, init_ipng, free_ipng, read_ipng, write_ipng, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IPNG, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_ipng (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_pplt (mng_handle hHandle, + mng_uint32 iCount) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_PPLT, init_pplt, free_pplt, read_pplt, write_pplt, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PPLT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_pplt (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_ppltp)pChunk)->iCount = iCount; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_pplt_entry (mng_handle hHandle, + mng_uint32 iEntry, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint16 iAlpha, + mng_bool bUsed) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_pplt_entryp pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PPLT_ENTRY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + + pChunk = pData->pLastchunk; /* last one must have been PPLT ! */ + + if (((mng_chunk_headerp)pChunk)->iChunkname != MNG_UINT_PPLT) + MNG_ERROR (pData, MNG_NOCORRCHUNK) + + /* index out of bounds ? */ + if (iEntry >= ((mng_ppltp)pChunk)->iCount) + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + /* address proper entry */ + pEntry = (mng_pplt_entryp)(((mng_ppltp)pChunk)->aEntries) + iEntry; + + pEntry->iRed = (mng_uint8)iRed; /* fill the entry */ + pEntry->iGreen = (mng_uint8)iGreen; + pEntry->iBlue = (mng_uint8)iBlue; + pEntry->iAlpha = (mng_uint8)iAlpha; + pEntry->bUsed = bUsed; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_PPLT_ENTRY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_ijng (mng_handle hHandle) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_IJNG, init_ijng, free_ijng, read_ijng, write_ijng, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IJNG, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_ijng (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_drop (mng_handle hHandle, + mng_uint32 iCount, + mng_chunkidp pChunknames) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_DROP, init_drop, free_drop, read_drop, write_drop, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DROP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_drop (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_dropp)pChunk)->iCount = iCount; + + if (iCount) + { + mng_uint32 iSize = iCount * sizeof (mng_chunkid); + + MNG_ALLOC (pData, ((mng_dropp)pChunk)->pChunknames, iSize) + MNG_COPY (((mng_dropp)pChunk)->pChunknames, pChunknames, iSize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DROP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_dbyk (mng_handle hHandle, + mng_chunkid iChunkname, + mng_uint8 iPolarity, + mng_uint32 iKeywordssize, + mng_pchar zKeywords) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_DBYK, init_dbyk, free_dbyk, read_dbyk, write_dbyk, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DBYK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_dbyk (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_dbykp)pChunk)->iChunkname = iChunkname; + ((mng_dbykp)pChunk)->iPolarity = iPolarity; + ((mng_dbykp)pChunk)->iKeywordssize = iKeywordssize; + + if (iKeywordssize) + { + MNG_ALLOC (pData, ((mng_dbykp)pChunk)->zKeywords, iKeywordssize + 1) + MNG_COPY (((mng_dbykp)pChunk)->zKeywords, zKeywords, iKeywordssize) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_DBYK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_ordr (mng_handle hHandle, + mng_uint32 iCount) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_ORDR, init_ordr, free_ordr, read_ordr, write_ordr, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ORDR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_ordr (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_ordrp)pChunk)->iCount = iCount; + + if (iCount) + MNG_ALLOC (pData, ((mng_ordrp)pChunk)->pEntries, iCount * sizeof (mng_ordr_entry)) + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ORDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_ordr_entry (mng_handle hHandle, + mng_uint32 iEntry, + mng_chunkid iChunkname, + mng_uint8 iOrdertype) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_ordr_entryp pEntry; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ORDR_ENTRY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + + pChunk = pData->pLastchunk; /* last one must have been ORDR ! */ + + if (((mng_chunk_headerp)pChunk)->iChunkname != MNG_UINT_ORDR) + MNG_ERROR (pData, MNG_NOCORRCHUNK) + /* index out of bounds ? */ + if (iEntry >= ((mng_ordrp)pChunk)->iCount) + MNG_ERROR (pData, MNG_INVALIDENTRYIX) + /* address proper entry */ + pEntry = ((mng_ordrp)pChunk)->pEntries + iEntry; + + pEntry->iChunkname = iChunkname; /* fill the entry */ + pEntry->iOrdertype = iOrdertype; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_ORDR_ENTRY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_magn (mng_handle hHandle, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint16 iMethodX, + mng_uint16 iMX, + mng_uint16 iMY, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint16 iMT, + mng_uint16 iMB, + mng_uint16 iMethodY) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_MAGN, init_magn, free_magn, read_magn, write_magn, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MAGN, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a MHDR first! */ + if (pData->iFirstchunkadded != MNG_UINT_MHDR) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_magn (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_magnp)pChunk)->iFirstid = iFirstid; + ((mng_magnp)pChunk)->iLastid = iLastid; + ((mng_magnp)pChunk)->iMethodX = iMethodX; + ((mng_magnp)pChunk)->iMX = iMX; + ((mng_magnp)pChunk)->iMY = iMY; + ((mng_magnp)pChunk)->iML = iML; + ((mng_magnp)pChunk)->iMR = iMR; + ((mng_magnp)pChunk)->iMT = iMT; + ((mng_magnp)pChunk)->iMB = iMB; + ((mng_magnp)pChunk)->iMethodY = iMethodY; + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putchunk_unknown (mng_handle hHandle, + mng_chunkid iChunkname, + mng_uint32 iRawlen, + mng_ptr pRawdata) +{ + mng_datap pData; + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_chunk_header sChunkheader = + {MNG_UINT_HUH, init_unknown, free_unknown, read_unknown, write_unknown, 0, 0}; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_UNKNOWN, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must have had a header first! */ + if (pData->iFirstchunkadded == 0) + MNG_ERROR (pData, MNG_NOHEADER) + /* create the chunk */ + iRetcode = init_unknown (pData, &sChunkheader, &pChunk); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fill the chunk */ + ((mng_unknown_chunkp)pChunk)->sHeader.iChunkname = iChunkname; + ((mng_unknown_chunkp)pChunk)->iDatasize = iRawlen; + + if (iRawlen) + { + MNG_ALLOC (pData, ((mng_unknown_chunkp)pChunk)->pData, iRawlen) + MNG_COPY (((mng_unknown_chunkp)pChunk)->pData, pRawdata, iRawlen) + } + + add_chunk (pData, pChunk); /* add it to the list */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTCHUNK_UNKNOWN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* B004 */ +#endif /* MNG_INCLUDE_WRITE_PROCS */ +/* B004 */ +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getimgdata_seq (mng_handle hHandle, + mng_uint32 iSeqnr, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETIMGDATA_SEQ, MNG_LC_START) +#endif + + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETIMGDATA_SEQ, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getimgdata_chunkseq (mng_handle hHandle, + mng_uint32 iSeqnr, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETIMGDATA_CHUNKSEQ, MNG_LC_START) +#endif + + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETIMGDATA_CHUNKSEQ, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getimgdata_chunk (mng_handle hHandle, + mng_handle hChunk, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETIMGDATA_CHUNK, MNG_LC_START) +#endif + + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETIMGDATA_CHUNK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ +/* B004 */ +#ifdef MNG_INCLUDE_WRITE_PROCS +/* B004 */ +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putimgdata_ihdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iColortype, + mng_uint8 iBitdepth, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTIMGDATA_IHDR, MNG_LC_START) +#endif + + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTIMGDATA_IHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_putimgdata_jhdr (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iColortype, + mng_uint8 iBitdepth, + mng_uint8 iCompression, + mng_uint8 iInterlace, + mng_uint8 iAlphaBitdepth, + mng_uint8 iAlphaCompression, + mng_uint8 iAlphaFilter, + mng_uint8 iAlphaInterlace, + mng_uint32 iCanvasstyle, + mng_getcanvasline fGetcanvasline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTIMGDATA_JHDR, MNG_LC_START) +#endif + + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_PUTIMGDATA_JHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_updatemngheader (mng_handle hHandle, + mng_uint32 iFramecount, + mng_uint32 iLayercount, + mng_uint32 iPlaytime) +{ + mng_datap pData; + mng_chunkp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_UPDATEMNGHEADER, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must be a MNG animation! */ + if ((pData->eImagetype != mng_it_mng) || (pData->iFirstchunkadded != MNG_UINT_MHDR)) + MNG_ERROR (pData, MNG_NOMHDR) + + pChunk = pData->pFirstchunk; /* get the first chunk */ + /* and update the variables */ + ((mng_mhdrp)pChunk)->iFramecount = iFramecount; + ((mng_mhdrp)pChunk)->iLayercount = iLayercount; + ((mng_mhdrp)pChunk)->iPlaytime = iPlaytime; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_UPDATEMNGHEADER, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_updatemngsimplicity (mng_handle hHandle, + mng_uint32 iSimplicity) +{ + mng_datap pData; + mng_chunkp pChunk; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_UPDATEMNGSIMPLICITY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = (mng_datap)hHandle; /* and make it addressable */ + + if (!pData->bCreating) /* aren't we creating a new file ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + /* must be a MNG animation! */ + if ((pData->eImagetype != mng_it_mng) || (pData->iFirstchunkadded != MNG_UINT_MHDR)) + MNG_ERROR (pData, MNG_NOMHDR) + + pChunk = pData->pFirstchunk; /* get the first chunk */ + /* and update the variable */ + ((mng_mhdrp)pChunk)->iSimplicity = iSimplicity; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_UPDATEMNGSIMPLICITY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* B004 */ +#endif /* MNG_INCLUDE_WRITE_PROCS */ +/* B004 */ +/* ************************************************************************** */ + +#endif /* MNG_ACCESS_CHUNKS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_chunks.h b/freeimage241/Source/LibMNG/libmng_chunks.h new file mode 100644 index 0000000..0fe7871 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_chunks.h @@ -0,0 +1,759 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_chunks.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Chunk structures (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of known chunk structures * */ +/* * * */ +/* * changes : 0.5.1 - 05/04/2000 - G.Juyn * */ +/* * - put in some extra comments * */ +/* * 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - fixed layout for sBIT, PPLT * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed write callback definition * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - fixed layout for PPLT again (missed deltatype ?!?) * */ +/* * * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - removed useless definition (contributed by Tim Rowley) * */ +/* * 0.5.2 - 06/03/2000 - G.Juyn * */ +/* * - fixed makeup for Linux gcc compile * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/10/2000 - G.Juyn * */ +/* * - fixed DEFI behavior * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added JDAA chunk * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_chunks_h_ +#define _libmng_chunks_h_ + +/* ************************************************************************** */ + +#ifdef MNG_SWAP_ENDIAN +#define PNG_SIG 0x474e5089L +#define JNG_SIG 0x474e4a8bL +#define MNG_SIG 0x474e4d8aL +#define POST_SIG 0x0a1a0a0dL +#else +#define PNG_SIG 0x89504e47L +#define JNG_SIG 0x8b4a4e47L +#define MNG_SIG 0x8a4d4e47L +#define POST_SIG 0x0d0a1a0aL +#endif + +/* ************************************************************************** */ + +typedef mng_retcode (*mng_createchunk) (mng_datap pData, + mng_chunkp pHeader, + mng_chunkp* ppChunk); + +typedef mng_retcode (*mng_cleanupchunk) (mng_datap pData, + mng_chunkp pHeader); + +typedef mng_retcode (*mng_readchunk) (mng_datap pData, + mng_chunkp pHeader, + mng_uint32 iRawlen, + mng_uint8p pRawdata, + mng_chunkp* pChunk); + +typedef mng_retcode (*mng_writechunk) (mng_datap pData, + mng_chunkp pChunk); + +/* ************************************************************************** */ + +typedef struct { /* generic header */ + mng_chunkid iChunkname; + mng_createchunk fCreate; + mng_cleanupchunk fCleanup; + mng_readchunk fRead; + mng_writechunk fWrite; + mng_chunkp pNext; /* for double-linked list */ + mng_chunkp pPrev; + } mng_chunk_header; +typedef mng_chunk_header * mng_chunk_headerp; + +/* ************************************************************************** */ + +typedef struct { /* IHDR */ + mng_chunk_header sHeader; + mng_uint32 iWidth; + mng_uint32 iHeight; + mng_uint8 iBitdepth; + mng_uint8 iColortype; + mng_uint8 iCompression; + mng_uint8 iFilter; + mng_uint8 iInterlace; + } mng_ihdr; +typedef mng_ihdr * mng_ihdrp; + +/* ************************************************************************** */ + +typedef struct { /* PLTE */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint32 iEntrycount; + mng_rgbpaltab aEntries; + } mng_plte; +typedef mng_plte * mng_pltep; + +/* ************************************************************************** */ + +typedef struct { /* IDAT */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint32 iDatasize; + mng_ptr pData; + } mng_idat; +typedef mng_idat * mng_idatp; + +/* ************************************************************************** */ + +typedef struct { /* IEND */ + mng_chunk_header sHeader; + } mng_iend; +typedef mng_iend * mng_iendp; + +/* ************************************************************************** */ + +typedef struct { /* tRNS */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_bool bGlobal; + mng_uint8 iType; /* colortype (0,2,3) */ + mng_uint32 iCount; + mng_uint8arr aEntries; + mng_uint16 iGray; + mng_uint16 iRed; + mng_uint16 iGreen; + mng_uint16 iBlue; + mng_uint32 iRawlen; + mng_uint8arr aRawdata; + } mng_trns; +typedef mng_trns * mng_trnsp; + +/* ************************************************************************** */ + +typedef struct { /* gAMA */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint32 iGamma; + } mng_gama; +typedef mng_gama * mng_gamap; + +/* ************************************************************************** */ + +typedef struct { /* cHRM */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint32 iWhitepointx; + mng_uint32 iWhitepointy; + mng_uint32 iRedx; + mng_uint32 iRedy; + mng_uint32 iGreenx; + mng_uint32 iGreeny; + mng_uint32 iBluex; + mng_uint32 iBluey; + } mng_chrm; +typedef mng_chrm * mng_chrmp; + +/* ************************************************************************** */ + +typedef struct { /* sRGB */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint8 iRenderingintent; + } mng_srgb; +typedef mng_srgb * mng_srgbp; + +/* ************************************************************************** */ + +typedef struct { /* iCCP */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint32 iNamesize; + mng_pchar zName; + mng_uint8 iCompression; + mng_uint32 iProfilesize; + mng_ptr pProfile; + } mng_iccp; +typedef mng_iccp * mng_iccpp; + +/* ************************************************************************** */ + +typedef struct { /* tEXt */ + mng_chunk_header sHeader; + mng_uint32 iKeywordsize; + mng_pchar zKeyword; + mng_uint32 iTextsize; + mng_pchar zText; + } mng_text; +typedef mng_text * mng_textp; + +/* ************************************************************************** */ + +typedef struct { /* zTXt */ + mng_chunk_header sHeader; + mng_uint32 iKeywordsize; + mng_pchar zKeyword; + mng_uint8 iCompression; + mng_uint32 iTextsize; + mng_pchar zText; + } mng_ztxt; +typedef mng_ztxt * mng_ztxtp; + +/* ************************************************************************** */ + +typedef struct { /* iTXt */ + mng_chunk_header sHeader; + mng_uint32 iKeywordsize; + mng_pchar zKeyword; + mng_uint8 iCompressionflag; + mng_uint8 iCompressionmethod; + mng_uint32 iLanguagesize; + mng_pchar zLanguage; + mng_uint32 iTranslationsize; + mng_pchar zTranslation; + mng_uint32 iTextsize; + mng_pchar zText; + } mng_itxt; +typedef mng_itxt * mng_itxtp; + +/* ************************************************************************** */ + +typedef struct { /* bKGD */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint8 iType; /* 3=indexed, 0=gray, 2=rgb */ + mng_uint8 iIndex; + mng_uint16 iGray; + mng_uint16 iRed; + mng_uint16 iGreen; + mng_uint16 iBlue; + } mng_bkgd; +typedef mng_bkgd * mng_bkgdp; + +/* ************************************************************************** */ + +typedef struct { /* pHYs */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint32 iSizex; + mng_uint32 iSizey; + mng_uint8 iUnit; + } mng_phys; +typedef mng_phys * mng_physp; + +/* ************************************************************************** */ + +typedef struct { /* sBIT */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint8 iType; /* colortype (0,2,3,4,6,10,12,14,16) */ + mng_uint8arr4 aBits; + } mng_sbit; +typedef mng_sbit * mng_sbitp; + +/* ************************************************************************** */ + +typedef struct { /* sPLT */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint32 iNamesize; + mng_pchar zName; + mng_uint8 iSampledepth; + mng_uint32 iEntrycount; + mng_ptr pEntries; + } mng_splt; +typedef mng_splt * mng_spltp; + +/* ************************************************************************** */ + +typedef struct { /* hIST */ + mng_chunk_header sHeader; + mng_uint32 iEntrycount; + mng_uint16arr aEntries; + } mng_hist; +typedef mng_hist * mng_histp; + +/* ************************************************************************** */ + +typedef struct { /* tIME */ + mng_chunk_header sHeader; + mng_uint16 iYear; + mng_uint8 iMonth; + mng_uint8 iDay; + mng_uint8 iHour; + mng_uint8 iMinute; + mng_uint8 iSecond; + } mng_time; +typedef mng_time * mng_timep; + +/* ************************************************************************** */ + +typedef struct { /* MHDR */ + mng_chunk_header sHeader; + mng_uint32 iWidth; + mng_uint32 iHeight; + mng_uint32 iTicks; + mng_uint32 iLayercount; + mng_uint32 iFramecount; + mng_uint32 iPlaytime; + mng_uint32 iSimplicity; + } mng_mhdr; +typedef mng_mhdr * mng_mhdrp; + +/* ************************************************************************** */ + +typedef struct { /* MEND */ + mng_chunk_header sHeader; + } mng_mend; +typedef mng_mend * mng_mendp; + +/* ************************************************************************** */ + +typedef struct { /* LOOP */ + mng_chunk_header sHeader; + mng_uint8 iLevel; + mng_uint32 iRepeat; + mng_uint8 iTermination; + mng_uint32 iItermin; + mng_uint32 iItermax; + mng_uint32 iCount; + mng_uint32p pSignals; + } mng_loop; +typedef mng_loop * mng_loopp; + +/* ************************************************************************** */ + +typedef struct { /* ENDL */ + mng_chunk_header sHeader; + mng_uint8 iLevel; + } mng_endl; +typedef mng_endl * mng_endlp; + +/* ************************************************************************** */ + +typedef struct { /* DEFI */ + mng_chunk_header sHeader; + mng_uint16 iObjectid; + mng_bool bHasdonotshow; + mng_uint8 iDonotshow; + mng_bool bHasconcrete; + mng_uint8 iConcrete; + mng_bool bHasloca; + mng_int32 iXlocation; + mng_int32 iYlocation; + mng_bool bHasclip; + mng_int32 iLeftcb; + mng_int32 iRightcb; + mng_int32 iTopcb; + mng_int32 iBottomcb; + } mng_defi; +typedef mng_defi * mng_defip; + +/* ************************************************************************** */ + +typedef struct { /* BASI */ + mng_chunk_header sHeader; + mng_uint32 iWidth; + mng_uint32 iHeight; + mng_uint8 iBitdepth; + mng_uint8 iColortype; + mng_uint8 iCompression; + mng_uint8 iFilter; + mng_uint8 iInterlace; + mng_uint16 iRed; + mng_uint16 iGreen; + mng_uint16 iBlue; + mng_uint16 iAlpha; + mng_uint8 iViewable; + } mng_basi; +typedef mng_basi * mng_basip; + +/* ************************************************************************** */ + +typedef struct { /* CLON */ + mng_chunk_header sHeader; + mng_uint16 iSourceid; + mng_uint16 iCloneid; + mng_uint8 iClonetype; + mng_uint8 iDonotshow; + mng_uint8 iConcrete; + mng_bool bHasloca; + mng_uint8 iLocationtype; + mng_int32 iLocationx; + mng_int32 iLocationy; + } mng_clon; +typedef mng_clon * mng_clonp; + +/* ************************************************************************** */ + +typedef struct { /* PAST source */ + mng_uint16 iSourceid; + mng_uint8 iComposition; + mng_uint8 iOrientation; + mng_uint8 iOffsettype; + mng_int32 iOffsetx; + mng_int32 iOffsety; + mng_uint8 iBoundarytype; + mng_int32 iBoundaryl; + mng_int32 iBoundaryr; + mng_int32 iBoundaryt; + mng_int32 iBoundaryb; + } mng_past_source; +typedef mng_past_source * mng_past_sourcep; + +typedef struct { /* PAST */ + mng_chunk_header sHeader; + mng_uint16 iDestid; + mng_uint8 iTargettype; + mng_int32 iTargetx; + mng_int32 iTargety; + mng_uint32 iCount; + mng_past_sourcep pSources; + } mng_past; +typedef mng_past * mng_pastp; + +/* ************************************************************************** */ + +typedef struct { /* DISC */ + mng_chunk_header sHeader; + mng_uint32 iCount; + mng_uint16p pObjectids; + } mng_disc; +typedef mng_disc * mng_discp; + +/* ************************************************************************** */ + +typedef struct { /* BACK */ + mng_chunk_header sHeader; + mng_uint16 iRed; + mng_uint16 iGreen; + mng_uint16 iBlue; + mng_uint8 iMandatory; + mng_uint16 iImageid; + mng_uint8 iTile; + } mng_back; +typedef mng_back * mng_backp; + +/* ************************************************************************** */ + +typedef struct { /* FRAM */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint8 iMode; + mng_uint32 iNamesize; + mng_pchar zName; + mng_uint8 iChangedelay; + mng_uint8 iChangetimeout; + mng_uint8 iChangeclipping; + mng_uint8 iChangesyncid; + mng_uint32 iDelay; + mng_uint32 iTimeout; + mng_uint8 iBoundarytype; + mng_int32 iBoundaryl; + mng_int32 iBoundaryr; + mng_int32 iBoundaryt; + mng_int32 iBoundaryb; + mng_uint32 iCount; + mng_uint32p pSyncids; + } mng_fram; +typedef mng_fram * mng_framp; + +/* ************************************************************************** */ + +typedef struct { /* MOVE */ + mng_chunk_header sHeader; + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint8 iMovetype; + mng_int32 iMovex; + mng_int32 iMovey; + } mng_move; +typedef mng_move * mng_movep; + +/* ************************************************************************** */ + +typedef struct { /* CLIP */ + mng_chunk_header sHeader; + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint8 iCliptype; + mng_int32 iClipl; + mng_int32 iClipr; + mng_int32 iClipt; + mng_int32 iClipb; + } mng_clip; +typedef mng_clip * mng_clipp; + +/* ************************************************************************** */ + +typedef struct { /* SHOW */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint8 iMode; + } mng_show; +typedef mng_show * mng_showp; + +/* ************************************************************************** */ + +typedef struct { /* TERM */ + mng_chunk_header sHeader; + mng_uint8 iTermaction; + mng_uint8 iIteraction; + mng_uint32 iDelay; + mng_uint32 iItermax; + } mng_term; +typedef mng_term * mng_termp; + +/* ************************************************************************** */ + +typedef struct { /* SAVE entry */ + mng_uint8 iEntrytype; + mng_uint32arr2 iOffset; /* 0=MSI, 1=LSI */ + mng_uint32arr2 iStarttime; /* 0=MSI, 1=LSI */ + mng_uint32 iLayernr; + mng_uint32 iFramenr; + mng_uint32 iNamesize; + mng_pchar zName; + } mng_save_entry; +typedef mng_save_entry * mng_save_entryp; + +typedef struct { /* SAVE */ + mng_chunk_header sHeader; + mng_bool bEmpty; + mng_uint8 iOffsettype; + mng_uint32 iCount; + mng_save_entryp pEntries; + } mng_save; +typedef mng_save * mng_savep; + +/* ************************************************************************** */ + +typedef struct { /* SEEK */ + mng_chunk_header sHeader; + mng_uint32 iNamesize; + mng_pchar zName; + } mng_seek; +typedef mng_seek * mng_seekp; + +/* ************************************************************************** */ + +typedef struct { /* eXPI */ + mng_chunk_header sHeader; + mng_uint16 iSnapshotid; + mng_uint32 iNamesize; + mng_pchar zName; + } mng_expi; +typedef mng_expi * mng_expip; + +/* ************************************************************************** */ + +typedef struct { /* fPRI */ + mng_chunk_header sHeader; + mng_uint8 iDeltatype; + mng_uint8 iPriority; + } mng_fpri; +typedef mng_fpri * mng_fprip; + +/* ************************************************************************** */ + +typedef struct { /* nEED */ + mng_chunk_header sHeader; + mng_uint32 iKeywordssize; + mng_pchar zKeywords; + } mng_need; +typedef mng_need * mng_needp; + +/* ************************************************************************** */ + +typedef mng_phys mng_phyg; /* pHYg */ +typedef mng_phyg * mng_phygp; + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG + +typedef struct { /* JHDR */ + mng_chunk_header sHeader; + mng_uint32 iWidth; + mng_uint32 iHeight; + mng_uint8 iColortype; + mng_uint8 iImagesampledepth; + mng_uint8 iImagecompression; + mng_uint8 iImageinterlace; + mng_uint8 iAlphasampledepth; + mng_uint8 iAlphacompression; + mng_uint8 iAlphafilter; + mng_uint8 iAlphainterlace; + } mng_jhdr; +typedef mng_jhdr * mng_jhdrp; + +/* ************************************************************************** */ + +typedef mng_idat mng_jdaa; /* JDAA */ +typedef mng_jdaa * mng_jdaap; + +/* ************************************************************************** */ + +typedef mng_idat mng_jdat; /* JDAT */ +typedef mng_jdat * mng_jdatp; + +/* ************************************************************************** */ + +typedef struct { /* JSEP */ + mng_chunk_header sHeader; + } mng_jsep; +typedef mng_jsep * mng_jsepp; + +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +typedef struct { /* DHDR */ + mng_chunk_header sHeader; + mng_uint16 iObjectid; + mng_uint8 iImagetype; + mng_uint8 iDeltatype; + mng_uint32 iBlockwidth; + mng_uint32 iBlockheight; + mng_uint32 iBlockx; + mng_uint32 iBlocky; + } mng_dhdr; +typedef mng_dhdr * mng_dhdrp; + +/* ************************************************************************** */ + +typedef struct { /* PROM */ + mng_chunk_header sHeader; + mng_uint8 iColortype; + mng_uint8 iSampledepth; + mng_uint8 iFilltype; + } mng_prom; +typedef mng_prom * mng_promp; + +/* ************************************************************************** */ + +typedef struct { /* IPNG */ + mng_chunk_header sHeader; + } mng_ipng; +typedef mng_ipng *mng_ipngp; + +/* ************************************************************************** */ + +typedef struct { /* PPLT entry */ + mng_uint8 iRed; + mng_uint8 iGreen; + mng_uint8 iBlue; + mng_uint8 iAlpha; + mng_bool bUsed; + } mng_pplt_entry; +typedef mng_pplt_entry * mng_pplt_entryp; + +typedef struct { /* PPLT */ + mng_chunk_header sHeader; + mng_uint8 iDeltatype; + mng_uint32 iCount; + mng_pplt_entry aEntries [256]; + } mng_pplt; +typedef mng_pplt * mng_ppltp; + +/* ************************************************************************** */ + +typedef struct { /* IJNG */ + mng_chunk_header sHeader; + } mng_ijng; +typedef mng_ijng *mng_ijngp; + +/* ************************************************************************** */ + +typedef struct { /* DROP */ + mng_chunk_header sHeader; + mng_uint32 iCount; + mng_chunkidp pChunknames; + } mng_drop; +typedef mng_drop * mng_dropp; + +/* ************************************************************************** */ + +typedef struct { /* DBYK */ + mng_chunk_header sHeader; + mng_chunkid iChunkname; + mng_uint8 iPolarity; + mng_uint32 iKeywordssize; + mng_pchar zKeywords; + } mng_dbyk; +typedef mng_dbyk * mng_dbykp; + +/* ************************************************************************** */ + +typedef struct { /* ORDR entry */ + mng_chunkid iChunkname; + mng_uint8 iOrdertype; + } mng_ordr_entry; +typedef mng_ordr_entry * mng_ordr_entryp; + +typedef struct mng_ordr_struct { /* ORDR */ + mng_chunk_header sHeader; + mng_uint32 iCount; + mng_ordr_entryp pEntries; + } mng_ordr; +typedef mng_ordr * mng_ordrp; + +/* ************************************************************************** */ + +typedef struct { /* MAGN */ + mng_chunk_header sHeader; + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint16 iMethodX; + mng_uint16 iMX; + mng_uint16 iMY; + mng_uint16 iML; + mng_uint16 iMR; + mng_uint16 iMT; + mng_uint16 iMB; + mng_uint16 iMethodY; + } mng_magn; +typedef mng_magn * mng_magnp; + +/* ************************************************************************** */ + +typedef struct { /* unknown chunk */ + mng_chunk_header sHeader; + mng_uint32 iDatasize; + mng_ptr pData; + } mng_unknown_chunk; +typedef mng_unknown_chunk * mng_unknown_chunkp; + +/* ************************************************************************** */ + +#endif /* _libmng_chunks_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_cms.c b/freeimage241/Source/LibMNG/libmng_cms.c new file mode 100644 index 0000000..d072e37 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_cms.c @@ -0,0 +1,928 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_cms.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.1 * */ +/* * * */ +/* * purpose : color management routines (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the color management routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/01/2000 - G.Juyn * */ +/* * - B001(105795) - fixed a typo and misconception about * */ +/* * freeing allocated gamma-table. (reported by Marti Maria) * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/09/2000 - G.Juyn * */ +/* * - filled application-based color-management routines * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added creatememprofile * */ +/* * - added callback error-reporting support * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.5.2 - 06/10/2000 - G.Juyn * */ +/* * - fixed some compilation-warnings (contrib Jason Morris) * */ +/* * * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - fixed problem with color-correction for stored images * */ +/* * 0.5.3 - 06/23/2000 - G.Juyn * */ +/* * - fixed problem with incorrect gamma-correction * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/31/2000 - G.Juyn * */ +/* * - fixed sRGB precedence for gamma_only corection * */ +/* * * */ +/* * 0.9.4 - 12/16/2000 - G.Juyn * */ +/* * - fixed mixup of data- & function-pointers (thanks Dimitri)* */ +/* * * */ +/* * 1.0.1 - 03/31/2001 - G.Juyn * */ +/* * - ignore gamma=0 (see png-list for more info) * */ +/* * 1.0.1 - 04/25/2001 - G.Juyn (reported by Gregg Kelly) * */ +/* * - fixed problem with cms profile being created multiple * */ +/* * times when both iCCP & cHRM/gAMA are present * */ +/* * 1.0.1 - 04/25/2001 - G.Juyn * */ +/* * - moved mng_clear_cms to libmng_cms * */ +/* * 1.0.1 - 05/02/2001 - G.Juyn * */ +/* * - added "default" sRGB generation (Thanks Marti!) * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_objects.h" +#include "libmng_cms.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_DISPLAY_PROCS + +/* ************************************************************************** */ +/* * * */ +/* * Little CMS helper routines * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_LCMS + +#define MNG_CMS_FLAGS 0 + +/* ************************************************************************** */ + +void mnglcms_initlibrary () +{ + cmsErrorAction (LCMS_ERROR_IGNORE); /* LCMS should ignore errors! */ +} + +/* ************************************************************************** */ + +mng_cmsprof mnglcms_createfileprofile (mng_pchar zFilename) +{ + return cmsOpenProfileFromFile (zFilename, "r"); +} + +/* ************************************************************************** */ + +mng_cmsprof mnglcms_creatememprofile (mng_uint32 iProfilesize, + mng_ptr pProfile) +{ + return cmsOpenProfileFromMem (pProfile, iProfilesize); +} + +/* ************************************************************************** */ + +mng_cmsprof mnglcms_createsrgbprofile (void) +{ + cmsCIExyY D65; + cmsCIExyYTRIPLE Rec709Primaries = { + {0.6400, 0.3300, 1.0}, + {0.3000, 0.6000, 1.0}, + {0.1500, 0.0600, 1.0} + }; + LPGAMMATABLE Gamma24[3]; + mng_cmsprof hsRGB; + + cmsWhitePointFromTemp(6504, &D65); + Gamma24[0] = Gamma24[1] = Gamma24[2] = cmsBuildGamma(256, 2.4); + hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma24); + cmsFreeGamma(Gamma24[0]); + + return hsRGB; +} + +/* ************************************************************************** */ + +void mnglcms_freeprofile (mng_cmsprof hProf) +{ + cmsCloseProfile (hProf); + return; +} + +/* ************************************************************************** */ + +void mnglcms_freetransform (mng_cmstrans hTrans) +{ +/* B001 start */ + cmsDeleteTransform (hTrans); +/* B001 end */ + return; +} + +/* ************************************************************************** */ + +mng_retcode mng_clear_cms (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLEAR_CMS, MNG_LC_START) +#endif + + if (pData->hTrans) /* transformation still active ? */ + mnglcms_freetransform (pData->hTrans); + + pData->hTrans = 0; + + if (pData->hProf1) /* file profile still active ? */ + mnglcms_freeprofile (pData->hProf1); + + pData->hProf1 = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLEAR_CMS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_LCMS */ + +/* ************************************************************************** */ +/* * * */ +/* * Color-management initialization & correction routines * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_LCMS + +mng_retcode init_full_cms (mng_datap pData) +{ + mng_cmsprof hProf; + mng_cmstrans hTrans; + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + mng_imagedatap pBuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS, MNG_LC_START) +#endif + + if (!pImage) /* no current object? then use object 0 */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address the buffer */ + + if ((pBuf->bHasICCP) || (pData->bHasglobalICCP)) + { + if (!pData->hProf2) /* output profile not defined ? */ + { /* then assume sRGB !! */ + pData->hProf2 = mnglcms_createsrgbprofile (); + + if (!pData->hProf2) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + } + + if (pBuf->bHasICCP) /* generate a profile handle */ + hProf = cmsOpenProfileFromMem (pBuf->pProfile, pBuf->iProfilesize); + else + hProf = cmsOpenProfileFromMem (pData->pGlobalProfile, pData->iGlobalProfilesize); + + pData->hProf1 = hProf; /* save for future use */ + + if (!hProf) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + + if (pData->bIsRGBA16) /* 16-bit intermediates ? */ + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, + pData->hProf2, TYPE_RGBA_16_SE, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + else + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, + pData->hProf2, TYPE_RGBA_8, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + + pData->hTrans = hTrans; /* save for future use */ + + if (!hTrans) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOTRANS) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_full_cms; + + return MNG_NOERROR; /* and done */ + } + else + if ((pBuf->bHasSRGB) || (pData->bHasglobalSRGB)) + { + mng_uint8 iIntent; + + if (pData->bIssRGB) /* sRGB system ? */ + return MNG_NOERROR; /* no conversion required */ + + if (!pData->hProf3) /* sRGB profile not defined ? */ + { /* then create it implicitly !! */ + pData->hProf3 = mnglcms_createsrgbprofile (); + + if (!pData->hProf3) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + } + + hProf = pData->hProf3; /* convert from sRGB profile */ + + if (pBuf->bHasSRGB) /* determine rendering intent */ + iIntent = pBuf->iRenderingintent; + else + iIntent = pData->iGlobalRendintent; + + if (pData->bIsRGBA16) /* 16-bit intermediates ? */ + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, + pData->hProf2, TYPE_RGBA_16_SE, + iIntent, MNG_CMS_FLAGS); + else + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, + pData->hProf2, TYPE_RGBA_8, + iIntent, MNG_CMS_FLAGS); + + pData->hTrans = hTrans; /* save for future use */ + + if (!hTrans) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOTRANS) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_full_cms; + + return MNG_NOERROR; /* and done */ + } + else + if ( ((pBuf->bHasCHRM) || (pData->bHasglobalCHRM)) && + ( ((pBuf->bHasGAMA) && (pBuf->iGamma > 0)) || + ((pData->bHasglobalGAMA) && (pData->iGlobalGamma > 0)) )) + { + mng_CIExyY sWhitepoint; + mng_CIExyYTRIPLE sPrimaries; + mng_gammatabp pGammatable[3]; + mng_float dGamma; + + if (!pData->hProf2) /* output profile not defined ? */ + { /* then assume sRGB !! */ + pData->hProf2 = mnglcms_createsrgbprofile (); + + if (!pData->hProf2) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + } + + if (pBuf->bHasCHRM) /* local cHRM ? */ + { + sWhitepoint.x = (mng_float)pBuf->iWhitepointx / 100000; + sWhitepoint.y = (mng_float)pBuf->iWhitepointy / 100000; + sPrimaries.Red.x = (mng_float)pBuf->iPrimaryredx / 100000; + sPrimaries.Red.y = (mng_float)pBuf->iPrimaryredy / 100000; + sPrimaries.Green.x = (mng_float)pBuf->iPrimarygreenx / 100000; + sPrimaries.Green.y = (mng_float)pBuf->iPrimarygreeny / 100000; + sPrimaries.Blue.x = (mng_float)pBuf->iPrimarybluex / 100000; + sPrimaries.Blue.y = (mng_float)pBuf->iPrimarybluey / 100000; + } + else + { + sWhitepoint.x = (mng_float)pData->iGlobalWhitepointx / 100000; + sWhitepoint.y = (mng_float)pData->iGlobalWhitepointy / 100000; + sPrimaries.Red.x = (mng_float)pData->iGlobalPrimaryredx / 100000; + sPrimaries.Red.y = (mng_float)pData->iGlobalPrimaryredy / 100000; + sPrimaries.Green.x = (mng_float)pData->iGlobalPrimarygreenx / 100000; + sPrimaries.Green.y = (mng_float)pData->iGlobalPrimarygreeny / 100000; + sPrimaries.Blue.x = (mng_float)pData->iGlobalPrimarybluex / 100000; + sPrimaries.Blue.y = (mng_float)pData->iGlobalPrimarybluey / 100000; + } + + sWhitepoint.Y = /* Y component is always 1.0 */ + sPrimaries.Red.Y = + sPrimaries.Green.Y = + sPrimaries.Blue.Y = 1.0; + + if (pBuf->bHasGAMA) /* get the gamma value */ + dGamma = (mng_float)pBuf->iGamma / 100000; + else + dGamma = (mng_float)pData->iGlobalGamma / 100000; + +/* dGamma = pData->dViewgamma / (dGamma * pData->dDisplaygamma); ??? */ + dGamma = pData->dViewgamma / dGamma; + + pGammatable [0] = /* and build the lookup tables */ + pGammatable [1] = + pGammatable [2] = cmsBuildGamma (256, dGamma); + +/* B001 start */ + if (!pGammatable [0]) /* enough memory ? */ +/* B001 end */ + MNG_ERRORL (pData, MNG_LCMS_NOMEM) + /* create the profile */ + hProf = cmsCreateRGBProfile (&sWhitepoint, &sPrimaries, pGammatable); + +/* B001 start */ + cmsFreeGamma (pGammatable [0]); /* free the temporary gamma tables ? */ + /* yes! but just the one! */ +/* B001 end */ + + pData->hProf1 = hProf; /* save for future use */ + + if (!hProf) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + + if (pData->bIsRGBA16) /* 16-bit intermediates ? */ + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, + pData->hProf2, TYPE_RGBA_16_SE, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + else + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, + pData->hProf2, TYPE_RGBA_8, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + + pData->hTrans = hTrans; /* save for future use */ + + if (!hTrans) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOTRANS) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_full_cms; + + return MNG_NOERROR; /* and done */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS, MNG_LC_END) +#endif + + return init_gamma_only (pData); /* if we get here, we'll only do gamma */ +} +#endif /* MNG_INCLUDE_LCMS */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_LCMS + +mng_retcode init_full_cms_object (mng_datap pData) +{ + mng_cmsprof hProf; + mng_cmstrans hTrans; + mng_imagedatap pBuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS_OBJ, MNG_LC_START) +#endif + /* address the object-buffer */ + pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + + if (pBuf->bHasICCP) + { + if (!pData->hProf2) /* output profile not defined ? */ + { /* then assume sRGB !! */ + pData->hProf2 = mnglcms_createsrgbprofile (); + + if (!pData->hProf2) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + } + /* generate a profile handle */ + hProf = cmsOpenProfileFromMem (pBuf->pProfile, pBuf->iProfilesize); + + pData->hProf1 = hProf; /* save for future use */ + + if (!hProf) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + + if (pData->bIsRGBA16) /* 16-bit intermediates ? */ + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, + pData->hProf2, TYPE_RGBA_16_SE, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + else + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, + pData->hProf2, TYPE_RGBA_8, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + + pData->hTrans = hTrans; /* save for future use */ + + if (!hTrans) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOTRANS) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_full_cms; + + return MNG_NOERROR; /* and done */ + } + else + if (pBuf->bHasSRGB) + { + if (pData->bIssRGB) /* sRGB system ? */ + return MNG_NOERROR; /* no conversion required */ + + if (!pData->hProf3) /* sRGB profile not defined ? */ + { /* then create it implicitly !! */ + pData->hProf3 = mnglcms_createsrgbprofile (); + + if (!pData->hProf3) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + } + + hProf = pData->hProf3; /* convert from sRGB profile */ + + if (pData->bIsRGBA16) /* 16-bit intermediates ? */ + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, + pData->hProf2, TYPE_RGBA_16_SE, + pBuf->iRenderingintent, MNG_CMS_FLAGS); + else + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, + pData->hProf2, TYPE_RGBA_8, + pBuf->iRenderingintent, MNG_CMS_FLAGS); + + pData->hTrans = hTrans; /* save for future use */ + + if (!hTrans) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOTRANS) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_full_cms; + + return MNG_NOERROR; /* and done */ + } + else + if ((pBuf->bHasCHRM) && (pBuf->bHasGAMA) && (pBuf->iGamma > 0)) + { + mng_CIExyY sWhitepoint; + mng_CIExyYTRIPLE sPrimaries; + mng_gammatabp pGammatable[3]; + mng_float dGamma; + + if (!pData->hProf2) /* output profile not defined ? */ + { /* then assume sRGB !! */ + pData->hProf2 = mnglcms_createsrgbprofile (); + + if (!pData->hProf2) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + } + + sWhitepoint.x = (mng_float)pBuf->iWhitepointx / 100000; + sWhitepoint.y = (mng_float)pBuf->iWhitepointy / 100000; + sPrimaries.Red.x = (mng_float)pBuf->iPrimaryredx / 100000; + sPrimaries.Red.y = (mng_float)pBuf->iPrimaryredy / 100000; + sPrimaries.Green.x = (mng_float)pBuf->iPrimarygreenx / 100000; + sPrimaries.Green.y = (mng_float)pBuf->iPrimarygreeny / 100000; + sPrimaries.Blue.x = (mng_float)pBuf->iPrimarybluex / 100000; + sPrimaries.Blue.y = (mng_float)pBuf->iPrimarybluey / 100000; + + sWhitepoint.Y = /* Y component is always 1.0 */ + sPrimaries.Red.Y = + sPrimaries.Green.Y = + sPrimaries.Blue.Y = 1.0; + + dGamma = (mng_float)pBuf->iGamma / 100000; + +/* dGamma = pData->dViewgamma / (dGamma * pData->dDisplaygamma); ??? */ + dGamma = pData->dViewgamma / dGamma; + + pGammatable [0] = /* and build the lookup tables */ + pGammatable [1] = + pGammatable [2] = cmsBuildGamma (256, dGamma); + +/* B001 start */ + if (!pGammatable [0]) /* enough memory ? */ +/* B001 end */ + MNG_ERRORL (pData, MNG_LCMS_NOMEM) + + /* create the profile */ + hProf = cmsCreateRGBProfile (&sWhitepoint, &sPrimaries, pGammatable); + +/* B001 start */ + cmsFreeGamma (pGammatable [0]); /* free the temporary gamma tables ? */ + /* yes! but just the one! */ +/* B001 end */ + + pData->hProf1 = hProf; /* save for future use */ + + if (!hProf) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) + + if (pData->bIsRGBA16) /* 16-bit intermediates ? */ + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, + pData->hProf2, TYPE_RGBA_16_SE, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + else + hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, + pData->hProf2, TYPE_RGBA_8, + INTENT_PERCEPTUAL, MNG_CMS_FLAGS); + + pData->hTrans = hTrans; /* save for future use */ + + if (!hTrans) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOTRANS) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_full_cms; + + return MNG_NOERROR; /* and done */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS_OBJ, MNG_LC_END) +#endif + /* if we get here, we'll only do gamma */ + return init_gamma_only_object (pData); +} +#endif /* MNG_INCLUDE_LCMS */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_LCMS +mng_retcode correct_full_cms (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CORRECT_FULL_CMS, MNG_LC_START) +#endif + + cmsDoTransform (pData->hTrans, pData->pRGBArow, pData->pRGBArow, pData->iRowsamples); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CORRECT_FULL_CMS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_LCMS */ + +/* ************************************************************************** */ + +#if defined(MNG_GAMMA_ONLY) || defined(MNG_FULL_CMS) +mng_retcode init_gamma_only (mng_datap pData) +{ + mng_float dGamma; + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + mng_imagedatap pBuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GAMMA_ONLY, MNG_LC_START) +#endif + + if (!pImage) /* no current object? then use object 0 */ + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; /* address the buffer */ + + if (pBuf->bHasSRGB) /* get the gamma value */ + dGamma = 0.45455; + else + if (pBuf->bHasGAMA) + dGamma = (mng_float)pBuf->iGamma / 100000; + else + if (pData->bHasglobalSRGB) + dGamma = 0.45455; + else + if (pData->bHasglobalGAMA) + dGamma = (mng_float)pData->iGlobalGamma / 100000; + else + dGamma = pData->dDfltimggamma; + + if (dGamma > 0) /* ignore gamma=0 */ + { + dGamma = pData->dViewgamma / (dGamma * pData->dDisplaygamma); + + if (dGamma != pData->dLastgamma) /* lookup table needs to be computed ? */ + { + mng_int32 iX; + + pData->aGammatab [0] = 0; + + for (iX = 1; iX <= 255; iX++) + pData->aGammatab [iX] = (mng_uint8)(pow (iX / 255.0, dGamma) * 255 + 0.5); + + pData->dLastgamma = dGamma; /* keep for next time */ + } + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_gamma_only; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GAMMA_ONLY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_GAMMA_ONLY || MNG_FULL_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_GAMMA_ONLY) || defined(MNG_FULL_CMS) +mng_retcode init_gamma_only_object (mng_datap pData) +{ + mng_float dGamma; + mng_imagedatap pBuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GAMMA_ONLY_OBJ, MNG_LC_START) +#endif + /* address the object-buffer */ + pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + + if (pBuf->bHasSRGB) /* get the gamma value */ + dGamma = 0.45455; + else + if (pBuf->bHasGAMA) + dGamma = (mng_float)pBuf->iGamma / 100000; + else + dGamma = pData->dDfltimggamma; + + if (dGamma) /* lets not divide by zero, shall we... */ + dGamma = pData->dViewgamma / (dGamma * pData->dDisplaygamma); + + if (dGamma != pData->dLastgamma) /* lookup table needs to be computed ? */ + { + mng_int32 iX; + + pData->aGammatab [0] = 0; + + for (iX = 1; iX <= 255; iX++) + pData->aGammatab [iX] = (mng_uint8)(pow (iX / 255.0, dGamma) * 255 + 0.5); + + pData->dLastgamma = dGamma; /* keep for next time */ + } + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_gamma_only; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GAMMA_ONLY_OBJ, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_GAMMA_ONLY || MNG_FULL_CMS */ + +/* ************************************************************************** */ + +#if defined(MNG_GAMMA_ONLY) || defined(MNG_FULL_CMS) +mng_retcode correct_gamma_only (mng_datap pData) +{ + mng_uint8p pWork; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CORRECT_GAMMA_ONLY, MNG_LC_START) +#endif + + pWork = pData->pRGBArow; /* address intermediate row */ + + if (pData->bIsRGBA16) /* 16-bit intermediate row ? */ + { + + + /* TODO: 16-bit precision gamma processing */ + /* we'll just do the high-order byte for now */ + + + /* convert all samples in the row */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* using the precalculated gamma lookup table */ + *pWork = pData->aGammatab [*pWork]; + *(pWork+2) = pData->aGammatab [*(pWork+2)]; + *(pWork+4) = pData->aGammatab [*(pWork+4)]; + + pWork += 8; + } + } + else + { /* convert all samples in the row */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* using the precalculated gamma lookup table */ + *pWork = pData->aGammatab [*pWork]; + *(pWork+1) = pData->aGammatab [*(pWork+1)]; + *(pWork+2) = pData->aGammatab [*(pWork+2)]; + + pWork += 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CORRECT_GAMMA_ONLY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_GAMMA_ONLY || MNG_FULL_CMS */ + +/* ************************************************************************** */ + +#ifdef MNG_APP_CMS +mng_retcode init_app_cms (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_APP_CMS, MNG_LC_START) +#endif + + if ( (pData->fProcessiccp) && + ((pBuf->bHasICCP) || (pData->bHasglobalICCP)) ) + { + mng_uint32 iProfilesize; + mng_ptr pProfile; + + if (pBuf->bHasICCP) /* get the right profile */ + { + iProfilesize = pBuf->iProfilesize; + pProfile = pBuf->pProfile; + } + else + { + iProfilesize = pData->iGlobalProfilesize; + pProfile = pData->pGlobalProfile; + } + /* inform the app */ + if (!pData->fProcessiccp ((mng_handle)pData, iProfilesize, pProfile)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + + if ( (pData->fProcesssrgb) && + ((pBuf->bHasSRGB) || (pData->bHasglobalSRGB)) ) + { + mng_uint8 iIntent; + + if (pBuf->bHasSRGB) /* determine rendering intent */ + iIntent = pBuf->iRenderingintent; + else + iIntent = pData->iGlobalRendintent; + /* inform the app */ + if (!pData->fProcesssrgb ((mng_handle)pData, iIntent)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + + if ( (pData->fProcesschroma) && + ( ((pBuf->bHasCHRM) || (pData->bHasglobalCHRM)) ) ) + { + mng_uint32 iWhitepointx, iWhitepointy; + mng_uint32 iPrimaryredx, iPrimaryredy; + mng_uint32 iPrimarygreenx, iPrimarygreeny; + mng_uint32 iPrimarybluex, iPrimarybluey; + + if (pBuf->bHasCHRM) /* local cHRM ? */ + { + iWhitepointx = pBuf->iWhitepointx; + iWhitepointy = pBuf->iWhitepointy; + iPrimaryredx = pBuf->iPrimaryredx; + iPrimaryredy = pBuf->iPrimaryredy; + iPrimarygreenx = pBuf->iPrimarygreenx; + iPrimarygreeny = pBuf->iPrimarygreeny; + iPrimarybluex = pBuf->iPrimarybluex; + iPrimarybluey = pBuf->iPrimarybluey; + } + else + { + iWhitepointx = pData->iGlobalWhitepointx; + iWhitepointy = pData->iGlobalWhitepointy; + iPrimaryredx = pData->iGlobalPrimaryredx; + iPrimaryredy = pData->iGlobalPrimaryredy; + iPrimarygreenx = pData->iGlobalPrimarygreenx; + iPrimarygreeny = pData->iGlobalPrimarygreeny; + iPrimarybluex = pData->iGlobalPrimarybluex; + iPrimarybluey = pData->iGlobalPrimarybluey; + } + /* inform the app */ + if (!pData->fProcesschroma ((mng_handle)pData, iWhitepointx, iWhitepointy, + iPrimaryredx, iPrimaryredy, + iPrimarygreenx, iPrimarygreeny, + iPrimarybluex, iPrimarybluey)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + + if ( (pData->fProcessgamma) && + ((pBuf->bHasGAMA) || (pData->bHasglobalGAMA)) ) + { + mng_uint32 iGamma; + + if (pBuf->bHasGAMA) /* get the gamma value */ + iGamma = pBuf->iGamma; + else + iGamma = pData->iGlobalGamma; + /* inform the app */ + if (!pData->fProcessgamma ((mng_handle)pData, iGamma)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_APP_CMS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_APP_CMS */ + +/* ************************************************************************** */ + +#ifdef MNG_APP_CMS +mng_retcode init_app_cms_object (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pCurrentobj)->pImgbuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_APP_CMS_OBJ, MNG_LC_START) +#endif + + if ((pData->fProcessiccp) && (pBuf->bHasICCP)) + { /* inform the app */ + if (!pData->fProcessiccp ((mng_handle)pData, pBuf->iProfilesize, pBuf->pProfile)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + + if ((pData->fProcesssrgb) && (pBuf->bHasSRGB)) + { /* inform the app */ + if (!pData->fProcesssrgb ((mng_handle)pData, pBuf->iRenderingintent)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + + if ((pData->fProcesschroma) && (pBuf->bHasCHRM)) + { /* inform the app */ + if (!pData->fProcesschroma ((mng_handle)pData, pBuf->iWhitepointx, pBuf->iWhitepointy, + pBuf->iPrimaryredx, pBuf->iPrimaryredy, + pBuf->iPrimarygreenx, pBuf->iPrimarygreeny, + pBuf->iPrimarybluex, pBuf->iPrimarybluey)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + + if ((pData->fProcessgamma) && (pBuf->bHasGAMA)) + { /* inform the app */ + if (!pData->fProcessgamma ((mng_handle)pData, pBuf->iGamma)) + MNG_ERROR (pData, MNG_APPCMSERROR) + /* load color-correction routine */ + pData->fCorrectrow = (mng_fptr)correct_app_cms; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_APP_CMS_OBJ, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_APP_CMS */ + +/* ************************************************************************** */ + +#ifdef MNG_APP_CMS +mng_retcode correct_app_cms (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CORRECT_APP_CMS, MNG_LC_START) +#endif + + if (pData->fProcessarow) /* let the app do something with our row */ + if (!pData->fProcessarow ((mng_handle)pData, pData->iRowsamples, + pData->bIsRGBA16, pData->pRGBArow)) + MNG_ERROR (pData, MNG_APPCMSERROR) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CORRECT_APP_CMS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_APP_CMS */ + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_DISPLAY_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + + + diff --git a/freeimage241/Source/LibMNG/libmng_cms.h b/freeimage241/Source/LibMNG/libmng_cms.h new file mode 100644 index 0000000..02d6c33 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_cms.h @@ -0,0 +1,80 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_cms.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.1 * */ +/* * * */ +/* * purpose : color management routines (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of color management routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added creatememprofile * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 1.0.1 - 04/25/2001 - G.Juyn * */ +/* * - moved mng_clear_cms to libmng_cms * */ +/* * 1.0.1 - 05/02/2001 - G.Juyn * */ +/* * - added "default" sRGB generation (Thanks Marti!) * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_cms_h_ +#define _libmng_cms_h_ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_LCMS +void mnglcms_initlibrary (void); +mng_cmsprof mnglcms_createfileprofile (mng_pchar zFilename); +mng_cmsprof mnglcms_creatememprofile (mng_uint32 iProfilesize, + mng_ptr pProfile ); +mng_cmsprof mnglcms_createsrgbprofile (void); +void mnglcms_freeprofile (mng_cmsprof hProf ); +void mnglcms_freetransform (mng_cmstrans hTrans ); + +mng_retcode mng_clear_cms (mng_datap pData ); +#endif + +/* ************************************************************************** */ + +#ifdef MNG_FULL_CMS +mng_retcode init_full_cms (mng_datap pData); +mng_retcode init_full_cms_object (mng_datap pData); +mng_retcode correct_full_cms (mng_datap pData); +#endif + +#if defined(MNG_FULL_CMS) || defined(MNG_GAMMA_ONLY) +mng_retcode init_gamma_only (mng_datap pData); +mng_retcode init_gamma_only_object (mng_datap pData); +mng_retcode correct_gamma_only (mng_datap pData); +#endif + +#ifdef MNG_APP_CMS +mng_retcode init_app_cms (mng_datap pData); +mng_retcode init_app_cms_object (mng_datap pData); +mng_retcode correct_app_cms (mng_datap pData); +#endif + +/* ************************************************************************** */ + +#endif /* _libmng_cms_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_conf.h b/freeimage241/Source/LibMNG/libmng_conf.h new file mode 100644 index 0000000..c844dfa --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_conf.h @@ -0,0 +1,209 @@ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_conf.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : main configuration file * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : The configuration file. Change this to include/exclude * */ +/* * the options you want or do not want in libmng. * */ +/* * * */ +/* * changes : 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - separated configuration-options into this file * */ +/* * - changed to most likely configuration (?) * */ +/* * 0.5.2 - 06/03/2000 - G.Juyn * */ +/* * - changed options to create a standard so-library * */ +/* * with everything enabled * */ +/* * 0.5.2 - 06/04/2000 - G.Juyn * */ +/* * - changed options to create a standard win32-dll * */ +/* * with everything enabled * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/12/2000 - G.Juyn * */ +/* * - added workaround for faulty PhotoShop iCCP chunk * */ +/* * 0.9.3 - 09/16/2000 - G.Juyn * */ +/* * - removed trace-options from default SO/DLL builds * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_conf_h_ +#define _libmng_conf_h_ + +/* ************************************************************************** */ +/* * * */ +/* * User-selectable compile-time options * */ +/* * * */ +/* ************************************************************************** */ + +/* enable exactly one(1) of the MNG-(sub)set selectors */ +/* use this to select which (sub)set of the MNG specification you wish + to support */ +/* generally you'll want full support as the library provides it automatically + for you! if you're really strung on memory-requirements you can opt + to enable less support (but it's just NOT a good idea!) */ +/* NOTE that this isn't actually implemented yet */ + +#if !defined(MNG_SUPPORT_FULL) && !defined(MNG_SUPPORT_LC) && !defined(MNG_SUPPORT_VLC) +#define MNG_SUPPORT_FULL +/* #define MNG_SUPPORT_LC */ +/* #define MNG_SUPPORT_VLC */ +#endif + +/* ************************************************************************** */ + +/* enable JPEG support if required */ +/* use this to enable the JNG support routines */ +/* this requires an external jpeg package; + currently only IJG's jpgsrc6b is supported! */ +/* NOTE that the IJG code can be either 8- or 12-bit (eg. not both); + so choose the one you've defined in jconfig.h; if you don't know what + the heck I'm talking about, just leave it at 8-bit support (thank you!) */ + +#ifdef MNG_SUPPORT_FULL /* full support includes JNG */ +#define MNG_SUPPORT_IJG6B +#endif + +#ifndef MNG_SUPPORT_IJG6B +#if defined(MNG_BUILD_SO) || defined(MNG_USE_SO) || defined(MNG_BUILD_DLL) || defined(MNG_USE_DLL) +#define MNG_SUPPORT_IJG6B +#endif +#endif + +#if defined(MNG_SUPPORT_IJG6B) && !defined(MNG_SUPPORT_JPEG8) && !defined(MNG_SUPPORT_JPEG12) +#define MNG_SUPPORT_JPEG8 +/* #define MNG_SUPPORT_JPEG12 */ +#endif + +/* ************************************************************************** */ + +/* enable required high-level functions */ +/* use this to select the high-level functions you require */ +/* if you only need to display a MNG, disable write support! */ +/* if you only need to examine a MNG, disable write & display support! */ +/* if you only need to copy a MNG, disable display support! */ +/* if you only need to create a MNG, disable read & display support! */ +/* NOTE that turning all options off will be very unuseful! */ + +#if !defined(MNG_SUPPORT_READ) && !defined(MNG_SUPPORT_WRITE) && !defined(MNG_SUPPORT_DISPLAY) +#define MNG_SUPPORT_READ +#if defined(MNG_BUILD_SO) || defined(MNG_USE_SO) || defined(MNG_BUILD_DLL) || defined(MNG_USE_DLL) +#define MNG_SUPPORT_WRITE +#endif +#define MNG_SUPPORT_DISPLAY +#endif + +/* ************************************************************************** */ + +/* enable chunk access functions */ +/* use this to select whether you need access to the individual chunks */ +/* useful if you want to examine a read MNG (you'll also need MNG_STORE_CHUNKS !)*/ +/* required if you need to create & write a new MNG! */ + +#ifndef MNG_ACCESS_CHUNKS +#if defined(MNG_BUILD_SO) || defined(MNG_USE_SO) || defined(MNG_BUILD_DLL) || defined(MNG_USE_DLL) +#define MNG_ACCESS_CHUNKS +#endif +#endif + +/* ************************************************************************** */ + +/* enable exactly one of the color-management-functionality selectors */ +/* use this to select the level of automatic color support */ +/* MNG_FULL_CMS requires the lcms (little cms) external package ! */ +/* if you want your own app (or the OS) to handle color-management + select MNG_APP_CMS */ + +#if !defined(MNG_FULL_CMS) && !defined(MNG_GAMMA_ONLY) && !defined(MNG_NO_CMS) && !defined(MNG_APP_CMS) +#if defined(MNG_BUILD_DLL) || defined(MNG_USE_DLL) +#define MNG_FULL_CMS +#else +#define MNG_GAMMA_ONLY +#endif +/* #define MNG_NO_CMS */ +/* #define MNG_APP_CMS */ +#endif + +/* ************************************************************************** */ + +/* enable automatic dithering */ +/* use this if you need dithering support to convert high-resolution + images to a low-resolution output-device */ +/* NOTE that this is not supported yet */ + +/* #define MNG_AUTO_DITHER */ + +/* ************************************************************************** */ + +/* enable whether chunks should be stored for reference later */ +/* use this if you need to examine the chunks of a MNG you have read, + or (re-)write a MNG you have read */ +/* turn this off if you want to reduce memory-consumption */ + +#ifndef MNG_STORE_CHUNKS +#if defined(MNG_BUILD_SO) || defined(MNG_USE_SO) || defined(MNG_BUILD_DLL) || defined(MNG_USE_DLL) +#define MNG_STORE_CHUNKS +#endif +#endif + +/* ************************************************************************** */ + +/* enable internal memory management (if your compiler supports it) */ +/* use this if your compiler supports the 'standard' memory functions + (calloc & free), and you want the library to use these functions and not + bother your app with memory-callbacks */ + +/* #define MNG_INTERNAL_MEMMNGMT */ + +/* ************************************************************************** */ + +/* enable internal tracing-functionality (manual debugging purposes) */ +/* use this if you have trouble location bugs or problems */ +/* NOTE that you'll need to specify the trace callback function! */ + +/* #define MNG_SUPPORT_TRACE */ + +/* ************************************************************************** */ + +/* enable extended error- and trace-telltaling */ +/* use this if you need explanatory messages with errors and/or tracing */ + +#if !defined(MNG_ERROR_TELLTALE) && !defined(MNG_TRACE_TELLTALE) +#if defined(MNG_BUILD_SO) || defined(MNG_USE_SO) || defined(MNG_BUILD_DLL) || defined(MNG_USE_DLL) +#define MNG_ERROR_TELLTALE +#define MNG_TRACE_TELLTALE +#endif +#endif + +/* ************************************************************************** */ + +/* enable big-endian support */ +/* enable this if you're on an architecture that supports big-endian reads + and writes that aren't word-aligned */ +/* according to reliable sources this only works for PowerPC (bigendian mode) + and 680x0 */ + +/* #define MNG_BIGENDIAN_SUPPORTED */ + +/* ************************************************************************** */ +/* * * */ +/* * End of user-selectable compile-time options * */ +/* * * */ +/* ************************************************************************** */ + +#endif /* _libmng_conf_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_data.h b/freeimage241/Source/LibMNG/libmng_data.h new file mode 100644 index 0000000..e881ce1 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_data.h @@ -0,0 +1,768 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_data.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : main data structure definition * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the library main data structure * */ +/* * * */ +/* * changes : 0.5.1 - 05/04/2000 - G.Juyn * */ +/* * - added CRC table to main structure (for thread-safety) * */ +/* * 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - added iPLTEentries for checking hIST-length * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed palette definition to exported palette-type * */ +/* * - removed frozen indicator * */ +/* * - added create/write indicators * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/13/2000 - G.Juyn * */ +/* * - added eMNGma hack (will be removed in 1.0.0 !!!) * */ +/* * - added TERM animation object pointer (easier reference) * */ +/* * - added saved-data structure for SAVE/SEEK processing * */ +/* * * */ +/* * 0.5.2 - 05/18/2000 - G.Juyn * */ +/* * - added fields for JNG support (IJG-based) * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - changed global tRNS definition * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added delta-image fields * */ +/* * 0.5.2 - 06/01/2000 - G.Juyn * */ +/* * - added internal delta-image processing callbacks * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - changed SWAP_ENDIAN to BIGENDIAN_SUPPORTED * */ +/* * (contributed by Tim Rowley) * */ +/* * - added getalphaline callback for RGB8_A8 canvasstyle * */ +/* * 0.5.2 - 06/06/2000 - G.Juyn * */ +/* * - added parameter for delayed buffer-processing * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - added update-region parms for refresh calback * */ +/* * - added Needrefresh parameter * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - added Deltaimmediate parm for faster delta-processing * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added Speed parameter to facilitate testing * */ +/* * - added Imagelevel parameter for processtext callback * */ +/* * 0.5.3 - 06/26/2000 - G.Juyn * */ +/* * - changed userdata variable to mng_ptr * */ +/* * * */ +/* * 0.9.1 - 07/07/2000 - G.Juyn * */ +/* * - added variables for go_xxxx processing * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - added variables for improved timing support * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added callbacks for SAVE/SEEK processing * */ +/* * - added variable for NEEDSECTIONWAIT breaks * */ +/* * - added variable for freeze & reset processing * */ +/* * 0.9.1 - 07/17/2000 - G.Juyn * */ +/* * - fixed suspension-buffering for 32K+ chunks * */ +/* * * */ +/* * 0.9.2 - 07/29/2000 - G.Juyn * */ +/* * - removed Nextbackxxx fields (no longer used) * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - fixed wrapping of suspension parameters * */ +/* * 0.9.2 - 08/04/2000 - G.Juyn * */ +/* * - B111096 - fixed large-buffer read-suspension * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 09/10/2000 - G.Juyn * */ +/* * - fixed DEFI behavior * */ +/* * 0.9.3 - 10/10/2000 - G.Juyn * */ +/* * - added support for alpha-depth prediction * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added optional support for bKGD for PNG images * */ +/* * - added support for JDAA * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * - fixed support for bKGD * */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - implemented delayed delta-processing * */ +/* * 0.9.4 - 12/16/2000 - G.Juyn * */ +/* * - fixed mixup of data- & function-pointers (thanks Dimitri)* */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * 1.0.1 - 02/13/2001 - G.Juyn * */ +/* * - fixed first FRAM_MODE=4 timing problem * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * - added processterm callback * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - added option to turn off progressive refresh * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_data_h_ +#define _libmng_data_h_ + +/* ************************************************************************** */ + +#define MNG_MAGIC 0x52530a0aL + +/* ************************************************************************** */ +/* * * */ +/* * Internal structures * */ +/* * * */ +/* ************************************************************************** */ + +typedef mng_palette8 mng_rgbpaltab; + +/* ************************************************************************** */ +/* * * */ +/* * The saved_data structure * */ +/* * * */ +/* * This contains the saved data after a SAVE chunk has been processed. * */ +/* * The data is saved from the main data structure during SAVE processing, * */ +/* * and restored to the main data structure during SEEK processing. * */ +/* * * */ +/* ************************************************************************** */ + +typedef struct mng_savedata_struct { + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + mng_bool bHasglobalPLTE; /* global PLTE chunk processed */ + mng_bool bHasglobalTRNS; /* global tRNS chunk processed */ + mng_bool bHasglobalGAMA; /* global gAMA chunk processed */ + mng_bool bHasglobalCHRM; /* global cHRM chunk processed */ + mng_bool bHasglobalSRGB; /* global sRGB chunk processed */ + mng_bool bHasglobalICCP; /* global iCCP chunk processed */ + mng_bool bHasglobalBKGD; /* global bKGD chunk processed */ +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +#ifdef MNG_SUPPORT_DISPLAY + mng_uint16 iBACKred; /* BACK fields */ + mng_uint16 iBACKgreen; + mng_uint16 iBACKblue; + mng_uint8 iBACKmandatory; + mng_uint16 iBACKimageid; + mng_uint8 iBACKtile; + + mng_uint8 iFRAMmode; /* FRAM fields (global) */ + mng_uint32 iFRAMdelay; + mng_uint32 iFRAMtimeout; + mng_bool bFRAMclipping; + mng_int32 iFRAMclipl; + mng_int32 iFRAMclipr; + mng_int32 iFRAMclipt; + mng_int32 iFRAMclipb; + + mng_uint32 iGlobalPLTEcount; /* global PLTE fields */ + mng_rgbpaltab aGlobalPLTEentries; + + mng_uint32 iGlobalTRNSrawlen; /* global tRNS fields */ + mng_uint8arr aGlobalTRNSrawdata; + + mng_uint32 iGlobalGamma; /* global gAMA fields */ + + mng_uint32 iGlobalWhitepointx; /* global cHRM fields */ + mng_uint32 iGlobalWhitepointy; + mng_uint32 iGlobalPrimaryredx; + mng_uint32 iGlobalPrimaryredy; + mng_uint32 iGlobalPrimarygreenx; + mng_uint32 iGlobalPrimarygreeny; + mng_uint32 iGlobalPrimarybluex; + mng_uint32 iGlobalPrimarybluey; + + mng_uint8 iGlobalRendintent; /* global sRGB fields */ + + mng_uint32 iGlobalProfilesize; /* global iCCP fields */ + mng_ptr pGlobalProfile; + + mng_uint16 iGlobalBKGDred; /* global bKGD fields */ + mng_uint16 iGlobalBKGDgreen; + mng_uint16 iGlobalBKGDblue; +#endif /* MNG_SUPPORT_DISPLAY */ + + } mng_savedata; + +typedef mng_savedata * mng_savedatap; + +/* ************************************************************************** */ +/* * * */ +/* * The main libmng data structure * */ +/* * * */ +/* * The handle used in all functions points to this structure which * */ +/* * contains all volatile data necessary to process the network graphic. * */ +/* * * */ +/* ************************************************************************** */ + +typedef struct mng_data_struct { + + mng_uint32 iMagic; /* magic number to validate + a given handle */ + mng_ptr pUserdata; /* application workdata */ + + mng_imgtype eSigtype; /* image information */ + mng_imgtype eImagetype; /* initially zeroed */ + mng_uint32 iWidth; /* filled after header is processed */ + mng_uint32 iHeight; + mng_uint32 iTicks; /* these only after MHDR */ + mng_uint32 iLayercount; + mng_uint32 iFramecount; + mng_uint32 iPlaytime; + mng_uint32 iSimplicity; + mng_uint8 iAlphadepth; /* indicates expected alpha-depth */ + + mng_uint32 iImagelevel; /* level an image inside a stream */ + + mng_uint32 iCanvasstyle; /* layout of the drawing-canvas */ + mng_uint32 iBkgdstyle; /* layout of the background-canvas */ + + mng_int8 iMagnify; /* magnification factor (not used yet) */ + mng_uint32 iOffsetx; /* x-offset for extremely large image */ + mng_uint32 iOffsety; /* y-offset for extremely large image */ + mng_uint32 iCanvaswidth; /* real canvas size */ + mng_uint32 iCanvasheight; /* must be set by processheader callback */ + + mng_uint16 iBGred; /* default background color */ + mng_uint16 iBGgreen; /* initially "black" */ + mng_uint16 iBGblue; + mng_bool bUseBKGD; /* preferred use of bKGD for PNG */ + + mng_bool bIssRGB; /* indicates sRGB system */ + +#ifdef MNG_FULL_CMS /* little CMS variables */ + mng_cmsprof hProf1; /* image input profile */ + mng_cmsprof hProf2; /* default output profile */ + mng_cmsprof hProf3; /* default sRGB profile */ + mng_cmstrans hTrans; /* current transformation handle */ +#endif + + mng_float dViewgamma; /* gamma calculation variables */ + mng_float dDisplaygamma; /* initially set for sRGB conditions */ + mng_float dDfltimggamma; + + mng_bool bStorechunks; /* switch for storing chunkdata */ + mng_bool bSectionbreaks; /* indicate NEEDSECTIONWAIT breaks */ + mng_bool bCacheplayback; /* switch to cache playback info */ + mng_bool bDoProgressive; /* progressive refresh for large images */ + + mng_speedtype iSpeed; /* speed-modifier for animations */ + + mng_uint32 iMaxwidth; /* maximum canvas size */ + mng_uint32 iMaxheight; /* initially set to 1024 x 1024 */ + + mng_int32 iErrorcode; /* error reporting fields */ + mng_int8 iSeverity; + mng_int32 iErrorx1; + mng_int32 iErrorx2; + mng_pchar zErrortext; + + mng_memalloc fMemalloc; /* callback pointers */ + mng_memfree fMemfree; /* initially nulled */ + mng_openstream fOpenstream; + mng_closestream fClosestream; + mng_readdata fReaddata; + mng_writedata fWritedata; + mng_errorproc fErrorproc; + mng_traceproc fTraceproc; + mng_processheader fProcessheader; + mng_processtext fProcesstext; + mng_processsave fProcesssave; + mng_processseek fProcessseek; + mng_processneed fProcessneed; + mng_processmend fProcessmend; + mng_processunknown fProcessunknown; + mng_processterm fProcessterm; + mng_getcanvasline fGetcanvasline; + mng_getbkgdline fGetbkgdline; + mng_getalphaline fGetalphaline; + mng_refresh fRefresh; + mng_gettickcount fGettickcount; + mng_settimer fSettimer; + mng_processgamma fProcessgamma; + mng_processchroma fProcesschroma; + mng_processsrgb fProcesssrgb; + mng_processiccp fProcessiccp; + mng_processarow fProcessarow; + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + mng_bool bPreDraft48; /* flags ancient style draft */ + + mng_chunkid iChunkname; /* read/write-state variables */ + mng_uint32 iChunkseq; + mng_chunkp pFirstchunk; /* double-linked list of */ + mng_chunkp pLastchunk; /* stored chunk-structures */ + + mng_bool bHasheader; /* first header chunk processed */ + mng_bool bHasMHDR; /* inside a MHDR-MEND sequence */ + mng_bool bHasIHDR; /* inside a IHDR-IEND sequence */ + mng_bool bHasBASI; /* inside a BASI-IEND sequence */ + mng_bool bHasDHDR; /* inside a DHDR-IEND sequence */ +#ifdef MNG_INCLUDE_JNG + mng_bool bHasJHDR; /* inside a JHDR-IEND sequence */ + mng_bool bHasJSEP; /* passed the JSEP separator */ + mng_bool bHasJDAA; /* at least 1 JDAA processed */ + mng_bool bHasJDAT; /* at least 1 JDAT processed */ +#endif + mng_bool bHasPLTE; /* PLTE chunk processed */ + mng_bool bHasTRNS; /* tRNS chunk processed */ + mng_bool bHasGAMA; /* gAMA chunk processed */ + mng_bool bHasCHRM; /* cHRM chunk processed */ + mng_bool bHasSRGB; /* sRGB chunk processed */ + mng_bool bHasICCP; /* iCCP chunk processed */ + mng_bool bHasBKGD; /* bKGD chunk processed */ + mng_bool bHasIDAT; /* at least 1 IDAT processed */ + + mng_bool bHasSAVE; /* SAVE chunk processed */ + mng_bool bHasBACK; /* BACK chunk processed */ + mng_bool bHasFRAM; /* FRAM chunk processed */ + mng_bool bHasTERM; /* TERM chunk processed */ + mng_bool bHasLOOP; /* at least 1 LOOP open */ + + mng_bool bHasglobalPLTE; /* global PLTE chunk processed */ + mng_bool bHasglobalTRNS; /* global tRNS chunk processed */ + mng_bool bHasglobalGAMA; /* global gAMA chunk processed */ + mng_bool bHasglobalCHRM; /* global cHRM chunk processed */ + mng_bool bHasglobalSRGB; /* global sRGB chunk processed */ + mng_bool bHasglobalICCP; /* global iCCP chunk processed */ + mng_bool bHasglobalBKGD; /* global bKGD chunk processed */ + + mng_uint32 iDatawidth; /* IHDR/BASI/DHDR fields */ + mng_uint32 iDataheight; /* valid if inside IHDR-IEND, */ + mng_uint8 iBitdepth; /* BASI-IEND or DHDR-IEND */ + mng_uint8 iColortype; + mng_uint8 iCompression; + mng_uint8 iFilter; + mng_uint8 iInterlace; + + mng_uint32 iPLTEcount; /* PLTE fields */ + + mng_bool bEMNGMAhack; /* TODO: to be removed in 1.0.0 !!! */ + +#ifdef MNG_INCLUDE_JNG + mng_uint8 iJHDRcolortype; /* JHDR fields */ + mng_uint8 iJHDRimgbitdepth; /* valid if inside JHDR-IEND */ + mng_uint8 iJHDRimgcompression; + mng_uint8 iJHDRimginterlace; + mng_uint8 iJHDRalphabitdepth; + mng_uint8 iJHDRalphacompression; + mng_uint8 iJHDRalphafilter; + mng_uint8 iJHDRalphainterlace; +#endif + +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +#ifdef MNG_SUPPORT_READ + mng_bool bReading; /* read processing variables */ + mng_bool bHavesig; + mng_bool bEOF; + mng_uint32 iReadbufsize; + mng_uint8p pReadbuf; + + mng_uint32 iLargebufsize; /* temp for very large chunks */ + mng_uint8p pLargebuf; + + mng_uint32 iSuspendtime; /* tickcount at last suspension */ + mng_bool bSuspended; /* input-reading has been suspended; + we're expecting a call to + mng_read_resume! */ + mng_uint8 iSuspendpoint; /* indicates at which point the flow + was broken to suspend input-reading */ + + mng_bool bSuspensionmode; /* I/O-suspension variables */ + mng_uint32 iSuspendbufsize; + mng_uint8p pSuspendbuf; + mng_uint8p pSuspendbufnext; + mng_uint32 iSuspendbufleft; + mng_uint32 iChunklen; /* chunk length */ + mng_uint8p pReadbufnext; /* 32K+ suspension-processing */ +#endif /* MNG_SUPPORT_READ */ + +#ifdef MNG_SUPPORT_WRITE + mng_bool bCreating; /* create/write processing variables */ + mng_bool bWriting; + mng_chunkid iFirstchunkadded; + mng_uint32 iWritebufsize; + mng_uint8p pWritebuf; +#endif + +#ifdef MNG_SUPPORT_DISPLAY + mng_bool bDisplaying; /* display-state variables */ + mng_bool bFramedone; + mng_uint32 iFrameseq; + mng_uint32 iLayerseq; + mng_uint32 iFrametime; /* millisecs */ + + mng_uint32 iRequestframe; /* go_xxxx variables */ + mng_uint32 iRequestlayer; + mng_uint32 iRequesttime; + mng_bool bSearching; + + mng_bool bRestorebkgd; /* flags restore required before IDAT/JDAT */ + + mng_uint32 iRuntime; /* millisecs since start */ + mng_uint32 iSynctime; /* tickcount at last framesync */ + mng_uint32 iStarttime; /* tickcount at start */ + mng_uint32 iEndtime; /* tickcount at end */ + mng_bool bRunning; /* animation is active */ + mng_bool bTimerset; /* the timer has been set; + we're expecting a call to + mng_display_resume! */ + mng_uint8 iBreakpoint; /* indicates at which point the + flow was broken to run the timer */ + mng_bool bSectionwait; /* indicates a section break */ + mng_bool bFreezing; /* indicates app requested a freeze */ + mng_bool bResetting; /* indicates app requested a reset */ + mng_bool bNeedrefresh; /* indicates screen-refresh is needed */ + mng_objectp pCurrentobj; /* current "object" */ + mng_objectp pCurraniobj; /* current animation object + "to be"/"being" processed */ + mng_objectp pTermaniobj; /* TERM animation object */ + mng_uint32 iIterations; /* TERM/MEND iteration count */ + mng_objectp pObjzero; /* "on-the-fly" image (object = 0) */ + mng_objectp pLastclone; /* last clone */ + mng_objectp pStoreobj; /* current store object for row routines */ + mng_objectp pStorebuf; /* current store object-buffer for row routines */ + mng_objectp pRetrieveobj; /* current retrieve object for row routines */ + mng_savedatap pSavedata; /* pointer to saved data (after SAVE) */ + + mng_uint32 iUpdateleft; /* update region for refresh */ + mng_uint32 iUpdateright; + mng_uint32 iUpdatetop; + mng_uint32 iUpdatebottom; + + mng_int8 iPass; /* current interlacing pass; + negative value means no interlace */ + mng_int32 iRow; /* current row counter */ + mng_int32 iRowinc; /* row increment for this pass */ + mng_int32 iCol; /* current starting column */ + mng_int32 iColinc; /* column increment for this pass */ + mng_int32 iRowsamples; /* nr. of samples in current workrow */ + mng_int32 iSamplemul; /* needed to calculate rowsize */ + mng_int32 iSampleofs; /* from rowsamples */ + mng_int32 iSamplediv; + mng_int32 iRowsize; /* size of actual data in work row */ + mng_int32 iRowmax; /* maximum size of data in work row */ + mng_int32 iFilterofs; /* offset to filter-byte in work row */ + mng_int32 iPixelofs; /* offset to pixel-bytes in work row */ + mng_uint32 iLevel0; /* leveling variables */ + mng_uint32 iLevel1; + mng_uint32 iLevel2; + mng_uint32 iLevel3; + mng_uint8p pWorkrow; /* working row of pixel-data */ + mng_uint8p pPrevrow; /* previous row of pixel-data */ + mng_uint8p pRGBArow; /* intermediate row of RGBA8 or RGBA16 data */ + mng_bool bIsRGBA16; /* indicates intermediate row is RGBA16 */ + mng_bool bIsOpaque; /* indicates intermediate row is fully opaque */ + mng_int32 iFilterbpp; /* bpp index for filtering routines */ + + mng_int32 iSourcel; /* variables for showing objects */ + mng_int32 iSourcer; + mng_int32 iSourcet; + mng_int32 iSourceb; + mng_int32 iDestl; + mng_int32 iDestr; + mng_int32 iDestt; + mng_int32 iDestb; + + mng_objectp pFirstimgobj; /* double-linked list of */ + mng_objectp pLastimgobj; /* image-object structures */ + mng_objectp pFirstaniobj; /* double-linked list of */ + mng_objectp pLastaniobj; /* animation-object structures */ + +#if defined(MNG_GAMMA_ONLY) || defined(MNG_FULL_CMS) + mng_uint8 aGammatab[256]; /* precomputed gamma lookup table */ + mng_float dLastgamma; /* last gamma used to compute table */ +#endif + + mng_fptr fDisplayrow; /* internal callback to display an + uncompressed/unfiltered/ + color-corrected row */ + mng_fptr fRestbkgdrow; /* internal callback for restore- + background processing of a row */ + mng_fptr fCorrectrow; /* internal callback to color-correct an + uncompressed/unfiltered row */ + mng_fptr fRetrieverow; /* internal callback to retrieve an + uncompressed/unfiltered row of data */ + mng_fptr fStorerow; /* internal callback to store an + uncompressed/unfiltered row of data */ + mng_fptr fProcessrow; /* internal callback to process an + uncompressed row of data */ + mng_fptr fDifferrow; /* internal callback to perform + added filter leveling and + differing on an unfiltered row */ + mng_fptr fScalerow; /* internal callback to scale a + delta-row to the bitdepth of its target */ + mng_fptr fDeltarow; /* internal callback to execute a + delta-row onto a target */ + mng_fptr fInitrowproc; /* internal callback to initialize + the row processing */ + + mng_uint16 iDEFIobjectid; /* DEFI fields */ + mng_bool bDEFIhasdonotshow; + mng_uint8 iDEFIdonotshow; + mng_bool bDEFIhasconcrete; + mng_uint8 iDEFIconcrete; + mng_bool bDEFIhasloca; + mng_int32 iDEFIlocax; + mng_int32 iDEFIlocay; + mng_bool bDEFIhasclip; + mng_int32 iDEFIclipl; + mng_int32 iDEFIclipr; + mng_int32 iDEFIclipt; + mng_int32 iDEFIclipb; + + mng_uint16 iBACKred; /* BACK fields */ + mng_uint16 iBACKgreen; + mng_uint16 iBACKblue; + mng_uint8 iBACKmandatory; + mng_uint16 iBACKimageid; + mng_uint8 iBACKtile; + + mng_uint8 iFRAMmode; /* FRAM fields (global) */ + mng_uint32 iFRAMdelay; + mng_uint32 iFRAMtimeout; + mng_bool bFRAMclipping; + mng_int32 iFRAMclipl; + mng_int32 iFRAMclipr; + mng_int32 iFRAMclipt; + mng_int32 iFRAMclipb; + + mng_uint8 iFramemode; /* current subframe variables */ + mng_uint32 iFramedelay; + mng_uint32 iFrametimeout; + mng_bool bFrameclipping; + mng_int32 iFrameclipl; + mng_int32 iFrameclipr; + mng_int32 iFrameclipt; + mng_int32 iFrameclipb; + + mng_uint32 iNextdelay; /* delay for *after* next image */ + + mng_uint8 iSHOWmode; /* SAVE fields */ + mng_uint16 iSHOWfromid; + mng_uint16 iSHOWtoid; + mng_uint16 iSHOWnextid; + mng_int16 iSHOWskip; + + mng_uint32 iGlobalPLTEcount; /* global PLTE fields */ + mng_rgbpaltab aGlobalPLTEentries; + + mng_uint32 iGlobalTRNSrawlen; /* global tRNS fields */ + mng_uint8arr aGlobalTRNSrawdata; + + mng_uint32 iGlobalGamma; /* global gAMA fields */ + + mng_uint32 iGlobalWhitepointx; /* global cHRM fields */ + mng_uint32 iGlobalWhitepointy; + mng_uint32 iGlobalPrimaryredx; + mng_uint32 iGlobalPrimaryredy; + mng_uint32 iGlobalPrimarygreenx; + mng_uint32 iGlobalPrimarygreeny; + mng_uint32 iGlobalPrimarybluex; + mng_uint32 iGlobalPrimarybluey; + + mng_uint8 iGlobalRendintent; /* global sRGB fields */ + + mng_uint32 iGlobalProfilesize; /* global iCCP fields */ + mng_ptr pGlobalProfile; + + mng_uint16 iGlobalBKGDred; /* global bKGD fields */ + mng_uint16 iGlobalBKGDgreen; + mng_uint16 iGlobalBKGDblue; + + mng_ptr pDeltaImage; /* delta-image fields */ + mng_uint8 iDeltaImagetype; + mng_uint8 iDeltatype; + mng_uint32 iDeltaBlockwidth; + mng_uint32 iDeltaBlockheight; + mng_uint32 iDeltaBlockx; + mng_uint32 iDeltaBlocky; + mng_bool bDeltaimmediate; + + mng_fptr fDeltagetrow; /* internal delta-proc callbacks */ + mng_fptr fDeltaaddrow; + mng_fptr fDeltareplacerow; + mng_fptr fDeltaputrow; + + mng_uint16 iMAGNfromid; + mng_uint16 iMAGNtoid; +#endif /* MNG_SUPPORT_DISPLAY */ + +#ifdef MNG_INCLUDE_ZLIB + z_stream sZlib; /* zlib (de)compression variables */ + + mng_int32 iZlevel; /* zlib compression parameters */ + mng_int32 iZmethod; + mng_int32 iZwindowbits; + mng_int32 iZmemlevel; + mng_int32 iZstrategy; + + mng_uint32 iMaxIDAT; /* maximum size of IDAT data */ + + mng_bool bInflating; /* indicates "inflate" in progress */ + mng_bool bDeflating; /* indicates "deflate" in progress */ +#endif /* MNG_INCLUDE_ZLIB */ + +#ifdef MNG_INCLUDE_JNG + mngjpeg_dctmethod eJPEGdctmethod; /* IJG compression variables */ + mng_int32 iJPEGquality; + mng_int32 iJPEGsmoothing; + mng_bool bJPEGcompressprogr; + mng_bool bJPEGcompressopt; + + mng_uint32 iMaxJDAT; /* maximum size of JDAT/JDAA data */ + + mngjpeg_compp pJPEGcinfo; /* compression structure */ + mngjpeg_errorp pJPEGcerr; /* error-manager compress */ + + mngjpeg_decompp pJPEGdinfo; /* decompression structure (JDAT) */ + mngjpeg_errorp pJPEGderr; /* error-manager decompress (JDAT) */ + mngjpeg_sourcep pJPEGdsrc; /* source-manager decompress (JDAT) */ + + mngjpeg_decompp pJPEGdinfo2; /* decompression structure (JDAA) */ + mngjpeg_errorp pJPEGderr2; /* error-manager decompress (JDAA) */ + mngjpeg_sourcep pJPEGdsrc2; /* source-manager decompress (JDAA) */ + + mng_uint8p pJPEGbuf; /* buffer for JPEG (de)compression (JDAT) */ + mng_uint32 iJPEGbufmax; /* allocated space for buffer (JDAT) */ + mng_uint8p pJPEGcurrent; /* current pointer into buffer (JDAT) */ + mng_uint32 iJPEGbufremain; /* remaining bytes in buffer (JDAT) */ + mng_uint32 iJPEGtoskip; /* bytes to skip on next input-block (JDAT) */ + + mng_uint8p pJPEGbuf2; /* buffer for JPEG (de)compression (JDAA) */ + mng_uint32 iJPEGbufmax2; /* allocated space for buffer (JDAA) */ + mng_uint8p pJPEGcurrent2; /* current pointer into buffer (JDAA) */ + mng_uint32 iJPEGbufremain2; /* remaining bytes in buffer (JDAA) */ + mng_uint32 iJPEGtoskip2; /* bytes to skip on next input-block (JDAA) */ + + mng_uint8p pJPEGrow; /* buffer for a JPEG row of samples (JDAT) */ + mng_uint32 iJPEGrowlen; + + mng_uint8p pJPEGrow2; /* buffer for a JPEG row of samples (JDAA) */ + mng_uint32 iJPEGrowlen2; + + mng_bool bJPEGcompress; /* indicates "compress" initialized */ + + mng_bool bJPEGdecompress; /* indicates "decompress" initialized (JDAT) */ + mng_bool bJPEGhasheader; /* indicates "readheader" succeeded (JDAT) */ + mng_bool bJPEGdecostarted; /* indicates "decompress" started (JDAT) */ + mng_bool bJPEGscanstarted; /* indicates "first scan" started (JDAT) */ + mng_bool bJPEGprogressive; /* indicates a progressive image (JDAT) */ + + mng_bool bJPEGdecompress2; /* indicates "decompress" initialized (JDAA) */ + mng_bool bJPEGhasheader2; /* indicates "readheader" succeeded (JDAA) */ + mng_bool bJPEGdecostarted2; /* indicates "decompress" started (JDAA) */ + mng_bool bJPEGscanstarted2; /* indicates "first scan" started (JDAA) */ + mng_bool bJPEGprogressive2; /* indicates a progressive image (JDAA) */ + + mng_fptr fStorerow2; /* internal callback to store an + uncompressed/unfiltered row of JPEG-data (JDAT) */ + + mng_fptr fStorerow3; /* internal callback to store an + uncompressed/unfiltered row of JPEG-data (JDAA) */ + + mng_uint32 iJPEGrow; /* row-number for current JPEG row */ + mng_uint32 iJPEGalpharow; /* nr. of rows filled with alpha */ + mng_uint32 iJPEGrgbrow; /* nr. of rows filled with 'color'-info */ + mng_uint32 iJPEGdisprow; /* nr. of rows already displayed "on-the-fly" */ + +#if defined(MNG_USE_SETJMP) && defined (MNG_INCLUDE_IJG6B) + jmp_buf sErrorbuf; /* setjmp/longjmp buffer (error-recovery) */ +#endif + +#endif /* MNG_INCLUDE_JNG */ + + mng_uint32 aCRCtable [256]; /* CRC prefab table */ + mng_bool bCRCcomputed; /* "has been build" indicator */ + + } mng_data; + +typedef mng_data * mng_datap; + +/* ************************************************************************** */ +/* * * */ +/* * Internal Callback-Function prototypes * */ +/* * * */ +/* ************************************************************************** */ + +typedef mng_retcode(*mng_displayrow) (mng_datap pData); +typedef mng_retcode(*mng_restbkgdrow) (mng_datap pData); +typedef mng_retcode(*mng_correctrow) (mng_datap pData); +typedef mng_retcode(*mng_retrieverow) (mng_datap pData); +typedef mng_retcode(*mng_storerow) (mng_datap pData); +typedef mng_retcode(*mng_processrow) (mng_datap pData); +typedef mng_retcode(*mng_initrowproc) (mng_datap pData); +typedef mng_retcode(*mng_differrow) (mng_datap pData); +typedef mng_retcode(*mng_scalerow) (mng_datap pData); +typedef mng_retcode(*mng_deltarow) (mng_datap pData); + +typedef mng_retcode(*mng_magnify_x) (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p iSrcline, + mng_uint8p iDstline); +typedef mng_retcode(*mng_magnify_y) (mng_datap pData, + mng_int32 iM, + mng_int32 iS, + mng_uint32 iWidth, + mng_uint8p iSrcline1, + mng_uint8p iSrcline2, + mng_uint8p iDstline); + +/* ************************************************************************** */ +/* * * */ +/* * Routines for swapping byte-order from and to graphic files * */ +/* * (This code is adapted from the libpng package) * */ +/* * * */ +/* ************************************************************************** */ + +#ifndef MNG_BIGENDIAN_SUPPORTED +mng_uint32 mng_get_uint32 (mng_uint8p pBuf); +mng_int32 mng_get_int32 (mng_uint8p pBuf); +mng_uint16 mng_get_uint16 (mng_uint8p pBuf); +void mng_put_uint32 (mng_uint8p pBuf, + mng_uint32 i); +void mng_put_int32 (mng_uint8p pBuf, + mng_int32 i); +void mng_put_uint16 (mng_uint8p pBuf, + mng_uint16 i); +#else /* MNG_BIGENDIAN_SUPPORTED */ +#define mng_get_uint32(P) *(mng_uint32p)(P) +#define mng_get_int32(P) *(mng_int32p)(P) +#define mng_get_uint16(P) *(mng_uint16p)(P) +#define mng_put_uint32(P,I) *(mng_uint32p)(P) = (I) +#define mng_put_int32(P,I) *(mng_int32p)(P) = (I) +#define mng_put_uint16(P,I) *(mng_uint16p)(P) = (I) +#endif /* MNG_BIGENDIAN_SUPPORTED */ + +/* ************************************************************************** */ +/* * * */ +/* * Some handy(?) macro definitions * */ +/* * * */ +/* ************************************************************************** */ + +#define MAX_COORD(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN_COORD(a, b) (((a) < (b)) ? (a) : (b)) + +/* ************************************************************************** */ + +#endif /* _libmng_data_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_display.c b/freeimage241/Source/LibMNG/libmng_display.c new file mode 100644 index 0000000..d2e460c --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_display.c @@ -0,0 +1,4699 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_display.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : Display management (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the display management routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added callback error-reporting support * */ +/* * - fixed frame_delay misalignment * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - added sanity check for frozen status * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * 0.5.1 - 05/13/2000 - G.Juyn * */ +/* * - changed display_mend to reset state to initial or SAVE * */ +/* * - added eMNGma hack (will be removed in 1.0.0 !!!) * */ +/* * - added TERM animation object pointer (easier reference) * */ +/* * - added process_save & process_seek routines * */ +/* * 0.5.1 - 05/14/2000 - G.Juyn * */ +/* * - added save_state and restore_state for SAVE/SEEK/TERM * */ +/* * processing * */ +/* * * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - added JNG support (JHDR/JDAT) * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - fixed problem with DEFI clipping * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added delta-image support (DHDR,PROM,IPNG,IJNG) * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - fixed pointer confusion (contributed by Tim Rowley) * */ +/* * 0.5.2 - 06/03/2000 - G.Juyn * */ +/* * - fixed makeup for Linux gcc compile * */ +/* * 0.5.2 - 06/05/2000 - G.Juyn * */ +/* * - added support for RGB8_A8 canvasstyle * */ +/* * 0.5.2 - 06/09/2000 - G.Juyn * */ +/* * - fixed timer-handling to run with Mozilla (Tim Rowley) * */ +/* * 0.5.2 - 06/10/2000 - G.Juyn * */ +/* * - fixed some compilation-warnings (contrib Jason Morris) * */ +/* * * */ +/* * 0.5.3 - 06/12/2000 - G.Juyn * */ +/* * - fixed display of stored JNG images * */ +/* * 0.5.3 - 06/13/2000 - G.Juyn * */ +/* * - fixed problem with BASI-IEND as object 0 * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - changed progressive-display processing * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - changed delta-image processing * */ +/* * 0.5.3 - 06/20/2000 - G.Juyn * */ +/* * - fixed some minor stuff * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added speed-modifier to timing routine * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - added support for PPLT chunk processing * */ +/* * 0.5.3 - 06/29/2000 - G.Juyn * */ +/* * - swapped refresh parameters * */ +/* * * */ +/* * 0.9.0 - 06/30/2000 - G.Juyn * */ +/* * - changed refresh parameters to 'x,y,width,height' * */ +/* * * */ +/* * 0.9.1 - 07/07/2000 - G.Juyn * */ +/* * - implemented support for freeze/reset/resume & go_xxxx * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - added support for improved timing * */ +/* * 0.9.1 - 07/14/2000 - G.Juyn * */ +/* * - changed EOF processing behavior * */ +/* * - fixed TERM delay processing * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - fixed freeze & reset processing * */ +/* * 0.9.1 - 07/16/2000 - G.Juyn * */ +/* * - fixed storage of images during mng_read() * */ +/* * - fixed support for mng_display() after mng_read() * */ +/* * 0.9.1 - 07/24/2000 - G.Juyn * */ +/* * - fixed reading of still-images * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/07/2000 - G.Juyn * */ +/* * - B111300 - fixup for improved portability * */ +/* * 0.9.3 - 08/21/2000 - G.Juyn * */ +/* * - fixed TERM processing delay of 0 msecs * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/10/2000 - G.Juyn * */ +/* * - fixed problem with no refresh after TERM * */ +/* * - fixed DEFI behavior * */ +/* * 0.9.3 - 09/16/2000 - G.Juyn * */ +/* * - fixed timing & refresh behavior for single PNG/JNG * */ +/* * 0.9.3 - 09/19/2000 - G.Juyn * */ +/* * - refixed timing & refresh behavior for single PNG/JNG * */ +/* * 0.9.3 - 10/02/2000 - G.Juyn * */ +/* * - fixed timing again (this is getting boring...) * */ +/* * - refixed problem with no refresh after TERM * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added JDAA chunk * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - fixed support for bKGD * */ +/* * 0.9.3 - 10/18/2000 - G.Juyn * */ +/* * - fixed delta-processing behavior * */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - added storage for pixel-/alpha-sampledepth for delta's * */ +/* * 0.9.3 - 10/27/2000 - G.Juyn * */ +/* * - fixed seperate read() & display() processing * */ +/* * * */ +/* * 0.9.4 - 10/31/2000 - G.Juyn * */ +/* * - fixed possible loop in display_resume() (Thanks Vova!) * */ +/* * 0.9.4 - 11/20/2000 - G.Juyn * */ +/* * - fixed unwanted repetition in mng_readdisplay() * */ +/* * 0.9.4 - 11/24/2000 - G.Juyn * */ +/* * - moved restore of object 0 to libmng_display * */ +/* * - added restore of object 0 to TERM processing !!! * */ +/* * - fixed TERM delay processing * */ +/* * - fixed TERM end processing (count = 0) * */ +/* * 0.9.4 - 12/16/2000 - G.Juyn * */ +/* * - fixed mixup of data- & function-pointers (thanks Dimitri)* */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - removed test filter-methods 1 & 65 * */ +/* * - set default level-set for filtertype=64 to all zeroes * */ +/* * * */ +/* * 0.9.5 - 1/20/2001 - G.Juyn * */ +/* * - fixed compiler-warnings Mozilla (thanks Tim) * */ +/* * 0.9.5 - 1/23/2001 - G.Juyn * */ +/* * - fixed timing-problem with switching framing_modes * */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * 1.0.1 - 02/13/2001 - G.Juyn * */ +/* * - fixed first FRAM_MODE=4 timing problem * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn * */ +/* * - fixed memory-leak for JNGs with alpha (Thanks Gregg!) * */ +/* * - added BGRA8 canvas with premultiplied alpha * */ +/* * * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - fixed memory-leak with delta-images (Thanks Michael!) * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_objects.h" +#include "libmng_object_prc.h" +#include "libmng_memory.h" +#include "libmng_zlib.h" +#include "libmng_jpeg.h" +#include "libmng_cms.h" +#include "libmng_pixels.h" +#include "libmng_display.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_DISPLAY_PROCS + +/* ************************************************************************** */ + +mng_retcode set_delay (mng_datap pData, + mng_uint32 iInterval) +{ + if (!iInterval) /* at least 1 msec please! */ + iInterval = 1; + + if (!pData->fSettimer ((mng_handle)pData, iInterval)) + MNG_ERROR (pData, MNG_APPTIMERERROR) + + pData->bTimerset = MNG_TRUE; /* and indicate so */ + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Progressive display refresh - does the call to the refresh callback * */ +/* * and sets the timer to allow the app to perform the actual refresh to * */ +/* * the screen (eg. process its main message-loop) * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode display_progressive_refresh (mng_datap pData, + mng_uint32 iInterval) +{ + if (!pData->bSearching) /* we mustn't be searching !!! */ + { + if ((pData->bRunning) && /* let the app refresh first ? */ + (pData->iUpdatetop < pData->iUpdatebottom) && (pData->iUpdateleft < pData->iUpdateright)) + { + if (!pData->fRefresh (((mng_handle)pData), + pData->iUpdateleft, pData->iUpdatetop, + pData->iUpdateright - pData->iUpdateleft, + pData->iUpdatebottom - pData->iUpdatetop)) + MNG_ERROR (pData, MNG_APPMISCERROR) + + pData->iUpdateleft = 0; /* reset update-region */ + pData->iUpdateright = 0; + pData->iUpdatetop = 0; + pData->iUpdatebottom = 0; /* reset refreshneeded indicator */ + pData->bNeedrefresh = MNG_FALSE; + /* interval requested ? */ + if ((!pData->bFreezing) && (iInterval)) + { /* setup the timer */ + mng_retcode iRetcode = set_delay (pData, iInterval); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + } + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Generic display routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode interframe_delay (mng_datap pData) +{ + mng_uint32 iWaitfor = 0; + mng_uint32 iInterval; + mng_uint32 iRuninterval; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INTERFRAME_DELAY, MNG_LC_START) +#endif + + if (!pData->bSearching) /* we mustn't be searching !!! */ + { + if (pData->iFramedelay > 0) /* real delay ? */ + { + if ((pData->bRunning) && /* let the app refresh first ? */ + (pData->iUpdatetop < pData->iUpdatebottom) && (pData->iUpdateleft < pData->iUpdateright)) + if (!pData->fRefresh (((mng_handle)pData), + pData->iUpdateleft, pData->iUpdatetop, + pData->iUpdateright - pData->iUpdateleft, + pData->iUpdatebottom - pData->iUpdatetop)) + MNG_ERROR (pData, MNG_APPMISCERROR) + + pData->iUpdateleft = 0; /* reset update-region */ + pData->iUpdateright = 0; + pData->iUpdatetop = 0; + pData->iUpdatebottom = 0; /* reset refreshneeded indicator */ + pData->bNeedrefresh = MNG_FALSE; + /* get current tickcount */ + pData->iRuntime = pData->fGettickcount ((mng_handle)pData); + /* calculate interval since last sync-point */ + if (pData->iRuntime < pData->iSynctime) + iRuninterval = pData->iRuntime + ~pData->iSynctime + 1; + else + iRuninterval = pData->iRuntime - pData->iSynctime; + /* calculate actual run-time */ + if (pData->iRuntime < pData->iStarttime) + pData->iRuntime = pData->iRuntime + ~pData->iStarttime + 1; + else + pData->iRuntime = pData->iRuntime - pData->iStarttime; + + if (pData->iTicks) /* what are we aiming for */ + { + switch (pData->iSpeed) /* honor speed modifier */ + { + case mng_st_fast : + { + iWaitfor = (mng_uint32)(( 500 * pData->iFramedelay) / pData->iTicks); + break; + } + case mng_st_slow : + { + iWaitfor = (mng_uint32)((3000 * pData->iFramedelay) / pData->iTicks); + break; + } + case mng_st_slowest : + { + iWaitfor = (mng_uint32)((8000 * pData->iFramedelay) / pData->iTicks); + break; + } + default : + { + iWaitfor = (mng_uint32)((1000 * pData->iFramedelay) / pData->iTicks); + } + } + } + else + { + if (pData->eImagetype == mng_it_mng) + iWaitfor = 1000; + else + iWaitfor = 1; + } + + if (iWaitfor > iRuninterval) /* delay necessary ? */ + iInterval = iWaitfor - iRuninterval; + else + iInterval = 1; /* force app to process messageloop */ + + if (pData->bRunning) /* set the timer ? */ + { + iRetcode = set_delay (pData, iInterval); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + + if (pData->bRunning) /* increase frametime in advance */ + pData->iFrametime = pData->iFrametime + iWaitfor; + /* setup for next delay */ + pData->iFramedelay = pData->iNextdelay; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INTERFRAME_DELAY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +void set_display_routine (mng_datap pData) +{ /* actively running ? */ + if ((pData->bRunning) && (!pData->bFreezing)) + { + switch (pData->iCanvasstyle) /* determine display routine */ + { + case MNG_CANVAS_RGB8 : { pData->fDisplayrow = (mng_fptr)display_rgb8; break; } + case MNG_CANVAS_RGBA8 : { pData->fDisplayrow = (mng_fptr)display_rgba8; break; } + case MNG_CANVAS_ARGB8 : { pData->fDisplayrow = (mng_fptr)display_argb8; break; } + case MNG_CANVAS_RGB8_A8 : { pData->fDisplayrow = (mng_fptr)display_rgb8_a8; break; } + case MNG_CANVAS_BGR8 : { pData->fDisplayrow = (mng_fptr)display_bgr8; break; } + case MNG_CANVAS_BGRA8 : { pData->fDisplayrow = (mng_fptr)display_bgra8; break; } + case MNG_CANVAS_BGRA8PM : { pData->fDisplayrow = (mng_fptr)display_bgra8_pm; break; } + case MNG_CANVAS_ABGR8 : { pData->fDisplayrow = (mng_fptr)display_abgr8; break; } +/* case MNG_CANVAS_RGB16 : { pData->fDisplayrow = (mng_fptr)display_rgb16; break; } */ +/* case MNG_CANVAS_RGBA16 : { pData->fDisplayrow = (mng_fptr)display_rgba16; break; } */ +/* case MNG_CANVAS_ARGB16 : { pData->fDisplayrow = (mng_fptr)display_argb16; break; } */ +/* case MNG_CANVAS_BGR16 : { pData->fDisplayrow = (mng_fptr)display_bgr16; break; } */ +/* case MNG_CANVAS_BGRA16 : { pData->fDisplayrow = (mng_fptr)display_bgra16; break; } */ +/* case MNG_CANVAS_ABGR16 : { pData->fDisplayrow = (mng_fptr)display_abgr16; break; } */ +/* case MNG_CANVAS_INDEX8 : { pData->fDisplayrow = (mng_fptr)display_index8; break; } */ +/* case MNG_CANVAS_INDEXA8 : { pData->fDisplayrow = (mng_fptr)display_indexa8; break; } */ +/* case MNG_CANVAS_AINDEX8 : { pData->fDisplayrow = (mng_fptr)display_aindex8; break; } */ +/* case MNG_CANVAS_GRAY8 : { pData->fDisplayrow = (mng_fptr)display_gray8; break; } */ +/* case MNG_CANVAS_GRAY16 : { pData->fDisplayrow = (mng_fptr)display_gray16; break; } */ +/* case MNG_CANVAS_GRAYA8 : { pData->fDisplayrow = (mng_fptr)display_graya8; break; } */ +/* case MNG_CANVAS_GRAYA16 : { pData->fDisplayrow = (mng_fptr)display_graya16; break; } */ +/* case MNG_CANVAS_AGRAY8 : { pData->fDisplayrow = (mng_fptr)display_agray8; break; } */ +/* case MNG_CANVAS_AGRAY16 : { pData->fDisplayrow = (mng_fptr)display_agray16; break; } */ +/* case MNG_CANVAS_DX15 : { pData->fDisplayrow = (mng_fptr)display_dx15; break; } */ +/* case MNG_CANVAS_DX16 : { pData->fDisplayrow = (mng_fptr)display_dx16; break; } */ + } + } + + return; +} + +/* ************************************************************************** */ + +mng_retcode load_bkgdlayer (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_LOAD_BKGDLAYER, MNG_LC_START) +#endif + /* actively running ? */ + if ((pData->bRunning) && (!pData->bFreezing)) + { + mng_int32 iY; + mng_retcode iRetcode; /* save values */ + mng_int32 iDestl = pData->iDestl; + mng_int32 iDestr = pData->iDestr; + mng_int32 iDestt = pData->iDestt; + mng_int32 iDestb = pData->iDestb; + mng_int32 iSourcel = pData->iSourcel; + mng_int32 iSourcer = pData->iSourcer; + mng_int32 iSourcet = pData->iSourcet; + mng_int32 iSourceb = pData->iSourceb; + mng_int8 iPass = pData->iPass; + mng_int32 iRow = pData->iRow; + mng_int32 iRowinc = pData->iRowinc; + mng_int32 iCol = pData->iCol; + mng_int32 iColinc = pData->iColinc; + mng_int32 iRowsamples = pData->iRowsamples; + mng_int32 iRowsize = pData->iRowsize; + mng_bool bIsRGBA16 = pData->bIsRGBA16; + mng_bool bIsOpaque = pData->bIsOpaque; + mng_fptr fCorrectrow = pData->fCorrectrow; + + pData->iDestl = 0; /* determine clipping region */ + pData->iDestt = 0; + pData->iDestr = pData->iWidth; + pData->iDestb = pData->iHeight; + + if (pData->bFrameclipping) /* frame clipping specified ? */ + { + pData->iDestl = MAX_COORD (pData->iDestl, pData->iFrameclipl); + pData->iDestt = MAX_COORD (pData->iDestt, pData->iFrameclipt); + pData->iDestr = MIN_COORD (pData->iDestr, pData->iFrameclipr); + pData->iDestb = MIN_COORD (pData->iDestb, pData->iFrameclipb); + } + /* anything to clear ? */ + if ((pData->iDestr >= pData->iDestl) && (pData->iDestb >= pData->iDestt)) + { + pData->iPass = -1; /* these are the object's dimensions now */ + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iWidth; + pData->iRowsize = pData->iRowsamples << 2; + pData->bIsRGBA16 = MNG_FALSE; /* let's keep it simple ! */ + pData->bIsOpaque = MNG_TRUE; + + pData->iSourcel = 0; /* source relative to destination */ + pData->iSourcer = pData->iDestr - pData->iDestl; + pData->iSourcet = 0; + pData->iSourceb = pData->iDestb - pData->iDestt; + + set_display_routine (pData); /* determine display routine */ + /* default restore using preset BG color */ + pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bgcolor; + + if (((pData->eImagetype == mng_it_png) || (pData->eImagetype == mng_it_jng)) && + (pData->bUseBKGD)) + { /* prefer bKGD in PNG/JNG */ + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) + pImage = (mng_imagep)pData->pObjzero; + + if (pImage->pImgbuf->bHasBKGD) + pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bkgd; + } + + if (pData->fGetbkgdline) /* background-canvas-access callback set ? */ + { + switch (pData->iBkgdstyle) + { + case MNG_CANVAS_RGB8 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_rgb8; break; } + case MNG_CANVAS_BGR8 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bgr8; break; } + /* case MNG_CANVAS_RGB16 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_rgb16; break; } */ + /* case MNG_CANVAS_BGR16 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_bgr16; break; } */ + /* case MNG_CANVAS_INDEX8 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_index8; break; } */ + /* case MNG_CANVAS_GRAY8 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_gray8; break; } */ + /* case MNG_CANVAS_GRAY16 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_gray16; break; } */ + /* case MNG_CANVAS_DX15 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_dx15; break; } */ + /* case MNG_CANVAS_DX16 : { pData->fRestbkgdrow = (mng_fptr)restore_bkgd_dx16; break; } */ + } + } + + if (pData->bHasBACK) + { /* background image ? */ + if ((pData->iBACKmandatory & 0x02) && (pData->iBACKimageid)) + pData->fRestbkgdrow = (mng_fptr)restore_bkgd_backimage; + else /* background color ? */ + if (pData->iBACKmandatory & 0x01) + pData->fRestbkgdrow = (mng_fptr)restore_bkgd_backcolor; + + } + + pData->fCorrectrow = MNG_NULL; /* default no color-correction */ + + + /* TODO: determine color correction; this is tricky; + the BACK color is treated differently as the image; + it probably requires a rewrite of the logic here... */ + + + /* get a temporary row-buffer */ + MNG_ALLOC (pData, pData->pRGBArow, pData->iRowsize) + + iY = pData->iDestt; /* this is where we start */ + iRetcode = MNG_NOERROR; /* so far, so good */ + + while ((!iRetcode) && (iY < pData->iDestb)) + { /* restore a background row */ + iRetcode = ((mng_restbkgdrow)pData->fRestbkgdrow) (pData); + /* color correction ? */ + if ((!iRetcode) && (pData->fCorrectrow)) + iRetcode = ((mng_correctrow)pData->fCorrectrow) (pData); + + if (!iRetcode) /* so... display it */ + iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData); + + if (!iRetcode) + iRetcode = next_row (pData); /* adjust variables for next row */ + + iY++; /* and next line */ + } + /* drop the temporary row-buffer */ + MNG_FREE (pData, pData->pRGBArow, pData->iRowsize) + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } + + pData->iDestl = iDestl; /* restore values */ + pData->iDestr = iDestr; + pData->iDestt = iDestt; + pData->iDestb = iDestb; + pData->iSourcel = iSourcel; + pData->iSourcer = iSourcer; + pData->iSourcet = iSourcet; + pData->iSourceb = iSourceb; + pData->iPass = iPass; + pData->iRow = iRow; + pData->iRowinc = iRowinc; + pData->iCol = iCol; + pData->iColinc = iColinc; + pData->iRowsamples = iRowsamples; + pData->iRowsize = iRowsize; + pData->bIsRGBA16 = bIsRGBA16; + pData->bIsOpaque = bIsOpaque; + pData->fCorrectrow = fCorrectrow; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_LOAD_BKGDLAYER, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode clear_canvas (mng_datap pData) +{ + mng_int32 iY; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLEAR_CANVAS, MNG_LC_START) +#endif + + pData->iDestl = 0; /* clipping region is full canvas! */ + pData->iDestt = 0; + pData->iDestr = pData->iWidth; + pData->iDestb = pData->iHeight; + + pData->iSourcel = 0; /* source is same as destination */ + pData->iSourcer = pData->iWidth; + pData->iSourcet = 0; + pData->iSourceb = pData->iHeight; + + pData->iPass = -1; /* these are the object's dimensions now */ + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iWidth; + pData->iRowsize = pData->iRowsamples << 2; + pData->bIsRGBA16 = MNG_FALSE; /* let's keep it simple ! */ + pData->bIsOpaque = MNG_TRUE; + + set_display_routine (pData); /* determine display routine */ + /* get a temporary row-buffer */ + /* it's transparent black by default!! */ + MNG_ALLOC (pData, pData->pRGBArow, pData->iRowsize) + + iY = pData->iDestt; /* this is where we start */ + iRetcode = MNG_NOERROR; /* so far, so good */ + + while ((!iRetcode) && (iY < pData->iDestb)) + { /* clear a row then */ + iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData); + + if (!iRetcode) + iRetcode = next_row (pData); /* adjust variables for next row */ + + iY++; /* and next line */ + } + /* drop the temporary row-buffer */ + MNG_FREE (pData, pData->pRGBArow, pData->iRowsize) + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLEAR_CANVAS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode next_frame (mng_datap pData, + mng_uint8 iFramemode, + mng_uint8 iChangedelay, + mng_uint32 iDelay, + mng_uint8 iChangetimeout, + mng_uint32 iTimeout, + mng_uint8 iChangeclipping, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb) +{ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_FRAME, MNG_LC_START) +#endif + + if (!pData->iBreakpoint) /* no previous break here ? */ + { + mng_uint8 iOldmode = pData->iFramemode; + /* interframe delay required ? */ + if ((iOldmode == 2) || (iOldmode == 4)) + { +/* changed here because FRAM 1/3 will delay themselves before each image */ + if ((pData->iFrameseq) && (iFramemode != 1) && (iFramemode != 3)) + iRetcode = interframe_delay (pData); + else + pData->iFramedelay = pData->iNextdelay; + } + else + { /* delay before inserting background layer? */ + if ((pData->bFramedone) && (iFramemode == 4)) + iRetcode = interframe_delay (pData); + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* now we'll assume we're in the next frame! */ + if (iFramemode) /* save the new framing mode ? */ + { + pData->iFRAMmode = iFramemode; + pData->iFramemode = iFramemode; + } + else /* reload default */ + pData->iFramemode = pData->iFRAMmode; + + if (iChangedelay) /* delay changed ? */ + { + pData->iNextdelay = iDelay; /* for *after* next subframe */ + + if ((iOldmode == 2) || (iOldmode == 4)) +/* pData->iFramedelay = iDelay; */ + pData->iFramedelay = pData->iFRAMdelay; + + if (iChangedelay == 2) /* also overall ? */ + pData->iFRAMdelay = iDelay; + } + else + { /* reload default */ + pData->iNextdelay = pData->iFRAMdelay; + +/* if ((iOldmode == 2) || (iOldmode == 4)) + pData->iFramedelay = pData->iNextdelay; */ + } + + if (iChangetimeout) /* timeout changed ? */ + { /* for next subframe */ + pData->iFrametimeout = iTimeout; + + if ((iChangetimeout == 2) || /* also overall ? */ + (iChangetimeout == 4) || + (iChangetimeout == 6) || + (iChangetimeout == 8)) + pData->iFRAMtimeout = iTimeout; + } + else /* reload default */ + pData->iFrametimeout = pData->iFRAMtimeout; + + if (iChangeclipping) /* clipping changed ? */ + { + pData->bFrameclipping = MNG_TRUE; + + if (!iCliptype) /* absolute ? */ + { + pData->iFrameclipl = iClipl; + pData->iFrameclipr = iClipr; + pData->iFrameclipt = iClipt; + pData->iFrameclipb = iClipb; + } + else /* relative */ + { + pData->iFrameclipl = pData->iFrameclipl + iClipl; + pData->iFrameclipr = pData->iFrameclipr + iClipr; + pData->iFrameclipt = pData->iFrameclipt + iClipt; + pData->iFrameclipb = pData->iFrameclipb + iClipb; + } + + if (iChangeclipping == 2) /* also overall ? */ + { + pData->bFRAMclipping = MNG_TRUE; + + if (!iCliptype) /* absolute ? */ + { + pData->iFRAMclipl = iClipl; + pData->iFRAMclipr = iClipr; + pData->iFRAMclipt = iClipt; + pData->iFRAMclipb = iClipb; + } + else /* relative */ + { + pData->iFRAMclipl = pData->iFRAMclipl + iClipl; + pData->iFRAMclipr = pData->iFRAMclipr + iClipr; + pData->iFRAMclipt = pData->iFRAMclipt + iClipt; + pData->iFRAMclipb = pData->iFRAMclipb + iClipb; + } + } + } + else + { /* reload defaults */ + pData->bFrameclipping = pData->bFRAMclipping; + pData->iFrameclipl = pData->iFRAMclipl; + pData->iFrameclipr = pData->iFRAMclipr; + pData->iFrameclipt = pData->iFRAMclipt; + pData->iFrameclipb = pData->iFRAMclipb; + } + } + + if (!pData->bTimerset) /* timer still off ? */ + { + if ((pData->iFramemode == 4) || /* insert background layer after a new frame */ + (!pData->iLayerseq)) /* and certainly before the very first layer */ + iRetcode = load_bkgdlayer (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if ((pData->bDisplaying) && (pData->bRunning)) + { + pData->iFrameseq++; /* count the frame ! */ + pData->bFramedone = MNG_TRUE; /* and indicate we've done one */ + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_FRAME, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode next_layer (mng_datap pData) +{ + mng_imagep pImage; + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_LAYER, MNG_LC_START) +#endif + + if (!pData->iBreakpoint) /* no previous break here ? */ + { /* interframe delay required ? */ + if ((pData->eImagetype == mng_it_mng) && (pData->iLayerseq) && + ((pData->iFramemode == 1) || (pData->iFramemode == 3))) + iRetcode = interframe_delay (pData); + else + pData->iFramedelay = pData->iNextdelay; + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + if (!pData->bTimerset) /* timer still off ? */ + { + if (!pData->iLayerseq) /* restore background for the very first layer ? */ + { /* wait till IDAT/JDAT for PNGs & JNGs !!! */ + if ((pData->eImagetype == mng_it_png) || (pData->eImagetype == mng_it_jng)) + pData->bRestorebkgd = MNG_TRUE; + else + { /* for MNG we do it right away */ + iRetcode = load_bkgdlayer (pData); + + if (pData->bRunning) + pData->iLayerseq++; /* and it counts as a layer then ! */ + } + } + else + if (pData->iFramemode == 3) /* restore background for each layer ? */ + iRetcode = load_bkgdlayer (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bHasDHDR) /* processing a delta-image ? */ + pImage = (mng_imagep)pData->pDeltaImage; + else + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* not an active object ? */ + pImage = (mng_imagep)pData->pObjzero; + /* determine display rectangle */ + pData->iDestl = MAX_COORD ((mng_int32)0, pImage->iPosx); + pData->iDestt = MAX_COORD ((mng_int32)0, pImage->iPosy); + /* is it a valid buffer ? */ + if ((pImage->pImgbuf->iWidth) && (pImage->pImgbuf->iHeight)) + { + pData->iDestr = MIN_COORD ((mng_int32)pData->iWidth, + pImage->iPosx + (mng_int32)pImage->pImgbuf->iWidth ); + pData->iDestb = MIN_COORD ((mng_int32)pData->iHeight, + pImage->iPosy + (mng_int32)pImage->pImgbuf->iHeight); + } + else /* it's a single image ! */ + { + pData->iDestr = MIN_COORD ((mng_int32)pData->iWidth, + (mng_int32)pData->iDatawidth ); + pData->iDestb = MIN_COORD ((mng_int32)pData->iHeight, + (mng_int32)pData->iDataheight); + } + + if (pData->bFrameclipping) /* frame clipping specified ? */ + { + pData->iDestl = MAX_COORD (pData->iDestl, pData->iFrameclipl); + pData->iDestt = MAX_COORD (pData->iDestt, pData->iFrameclipt); + pData->iDestr = MIN_COORD (pData->iDestr, pData->iFrameclipr); + pData->iDestb = MIN_COORD (pData->iDestb, pData->iFrameclipb); + } + + if (pImage->bClipped) /* is the image clipped itself ? */ + { + pData->iDestl = MAX_COORD (pData->iDestl, pImage->iClipl); + pData->iDestt = MAX_COORD (pData->iDestt, pImage->iClipt); + pData->iDestr = MIN_COORD (pData->iDestr, pImage->iClipr); + pData->iDestb = MIN_COORD (pData->iDestb, pImage->iClipb); + } + /* determine source starting point */ + pData->iSourcel = MAX_COORD ((mng_int32)0, pData->iDestl - pImage->iPosx); + pData->iSourcet = MAX_COORD ((mng_int32)0, pData->iDestt - pImage->iPosy); + + if ((pImage->pImgbuf->iWidth) && (pImage->pImgbuf->iHeight)) + { /* and maximum size */ + pData->iSourcer = MIN_COORD ((mng_int32)pImage->pImgbuf->iWidth, + pData->iSourcel + pData->iDestr - pData->iDestl); + pData->iSourceb = MIN_COORD ((mng_int32)pImage->pImgbuf->iHeight, + pData->iSourcet + pData->iDestb - pData->iDestt); + } + else /* it's a single image ! */ + { + pData->iSourcer = pData->iSourcel + pData->iDestr - pData->iDestl; + pData->iSourceb = pData->iSourcet + pData->iDestb - pData->iDestt; + } + + if (pData->bRunning) + pData->iLayerseq++; /* count the layer ! */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_LAYER, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_image (mng_datap pData, + mng_imagep pImage, + mng_bool bLayeradvanced) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_IMAGE, MNG_LC_START) +#endif + /* actively running ? */ + if ((pData->bRunning) && (!pData->bFreezing)) + { + if ( (!pData->iBreakpoint) && /* needs magnification ? */ + ( (pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY) ) ) + { + iRetcode = magnify_imageobject (pData, pImage); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + + pData->pRetrieveobj = pImage; /* so retrieve-row and color-correction can find it */ + + if (!bLayeradvanced) /* need to advance the layer ? */ + { + mng_imagep pSave = pData->pCurrentobj; + pData->pCurrentobj = pImage; + next_layer (pData); /* advance to next layer */ + pData->pCurrentobj = pSave; + } + /* need to restore the background ? */ + if ((!pData->bTimerset) && (pData->bRestorebkgd)) + { + mng_imagep pSave = pData->pCurrentobj; + pData->pCurrentobj = pImage; + pData->bRestorebkgd = MNG_FALSE; + iRetcode = load_bkgdlayer (pData); + pData->pCurrentobj = pSave; + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bRunning) + pData->iLayerseq++; /* and it counts as a layer then ! */ + } + /* actively running ? */ + if ((pData->bRunning) && (!pData->bFreezing)) + { + if (!pData->bTimerset) /* all systems still go ? */ + { + pData->iBreakpoint = 0; /* let's make absolutely sure... */ + /* anything to display ? */ + if ((pData->iDestr >= pData->iDestl) && (pData->iDestb >= pData->iDestt)) + { + mng_int32 iY; + + set_display_routine (pData); /* determine display routine */ + /* and image-buffer retrieval routine */ + switch (pImage->pImgbuf->iColortype) + { + case 0 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_g16; + else + pData->fRetrieverow = (mng_fptr)retrieve_g8; + + pData->bIsOpaque = (mng_bool)(!pImage->pImgbuf->bHasTRNS); + break; + } + + case 2 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_rgb16; + else + pData->fRetrieverow = (mng_fptr)retrieve_rgb8; + + pData->bIsOpaque = (mng_bool)(!pImage->pImgbuf->bHasTRNS); + break; + } + + + case 3 : { pData->fRetrieverow = (mng_fptr)retrieve_idx8; + pData->bIsOpaque = (mng_bool)(!pImage->pImgbuf->bHasTRNS); + break; + } + + + case 4 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_ga16; + else + pData->fRetrieverow = (mng_fptr)retrieve_ga8; + + pData->bIsOpaque = MNG_FALSE; + break; + } + + + case 6 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_rgba16; + else + pData->fRetrieverow = (mng_fptr)retrieve_rgba8; + + pData->bIsOpaque = MNG_FALSE; + break; + } + + case 8 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_g16; + else + pData->fRetrieverow = (mng_fptr)retrieve_g8; + + pData->bIsOpaque = MNG_TRUE; + break; + } + + case 10 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_rgb16; + else + pData->fRetrieverow = (mng_fptr)retrieve_rgb8; + + pData->bIsOpaque = MNG_TRUE; + break; + } + + + case 12 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_ga16; + else + pData->fRetrieverow = (mng_fptr)retrieve_ga8; + + pData->bIsOpaque = MNG_FALSE; + break; + } + + + case 14 : { if (pImage->pImgbuf->iBitdepth > 8) + pData->fRetrieverow = (mng_fptr)retrieve_rgba16; + else + pData->fRetrieverow = (mng_fptr)retrieve_rgba8; + + pData->bIsOpaque = MNG_FALSE; + break; + } + + } + + pData->iPass = -1; /* these are the object's dimensions now */ + pData->iRow = pData->iSourcet; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pImage->pImgbuf->iWidth; + pData->iRowsize = pData->iRowsamples << 2; + pData->bIsRGBA16 = MNG_FALSE; + /* adjust for 16-bit object ? */ + if (pImage->pImgbuf->iBitdepth > 8) + { + pData->bIsRGBA16 = MNG_TRUE; + pData->iRowsize = pData->iRowsamples << 3; + } + + pData->fCorrectrow = MNG_NULL; /* default no color-correction */ + +#ifdef MNG_NO_CMS + iRetcode = MNG_NOERROR; +#else +#if defined(MNG_FULL_CMS) /* determine color-management routine */ + iRetcode = init_full_cms_object (pData); +#elif defined(MNG_GAMMA_ONLY) + iRetcode = init_gamma_only_object (pData); +#elif defined(MNG_APP_CMS) + iRetcode = init_app_cms_object (pData); +#endif + if (iRetcode) /* on error bail out */ + return iRetcode; +#endif /* MNG_NO_CMS */ + /* get a temporary row-buffer */ + MNG_ALLOC (pData, pData->pRGBArow, pData->iRowsize) + + iY = pData->iSourcet; /* this is where we start */ + + while ((!iRetcode) && (iY < pData->iSourceb)) + { /* get a row */ + iRetcode = ((mng_retrieverow)pData->fRetrieverow) (pData); + /* color correction ? */ + if ((!iRetcode) && (pData->fCorrectrow)) + iRetcode = ((mng_correctrow)pData->fCorrectrow) (pData); + + if (!iRetcode) /* so... display it */ + iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData); + + if (!iRetcode) /* adjust variables for next row */ + iRetcode = next_row (pData); + + iY++; /* and next line */ + } + /* drop the temporary row-buffer */ + MNG_FREE (pData, pData->pRGBArow, pData->iRowsize) + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#if defined(MNG_INCLUDE_LCMS) /* cleanup cms stuff */ + iRetcode = mng_clear_cms (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; +#endif + } + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_IMAGE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* whehehe, this is good ! */ +} + +/* ************************************************************************** */ + +mng_retcode execute_delta_image (mng_datap pData, + mng_imagep pTarget, + mng_imagep pDelta) +{ + mng_imagedatap pBuftarget = pTarget->pImgbuf; + mng_imagedatap pBufdelta = pDelta->pImgbuf; + mng_uint32 iY; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_EXECUTE_DELTA_IMAGE, MNG_LC_START) +#endif + /* actively running ? */ + if ((pData->bRunning) && (!pData->bFreezing)) + { + if (pBufdelta->bHasPLTE) /* palette in delta ? */ + { + mng_uint32 iX; + /* new palette larger than old one ? */ + if ((!pBuftarget->bHasPLTE) || (pBuftarget->iPLTEcount < pBufdelta->iPLTEcount)) + pBuftarget->iPLTEcount = pBufdelta->iPLTEcount; + /* it's definitely got a PLTE now */ + pBuftarget->bHasPLTE = MNG_TRUE; + + for (iX = 0; iX < pBufdelta->iPLTEcount; iX++) + { + pBuftarget->aPLTEentries[iX].iRed = pBufdelta->aPLTEentries[iX].iRed; + pBuftarget->aPLTEentries[iX].iGreen = pBufdelta->aPLTEentries[iX].iGreen; + pBuftarget->aPLTEentries[iX].iBlue = pBufdelta->aPLTEentries[iX].iBlue; + } + } + + if (pBufdelta->bHasTRNS) /* cheap transparency in delta ? */ + { + switch (pData->iColortype) /* drop it into the target */ + { + case 0: { /* gray */ + pBuftarget->iTRNSgray = pBufdelta->iTRNSgray; + pBuftarget->iTRNSred = 0; + pBuftarget->iTRNSgreen = 0; + pBuftarget->iTRNSblue = 0; + pBuftarget->iTRNScount = 0; + break; + } + case 2: { /* rgb */ + pBuftarget->iTRNSgray = 0; + pBuftarget->iTRNSred = pBufdelta->iTRNSred; + pBuftarget->iTRNSgreen = pBufdelta->iTRNSgreen; + pBuftarget->iTRNSblue = pBufdelta->iTRNSblue; + pBuftarget->iTRNScount = 0; + break; + } + case 3: { /* indexed */ + pBuftarget->iTRNSgray = 0; + pBuftarget->iTRNSred = 0; + pBuftarget->iTRNSgreen = 0; + pBuftarget->iTRNSblue = 0; + /* existing range smaller than new one ? */ + if ((!pBuftarget->bHasTRNS) || (pBuftarget->iTRNScount < pBufdelta->iTRNScount)) + pBuftarget->iTRNScount = pBufdelta->iTRNScount; + + MNG_COPY (pBuftarget->aTRNSentries, pBufdelta->aTRNSentries, pBufdelta->iTRNScount) + break; + } + } + + pBuftarget->bHasTRNS = MNG_TRUE; /* tell it it's got a tRNS now */ + } + + if (pBufdelta->bHasBKGD) /* bkgd in source ? */ + { /* drop it onto the target */ + pBuftarget->bHasBKGD = MNG_TRUE; + pBuftarget->iBKGDindex = pBufdelta->iBKGDindex; + pBuftarget->iBKGDgray = pBufdelta->iBKGDgray; + pBuftarget->iBKGDred = pBufdelta->iBKGDred; + pBuftarget->iBKGDgreen = pBufdelta->iBKGDgreen; + pBuftarget->iBKGDblue = pBufdelta->iBKGDblue; + } + + if (pBufdelta->bHasGAMA) /* gamma in source ? */ + { + pBuftarget->bHasGAMA = MNG_TRUE; /* drop it onto the target */ + pBuftarget->iGamma = pBufdelta->iGamma; + } + + if (pBufdelta->bHasCHRM) /* chroma in delta ? */ + { /* drop it onto the target */ + pBuftarget->bHasCHRM = MNG_TRUE; + pBuftarget->iWhitepointx = pBufdelta->iWhitepointx; + pBuftarget->iWhitepointy = pBufdelta->iWhitepointy; + pBuftarget->iPrimaryredx = pBufdelta->iPrimaryredx; + pBuftarget->iPrimaryredy = pBufdelta->iPrimaryredy; + pBuftarget->iPrimarygreenx = pBufdelta->iPrimarygreenx; + pBuftarget->iPrimarygreeny = pBufdelta->iPrimarygreeny; + pBuftarget->iPrimarybluex = pBufdelta->iPrimarybluex; + pBuftarget->iPrimarybluey = pBufdelta->iPrimarybluey; + } + + if (pBufdelta->bHasSRGB) /* sRGB in delta ? */ + { /* drop it onto the target */ + pBuftarget->bHasSRGB = MNG_TRUE; + pBuftarget->iRenderingintent = pBufdelta->iRenderingintent; + } + + if (pBufdelta->bHasICCP) /* ICC profile in delta ? */ + { + pBuftarget->bHasICCP = MNG_TRUE; /* drop it onto the target */ + + if (pBuftarget->pProfile) /* profile existed ? */ + MNG_FREEX (pData, pBuftarget->pProfile, pBuftarget->iProfilesize) + /* allocate a buffer & copy it */ + MNG_ALLOC (pData, pBuftarget->pProfile, pBufdelta->iProfilesize) + MNG_COPY (pBuftarget->pProfile, pBufdelta->pProfile, pBufdelta->iProfilesize) + /* store it's length as well */ + pBuftarget->iProfilesize = pBufdelta->iProfilesize; + } + /* need to execute delta pixels ? */ + if ((!pData->bDeltaimmediate) && (pData->iDeltatype != MNG_DELTATYPE_NOCHANGE)) + { + pData->fScalerow = MNG_NULL; /* not needed by default */ + + switch (pBuftarget->iBitdepth) /* determine scaling routine */ + { + + + } + + pData->fDeltarow = MNG_NULL; /* let's assume there's nothing to do */ + + switch (pBuftarget->iColortype) /* determine delta processing routine */ + { + case 0 : ; + case 8 : { /* gray */ + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3) || + (pBufdelta->iColortype == 8)) + { + switch (pBuftarget->iBitdepth) + { + case 1 : { pData->fDeltarow = (mng_fptr)delta_g1_g1; break; } + case 2 : { pData->fDeltarow = (mng_fptr)delta_g2_g2; break; } + case 4 : { pData->fDeltarow = (mng_fptr)delta_g4_g4; break; } + case 8 : { pData->fDeltarow = (mng_fptr)delta_g8_g8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_g16_g16; break; } + } + } + } + + break; + } + + case 2 : ; + case 10 : { /* rgb */ + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + if ((pBufdelta->iColortype == 2) || (pBufdelta->iColortype == 10)) + { + switch (pBuftarget->iBitdepth) + { + case 8 : { pData->fDeltarow = (mng_fptr)delta_rgb8_rgb8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_rgb16_rgb16; break; } + } + } + } + + break; + } + + case 3 : { /* indexed; abuse gray routines */ + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3)) + { + switch (pBuftarget->iBitdepth) + { + case 1 : { pData->fDeltarow = (mng_fptr)delta_g1_g1; break; } + case 2 : { pData->fDeltarow = (mng_fptr)delta_g2_g2; break; } + case 4 : { pData->fDeltarow = (mng_fptr)delta_g4_g4; break; } + case 8 : { pData->fDeltarow = (mng_fptr)delta_g8_g8; break; } + } + } + } + + break; + } + + case 4 : ; + case 12 : { /* gray + alpha */ + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + if ((pBufdelta->iColortype == 4) || (pBufdelta->iColortype == 12)) + { + switch (pBuftarget->iBitdepth) + { + case 8 : { pData->fDeltarow = (mng_fptr)delta_ga8_ga8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_ga16_ga16; break; } + } + } + } + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE) ) + { + if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3) || + (pBufdelta->iColortype == 8)) + { + switch (pBuftarget->iBitdepth) + { + case 8 : { pData->fDeltarow = (mng_fptr)delta_ga8_g8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_ga16_g16; break; } + } + } + } + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE) ) + { + if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3)) + { + switch (pBuftarget->iBitdepth) + { + case 8 : { pData->fDeltarow = (mng_fptr)delta_ga8_a8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_ga16_a16; break; } + } + } + } + + break; + } + + case 6 : ; + case 14 : { /* rgb + alpha */ + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + if ((pBufdelta->iColortype == 6) || (pBufdelta->iColortype == 14)) + { + switch (pBuftarget->iBitdepth) + { + case 8 : { pData->fDeltarow = (mng_fptr)delta_rgba8_rgba8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_rgba16_rgba16; break; } + } + } + } + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE) ) + { + if ((pBufdelta->iColortype == 2) || (pBufdelta->iColortype == 10)) + { + switch (pBuftarget->iBitdepth) + { + case 8 : { pData->fDeltarow = (mng_fptr)delta_rgba8_rgb8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_rgba16_rgb16; break; } + } + } + } + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE) ) + { + if ((pBufdelta->iColortype == 0) || (pBufdelta->iColortype == 3)) + { + switch (pBuftarget->iBitdepth) + { + case 8 : { pData->fDeltarow = (mng_fptr)delta_rgba8_a8; break; } + case 16 : { pData->fDeltarow = (mng_fptr)delta_rgba16_a16; break; } + } + } + } + + break; + } + + } + + if (pData->fDeltarow) /* do we need to take action ? */ + { + pData->iPass = -1; /* setup row dimensions and stuff */ + pData->iRow = pData->iDeltaBlocky; + pData->iRowinc = 1; + pData->iCol = pData->iDeltaBlockx; + pData->iColinc = 1; + pData->iRowsamples = pBufdelta->iWidth; + pData->iRowsize = pBuftarget->iRowsize; + /* indicate where to retrieve & where to store */ + pData->pRetrieveobj = (mng_objectp)pDelta; + pData->pStoreobj = (mng_objectp)pTarget; + + if (pData->pRGBArow) /* prevent duplicate allocation! */ + MNG_FREE (pData, pData->pRGBArow, (pData->iDatawidth << 3)) + /* get a temporary row-buffer */ + MNG_ALLOC (pData, pData->pRGBArow, pBufdelta->iRowsize) + + iY = 0; /* this is where we start */ + iRetcode = MNG_NOERROR; /* still oke for now */ + + while ((!iRetcode) && (iY < pBufdelta->iHeight)) + { /* get a row */ + mng_uint8p pWork = pBufdelta->pImgdata + (iY * pBufdelta->iRowsize); + + MNG_COPY (pData->pRGBArow, pWork, pBufdelta->iRowsize); + + if (pData->fScalerow) /* scale it (if necessary) */ + iRetcode = ((mng_scalerow)pData->fScalerow) (pData); + + if (!iRetcode) /* and... execute it */ + iRetcode = ((mng_deltarow)pData->fDeltarow) (pData); + + if (!iRetcode) /* adjust variables for next row */ + iRetcode = next_row (pData); + + iY++; /* and next line */ + } + /* drop the temporary row-buffer */ + MNG_FREE (pData, pData->pRGBArow, pBufdelta->iRowsize) + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } + else + MNG_ERROR (pData, MNG_INVALIDDELTA) + + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_EXECUTE_DELTA_IMAGE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode save_state (mng_datap pData) +{ + mng_savedatap pSave; + mng_imagep pImage; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_SAVE_STATE, MNG_LC_START) +#endif + + if (pData->pSavedata) /* sanity check */ + MNG_ERROR (pData, MNG_INTERNALERROR) + /* get a buffer for saving */ + MNG_ALLOC (pData, pData->pSavedata, sizeof (mng_savedata)) + + pSave = pData->pSavedata; /* address it more directly */ + /* and copy global data from the main struct */ +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + pSave->bHasglobalPLTE = pData->bHasglobalPLTE; + pSave->bHasglobalTRNS = pData->bHasglobalTRNS; + pSave->bHasglobalGAMA = pData->bHasglobalGAMA; + pSave->bHasglobalCHRM = pData->bHasglobalCHRM; + pSave->bHasglobalSRGB = pData->bHasglobalSRGB; + pSave->bHasglobalICCP = pData->bHasglobalICCP; + pSave->bHasglobalBKGD = pData->bHasglobalBKGD; +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + + pSave->iBACKred = pData->iBACKred; + pSave->iBACKgreen = pData->iBACKgreen; + pSave->iBACKblue = pData->iBACKblue; + pSave->iBACKmandatory = pData->iBACKmandatory; + pSave->iBACKimageid = pData->iBACKimageid; + pSave->iBACKtile = pData->iBACKtile; + + pSave->iFRAMmode = pData->iFRAMmode; + pSave->iFRAMdelay = pData->iFRAMdelay; + pSave->iFRAMtimeout = pData->iFRAMtimeout; + pSave->bFRAMclipping = pData->bFRAMclipping; + pSave->iFRAMclipl = pData->iFRAMclipl; + pSave->iFRAMclipr = pData->iFRAMclipr; + pSave->iFRAMclipt = pData->iFRAMclipt; + pSave->iFRAMclipb = pData->iFRAMclipb; + + pSave->iGlobalPLTEcount = pData->iGlobalPLTEcount; + + MNG_COPY (pSave->aGlobalPLTEentries, pData->aGlobalPLTEentries, sizeof (mng_rgbpaltab)) + + pSave->iGlobalTRNSrawlen = pData->iGlobalTRNSrawlen; + MNG_COPY (pSave->aGlobalTRNSrawdata, pData->aGlobalTRNSrawdata, 256) + + pSave->iGlobalGamma = pData->iGlobalGamma; + + pSave->iGlobalWhitepointx = pData->iGlobalWhitepointx; + pSave->iGlobalWhitepointy = pData->iGlobalWhitepointy; + pSave->iGlobalPrimaryredx = pData->iGlobalPrimaryredx; + pSave->iGlobalPrimaryredy = pData->iGlobalPrimaryredy; + pSave->iGlobalPrimarygreenx = pData->iGlobalPrimarygreenx; + pSave->iGlobalPrimarygreeny = pData->iGlobalPrimarygreeny; + pSave->iGlobalPrimarybluex = pData->iGlobalPrimarybluex; + pSave->iGlobalPrimarybluey = pData->iGlobalPrimarybluey; + + pSave->iGlobalRendintent = pData->iGlobalRendintent; + + pSave->iGlobalProfilesize = pData->iGlobalProfilesize; + + if (pSave->iGlobalProfilesize) /* has a profile ? */ + { /* then copy that ! */ + MNG_ALLOC (pData, pSave->pGlobalProfile, pSave->iGlobalProfilesize) + MNG_COPY (pSave->pGlobalProfile, pData->pGlobalProfile, pSave->iGlobalProfilesize) + } + + pSave->iGlobalBKGDred = pData->iGlobalBKGDred; + pSave->iGlobalBKGDgreen = pData->iGlobalBKGDgreen; + pSave->iGlobalBKGDblue = pData->iGlobalBKGDblue; + + /* freeze current image objects */ + pImage = (mng_imagep)pData->pFirstimgobj; + + while (pImage) + { /* freeze the object AND it's buffer */ + pImage->bFrozen = MNG_TRUE; + pImage->pImgbuf->bFrozen = MNG_TRUE; + /* neeeext */ + pImage = (mng_imagep)pImage->sHeader.pNext; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_SAVE_STATE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode mng_reset_objzero (mng_datap pData) +{ + mng_imagep pImage = (mng_imagep)pData->pObjzero; + mng_retcode iRetcode = reset_object_details (pData, pImage, 0, 0, 0, + 0, 0, 0, 0, MNG_TRUE); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + pImage->bVisible = MNG_TRUE; + pImage->bViewable = MNG_TRUE; + pImage->iPosx = 0; + pImage->iPosy = 0; + pImage->bClipped = MNG_FALSE; + pImage->iClipl = 0; + pImage->iClipr = 0; + pImage->iClipt = 0; + pImage->iClipb = 0; + pImage->iMAGN_MethodX = 0; + pImage->iMAGN_MethodY = 0; + pImage->iMAGN_MX = 0; + pImage->iMAGN_MY = 0; + pImage->iMAGN_ML = 0; + pImage->iMAGN_MR = 0; + pImage->iMAGN_MT = 0; + pImage->iMAGN_MB = 0; + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode restore_state (mng_datap pData) +{ + mng_savedatap pSave; + mng_imagep pImage; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_STATE, MNG_LC_START) +#endif + /* restore object 0 status !!! */ + iRetcode = mng_reset_objzero (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* fresh cycle; fake no frames done yet */ + pData->bFramedone = MNG_FALSE; + + if (pData->pSavedata) /* do we have a saved state ? */ + { + pSave = pData->pSavedata; /* address it more directly */ + /* and copy it back to the main struct */ +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + pData->bHasglobalPLTE = pSave->bHasglobalPLTE; + pData->bHasglobalTRNS = pSave->bHasglobalTRNS; + pData->bHasglobalGAMA = pSave->bHasglobalGAMA; + pData->bHasglobalCHRM = pSave->bHasglobalCHRM; + pData->bHasglobalSRGB = pSave->bHasglobalSRGB; + pData->bHasglobalICCP = pSave->bHasglobalICCP; + pData->bHasglobalBKGD = pSave->bHasglobalBKGD; +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + + pData->iBACKred = pSave->iBACKred; + pData->iBACKgreen = pSave->iBACKgreen; + pData->iBACKblue = pSave->iBACKblue; + pData->iBACKmandatory = pSave->iBACKmandatory; + pData->iBACKimageid = pSave->iBACKimageid; + pData->iBACKtile = pSave->iBACKtile; + + pData->iFRAMmode = pSave->iFRAMmode; + pData->iFRAMdelay = pSave->iFRAMdelay; + pData->iFRAMtimeout = pSave->iFRAMtimeout; + pData->bFRAMclipping = pSave->bFRAMclipping; + pData->iFRAMclipl = pSave->iFRAMclipl; + pData->iFRAMclipr = pSave->iFRAMclipr; + pData->iFRAMclipt = pSave->iFRAMclipt; + pData->iFRAMclipb = pSave->iFRAMclipb; + /* also the next subframe parms */ + pData->iFramemode = pSave->iFRAMmode; + pData->iFramedelay = pSave->iFRAMdelay; + pData->iFrametimeout = pSave->iFRAMtimeout; + pData->bFrameclipping = pSave->bFRAMclipping; + pData->iFrameclipl = pSave->iFRAMclipl; + pData->iFrameclipr = pSave->iFRAMclipr; + pData->iFrameclipt = pSave->iFRAMclipt; + pData->iFrameclipb = pSave->iFRAMclipb; + + pData->iNextdelay = pSave->iFRAMdelay; + + pData->iGlobalPLTEcount = pSave->iGlobalPLTEcount; + MNG_COPY (pData->aGlobalPLTEentries, pSave->aGlobalPLTEentries, sizeof (mng_rgbpaltab)) + + pData->iGlobalTRNSrawlen = pSave->iGlobalTRNSrawlen; + MNG_COPY (pData->aGlobalTRNSrawdata, pSave->aGlobalTRNSrawdata, 256) + + pData->iGlobalGamma = pSave->iGlobalGamma; + + pData->iGlobalWhitepointx = pSave->iGlobalWhitepointx; + pData->iGlobalWhitepointy = pSave->iGlobalWhitepointy; + pData->iGlobalPrimaryredx = pSave->iGlobalPrimaryredx; + pData->iGlobalPrimaryredy = pSave->iGlobalPrimaryredy; + pData->iGlobalPrimarygreenx = pSave->iGlobalPrimarygreenx; + pData->iGlobalPrimarygreeny = pSave->iGlobalPrimarygreeny; + pData->iGlobalPrimarybluex = pSave->iGlobalPrimarybluex; + pData->iGlobalPrimarybluey = pSave->iGlobalPrimarybluey; + + pData->iGlobalRendintent = pSave->iGlobalRendintent; + + pData->iGlobalProfilesize = pSave->iGlobalProfilesize; + + if (pData->iGlobalProfilesize) /* has a profile ? */ + { /* then copy that ! */ + MNG_ALLOC (pData, pData->pGlobalProfile, pData->iGlobalProfilesize) + MNG_COPY (pData->pGlobalProfile, pSave->pGlobalProfile, pData->iGlobalProfilesize) + } + + pData->iGlobalBKGDred = pSave->iGlobalBKGDred; + pData->iGlobalBKGDgreen = pSave->iGlobalBKGDgreen; + pData->iGlobalBKGDblue = pSave->iGlobalBKGDblue; + } + else /* no saved-data; so reset the lot */ + { +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + pData->bHasglobalPLTE = MNG_FALSE; + pData->bHasglobalTRNS = MNG_FALSE; + pData->bHasglobalGAMA = MNG_FALSE; + pData->bHasglobalCHRM = MNG_FALSE; + pData->bHasglobalSRGB = MNG_FALSE; + pData->bHasglobalICCP = MNG_FALSE; + pData->bHasglobalBKGD = MNG_FALSE; +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + + if (!pData->bEMNGMAhack) /* TODO: remove line in 1.0.0 !!! */ + { /* TODO: remove line in 1.0.0 !!! */ + pData->iBACKred = 0; + pData->iBACKgreen = 0; + pData->iBACKblue = 0; + pData->iBACKmandatory = 0; + pData->iBACKimageid = 0; + pData->iBACKtile = 0; + } /* TODO: remove line in 1.0.0 !!! */ + + pData->iFRAMmode = 1; + pData->iFRAMdelay = 1; + pData->iFRAMtimeout = 0x7fffffffl; + pData->bFRAMclipping = MNG_FALSE; + pData->iFRAMclipl = 0; + pData->iFRAMclipr = 0; + pData->iFRAMclipt = 0; + pData->iFRAMclipb = 0; + /* also the next subframe parms */ + pData->iFramemode = 1; + pData->iFramedelay = 1; + pData->iFrametimeout = 0x7fffffffl; + pData->bFrameclipping = MNG_FALSE; + pData->iFrameclipl = 0; + pData->iFrameclipr = 0; + pData->iFrameclipt = 0; + pData->iFrameclipb = 0; + + pData->iNextdelay = 1; + + pData->iGlobalPLTEcount = 0; + + pData->iGlobalTRNSrawlen = 0; + + pData->iGlobalGamma = 0; + + pData->iGlobalWhitepointx = 0; + pData->iGlobalWhitepointy = 0; + pData->iGlobalPrimaryredx = 0; + pData->iGlobalPrimaryredy = 0; + pData->iGlobalPrimarygreenx = 0; + pData->iGlobalPrimarygreeny = 0; + pData->iGlobalPrimarybluex = 0; + pData->iGlobalPrimarybluey = 0; + + pData->iGlobalRendintent = 0; + + if (pData->iGlobalProfilesize) /* free a previous profile ? */ + MNG_FREE (pData, pData->pGlobalProfile, pData->iGlobalProfilesize) + + pData->iGlobalProfilesize = 0; + + pData->iGlobalBKGDred = 0; + pData->iGlobalBKGDgreen = 0; + pData->iGlobalBKGDblue = 0; + } + + if (!pData->bEMNGMAhack) /* TODO: remove line in 1.0.0 !!! */ + { /* TODO: remove line in 1.0.0 !!! */ + /* drop un-frozen image objects */ + pImage = (mng_imagep)pData->pFirstimgobj; + + while (pImage) + { /* is it un-frozen ? */ + if (!pImage->bFrozen) + { + mng_imagep pPrev = (mng_imagep)pImage->sHeader.pPrev; + mng_imagep pNext = (mng_imagep)pImage->sHeader.pNext; + + if (pPrev) /* unlink it */ + pPrev->sHeader.pNext = pNext; + else + pData->pFirstimgobj = pNext; + + if (pNext) + pNext->sHeader.pPrev = pPrev; + else + pData->pLastimgobj = pPrev; + + if (pImage->pImgbuf->bFrozen) /* buffer frozen ? */ + { + if (pImage->pImgbuf->iRefcount <= 2) + MNG_ERROR (pData, MNG_INTERNALERROR) + /* decrease ref counter */ + pImage->pImgbuf->iRefcount--; + /* just cleanup the object then */ + MNG_FREEX (pData, pImage, sizeof (mng_image)) + } + else + { /* free the image buffer */ + iRetcode = free_imagedataobject (pData, pImage->pImgbuf); + /* and cleanup the object */ + MNG_FREEX (pData, pImage, sizeof (mng_image)) + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + pImage = pNext; /* this is the next */ + } + else /* neeeext */ + pImage = (mng_imagep)pImage->sHeader.pNext; + + } + } /* TODO: remove line in 1.0.0 !!! */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_STATE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * General display processing routine * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode process_display (mng_datap pData) +{ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY, MNG_LC_START) +#endif + + if (!pData->iBreakpoint) /* not broken previously ? */ + { + if ((pData->iRequestframe) || (pData->iRequestlayer) || (pData->iRequesttime)) + { + pData->bSearching = MNG_TRUE; /* indicate we're searching */ + + iRetcode = clear_canvas (pData); /* make the canvas virgin black ?!? */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* let's start from the top, shall we */ + pData->pCurraniobj = pData->pFirstaniobj; + } + } + + do /* process the objects */ + { + if (pData->bSearching) /* are we looking sor something ? */ + { + if ((pData->iRequestframe) && + (pData->iRequestframe < ((mng_object_headerp)pData->pCurraniobj)->iFramenr)) + { + pData->iRequestframe = 0; /* found the frame ! */ + pData->bSearching = MNG_FALSE; + } + else + if ((pData->iRequestlayer) && + (pData->iRequestlayer < ((mng_object_headerp)pData->pCurraniobj)->iLayernr)) + { + pData->iRequestlayer = 0; /* found the layer ! */ + pData->bSearching = MNG_FALSE; + } + else + if ((pData->iRequesttime) && + (pData->iRequesttime < ((mng_object_headerp)pData->pCurraniobj)->iPlaytime)) + { + pData->iRequesttime = 0; /* found the playtime ! */ + pData->bSearching = MNG_FALSE; + } + } + /* do we need to finish something first ? */ + if ((pData->iBreakpoint) && (pData->iBreakpoint < 99)) + { + switch (pData->iBreakpoint) /* return to broken display routine */ + { + case 1 : { iRetcode = process_display_fram2 (pData); break; } + case 3 : ; /* same as 4 !!! */ + case 4 : { iRetcode = process_display_show (pData); break; } + case 5 : { iRetcode = process_display_clon2 (pData); break; } + case 9 : { iRetcode = process_display_magn2 (pData); break; } + default : MNG_ERROR (pData, MNG_INTERNALERROR) + } + } + else + { + if (pData->pCurraniobj) + iRetcode = ((mng_object_headerp)pData->pCurraniobj)->fProcess (pData, pData->pCurraniobj); + } + + if (!pData->bTimerset) /* reset breakpoint flag ? */ + pData->iBreakpoint = 0; + /* can we advance to next object ? */ + if ((!iRetcode) && (pData->pCurraniobj) && + (!pData->bTimerset) && (!pData->bSectionwait)) + { + pData->pCurraniobj = ((mng_object_headerp)pData->pCurraniobj)->pNext; + /* MEND processing to be done ? */ + if ((pData->eImagetype == mng_it_mng) && (!pData->pCurraniobj)) + iRetcode = process_display_mend (pData); + + if (!pData->pCurraniobj) /* refresh after last image ? */ + pData->bNeedrefresh = MNG_TRUE; + } + } /* until error or a break or no more objects */ + while ((!iRetcode) && (pData->pCurraniobj) && + (!pData->bTimerset) && (!pData->bSectionwait) && (!pData->bFreezing)); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* refresh needed ? */ + if ((!pData->bTimerset) && (pData->bNeedrefresh)) + { + iRetcode = display_progressive_refresh (pData, 1); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + /* timer break ? */ + if ((pData->bTimerset) && (!pData->iBreakpoint)) + pData->iBreakpoint = 99; + else + if (!pData->bTimerset) + pData->iBreakpoint = 0; /* reset if no timer break */ + + if ((!pData->bTimerset) && (!pData->pCurraniobj)) + pData->bRunning = MNG_FALSE; /* all done now ! */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Chunk display processing routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode process_display_ihdr (mng_datap pData) +{ /* address the current "object" if any */ + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IHDR, MNG_LC_START) +#endif + + if (!pData->bHasDHDR) + { + pData->fInitrowproc = MNG_NULL; /* do nothing by default */ + pData->fDisplayrow = MNG_NULL; + pData->fCorrectrow = MNG_NULL; + pData->fStorerow = MNG_NULL; + pData->fProcessrow = MNG_NULL; + pData->fDifferrow = MNG_NULL; + pData->pStoreobj = MNG_NULL; + } + + if (!pData->iBreakpoint) /* not previously broken ? */ + { + mng_retcode iRetcode = MNG_NOERROR; + + if (pData->bHasDHDR) /* is a delta-image ? */ + { + if (pData->iDeltatype == MNG_DELTATYPE_REPLACE) + iRetcode = reset_object_details (pData, (mng_imagep)pData->pDeltaImage, + pData->iDatawidth, pData->iDataheight, + pData->iBitdepth, pData->iColortype, + pData->iCompression, pData->iFilter, + pData->iInterlace, MNG_TRUE); + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iBitdepth; + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iBitdepth; + } + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE) ) + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iBitdepth; + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE) ) + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iBitdepth; + + /* process immediatly if bitdepth & colortype are equal */ + pData->bDeltaimmediate = + (mng_bool)((pData->iBitdepth == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iBitdepth ) && + (pData->iColortype == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iColortype) ); + } + else + { + if (pImage) /* update object buffer ? */ + iRetcode = reset_object_details (pData, pImage, + pData->iDatawidth, pData->iDataheight, + pData->iBitdepth, pData->iColortype, + pData->iCompression, pData->iFilter, + pData->iInterlace, MNG_TRUE); + else + iRetcode = reset_object_details (pData, (mng_imagep)pData->pObjzero, + pData->iDatawidth, pData->iDataheight, + pData->iBitdepth, pData->iColortype, + pData->iCompression, pData->iFilter, + pData->iInterlace, MNG_TRUE); + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + if (!pData->bHasDHDR) + { + if (pImage) /* real object ? */ + pData->pStoreobj = pImage; /* tell the row routines */ + else /* otherwise use object 0 */ + pData->pStoreobj = pData->pObjzero; + /* display "on-the-fly" ? */ + if ( (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX == 0) && + (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY == 0) && + ( (pData->eImagetype == mng_it_png ) || + (((mng_imagep)pData->pStoreobj)->bVisible) ) ) + { + next_layer (pData); /* that's a new layer then ! */ + + if (pData->bTimerset) /* timer break ? */ + pData->iBreakpoint = 2; + else + { + pData->iBreakpoint = 0; + /* anything to display ? */ + if ((pData->iDestr > pData->iDestl) && (pData->iDestb > pData->iDestt)) + set_display_routine (pData); /* then determine display routine */ + } + } + } + + if (!pData->bTimerset) /* no timer break ? */ + { + switch (pData->iColortype) /* determine row initialization routine */ + { + case 0 : { /* gray */ + switch (pData->iBitdepth) + { + case 1 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g1_ni; + else + pData->fInitrowproc = (mng_fptr)init_g1_i; + + break; + } + case 2 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g2_ni; + else + pData->fInitrowproc = (mng_fptr)init_g2_i; + + break; + } + case 4 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g4_ni; + else + pData->fInitrowproc = (mng_fptr)init_g4_i; + + break; + } + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g8_ni; + else + pData->fInitrowproc = (mng_fptr)init_g8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g16_ni; + else + pData->fInitrowproc = (mng_fptr)init_g16_i; + + break; + } + } + + break; + } + case 2 : { /* rgb */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgb8_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgb8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgb16_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgb16_i; + + break; + } + } + + break; + } + case 3 : { /* indexed */ + switch (pData->iBitdepth) + { + case 1 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx1_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx1_i; + + break; + } + case 2 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx2_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx2_i; + + break; + } + case 4 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx4_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx4_i; + + break; + } + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx8_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx8_i; + + break; + } + } + + break; + } + case 4 : { /* gray+alpha */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_ga8_ni; + else + pData->fInitrowproc = (mng_fptr)init_ga8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_ga16_ni; + else + pData->fInitrowproc = (mng_fptr)init_ga16_i; + + break; + } + } + + break; + } + case 6 : { /* rgb+alpha */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgba8_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgba8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgba16_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgba16_i; + + break; + } + } + + break; + } + } + + pData->iFilterofs = 0; /* determine filter characteristics */ + pData->iLevel0 = 0; /* default levels */ + pData->iLevel1 = 0; + pData->iLevel2 = 0; + pData->iLevel3 = 0; + /* leveling & differing ? */ +/* if (pData->iFilter & 0x40) + { + switch (pData->iColortype) + { + case 0 : { + if (pData->iBitdepth <= 8) + pData->iFilterofs = 1; + else + pData->iFilterofs = 2; + + break; + } + case 2 : { + if (pData->iBitdepth <= 8) + pData->iFilterofs = 3; + else + pData->iFilterofs = 6; + + break; + } + case 3 : { + pData->iFilterofs = 1; + break; + } + case 4 : { + if (pData->iBitdepth <= 8) + pData->iFilterofs = 2; + else + pData->iFilterofs = 4; + + break; + } + case 6 : { + if (pData->iBitdepth <= 8) + pData->iPixelofs = 5; + else + pData->iFilterofs = 8; + + break; + } + } + } */ + /* no adaptive filtering ? */ +/* if (pData->iFilter & 0x01) + pData->iPixelofs = pData->iFilterofs; + else */ + pData->iPixelofs = pData->iFilterofs + 1; + + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_idat (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata) +{ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IDAT, MNG_LC_START) +#endif + + if (pData->bRestorebkgd) /* need to restore the background ? */ + { + pData->bRestorebkgd = MNG_FALSE; + iRetcode = load_bkgdlayer (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if ((pData->bDisplaying) && (pData->bRunning)) + pData->iLayerseq++; /* and it counts as a layer then ! */ + } + + if (pData->fInitrowproc) /* need to initialize row processing? */ + { + iRetcode = ((mng_initrowproc)pData->fInitrowproc) (pData); + pData->fInitrowproc = MNG_NULL; /* only call this once !!! */ + } + + if ((!iRetcode) && (!pData->bInflating)) + /* initialize inflate */ + iRetcode = mngzlib_inflateinit (pData); + + if (!iRetcode) /* all ok? then inflate, my man */ + iRetcode = mngzlib_inflaterows (pData, iRawlen, pRawdata); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_iend (mng_datap pData) +{ + mng_retcode iRetcode, iRetcode2; + mng_bool bDodisplay = MNG_FALSE; + mng_bool bMagnify = MNG_FALSE; + mng_bool bCleanup = (mng_bool)(pData->iBreakpoint != 0); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IEND, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_JNG /* progressive+alpha JNG can be displayed now */ + if ( (pData->bHasJHDR ) && + ( (pData->bJPEGprogressive) || (pData->bJPEGprogressive2)) && + ( (pData->eImagetype == mng_it_jng ) || + (((mng_imagep)pData->pStoreobj)->bVisible) ) && + ( (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) ) ) + bDodisplay = MNG_TRUE; +#endif + + if ( (pData->pStoreobj) && /* on-the-fly magnification ? */ + ( (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX) || + (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY) ) ) + bMagnify = MNG_TRUE; + + if ((pData->bHasBASI) || /* was it a BASI stream */ + (bDodisplay) || /* or should we display the JNG */ + (bMagnify) || /* or should we magnify it */ + /* or did we get broken here last time ? */ + ((pData->iBreakpoint) && (pData->iBreakpoint != 8))) + { + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) /* or was it object 0 ? */ + pImage = (mng_imagep)pData->pObjzero; + /* display it now then ? */ + if ((pImage->bVisible) && (pImage->bViewable)) + { /* ok, so do it */ + iRetcode = display_image (pData, pImage, bDodisplay); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bTimerset) /* timer break ? */ + pData->iBreakpoint = 6; + } + } + else + if ((pData->bHasDHDR) || /* was it a DHDR stream */ + (pData->iBreakpoint == 8)) /* or did we get broken here last time ? */ + { + mng_imagep pImage = (mng_imagep)pData->pDeltaImage; + + if (!pData->iBreakpoint) + { /* perform the delta operations needed */ + iRetcode = execute_delta_image (pData, pImage, (mng_imagep)pData->pObjzero); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + /* display it now then ? */ + if ((pImage->bVisible) && (pImage->bViewable)) + { /* ok, so do it */ + iRetcode = display_image (pData, pImage, MNG_FALSE); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bTimerset) /* timer break ? */ + pData->iBreakpoint = 8; + } + } + + if (!pData->bTimerset) /* can we continue ? */ + { + pData->iBreakpoint = 0; /* clear this flag now ! */ + /* cleanup object 0 */ + reset_object_details (pData, (mng_imagep)pData->pObjzero, + 0, 0, 0, 0, 0, 0, 0, MNG_TRUE); + + if (pData->bInflating) /* if we've been inflating */ + { /* cleanup row-processing, */ + iRetcode = cleanup_rowproc (pData); + /* also cleanup inflate! */ + iRetcode2 = mngzlib_inflatefree (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + if (iRetcode2) + return iRetcode2; + } + +#ifdef MNG_INCLUDE_JNG + if (pData->bJPEGdecompress) /* if we've been decompressing JDAT */ + { /* cleanup row-processing, */ + iRetcode = cleanup_rowproc (pData); + /* also cleanup decompress! */ + iRetcode2 = mngjpeg_decompressfree (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + if (iRetcode2) + return iRetcode2; + } + + if (pData->bJPEGdecompress2) /* if we've been decompressing JDAA */ + { /* cleanup row-processing, */ + iRetcode = cleanup_rowproc (pData); + /* also cleanup decompress! */ + iRetcode2 = mngjpeg_decompressfree2 (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + if (iRetcode2) + return iRetcode2; + } +#endif + + if (bCleanup) /* if we got broken last time we need to cleanup */ + { + pData->bHasIHDR = MNG_FALSE; /* IEND signals the end for most ... */ + pData->bHasBASI = MNG_FALSE; + pData->bHasDHDR = MNG_FALSE; +#ifdef MNG_INCLUDE_JNG + pData->bHasJHDR = MNG_FALSE; + pData->bHasJSEP = MNG_FALSE; + pData->bHasJDAA = MNG_FALSE; + pData->bHasJDAT = MNG_FALSE; +#endif + pData->bHasPLTE = MNG_FALSE; + pData->bHasTRNS = MNG_FALSE; + pData->bHasGAMA = MNG_FALSE; + pData->bHasCHRM = MNG_FALSE; + pData->bHasSRGB = MNG_FALSE; + pData->bHasICCP = MNG_FALSE; + pData->bHasBKGD = MNG_FALSE; + pData->bHasIDAT = MNG_FALSE; + } + /* if the image was displayed on the fly, */ + /* we'll have to make the app refresh */ + if ((pData->eImagetype != mng_it_mng) && (pData->fDisplayrow)) + pData->bNeedrefresh = MNG_TRUE; + + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_mend (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MEND, MNG_LC_START) +#endif + /* TERM processed ? */ + if ((pData->bDisplaying) && (pData->bRunning) && + (pData->bHasTERM) && (pData->pTermaniobj)) + { + mng_retcode iRetcode; + mng_ani_termp pTERM; + /* get the right animation object ! */ + pTERM = (mng_ani_termp)pData->pTermaniobj; + + pData->iIterations++; /* increase iteration count */ + + switch (pTERM->iTermaction) /* determine what to do! */ + { + case 0 : { /* show last frame indefinitly */ + break; /* piece of cake, that is... */ + } + + case 1 : { /* cease displaying anything */ + pData->bFrameclipping = MNG_FALSE; + load_bkgdlayer (pData); + break; + } + + case 2 : { /* show first image after TERM */ + + /* TODO: something */ + + break; + } + + case 3 : { /* repeat */ + if ((pTERM->iItermax) && (pTERM->iItermax < 0x7FFFFFFF)) + pTERM->iItermax--; + + if (pTERM->iItermax) /* go back to TERM ? */ + { /* restore to initial or SAVE state */ + iRetcode = restore_state (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* notify the app ? */ + if (pData->fProcessmend) + { + mng_bool bOke = pData->fProcessmend ((mng_handle)pData, + pData->iIterations, + pTERM->iItermax); + if (!bOke) /* stop here and now ? */ + break; + } + /* restart from TERM chunk */ + pData->pCurraniobj = pTERM; + + if (pTERM->iDelay) /* set the delay (?) */ + { + mng_uint32 iWaitfor = 1000; + /* what are we aiming for */ + if (pData->iTicks) + { /* honor speed modifier */ + switch (pData->iSpeed) + { + case mng_st_fast : + { + iWaitfor = (mng_uint32)(( 500 * pTERM->iDelay) / pData->iTicks); + break; + } + case mng_st_slow : + { + iWaitfor = (mng_uint32)((3000 * pTERM->iDelay) / pData->iTicks); + break; + } + case mng_st_slowest : + { + iWaitfor = (mng_uint32)((8000 * pTERM->iDelay) / pData->iTicks); + break; + } + default : + { + iWaitfor = (mng_uint32)((1000 * pTERM->iDelay) / pData->iTicks); + } + } + } + + iRetcode = display_progressive_refresh (pData, iWaitfor); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + else + { + switch (pTERM->iIteraction) + { + case 0 : { /* show last frame indefinitly */ + break; /* piece of cake, that is... */ + } + + case 1 : { /* cease displaying anything */ + pData->bFrameclipping = MNG_FALSE; + load_bkgdlayer (pData); + break; + } + + case 2 : { /* show first image after TERM */ + + /* TODO: something */ + + break; + } + + } + } + + break; + } + + } + } + + if (!pData->pCurraniobj) /* always let the app refresh at the end ! */ + pData->bNeedrefresh = MNG_TRUE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MEND, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_defi (mng_datap pData) +{ + mng_imagep pImage; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DEFI, MNG_LC_START) +#endif + + if (!pData->iDEFIobjectid) /* object id=0 ? */ + { + pImage = (mng_imagep)pData->pObjzero; + + if (pData->bDEFIhasdonotshow) + pImage->bVisible = (mng_bool)(pData->iDEFIdonotshow == 0); + + if (pData->bDEFIhasloca) + { + pImage->iPosx = pData->iDEFIlocax; + pImage->iPosy = pData->iDEFIlocay; + } + + if (pData->bDEFIhasclip) + { + pImage->bClipped = pData->bDEFIhasclip; + pImage->iClipl = pData->iDEFIclipl; + pImage->iClipr = pData->iDEFIclipr; + pImage->iClipt = pData->iDEFIclipt; + pImage->iClipb = pData->iDEFIclipb; + } + + pData->pCurrentobj = 0; /* not a real object ! */ + } + else + { /* already exists ? */ + pImage = (mng_imagep)find_imageobject (pData, pData->iDEFIobjectid); + + if (!pImage) /* if not; create new */ + { + mng_retcode iRetcode = create_imageobject (pData, pData->iDEFIobjectid, + (mng_bool)(pData->iDEFIconcrete == 1), + (mng_bool)(pData->iDEFIdonotshow == 0), + MNG_FALSE, 0, 0, 0, 0, 0, 0, 0, + pData->iDEFIlocax, pData->iDEFIlocay, + pData->bDEFIhasclip, + pData->iDEFIclipl, pData->iDEFIclipr, + pData->iDEFIclipt, pData->iDEFIclipb, + &pImage); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + else + { /* exists; then set new info */ + if (pData->bDEFIhasdonotshow) + pImage->bVisible = (mng_bool)(pData->iDEFIdonotshow == 0); + + pImage->bViewable = MNG_FALSE; + + if (pData->bDEFIhasloca) + { + pImage->iPosx = pData->iDEFIlocax; + pImage->iPosy = pData->iDEFIlocay; + } + + if (pData->bDEFIhasclip) + { + pImage->bClipped = pData->bDEFIhasclip; + pImage->iClipl = pData->iDEFIclipl; + pImage->iClipr = pData->iDEFIclipr; + pImage->iClipt = pData->iDEFIclipt; + pImage->iClipb = pData->iDEFIclipb; + } + + if (pData->bDEFIhasconcrete) + pImage->pImgbuf->bConcrete = (mng_bool)(pData->iDEFIconcrete == 1); + } + + pData->pCurrentobj = pImage; /* others may want to know this */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_basi (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_bool bHasalpha, + mng_uint16 iAlpha, + mng_uint8 iViewable) +{ /* address the current "object" if any */ + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + mng_uint8p pWork; + mng_uint32 iX; + mng_imagedatap pBuf; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_BASI, MNG_LC_START) +#endif + + if (!pImage) /* or is it an "on-the-fly" image ? */ + pImage = (mng_imagep)pData->pObjzero; + /* address the object-buffer */ + pBuf = pImage->pImgbuf; + + pData->fDisplayrow = MNG_NULL; /* do nothing by default */ + pData->fCorrectrow = MNG_NULL; + pData->fStorerow = MNG_NULL; + pData->fProcessrow = MNG_NULL; + /* set parms now that they're known */ + iRetcode = reset_object_details (pData, pImage, pData->iDatawidth, + pData->iDataheight, pData->iBitdepth, + pData->iColortype, pData->iCompression, + pData->iFilter, pData->iInterlace, MNG_FALSE); + if (iRetcode) /* on error bail out */ + return iRetcode; + /* save the viewable flag */ + pImage->bViewable = (mng_bool)(iViewable == 1); + pBuf->bViewable = pImage->bViewable; + pData->pStoreobj = pImage; /* let row-routines know which object */ + + pWork = pBuf->pImgdata; /* fill the object-buffer with the specified + "color" sample */ + switch (pData->iColortype) /* depending on color_type & bit_depth */ + { + case 0 : { /* gray */ + if (pData->iBitdepth == 16) + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + mng_put_uint16 (pWork, iRed); + pWork += 2; + } + } + else + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + *pWork = (mng_uint8)iRed; + pWork++; + } + } + /* force tRNS ? */ + if ((bHasalpha) && (!iAlpha)) + { + pBuf->bHasTRNS = MNG_TRUE; + pBuf->iTRNSgray = iRed; + } + + break; + } + + case 2 : { /* rgb */ + if (pData->iBitdepth == 16) + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + mng_put_uint16 (pWork, iRed ); + mng_put_uint16 (pWork+2, iGreen); + mng_put_uint16 (pWork+4, iBlue ); + pWork += 6; + } + } + else + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + *pWork = (mng_uint8)iRed; + *(pWork+1) = (mng_uint8)iGreen; + *(pWork+2) = (mng_uint8)iBlue; + pWork += 3; + } + } + /* force tRNS ? */ + if ((bHasalpha) && (!iAlpha)) + { + pBuf->bHasTRNS = MNG_TRUE; + pBuf->iTRNSred = iRed; + pBuf->iTRNSgreen = iGreen; + pBuf->iTRNSblue = iBlue; + } + + break; + } + + case 3 : { /* indexed */ + pBuf->bHasPLTE = MNG_TRUE; + + switch (pData->iBitdepth) + { + case 1 : { pBuf->iPLTEcount = 2; break; } + case 2 : { pBuf->iPLTEcount = 4; break; } + case 4 : { pBuf->iPLTEcount = 16; break; } + case 8 : { pBuf->iPLTEcount = 256; break; } + default : { pBuf->iPLTEcount = 1; break; } + } + + pBuf->aPLTEentries [0].iRed = (mng_uint8)iRed; + pBuf->aPLTEentries [0].iGreen = (mng_uint8)iGreen; + pBuf->aPLTEentries [0].iBlue = (mng_uint8)iBlue; + + for (iX = 1; iX < pBuf->iPLTEcount; iX++) + { + pBuf->aPLTEentries [iX].iRed = 0; + pBuf->aPLTEentries [iX].iGreen = 0; + pBuf->aPLTEentries [iX].iBlue = 0; + } + /* force tRNS ? */ + if ((bHasalpha) && (iAlpha < 255)) + { + pBuf->bHasTRNS = MNG_TRUE; + pBuf->iTRNScount = 1; + pBuf->aTRNSentries [0] = (mng_uint8)iAlpha; + } + + break; + } + + case 4 : { /* gray+alpha */ + if (pData->iBitdepth == 16) + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + mng_put_uint16 (pWork, iRed); + mng_put_uint16 (pWork+2, iAlpha); + pWork += 4; + } + } + else + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + *pWork = (mng_uint8)iRed; + *(pWork+1) = (mng_uint8)iAlpha; + pWork += 2; + } + } + + break; + } + + case 6 : { /* rgb+alpha */ + if (pData->iBitdepth == 16) + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + mng_put_uint16 (pWork, iRed); + mng_put_uint16 (pWork+2, iGreen); + mng_put_uint16 (pWork+4, iBlue); + mng_put_uint16 (pWork+6, iAlpha); + pWork += 8; + } + } + else + { + for (iX = 0; iX < pData->iDatawidth * pData->iDataheight; iX++) + { + *pWork = (mng_uint8)iRed; + *(pWork+1) = (mng_uint8)iGreen; + *(pWork+2) = (mng_uint8)iBlue; + *(pWork+3) = (mng_uint8)iAlpha; + pWork += 4; + } + } + + break; + } + + } + + switch (pData->iColortype) /* determine row initialization routine */ + { /* just to accomodate IDAT if it arrives */ + case 0 : { /* gray */ + switch (pData->iBitdepth) + { + case 1 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g1_ni; + else + pData->fInitrowproc = (mng_fptr)init_g1_i; + + break; + } + case 2 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g2_ni; + else + pData->fInitrowproc = (mng_fptr)init_g2_i; + + break; + } + case 4 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g4_ni; + else + pData->fInitrowproc = (mng_fptr)init_g4_i; + + break; + } + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g8_ni; + else + pData->fInitrowproc = (mng_fptr)init_g8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g16_ni; + else + pData->fInitrowproc = (mng_fptr)init_g16_i; + + break; + } + } + + break; + } + case 2 : { /* rgb */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgb8_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgb8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgb16_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgb16_i; + + break; + } + } + + break; + } + case 3 : { /* indexed */ + switch (pData->iBitdepth) + { + case 1 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx1_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx1_i; + + break; + } + case 2 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx2_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx2_i; + + break; + } + case 4 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx4_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx4_i; + + break; + } + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx8_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx8_i; + + break; + } + } + + break; + } + case 4 : { /* gray+alpha */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_ga8_ni; + else + pData->fInitrowproc = (mng_fptr)init_ga8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_ga16_ni; + else + pData->fInitrowproc = (mng_fptr)init_ga16_i; + + break; + } + } + + break; + } + case 6 : { /* rgb+alpha */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgba8_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgba8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgba16_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgba16_i; + + break; + } + } + + break; + } + } + + pData->iFilterofs = 0; /* determine filter characteristics */ + pData->iLevel0 = 0; /* default levels */ + pData->iLevel1 = 0; + pData->iLevel2 = 0; + pData->iLevel3 = 0; + /* leveling & differing ? */ +/* if (pData->iFilter & 0x40) + { + switch (pData->iColortype) + { + case 0 : { + if (pData->iBitdepth <= 8) + pData->iFilterofs = 1; + else + pData->iFilterofs = 2; + + break; + } + case 2 : { + if (pData->iBitdepth <= 8) + pData->iFilterofs = 3; + else + pData->iFilterofs = 6; + + break; + } + case 3 : { + pData->iFilterofs = 1; + break; + } + case 4 : { + if (pData->iBitdepth <= 8) + pData->iFilterofs = 2; + else + pData->iFilterofs = 4; + + break; + } + case 6 : { + if (pData->iBitdepth <= 8) + pData->iPixelofs = 5; + else + pData->iFilterofs = 8; + + break; + } + } + } */ + /* no adaptive filtering ? */ +/* if (pData->iFilter & 0x01) + pData->iPixelofs = pData->iFilterofs; + else */ + pData->iPixelofs = pData->iFilterofs + 1; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_clon (mng_datap pData, + mng_uint16 iSourceid, + mng_uint16 iCloneid, + mng_uint8 iClonetype, + mng_bool bHasdonotshow, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy) +{ + mng_imagep pSource, pClone; + mng_bool bVisible, bAbstract; + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_START) +#endif + /* locate the source object first */ + pSource = find_imageobject (pData, iSourceid); + /* check if the clone exists */ + pClone = find_imageobject (pData, iCloneid); + + if (!pSource) /* source must exist ! */ + MNG_ERROR (pData, MNG_OBJECTUNKNOWN); + + if (pClone) /* clone must not exist ! */ + MNG_ERROR (pData, MNG_OBJECTEXISTS); + + if (bHasdonotshow) /* DoNotShow flag filled ? */ + bVisible = (mng_bool)(iDonotshow == 0); + else + bVisible = pSource->bVisible; + + bAbstract = (mng_bool)(iConcrete == 1); + + switch (iClonetype) /* determine action to take */ + { + case 0 : { /* full clone */ + iRetcode = clone_imageobject (pData, iCloneid, MNG_FALSE, + bVisible, bAbstract, bHasloca, + iLocationtype, iLocationx, iLocationy, + pSource, &pClone); + break; + } + + case 1 : { /* partial clone */ + iRetcode = clone_imageobject (pData, iCloneid, MNG_TRUE, + bVisible, bAbstract, bHasloca, + iLocationtype, iLocationx, iLocationy, + pSource, &pClone); + break; + } + + case 2 : { /* renumber object */ + iRetcode = renum_imageobject (pData, pSource, iCloneid, + bVisible, bAbstract, bHasloca, + iLocationtype, iLocationx, iLocationy); + pClone = pSource; + break; + } + + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + + /* display on the fly ? */ + if ((pClone->bViewable) && (pClone->bVisible)) + { + pData->pLastclone = pClone; /* remember in case of timer break ! */ + /* display it */ + display_image (pData, pClone, MNG_FALSE); + + if (pData->bTimerset) /* timer break ? */ + pData->iBreakpoint = 5; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_clon2 (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_START) +#endif + /* only called after timer break ! */ + display_image (pData, (mng_imagep)pData->pLastclone, MNG_FALSE); + pData->iBreakpoint = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_disc (mng_datap pData, + mng_uint32 iCount, + mng_uint16p pIds) +{ + mng_uint32 iX; + mng_imagep pImage; + mng_uint32 iRetcode; +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DISC, MNG_LC_START) +#endif + + if (iCount) /* specific list ? */ + { + mng_uint16p pWork = pIds; + + for (iX = 0; iX < iCount; iX++) /* iterate the list */ + { + pImage = find_imageobject (pData, *pWork++); + + if (pImage) /* found the object ? */ + { /* then drop it */ + iRetcode = free_imageobject (pData, pImage); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + } + else /* empty: drop all un-frozen objects */ + { + mng_imagep pNext = (mng_imagep)pData->pFirstimgobj; + + while (pNext) /* any left ? */ + { + pImage = pNext; + pNext = pImage->sHeader.pNext; + + if (!pImage->bFrozen) /* not frozen ? */ + { /* then drop it */ + iRetcode = free_imageobject (pData, pImage); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DISC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_fram (mng_datap pData, + mng_uint8 iFramemode, + mng_uint8 iChangedelay, + mng_uint32 iDelay, + mng_uint8 iChangetimeout, + mng_uint32 iTimeout, + mng_uint8 iChangeclipping, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_START) +#endif + /* advance a frame then */ + iRetcode = next_frame (pData, iFramemode, iChangedelay, iDelay, + iChangetimeout, iTimeout, iChangeclipping, + iCliptype, iClipl, iClipr, iClipt, iClipb); + + if (pData->bTimerset) /* timer break ? */ + pData->iBreakpoint = 1; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +mng_retcode process_display_fram2 (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_START) +#endif + /* again; after the break */ + iRetcode = next_frame (pData, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + pData->iBreakpoint = 0; /* not again! */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_FRAM, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +mng_retcode process_display_move (mng_datap pData, + mng_uint16 iFromid, + mng_uint16 iToid, + mng_uint8 iMovetype, + mng_int32 iMovex, + mng_int32 iMovey) +{ + mng_uint16 iX; + mng_imagep pImage; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MOVE, MNG_LC_START) +#endif + /* iterate the list */ + for (iX = iFromid; iX <= iToid; iX++) + { + if (!iX) /* object id=0 ? */ + pImage = (mng_imagep)pData->pObjzero; + else + pImage = find_imageobject (pData, iX); + + if (pImage) /* object exists ? */ + { + switch (iMovetype) + { + case 0 : { /* absolute */ + pImage->iPosx = iMovex; + pImage->iPosy = iMovey; + break; + } + case 1 : { /* relative */ + pImage->iPosx = pImage->iPosx + iMovex; + pImage->iPosy = pImage->iPosy + iMovey; + break; + } + } + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_clip (mng_datap pData, + mng_uint16 iFromid, + mng_uint16 iToid, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb) +{ + mng_uint16 iX; + mng_imagep pImage; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLIP, MNG_LC_START) +#endif + /* iterate the list */ + for (iX = iFromid; iX <= iToid; iX++) + { + if (!iX) /* object id=0 ? */ + pImage = (mng_imagep)pData->pObjzero; + else + pImage = find_imageobject (pData, iX); + + if (pImage) /* object exists ? */ + { + switch (iCliptype) + { + case 0 : { /* absolute */ + pImage->bClipped = MNG_TRUE; + pImage->iClipl = iClipl; + pImage->iClipr = iClipr; + pImage->iClipt = iClipt; + pImage->iClipb = iClipb; + break; + } + case 1 : { /* relative */ + pImage->bClipped = MNG_TRUE; + pImage->iClipl = pImage->iClipl + iClipl; + pImage->iClipr = pImage->iClipr + iClipr; + pImage->iClipt = pImage->iClipt + iClipt; + pImage->iClipb = pImage->iClipb + iClipb; + break; + } + } + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_show (mng_datap pData) +{ + mng_int16 iX, iS, iFrom, iTo; + mng_imagep pImage; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SHOW, MNG_LC_START) +#endif + + /* TODO: optimization for the cases where "abs (iTo - iFrom)" is rather high; + especially where ((iFrom==1) && (iTo==65535)); eg. an empty SHOW !!! */ + + if (pData->iBreakpoint == 3) /* previously broken during cycle-mode ? */ + { + pImage = find_imageobject (pData, pData->iSHOWnextid); + + if (pImage) /* still there ? */ + display_image (pData, pImage, MNG_FALSE); + + pData->iBreakpoint = 0; /* let's not go through this again! */ + } + else + { + if (pData->iBreakpoint) /* previously broken at other point ? */ + { /* restore last parms */ + iFrom = (mng_int16)pData->iSHOWfromid; + iTo = (mng_int16)pData->iSHOWtoid; + iX = (mng_int16)pData->iSHOWnextid; + iS = (mng_int16)pData->iSHOWskip; + } + else + { /* regular sequence ? */ + if (pData->iSHOWtoid >= pData->iSHOWfromid) + iS = 1; + else /* reverse sequence ! */ + iS = -1; + + iFrom = (mng_int16)pData->iSHOWfromid; + iTo = (mng_int16)pData->iSHOWtoid; + iX = iFrom; + + pData->iSHOWfromid = (mng_uint16)iFrom; + pData->iSHOWtoid = (mng_uint16)iTo; + pData->iSHOWskip = iS; + } + /* cycle mode ? */ + if ((pData->iSHOWmode == 6) || (pData->iSHOWmode == 7)) + { + mng_uint16 iTrigger = 0; + mng_uint16 iFound = 0; + mng_uint16 iPass = 0; + mng_imagep pFound = 0; + + do + { + iPass++; /* lets prevent endless loops when there + are no potential candidates in the list! */ + + if (iS > 0) /* forward ? */ + { + for (iX = iFrom; iX <= iTo; iX += iS) + { + pImage = find_imageobject (pData, (mng_uint16)iX); + + if (pImage) /* object exists ? */ + { + if (iFound) /* already found a candidate ? */ + pImage->bVisible = MNG_FALSE; + else + if (iTrigger) /* found the trigger ? */ + { + pImage->bVisible = MNG_TRUE; + iFound = iX; + pFound = pImage; + } + else + if (pImage->bVisible) /* ok, this is the trigger */ + { + pImage->bVisible = MNG_FALSE; + iTrigger = iX; + } + } + } + } + else + { + for (iX = iFrom; iX >= iTo; iX += iS) + { + pImage = find_imageobject (pData, (mng_uint16)iX); + + if (pImage) /* object exists ? */ + { + if (iFound) /* already found a candidate ? */ + pImage->bVisible = MNG_FALSE; + else + if (iTrigger) /* found the trigger ? */ + { + pImage->bVisible = MNG_TRUE; + iFound = iX; + pFound = pImage; + } + else + if (pImage->bVisible) /* ok, this is the trigger */ + { + pImage->bVisible = MNG_FALSE; + iTrigger = iX; + } + } + } + } + + if (!iTrigger) /* did not find a trigger ? */ + iTrigger = 1; /* then fake it so the first image + gets nominated */ + } /* cycle back to beginning ? */ + while ((iPass < 2) && (iTrigger) && (!iFound)); + + pData->iBreakpoint = 0; /* just a sanity precaution */ + /* display it ? */ + if ((pData->iSHOWmode == 6) && (pFound)) + { + display_image (pData, pFound, MNG_FALSE); + + if (pData->bTimerset) /* timer set ? */ + { + pData->iBreakpoint = 3; + pData->iSHOWnextid = iFound; /* save it for after the break */ + } + } + } + else + { + do + { + pImage = find_imageobject (pData, iX); + + if (pImage) /* object exists ? */ + { + if (pData->iBreakpoint) /* did we get broken last time ? */ + { /* could only happen in the display routine */ + display_image (pData, pImage, MNG_FALSE); + pData->iBreakpoint = 0; /* only once inside this loop please ! */ + } + else + { + switch (pData->iSHOWmode) /* do what ? */ + { + case 0 : { + pImage->bVisible = MNG_TRUE; + display_image (pData, pImage, MNG_FALSE); + break; + } + case 1 : { + pImage->bVisible = MNG_FALSE; + break; + } + case 2 : { + if (pImage->bVisible) + display_image (pData, pImage, MNG_FALSE); + break; + } + case 3 : { + pImage->bVisible = MNG_TRUE; + break; + } + case 4 : { + pImage->bVisible = (mng_bool)(!pImage->bVisible); + if (pImage->bVisible) + display_image (pData, pImage, MNG_FALSE); + break; + } + case 5 : { + pImage->bVisible = (mng_bool)(!pImage->bVisible); + } + } + } + } + + if (!pData->bTimerset) /* next ? */ + iX += iS; + + } /* continue ? */ + while ((!pData->bTimerset) && (((iS > 0) && (iX <= iTo)) || + ((iS < 0) && (iX >= iTo)) )); + + if (pData->bTimerset) /* timer set ? */ + { + pData->iBreakpoint = 4; + pData->iSHOWnextid = iX; /* save for next time */ + } + else + pData->iBreakpoint = 0; + + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_save (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SAVE, MNG_LC_START) +#endif + + iRetcode = save_state (pData); /* save the current state */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_seek (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SEEK, MNG_LC_START) +#endif + + iRetcode = restore_state (pData); /* restore the initial or SAVE state */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode process_display_jhdr (mng_datap pData) +{ /* address the current "object" if any */ + mng_imagep pImage = (mng_imagep)pData->pCurrentobj; + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JHDR, MNG_LC_START) +#endif + + if (!pData->bHasDHDR) + { + pData->fInitrowproc = MNG_NULL; /* do nothing by default */ + pData->fDisplayrow = MNG_NULL; + pData->fCorrectrow = MNG_NULL; + pData->fStorerow = MNG_NULL; + pData->fProcessrow = MNG_NULL; + pData->fDifferrow = MNG_NULL; + pData->fStorerow2 = MNG_NULL; + pData->fStorerow3 = MNG_NULL; + + pData->pStoreobj = MNG_NULL; /* initialize important work-parms */ + + pData->iJPEGrow = 0; + pData->iJPEGalpharow = 0; + pData->iJPEGrgbrow = 0; + pData->iRowmax = 0; /* so init_rowproc does the right thing ! */ + } + + if (!pData->iBreakpoint) /* not previously broken ? */ + { + if (pData->bHasDHDR) /* delta-image ? */ + { + if (pData->iDeltatype == MNG_DELTATYPE_REPLACE) + { + iRetcode = reset_object_details (pData, (mng_imagep)pData->pDeltaImage, + pData->iDatawidth, pData->iDataheight, + pData->iJHDRimgbitdepth, pData->iJHDRcolortype, + pData->iJHDRalphacompression, pData->iJHDRalphafilter, + pData->iJHDRalphainterlace, MNG_TRUE); + + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphabitdepth = pData->iJHDRalphabitdepth; + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iJHDRcompression = pData->iJHDRimgcompression; + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iJHDRinterlace = pData->iJHDRimginterlace; + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth; + } + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iJHDRimgbitdepth; + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth; + } + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKALPHAREPLACE) ) + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth; + else + if ((pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORADD ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKCOLORREPLACE) ) + ((mng_imagep)pData->pDeltaImage)->pImgbuf->iPixelsampledepth = pData->iJHDRimgbitdepth; + + } + else + { + if (pImage) /* update object buffer ? */ + { + iRetcode = reset_object_details (pData, pImage, + pData->iDatawidth, pData->iDataheight, + pData->iJHDRimgbitdepth, pData->iJHDRcolortype, + pData->iJHDRalphacompression, pData->iJHDRalphafilter, + pData->iJHDRalphainterlace, MNG_TRUE); + + pImage->pImgbuf->iAlphabitdepth = pData->iJHDRalphabitdepth; + pImage->pImgbuf->iJHDRcompression = pData->iJHDRimgcompression; + pImage->pImgbuf->iJHDRinterlace = pData->iJHDRimginterlace; + pImage->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth; + } + else /* update object 0 */ + { + iRetcode = reset_object_details (pData, (mng_imagep)pData->pObjzero, + pData->iDatawidth, pData->iDataheight, + pData->iJHDRimgbitdepth, pData->iJHDRcolortype, + pData->iJHDRalphacompression, pData->iJHDRalphafilter, + pData->iJHDRalphainterlace, MNG_TRUE); + + ((mng_imagep)pData->pObjzero)->pImgbuf->iAlphabitdepth = pData->iJHDRalphabitdepth; + ((mng_imagep)pData->pObjzero)->pImgbuf->iJHDRcompression = pData->iJHDRimgcompression; + ((mng_imagep)pData->pObjzero)->pImgbuf->iJHDRinterlace = pData->iJHDRimginterlace; + ((mng_imagep)pData->pObjzero)->pImgbuf->iAlphasampledepth = pData->iJHDRalphabitdepth; + } + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + if (!pData->bHasDHDR) + { /* we're always storing a JPEG */ + if (pImage) /* real object ? */ + pData->pStoreobj = pImage; /* tell the row routines */ + else /* otherwise use object 0 */ + pData->pStoreobj = pData->pObjzero; + /* display "on-the-fly" ? */ + if ( (((mng_imagep)pData->pStoreobj)->iMAGN_MethodX == 0) && + (((mng_imagep)pData->pStoreobj)->iMAGN_MethodY == 0) && + ( (pData->eImagetype == mng_it_jng ) || + (((mng_imagep)pData->pStoreobj)->bVisible) ) ) + { + next_layer (pData); /* that's a new layer then ! */ + + if (pData->bTimerset) /* timer break ? */ + pData->iBreakpoint = 7; + else + { + pData->iBreakpoint = 0; + /* anything to display ? */ + if ((pData->iDestr > pData->iDestl) && (pData->iDestb > pData->iDestt)) + { + set_display_routine (pData); /* then determine display routine */ + /* display from the object we store in */ + pData->pRetrieveobj = pData->pStoreobj; + } + } + } + } + + if (!pData->bTimerset) /* no timer break ? */ + { /* default row initialization ! */ + pData->fInitrowproc = (mng_fptr)init_rowproc; + + if ((!pData->bHasDHDR) || (pData->iDeltatype == MNG_DELTATYPE_REPLACE)) + { /* 8-bit JPEG ? */ + if (pData->iJHDRimgbitdepth == 8) + { /* intermediate row is 8-bit deep */ + pData->bIsRGBA16 = MNG_FALSE; + pData->iRowsamples = pData->iDatawidth; + + switch (pData->iJHDRcolortype) /* determine pixel processing routines */ + { + case MNG_COLORTYPE_JPEGGRAY : + { + pData->fStorerow2 = (mng_fptr)store_jpeg_g8; + pData->fRetrieverow = (mng_fptr)retrieve_g8; + pData->bIsOpaque = MNG_TRUE; + break; + } + case MNG_COLORTYPE_JPEGCOLOR : + { + pData->fStorerow2 = (mng_fptr)store_jpeg_rgb8; + pData->fRetrieverow = (mng_fptr)retrieve_rgb8; + pData->bIsOpaque = MNG_TRUE; + break; + } + case MNG_COLORTYPE_JPEGGRAYA : + { + pData->fStorerow2 = (mng_fptr)store_jpeg_ga8; + pData->fRetrieverow = (mng_fptr)retrieve_ga8; + pData->bIsOpaque = MNG_FALSE; + break; + } + case MNG_COLORTYPE_JPEGCOLORA : + { + pData->fStorerow2 = (mng_fptr)store_jpeg_rgba8; + pData->fRetrieverow = (mng_fptr)retrieve_rgba8; + pData->bIsOpaque = MNG_FALSE; + break; + } + } + } + else + { + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + + /* TODO: 12-bit JPEG */ + /* TODO: 8- + 12-bit JPEG (eg. type=20) */ + + } + /* possible IDAT alpha-channel ? */ + if (pData->iJHDRalphacompression == MNG_COMPRESSION_DEFLATE) + { + /* determine alpha processing routine */ + switch (pData->iJHDRalphabitdepth) + { + case 1 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a1_ni; break; } + case 2 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a2_ni; break; } + case 4 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a4_ni; break; } + case 8 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a8_ni; break; } + case 16 : { pData->fInitrowproc = (mng_fptr)init_jpeg_a16_ni; break; } + } + } + else /* possible JDAA alpha-channel ? */ + if (pData->iJHDRalphacompression == MNG_COMPRESSION_BASELINEJPEG) + { /* 8-bit JPEG ? */ + if (pData->iJHDRimgbitdepth == 8) + { + if (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA) + pData->fStorerow3 = (mng_fptr)store_jpeg_g8_alpha; + else + if (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) + pData->fStorerow3 = (mng_fptr)store_jpeg_rgb8_alpha; + } + else + { + /* TODO: 12-bit JPEG with 8-bit JDAA */ + } + } + /* initialize JPEG library */ + iRetcode = mngjpeg_initialize (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + else + { /* must be alpha add/replace !! */ + if ((pData->iDeltatype != MNG_DELTATYPE_BLOCKALPHAADD ) && + (pData->iDeltatype != MNG_DELTATYPE_BLOCKALPHAREPLACE) ) + MNG_ERROR (pData, MNG_INVDELTATYPE) + /* determine alpha processing routine */ + switch (pData->iJHDRalphabitdepth) + { + case 1 : { pData->fInitrowproc = (mng_fptr)init_g1_ni; break; } + case 2 : { pData->fInitrowproc = (mng_fptr)init_g2_ni; break; } + case 4 : { pData->fInitrowproc = (mng_fptr)init_g4_ni; break; } + case 8 : { pData->fInitrowproc = (mng_fptr)init_g8_ni; break; } + case 16 : { pData->fInitrowproc = (mng_fptr)init_g16_ni; break; } + } + } + + pData->iFilterofs = 0; /* determine filter characteristics */ + pData->iLevel0 = 0; /* default levels */ + pData->iLevel1 = 0; + pData->iLevel2 = 0; + pData->iLevel3 = 0; + /* leveling & differing ? */ +/* if (pData->iJHDRalphafilter & 0x40) + { + if (pData->iJHDRalphabitdepth <= 8) + pData->iFilterofs = 1; + else + pData->iFilterofs = 2; + + } */ + /* no adaptive filtering ? */ +/* if (pData->iJHDRalphafilter & 0x01) + pData->iPixelofs = pData->iFilterofs; + else */ + pData->iPixelofs = pData->iFilterofs + 1; + + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode process_display_jdaa (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata) +{ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAA, MNG_LC_START) +#endif + + if (!pData->bJPEGdecompress2) /* if we're not decompressing already */ + { + if (pData->fInitrowproc) /* initialize row-processing? */ + { + iRetcode = ((mng_initrowproc)pData->fInitrowproc) (pData); + pData->fInitrowproc = MNG_NULL; /* only call this once !!! */ + } + + if (!iRetcode) /* initialize decompress */ + iRetcode = mngjpeg_decompressinit2 (pData); + } + + if (!iRetcode) /* all ok? then decompress, my man */ + iRetcode = mngjpeg_decompressdata2 (pData, iRawlen, pRawdata); + + if (iRetcode) + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode process_display_jdat (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata) +{ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAT, MNG_LC_START) +#endif + + if (pData->bRestorebkgd) /* need to restore the background ? */ + { + pData->bRestorebkgd = MNG_FALSE; + iRetcode = load_bkgdlayer (pData); + + if ((pData->bDisplaying) && (pData->bRunning)) + pData->iLayerseq++; /* and it counts as a layer then ! */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + if (!pData->bJPEGdecompress) /* if we're not decompressing already */ + { + if (pData->fInitrowproc) /* initialize row-processing? */ + { + iRetcode = ((mng_initrowproc)pData->fInitrowproc) (pData); + pData->fInitrowproc = MNG_NULL; /* only call this once !!! */ + } + + if (!iRetcode) /* initialize decompress */ + iRetcode = mngjpeg_decompressinit (pData); + } + + if (!iRetcode) /* all ok? then decompress, my man */ + iRetcode = mngjpeg_decompressdata (pData, iRawlen, pRawdata); + + if (iRetcode) + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_JDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +mng_retcode process_display_dhdr (mng_datap pData, + mng_uint16 iObjectid, + mng_uint8 iImagetype, + mng_uint8 iDeltatype, + mng_uint32 iBlockwidth, + mng_uint32 iBlockheight, + mng_uint32 iBlockx, + mng_uint32 iBlocky) +{ + mng_imagep pImage; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DHDR, MNG_LC_START) +#endif + + pData->fInitrowproc = MNG_NULL; /* do nothing by default */ + pData->fDisplayrow = MNG_NULL; + pData->fCorrectrow = MNG_NULL; + pData->fStorerow = MNG_NULL; + pData->fProcessrow = MNG_NULL; + pData->pStoreobj = MNG_NULL; + + pData->fDeltagetrow = MNG_NULL; + pData->fDeltaaddrow = MNG_NULL; + pData->fDeltareplacerow = MNG_NULL; + pData->fDeltaputrow = MNG_NULL; + + pImage = find_imageobject (pData, iObjectid); + + if (pImage) /* object exists ? */ + { + if (pImage->pImgbuf->bConcrete) /* is it concrete ? */ + { /* previous magnification to be done ? */ + if ((pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY)) + { + iRetcode = magnify_imageobject (pData, pImage); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + /* save delta fields */ + pData->pDeltaImage = (mng_ptr)pImage; + pData->iDeltaImagetype = iImagetype; + pData->iDeltatype = iDeltatype; + pData->iDeltaBlockwidth = iBlockwidth; + pData->iDeltaBlockheight = iBlockheight; + pData->iDeltaBlockx = iBlockx; + pData->iDeltaBlocky = iBlocky; + /* restore target-object fields */ + pData->iDatawidth = pImage->pImgbuf->iWidth; + pData->iDataheight = pImage->pImgbuf->iHeight; + pData->iBitdepth = pImage->pImgbuf->iBitdepth; + pData->iColortype = pImage->pImgbuf->iColortype; + pData->iCompression = pImage->pImgbuf->iCompression; + pData->iFilter = pImage->pImgbuf->iFilter; + pData->iInterlace = pImage->pImgbuf->iInterlace; + +#ifdef MNG_INCLUDE_JNG + pData->iJHDRimgbitdepth = pImage->pImgbuf->iBitdepth; + pData->iJHDRcolortype = pImage->pImgbuf->iColortype; + pData->iJHDRimgcompression = pImage->pImgbuf->iJHDRcompression; + pData->iJHDRimginterlace = pImage->pImgbuf->iJHDRinterlace; + pData->iJHDRalphacompression = pImage->pImgbuf->iCompression; + pData->iJHDRalphafilter = pImage->pImgbuf->iFilter; + pData->iJHDRalphainterlace = pImage->pImgbuf->iInterlace; + pData->iJHDRalphabitdepth = pImage->pImgbuf->iAlphabitdepth; +#endif + /* block size specified ? */ + if (iDeltatype != MNG_DELTATYPE_NOCHANGE) + { + pData->iDatawidth = iBlockwidth; + pData->iDataheight = iBlockheight; + } + + switch (iDeltatype) /* determine nr of delta-channels */ + { + case MNG_DELTATYPE_BLOCKALPHAADD : ; + case MNG_DELTATYPE_BLOCKALPHAREPLACE : + { +#ifdef MNG_INCLUDE_JNG + if ((pData->iColortype == MNG_COLORTYPE_GRAYA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA) ) + { + pData->iColortype = MNG_COLORTYPE_GRAY; + pData->iJHDRcolortype = MNG_COLORTYPE_JPEGGRAY; + } + else + if ((pData->iColortype == MNG_COLORTYPE_RGBA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) ) + { + pData->iColortype = MNG_COLORTYPE_GRAY; + pData->iJHDRcolortype = MNG_COLORTYPE_JPEGGRAY; + } +#else + if (pData->iColortype == MNG_COLORTYPE_GRAYA) + pData->iColortype = MNG_COLORTYPE_GRAY; + else + if (pData->iColortype == MNG_COLORTYPE_RGBA) + pData->iColortype = MNG_COLORTYPE_GRAY; +#endif + else /* target has no alpha; that sucks! */ + MNG_ERROR (pData, MNG_TARGETNOALPHA) + + break; + } + + case MNG_DELTATYPE_BLOCKCOLORADD : ; + case MNG_DELTATYPE_BLOCKCOLORREPLACE : + { +#ifdef MNG_INCLUDE_JNG + if ((pData->iColortype == MNG_COLORTYPE_GRAYA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA) ) + { + pData->iColortype = MNG_COLORTYPE_GRAY; + pData->iJHDRcolortype = MNG_COLORTYPE_JPEGGRAY; + } + else + if ((pData->iColortype == MNG_COLORTYPE_RGBA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) ) + { + pData->iColortype = MNG_COLORTYPE_RGB; + pData->iJHDRcolortype = MNG_COLORTYPE_JPEGCOLOR; + } +#else + if (pData->iColortype == MNG_COLORTYPE_GRAYA) + pData->iColortype = MNG_COLORTYPE_GRAY; + else + if (pData->iColortype == MNG_COLORTYPE_RGBA) + pData->iColortype = MNG_COLORTYPE_RGB; +#endif + else /* target has no alpha; that sucks! */ + MNG_ERROR (pData, MNG_TARGETNOALPHA) + + break; + } + + } + /* full image replace ? */ + if (iDeltatype == MNG_DELTATYPE_REPLACE) + { + iRetcode = reset_object_details (pData, pImage, + pData->iDatawidth, pData->iDataheight, + pData->iBitdepth, pData->iColortype, + pData->iCompression, pData->iFilter, + pData->iInterlace, MNG_FALSE); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + pData->pStoreobj = pImage; /* and store straight into this object */ + } + else + { + mng_imagedatap pBufzero, pBuf; + /* we store in object 0 and process it later */ + pData->pStoreobj = pData->pObjzero; + /* make sure to initialize object 0 then */ + iRetcode = reset_object_details (pData, (mng_imagep)pData->pObjzero, + pData->iDatawidth, pData->iDataheight, + pData->iBitdepth, pData->iColortype, + pData->iCompression, pData->iFilter, + pData->iInterlace, MNG_TRUE); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + pBuf = pImage->pImgbuf; /* copy possible palette & cheap transparency */ + pBufzero = ((mng_imagep)pData->pObjzero)->pImgbuf; + + pBufzero->bHasPLTE = pBuf->bHasPLTE; + pBufzero->bHasTRNS = pBuf->bHasTRNS; + + if (pBufzero->bHasPLTE) /* copy palette ? */ + { + mng_uint32 iX; + + pBufzero->iPLTEcount = pBuf->iPLTEcount; + + for (iX = 0; iX < pBuf->iPLTEcount; iX++) + { + pBufzero->aPLTEentries [iX].iRed = pBuf->aPLTEentries [iX].iRed; + pBufzero->aPLTEentries [iX].iGreen = pBuf->aPLTEentries [iX].iGreen; + pBufzero->aPLTEentries [iX].iBlue = pBuf->aPLTEentries [iX].iBlue; + } + } + + if (pBufzero->bHasTRNS) /* copy cheap transparency ? */ + { + pBufzero->iTRNSgray = pBuf->iTRNSgray; + pBufzero->iTRNSred = pBuf->iTRNSred; + pBufzero->iTRNSgreen = pBuf->iTRNSgreen; + pBufzero->iTRNSblue = pBuf->iTRNSblue; + pBufzero->iTRNScount = pBuf->iTRNScount; + + MNG_COPY (pBufzero->aTRNSentries, pBuf->aTRNSentries, + sizeof (pBufzero->aTRNSentries)) + } + /* process immediatly if bitdepth & colortype are equal */ + pData->bDeltaimmediate = + (mng_bool)((pData->bDisplaying) && (pData->bRunning) && + (pData->iBitdepth == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iBitdepth ) && + (pData->iColortype == ((mng_imagep)pData->pDeltaImage)->pImgbuf->iColortype) ); + } + + switch (pData->iColortype) /* determine row initialization routine */ + { + case 0 : { /* gray */ + switch (pData->iBitdepth) + { + case 1 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g1_ni; + else + pData->fInitrowproc = (mng_fptr)init_g1_i; + + break; + } + case 2 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g2_ni; + else + pData->fInitrowproc = (mng_fptr)init_g2_i; + + break; + } + case 4 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g4_ni; + else + pData->fInitrowproc = (mng_fptr)init_g4_i; + + break; + } + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g8_ni; + else + pData->fInitrowproc = (mng_fptr)init_g8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_g16_ni; + else + pData->fInitrowproc = (mng_fptr)init_g16_i; + + break; + } + } + + break; + } + case 2 : { /* rgb */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgb8_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgb8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgb16_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgb16_i; + + break; + } + } + + break; + } + case 3 : { /* indexed */ + switch (pData->iBitdepth) + { + case 1 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx1_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx1_i; + + break; + } + case 2 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx2_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx2_i; + + break; + } + case 4 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx4_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx4_i; + + break; + } + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_idx8_ni; + else + pData->fInitrowproc = (mng_fptr)init_idx8_i; + + break; + } + } + + break; + } + case 4 : { /* gray+alpha */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_ga8_ni; + else + pData->fInitrowproc = (mng_fptr)init_ga8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_ga16_ni; + else + pData->fInitrowproc = (mng_fptr)init_ga16_i; + + break; + } + } + + break; + } + case 6 : { /* rgb+alpha */ + switch (pData->iBitdepth) + { + case 8 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgba8_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgba8_i; + + break; + } + case 16 : { + if (!pData->iInterlace) + pData->fInitrowproc = (mng_fptr)init_rgba16_ni; + else + pData->fInitrowproc = (mng_fptr)init_rgba16_i; + + break; + } + } + + break; + } + } + } + else + MNG_ERROR (pData, MNG_OBJNOTCONCRETE) + + } + else + MNG_ERROR (pData, MNG_OBJECTUNKNOWN) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_prom (mng_datap pData, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iFilltype) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PROM, MNG_LC_START) +#endif + + + /* TODO: everything */ + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_ipng (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IPNG, MNG_LC_START) +#endif + /* indicate it for what it is now */ + pData->iDeltaImagetype = MNG_IMAGETYPE_PNG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_ijng (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IJNG, MNG_LC_START) +#endif + /* indicate it for what it is now */ + pData->iDeltaImagetype = MNG_IMAGETYPE_JNG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_pplt (mng_datap pData, + mng_uint8 iType, + mng_uint32 iCount, + mng_palette8ep paIndexentries, + mng_uint8p paAlphaentries, + mng_uint8p paUsedentries) +{ + mng_uint32 iX; + mng_imagep pImage = (mng_imagep)pData->pObjzero; + mng_imagedatap pBuf = pImage->pImgbuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PPLT, MNG_LC_START) +#endif + + switch (iType) + { + case MNG_DELTATYPE_REPLACERGB : + { + for (iX = 0; iX < iCount; iX++) + { + if (paUsedentries [iX]) + { + pBuf->aPLTEentries [iX].iRed = paIndexentries [iX].iRed; + pBuf->aPLTEentries [iX].iGreen = paIndexentries [iX].iGreen; + pBuf->aPLTEentries [iX].iBlue = paIndexentries [iX].iBlue; + } + } + + break; + } + case MNG_DELTATYPE_DELTARGB : + { + for (iX = 0; iX < iCount; iX++) + { + if (paUsedentries [iX]) + { + pBuf->aPLTEentries [iX].iRed = + (mng_uint8)(pBuf->aPLTEentries [iX].iRed + + paIndexentries [iX].iRed ); + pBuf->aPLTEentries [iX].iGreen = + (mng_uint8)(pBuf->aPLTEentries [iX].iGreen + + paIndexentries [iX].iGreen); + pBuf->aPLTEentries [iX].iBlue = + (mng_uint8)(pBuf->aPLTEentries [iX].iBlue + + paIndexentries [iX].iBlue ); + } + } + + break; + } + case MNG_DELTATYPE_REPLACEALPHA : + { + for (iX = 0; iX < iCount; iX++) + { + if (paUsedentries [iX]) + pBuf->aTRNSentries [iX] = paAlphaentries [iX]; + } + + break; + } + case MNG_DELTATYPE_DELTAALPHA : + { + for (iX = 0; iX < iCount; iX++) + { + if (paUsedentries [iX]) + pBuf->aTRNSentries [iX] = + (mng_uint8)(pBuf->aTRNSentries [iX] + + paAlphaentries [iX]); + } + + break; + } + case MNG_DELTATYPE_REPLACERGBA : + { + for (iX = 0; iX < iCount; iX++) + { + if (paUsedentries [iX]) + { + pBuf->aPLTEentries [iX].iRed = paIndexentries [iX].iRed; + pBuf->aPLTEentries [iX].iGreen = paIndexentries [iX].iGreen; + pBuf->aPLTEentries [iX].iBlue = paIndexentries [iX].iBlue; + pBuf->aTRNSentries [iX] = paAlphaentries [iX]; + } + } + + break; + } + case MNG_DELTATYPE_DELTARGBA : + { + for (iX = 0; iX < iCount; iX++) + { + if (paUsedentries [iX]) + { + pBuf->aPLTEentries [iX].iRed = + (mng_uint8)(pBuf->aPLTEentries [iX].iRed + + paIndexentries [iX].iRed ); + pBuf->aPLTEentries [iX].iGreen = + (mng_uint8)(pBuf->aPLTEentries [iX].iGreen + + paIndexentries [iX].iGreen); + pBuf->aPLTEentries [iX].iBlue = + (mng_uint8)(pBuf->aPLTEentries [iX].iBlue + + paIndexentries [iX].iBlue ); + pBuf->aTRNSentries [iX] = + (mng_uint8)(pBuf->aTRNSentries [iX] + + paAlphaentries [iX]); + } + } + + break; + } + } + + if ((iType != MNG_DELTATYPE_REPLACERGB) && (iType != MNG_DELTATYPE_DELTARGB)) + { + if (pBuf->bHasTRNS) + { + if (iCount > pBuf->iTRNScount) + pBuf->iTRNScount = iCount; + } + else + { + pBuf->iTRNScount = iCount; + pBuf->bHasTRNS = MNG_TRUE; + } + } + + if ((iType != MNG_DELTATYPE_REPLACEALPHA) && (iType != MNG_DELTATYPE_DELTAALPHA)) + { + if (iCount > pBuf->iPLTEcount) + pBuf->iPLTEcount = iCount; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_magn (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint16 iMethodX, + mng_uint16 iMX, + mng_uint16 iMY, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint16 iMT, + mng_uint16 iMB, + mng_uint16 iMethodY) +{ + mng_uint16 iX; + mng_imagep pImage; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_START) +#endif + /* iterate the object-ids */ + for (iX = iFirstid; iX <= iLastid; iX++) + { + if (iX == 0) /* process object 0 ? */ + { + pImage = (mng_imagep)pData->pObjzero; + + pImage->iMAGN_MethodX = iMethodX; + pImage->iMAGN_MethodY = iMethodY; + pImage->iMAGN_MX = iMX; + pImage->iMAGN_MY = iMY; + pImage->iMAGN_ML = iML; + pImage->iMAGN_MR = iMR; + pImage->iMAGN_MT = iMT; + pImage->iMAGN_MB = iMB; + } + else + { + pImage = find_imageobject (pData, iX); + /* object exists & is not frozen ? */ + if ((pImage) && (!pImage->bFrozen)) + { /* previous magnification to be done ? */ + if ((pImage->iMAGN_MethodX) || (pImage->iMAGN_MethodY)) + { + mng_retcode iRetcode = magnify_imageobject (pData, pImage); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + pImage->iMAGN_MethodX = iMethodX; + pImage->iMAGN_MethodY = iMethodY; + pImage->iMAGN_MX = iMX; + pImage->iMAGN_MY = iMY; + pImage->iMAGN_ML = iML; + pImage->iMAGN_MR = iMR; + pImage->iMAGN_MT = iMT; + pImage->iMAGN_MB = iMB; + } + } + } + + iX = iFirstid; + /* iterate again for showing */ + while ((iX <= iLastid) && (!pData->bTimerset)) + { + if (iX) /* only real objects ! */ + { + pImage = find_imageobject (pData, iX); + /* object exists & is not frozen & + is visible & is viewable ? */ + if ((pImage) && (!pImage->bFrozen) && + (pImage->bVisible) && (pImage->bViewable)) + display_image (pData, pImage, MNG_FALSE); + } + + iX++; + } + + if (pData->bTimerset) /* broken ? */ + { + pData->iMAGNfromid = iFirstid; + pData->iMAGNtoid = iLastid; + pData->iBreakpoint = 9; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_display_magn2 (mng_datap pData) +{ + mng_uint16 iX; + mng_imagep pImage; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_START) +#endif + + iX = pData->iMAGNfromid; + /* iterate again for showing */ + while ((iX <= pData->iMAGNtoid) && (!pData->bTimerset)) + { + if (iX) /* only real objects ! */ + { + pImage = find_imageobject (pData, iX); + /* object exists & is not frozen & + is visible & is viewable ? */ + if ((pImage) && (!pImage->bFrozen) && + (pImage->bVisible) && (pImage->bViewable)) + display_image (pData, pImage, MNG_FALSE); + } + + iX++; + } + + if (pData->bTimerset) /* broken ? */ + pData->iBreakpoint = 9; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_DISPLAY_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_DISPLAY_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_display.h b/freeimage241/Source/LibMNG/libmng_display.h new file mode 100644 index 0000000..32d3b5c --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_display.h @@ -0,0 +1,195 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_display.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Display management (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the display managament routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - added JNG support stuff * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - changed progressive-display processing * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - added support for delta-image processing * */ +/* * - added support for PPLT chunk processing * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * 0.9.3 - 08/07/2000 - G.Juyn * */ +/* * - B111300 - fixup for improved portability * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added JDAA chunk * */ +/* * * */ +/* * 0.9.4 - 11/24/2000 - G.Juyn * */ +/* * - moved restore of object 0 to libmng_display * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_display_h_ +#define _libmng_display_h_ + +/* ************************************************************************** */ + +mng_retcode display_progressive_refresh (mng_datap pData, + mng_uint32 iInterval); + +/* ************************************************************************** */ + +mng_retcode mng_reset_objzero (mng_datap pData); + +mng_retcode display_image (mng_datap pData, + mng_imagep pImage, + mng_bool bLayeradvanced); + +mng_retcode execute_delta_image (mng_datap pData, + mng_imagep pTarget, + mng_imagep pDelta); + +/* ************************************************************************** */ + +mng_retcode process_display (mng_datap pData); + +/* ************************************************************************** */ + +mng_retcode process_display_ihdr (mng_datap pData); + +mng_retcode process_display_idat (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata); + +mng_retcode process_display_iend (mng_datap pData); +mng_retcode process_display_mend (mng_datap pData); +mng_retcode process_display_defi (mng_datap pData); + +mng_retcode process_display_basi (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_bool bHasalpha, + mng_uint16 iAlpha, + mng_uint8 iViewable); + +mng_retcode process_display_clon (mng_datap pData, + mng_uint16 iSourceid, + mng_uint16 iCloneid, + mng_uint8 iClonetype, + mng_bool bHasdonotshow, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy); +mng_retcode process_display_clon2 (mng_datap pData); + +mng_retcode process_display_disc (mng_datap pData, + mng_uint32 iCount, + mng_uint16p pIds); + +mng_retcode process_display_fram (mng_datap pData, + mng_uint8 iFramemode, + mng_uint8 iChangedelay, + mng_uint32 iDelay, + mng_uint8 iChangetimeout, + mng_uint32 iTimeout, + mng_uint8 iChangeclipping, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb); +mng_retcode process_display_fram2 (mng_datap pData); + +mng_retcode process_display_move (mng_datap pData, + mng_uint16 iFromid, + mng_uint16 iToid, + mng_uint8 iMovetype, + mng_int32 iMovex, + mng_int32 iMovey); + +mng_retcode process_display_clip (mng_datap pData, + mng_uint16 iFromid, + mng_uint16 iToid, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb); + +mng_retcode process_display_show (mng_datap pData); +mng_retcode process_display_save (mng_datap pData); +mng_retcode process_display_seek (mng_datap pData); +mng_retcode process_display_jhdr (mng_datap pData); + +mng_retcode process_display_jdaa (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata); + +mng_retcode process_display_jdat (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata); + +mng_retcode process_display_dhdr (mng_datap pData, + mng_uint16 iObjectid, + mng_uint8 iImagetype, + mng_uint8 iDeltatype, + mng_uint32 iBlockwidth, + mng_uint32 iBlockheight, + mng_uint32 iBlockx, + mng_uint32 iBlocky); + +mng_retcode process_display_prom (mng_datap pData, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iFilltype); + +mng_retcode process_display_ipng (mng_datap pData); +mng_retcode process_display_ijng (mng_datap pData); + +mng_retcode process_display_pplt (mng_datap pData, + mng_uint8 iType, + mng_uint32 iCount, + mng_palette8ep paIndexentries, + mng_uint8p paAlphaentries, + mng_uint8p paUsedentries); + +mng_retcode process_display_magn (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint16 iMethodX, + mng_uint16 iMX, + mng_uint16 iMY, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint16 iMT, + mng_uint16 iMB, + mng_uint16 iMethodY); +mng_retcode process_display_magn2 (mng_datap pData); + +/* ************************************************************************** */ + +#endif /* _libmng_display_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_dither.c b/freeimage241/Source/LibMNG/libmng_dither.c new file mode 100644 index 0000000..4f308e5 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_dither.c @@ -0,0 +1,54 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_dither.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Dithering routines (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the dithering routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_dither.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +mng_retcode dither_a_row (mng_datap pData, + mng_uint8p pRow) +{ + + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + + + diff --git a/freeimage241/Source/LibMNG/libmng_dither.h b/freeimage241/Source/LibMNG/libmng_dither.h new file mode 100644 index 0000000..7c8ab8a --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_dither.h @@ -0,0 +1,44 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_dither.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Dithering routines (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the dithering routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_dither_h_ +#define _libmng_dither_h_ + +/* ************************************************************************** */ + +mng_retcode dither_a_row (mng_datap pData, + mng_uint8p pRow); + +/* ************************************************************************** */ + +#endif /* _libmng_dither_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_error.c b/freeimage241/Source/LibMNG/libmng_error.c new file mode 100644 index 0000000..237f467 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_error.c @@ -0,0 +1,271 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_error.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : Error routines (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the general error handling routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - added error telltaling * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added errorstrings for delta-image processing * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - fixed up punctuation (contributed by Tim Rowley) * */ +/* * 0.5.2 - 06/06/2000 - G.Juyn * */ +/* * - added errorstring for delayed buffer-processing * */ +/* * * */ +/* * 0.9.1 - 07/06/2000 - G.Juyn * */ +/* * - added MNG_NEEDTIMERWAIT errorstring * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added NEEDSECTIONWAIT errorstring * */ +/* * - added macro + routine to set returncode without * */ +/* * calling error callback * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - added errorstring for updatemngheader if not a MNG * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/09/2000 - G.Juyn * */ +/* * - added check for simplicity-bits in MHDR * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - fixed processing of unknown critical chunks * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/20/2000 - G.Juyn * */ +/* * - added errorcode for delayed delta-processing * */ +/* * * */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - added errorcode for MAGN methods * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ERROR_STRINGS + mng_error_entry error_table [] = + { + {MNG_NOERROR, "No error"}, + {MNG_OUTOFMEMORY, "Out of memory"}, + {MNG_INVALIDHANDLE, "The handle is invalid"}, + {MNG_NOCALLBACK, "A required callback is not defined"}, + {MNG_UNEXPECTEDEOF, "Encountered unexpected end-of-file"}, + {MNG_ZLIBERROR, "zlib encountered an error"}, + {MNG_JPEGERROR, "ijgsrc6b encountered an error"}, + {MNG_LCMSERROR, "lcms encountered an error"}, + {MNG_NOOUTPUTPROFILE, "No output-profile defined for CMS"}, + {MNG_NOSRGBPROFILE, "No sRGB-profile defined for CMS"}, + {MNG_BUFOVERFLOW, "Internal buffer-overflow"}, + {MNG_FUNCTIONINVALID, "Function is invalid at this point"}, + {MNG_OUTPUTERROR, "Writing was unsuccessful; disk full?"}, + {MNG_JPEGBUFTOOSMALL, "Internal buffer for JPEG processing too small"}, + {MNG_NEEDMOREDATA, "Reading suspended; waiting for I/O to catch up"}, + {MNG_NEEDTIMERWAIT, "Timer suspension; normal animation delay"}, + {MNG_NEEDSECTIONWAIT, "SEEK suspension; application decides"}, + {MNG_LOOPWITHCACHEOFF, "LOOP encountered when playback cache is turned off"}, + + {MNG_APPIOERROR, "Application signalled I/O error"}, + {MNG_APPTIMERERROR, "Application signalled timing error"}, + {MNG_APPCMSERROR, "Application signalled CMS error"}, + {MNG_APPMISCERROR, "Application signalled an error"}, + {MNG_APPTRACEABORT, "Application signalled error during trace-callback"}, + + {MNG_INTERNALERROR, "Internal error in libmng"}, + + {MNG_INVALIDSIG, "The signature is invalid"}, + {MNG_INVALIDCRC, "The CRC for this chunk is invalid"}, + {MNG_INVALIDLENGTH, "Chunk-length is invalid"}, + {MNG_SEQUENCEERROR, "Chunk out of sequence"}, + {MNG_CHUNKNOTALLOWED, "Chunk not allowed at this point"}, + {MNG_MULTIPLEERROR, "Chunk cannot occur multiple times"}, + {MNG_PLTEMISSING, "Missing PLTE chunk"}, + {MNG_IDATMISSING, "Missing IDAT chunk(s)"}, + {MNG_CANNOTBEEMPTY, "Chunk cannot be empty"}, + {MNG_GLOBALLENGTHERR, "Global data length invalid"}, + {MNG_INVALIDBITDEPTH, "The bit_depth is invalid"}, + {MNG_INVALIDCOLORTYPE, "The color_type is invalid"}, + {MNG_INVALIDCOMPRESS, "The compression_method is invalid"}, + {MNG_INVALIDFILTER, "The filter_method or filter_type is invalid"}, + {MNG_INVALIDINTERLACE, "The interlace_method is invalid"}, + {MNG_NOTENOUGHIDAT, "There is not enough data in the IDAT chunk(s)"}, + {MNG_PLTEINDEXERROR, "Palette-index out of bounds"}, + {MNG_NULLNOTFOUND, "NULL separator not found"}, + {MNG_KEYWORDNULL, "Keyword cannot be zero-length"}, + {MNG_OBJECTUNKNOWN, "Object does not exist"}, + {MNG_OBJECTEXISTS, "Object already exists"}, + {MNG_TOOMUCHIDAT, "Too much data in IDAT chunk(s)"}, + {MNG_INVSAMPLEDEPTH, "The sample_depth is invalid"}, + {MNG_INVOFFSETSIZE, "The offset_type is invalid"}, + {MNG_INVENTRYTYPE, "The entry_type is invalid"}, + {MNG_ENDWITHNULL, "Chunk must not end with NULL byte"}, + {MNG_INVIMAGETYPE, "The image_type is invalid"}, + {MNG_INVDELTATYPE, "The delta_type is invalid"}, + {MNG_INVALIDINDEX, "Index-value out of bounds"}, + {MNG_TOOMUCHJDAT, "Too much data in JDAT chunk(s)"}, + {MNG_JPEGPARMSERR, "JHDR parameters & JFIF-data do not match"}, + {MNG_INVFILLMETHOD, "The fill_method is invalid"}, + {MNG_OBJNOTCONCRETE, "Target object for DHDR must be concrete"}, + {MNG_TARGETNOALPHA, "Target object must have alpha-channel"}, + {MNG_MNGTOOCOMPLEX, "MHDR simplicity indicates unsupported feature(s)"}, + {MNG_UNKNOWNCRITICAL, "Unknown critical chunk encountered"}, + {MNG_UNSUPPORTEDNEED, "Requested nEED resources are not supported"}, + {MNG_INVALIDDELTA, "The delta operation is invalid (mismatched color_types?)"}, + {MNG_INVALIDMETHOD, "Method is invalid"}, + + {MNG_INVALIDCNVSTYLE, "Canvas_style is invalid"}, + {MNG_WRONGCHUNK, "Attempt to access the wrong chunk"}, + {MNG_INVALIDENTRYIX, "Attempt to access an non-existing entry"}, + {MNG_NOHEADER, "No valid header-chunk"}, + {MNG_NOCORRCHUNK, "Parent chunk not found"}, + {MNG_NOMHDR, "No MNG header (MHDR) found"}, + + {MNG_IMAGETOOLARGE, "Image is larger than defined maximum"}, + {MNG_NOTANANIMATION, "Image is not an animation"}, + {MNG_FRAMENRTOOHIGH, "Framenr out of bounds"}, + {MNG_LAYERNRTOOHIGH, "Layernr out of bounds"}, + {MNG_PLAYTIMETOOHIGH, "Playtime out of bounds"}, + {MNG_FNNOTIMPLEMENTED, "Function not yet implemented"}, + {MNG_IMAGEFROZEN, "Image is frozen"}, + + {MNG_LCMS_NOHANDLE, "Handle could not be initialized"}, + {MNG_LCMS_NOMEM, "No memory for gamma-table(s)"}, + {MNG_LCMS_NOTRANS, "Transformation could not be initialized"}, + }; +#endif /* MNG_INCLUDE_ERROR_STRINGS */ + +/* ************************************************************************** */ + +mng_bool mng_store_error (mng_datap pData, + mng_retcode iError, + mng_retcode iExtra1, + mng_retcode iExtra2) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (pData, MNG_FN_STORE_ERROR, MNG_LC_START) +#endif + + if (pData != 0) + { + pData->iErrorcode = iError; /* save also for getlasterror */ + pData->iErrorx1 = iExtra1; + pData->iErrorx2 = iExtra2; + +#ifdef MNG_INCLUDE_ERROR_STRINGS + { /* binary search variables */ + mng_int32 iTop, iLower, iUpper, iMiddle; + mng_error_entryp pEntry; /* pointer to found entry */ + /* determine max index of table */ + iTop = (sizeof (error_table) / sizeof (error_table [0])) - 1; + + iLower = 0; /* initialize binary search */ + iMiddle = iTop >> 1; /* start in the middle */ + iUpper = iTop; + pEntry = 0; /* no goods yet! */ + + do /* the binary search itself */ + { + if (error_table [iMiddle].iError < iError) + iLower = iMiddle + 1; + else if (error_table [iMiddle].iError > iError) + iUpper = iMiddle - 1; + else + { + pEntry = &error_table [iMiddle]; + break; + } + + iMiddle = (iLower + iUpper) >> 1; + } + while (iLower <= iUpper); + + if (pEntry) /* found it ? */ + pData->zErrortext = pEntry->zErrortext; + else + pData->zErrortext = "Unknown error"; + } +#else + pData->zErrortext = 0; +#endif /* mng_error_telltale */ + + if (iError == 0) /* no error is not severe ! */ + { + pData->iSeverity = 0; + } + else + { + switch (iError&0x3C00) /* determine the severity */ + { + case 0x0800 : { pData->iSeverity = 5; break; } + case 0x1000 : { pData->iSeverity = 2; break; } + case 0x2000 : { pData->iSeverity = 1; break; } + default : { pData->iSeverity = 9; } + } + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (pData, MNG_FN_STORE_ERROR, MNG_LC_END) +#endif + + return MNG_TRUE; +} + +/* ************************************************************************** */ + +mng_bool mng_process_error (mng_datap pData, + mng_retcode iError, + mng_retcode iExtra1, + mng_retcode iExtra2) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (pData, MNG_FN_PROCESS_ERROR, MNG_LC_START) +#endif + + mng_store_error (pData, iError, iExtra1, iExtra2); + + if (pData != 0) + { + if (pData->fErrorproc) /* callback defined ? */ + return pData->fErrorproc (((mng_handle)pData), iError, pData->iSeverity, + pData->iChunkname, pData->iChunkseq, + pData->iErrorx1, pData->iErrorx2, pData->zErrortext); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (pData, MNG_FN_PROCESS_ERROR, MNG_LC_END) +#endif + + return MNG_FALSE; /* automatic failure */ +} + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_error.h b/freeimage241/Source/LibMNG/libmng_error.h new file mode 100644 index 0000000..9ea9316 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_error.h @@ -0,0 +1,109 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_error.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Error functions (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the generic error-codes and functions * */ +/* * * */ +/* * changes : 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - added some errorcodes * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - added some errorcodes * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added application errorcodes (used with callbacks) * */ +/* * - moved chunk-access errorcodes to severity 5 * */ +/* * * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - added JNG errorcodes * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - added error tell-tale definition * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added errorcodes for delta-image processing * */ +/* * 0.5.2 - 06/06/2000 - G.Juyn * */ +/* * - added errorcode for delayed buffer-processing * */ +/* * - moved errorcodes to "libmng.h" * */ +/* * * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added macro + routine to set returncode without * */ +/* * calling error callback * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_error_h_ +#define _libmng_error_h_ + +/* ************************************************************************** */ +/* * * */ +/* * Default error routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_bool mng_store_error (mng_datap pData, + mng_retcode iError, + mng_retcode iExtra1, + mng_retcode iExtra2); + +mng_bool mng_process_error (mng_datap pData, + mng_retcode iError, + mng_retcode iExtra1, + mng_retcode iExtra2); + +/* ************************************************************************** */ +/* * * */ +/* * Error handling macros * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_ERROR(D,C) { mng_process_error (D, C, 0, 0); return C; } +#define MNG_ERRORZ(D,Z) { mng_process_error (D, MNG_ZLIBERROR, Z, 0); return MNG_ZLIBERROR; } +#define MNG_ERRORJ(D,J) { mng_process_error (D, MNG_JPEGERROR, J, 0); return MNG_JPEGERROR; } +#define MNG_ERRORL(D,L) { mng_process_error (D, MNG_LCMSERROR, L, 0); return MNG_LCMSERROR; } + +#define MNG_RETURN(D,C) { mng_store_error (D, C, 0, 0); return C; } + +#define MNG_WARNING(D,C) { if (!mng_process_error (D, C, 0, 0)) return C; } + +#define MNG_VALIDHANDLE(H) { if ((H == 0) || (((mng_datap)H)->iMagic != MNG_MAGIC)) \ + return MNG_INVALIDHANDLE; } +#define MNG_VALIDHANDLEX(H) { if ((H == 0) || (((mng_datap)H)->iMagic != MNG_MAGIC)) \ + return 0; } +#define MNG_VALIDCB(D,C) { if (!((mng_datap)D)->C) \ + MNG_ERROR (((mng_datap)D), MNG_NOCALLBACK) } + +/* ************************************************************************** */ +/* * * */ +/* * Error string-table entry * */ +/* * * */ +/* ************************************************************************** */ + +typedef struct { + mng_retcode iError; + mng_pchar zErrortext; + } mng_error_entry; +typedef mng_error_entry * mng_error_entryp; + +/* ************************************************************************** */ + +#endif /* _libmng_error_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_filter.c b/freeimage241/Source/LibMNG/libmng_filter.c new file mode 100644 index 0000000..a055f5c --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_filter.c @@ -0,0 +1,890 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_filter.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Filtering routines (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the filtering routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_filter.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_FILTERS + +/* ************************************************************************** */ + +mng_retcode filter_a_row (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_A_ROW, MNG_LC_START) +#endif + + switch (*(pData->pWorkrow + pData->iFilterofs)) + { + case 1 : { + iRetcode = filter_sub (pData); + break; + } + case 2 : { + iRetcode = filter_up (pData); + break; + } + case 3 : { + iRetcode = filter_average (pData); + break; + } + case 4 : { + iRetcode = filter_paeth (pData); + break; + } + + default : iRetcode = MNG_INVALIDFILTER; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_A_ROW, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +mng_retcode filter_sub (mng_datap pData) +{ + mng_uint32 iBpp; + mng_uint8p pRawx; + mng_uint8p pRawx_prev; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_SUB, MNG_LC_START) +#endif + + iBpp = pData->iFilterbpp; + pRawx = pData->pWorkrow + pData->iPixelofs + iBpp; + pRawx_prev = pData->pWorkrow + pData->iPixelofs; + + for (iX = iBpp; iX < pData->iRowsize; iX++) + { + *pRawx = (mng_uint8)(*pRawx + *pRawx_prev); + pRawx++; + pRawx_prev++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_SUB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode filter_up (mng_datap pData) +{ + mng_uint8p pRawx; + mng_uint8p pPriorx; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_UP, MNG_LC_START) +#endif + + pRawx = pData->pWorkrow + pData->iPixelofs; + pPriorx = pData->pPrevrow + pData->iPixelofs; + + for (iX = 0; iX < pData->iRowsize; iX++) + { + *pRawx = (mng_uint8)(*pRawx + *pPriorx); + pRawx++; + pPriorx++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_UP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode filter_average (mng_datap pData) +{ + mng_int32 iBpp; + mng_uint8p pRawx; + mng_uint8p pRawx_prev; + mng_uint8p pPriorx; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_AVERAGE, MNG_LC_START) +#endif + + iBpp = pData->iFilterbpp; + pRawx = pData->pWorkrow + pData->iPixelofs; + pPriorx = pData->pPrevrow + pData->iPixelofs; + pRawx_prev = pData->pWorkrow + pData->iPixelofs; + + for (iX = 0; iX < iBpp; iX++) + { + *pRawx = (mng_uint8)(*pRawx + ((*pPriorx) >> 1)); + pRawx++; + pPriorx++; + } + + for (iX = iBpp; iX < pData->iRowsize; iX++) + { + *pRawx = (mng_uint8)(*pRawx + ((*pRawx_prev + *pPriorx) >> 1)); + pRawx++; + pPriorx++; + pRawx_prev++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_AVERAGE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode filter_paeth (mng_datap pData) +{ + mng_int32 iBpp; + mng_uint8p pRawx; + mng_uint8p pRawx_prev; + mng_uint8p pPriorx; + mng_uint8p pPriorx_prev; + mng_int32 iX; + mng_uint32 iA, iB, iC; + mng_uint32 iP; + mng_uint32 iPa, iPb, iPc; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_PAETH, MNG_LC_START) +#endif + + iBpp = pData->iFilterbpp; + pRawx = pData->pWorkrow + pData->iPixelofs; + pPriorx = pData->pPrevrow + pData->iPixelofs; + pRawx_prev = pData->pWorkrow + pData->iPixelofs; + pPriorx_prev = pData->pPrevrow + pData->iPixelofs; + + for (iX = 0; iX < iBpp; iX++) + { + *pRawx = (mng_uint8)(*pRawx + *pPriorx); + + pRawx++; + pPriorx++; + } + + for (iX = iBpp; iX < pData->iRowsize; iX++) + { + iA = (mng_uint32)*pRawx_prev; + iB = (mng_uint32)*pPriorx; + iC = (mng_uint32)*pPriorx_prev; + iP = iA + iB - iC; + iPa = abs (iP - iA); + iPb = abs (iP - iB); + iPc = abs (iP - iC); + + if ((iPa <= iPb) && (iPa <= iPc)) + *pRawx = (mng_uint8)(*pRawx + iA); + else + if (iPb <= iPc) + *pRawx = (mng_uint8)(*pRawx + iB); + else + *pRawx = (mng_uint8)(*pRawx + iC); + + pRawx++; + pPriorx++; + pRawx_prev++; + pPriorx_prev++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FILTER_PAETH, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode init_rowdiffering (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ROWDIFFERING, MNG_LC_START) +#endif + + if (pData->iFilter & 0x40) /* has leveling parameters ? */ + { + switch (pData->iColortype) /* salvage leveling parameters */ + { + case 0 : { /* gray */ + if (pData->iBitdepth <= 8) + pData->iLevel0 = (mng_uint16)*pData->pWorkrow; + else + pData->iLevel0 = mng_get_uint16 (pData->pWorkrow); + + break; + } + case 2 : { /* rgb */ + if (pData->iBitdepth <= 8) + { + pData->iLevel0 = (mng_uint16)*pData->pWorkrow; + pData->iLevel1 = (mng_uint16)*(pData->pWorkrow+1); + pData->iLevel2 = (mng_uint16)*(pData->pWorkrow+2); + } + else + { + pData->iLevel0 = mng_get_uint16 (pData->pWorkrow); + pData->iLevel1 = mng_get_uint16 (pData->pWorkrow+2); + pData->iLevel2 = mng_get_uint16 (pData->pWorkrow+4); + } + + break; + } + case 3 : { /* indexed */ + pData->iLevel0 = (mng_uint16)*pData->pWorkrow; + break; + } + case 4 : { /* gray+alpha */ + if (pData->iBitdepth <= 8) + { + pData->iLevel0 = (mng_uint16)*pData->pWorkrow; + pData->iLevel1 = (mng_uint16)*(pData->pWorkrow+1); + } + else + { + pData->iLevel0 = mng_get_uint16 (pData->pWorkrow); + pData->iLevel1 = mng_get_uint16 (pData->pWorkrow+2); + } + + break; + } + case 6 : { /* rgb+alpha */ + if (pData->iBitdepth <= 8) + { + pData->iLevel0 = (mng_uint16)*pData->pWorkrow; + pData->iLevel1 = (mng_uint16)*(pData->pWorkrow+1); + pData->iLevel2 = (mng_uint16)*(pData->pWorkrow+2); + pData->iLevel3 = (mng_uint16)*(pData->pWorkrow+3); + } + else + { + pData->iLevel0 = mng_get_uint16 (pData->pWorkrow); + pData->iLevel1 = mng_get_uint16 (pData->pWorkrow+2); + pData->iLevel2 = mng_get_uint16 (pData->pWorkrow+4); + pData->iLevel3 = mng_get_uint16 (pData->pWorkrow+6); + } + + break; + } + } + } + /* shift the entire row back in place */ + pRawi = pData->pWorkrow + pData->iFilterofs; + pRawo = pData->pWorkrow; + + for (iX = 0; iX < pData->iRowsize + pData->iPixelofs - pData->iFilterofs; iX++) + *pRawo++ = *pRawi++; + + pData->iFilterofs = 0; /* indicate so ! */ + + if (pData->iFilter & 0x01) /* no adaptive filtering ? */ + pData->iPixelofs = pData->iFilterofs; + else + pData->iPixelofs = pData->iFilterofs + 1; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ROWDIFFERING, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_g1 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G1, MNG_LC_START) +#endif + + if (pData->iLevel0 & 0x01) /* is it uneven level ? */ + { + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + /* just invert every bit */ + for (iX = 0; iX < pData->iRowsize; iX++) + *pRawo++ = (mng_uint8)(~(*pRawi++)); + + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_g2 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + mng_int32 iC, iS; + mng_uint8 iB, iN, iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G2, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + iC = 0; + iB = 0; + iN = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iC) + { + iC = 4; + iB = *pRawi++; + iN = 0; + iS = 8; + } + + iS -= 2; + iQ = (mng_uint8)(((iB >> iS) + pData->iLevel0) & 0x03); + iN = (mng_uint8)((iN << 2) + iQ); + iC--; + + if (!iC) + *pRawo++ = iN; + + } + + if (iC) + *pRawo = (mng_uint8)(iN << iS); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_g4 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + mng_int32 iC, iS; + mng_uint8 iB, iN, iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G4, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + iC = 0; + iB = 0; + iN = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iC) + { + iC = 2; + iB = *pRawi++; + iN = 0; + iS = 8; + } + + iS -= 4; + iQ = (mng_uint8)(((iB >> iS) + pData->iLevel0) & 0x0F); + iN = (mng_uint8)((iN << 4) + iQ); + iC--; + + if (!iC) + *pRawo++ = iN; + + } + + if (iC) + *pRawo = (mng_uint8)(iN << iS); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_g8 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G8, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRawo++ = (mng_uint8)(((mng_uint16)*pRawi + pData->iLevel0) & 0xFF); + + pRawi++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_g16 (mng_datap pData) +{ + mng_uint16p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G16, MNG_LC_START) +#endif + + pRawi = (mng_uint16p)(pData->pWorkrow + pData->iPixelofs); + pRawo = (mng_uint16p)(pData->pPrevrow + pData->iPixelofs); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRawo++ = (mng_uint16)(((mng_uint32)*pRawi + (mng_uint32)pData->iLevel0) & 0xFFFF); + + pRawi++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_G16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_rgb8 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGB8, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *(pRawo+1) = (mng_uint8)(((mng_uint16)*(pRawi+1) + pData->iLevel1) & 0xFF); + *pRawo = (mng_uint8)(((mng_uint16)*pRawi + pData->iLevel0 + + (mng_uint16)*(pRawo+1)) & 0xFF); + *(pRawo+2) = (mng_uint8)(((mng_uint16)*(pRawi+2) + pData->iLevel2 + + (mng_uint16)*(pRawo+1)) & 0xFF); + + pRawi += 3; + pRawo += 3; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_rgb16 (mng_datap pData) +{ + mng_uint16p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGB16, MNG_LC_START) +#endif + + pRawi = (mng_uint16p)(pData->pWorkrow + pData->iPixelofs); + pRawo = (mng_uint16p)(pData->pPrevrow + pData->iPixelofs); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *(pRawo+1) = (mng_uint16)(((mng_uint32)*(pRawi+1) + (mng_uint32)pData->iLevel1) & 0xFFFF); + *pRawo = (mng_uint16)(((mng_uint32)*pRawi + (mng_uint32)pData->iLevel0 + + (mng_uint32)*(pRawo+1)) & 0xFFFF); + *(pRawo+2) = (mng_uint16)(((mng_uint32)*(pRawi+2) + (mng_uint32)pData->iLevel2 + + (mng_uint32)*(pRawo+1)) & 0xFFFF); + + pRawi += 3; + pRawo += 3; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGB16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_idx1 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX1, MNG_LC_START) +#endif + + if (pData->iLevel0 & 0x01) /* is it uneven level ? */ + { + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + /* just invert every bit */ + for (iX = 0; iX < pData->iRowsize; iX++) + *pRawo++ = (mng_uint8)(~(*pRawi++)); + + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_idx2 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + mng_int32 iC, iS; + mng_uint8 iB, iN, iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX2, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + iC = 0; + iB = 0; + iN = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iC) + { + iC = 4; + iB = *pRawi++; + iN = 0; + iS = 8; + } + + iS -= 2; + iQ = (mng_uint8)(((iB >> iS) + pData->iLevel0) & 0x03); + iN = (mng_uint8)((iN << 2) + iQ); + iC--; + + if (!iC) + *pRawo++ = iN; + + } + + if (iC) + *pRawo = (mng_uint8)(iN << iS); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_idx4 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + mng_int32 iC, iS; + mng_uint8 iB, iN, iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX4, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + iC = 0; + iB = 0; + iN = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iC) + { + iC = 2; + iB = *pRawi++; + iN = 0; + iS = 8; + } + + iS -= 4; + iQ = (mng_uint8)(((iB >> iS) + pData->iLevel0) & 0x0F); + iN = (mng_uint8)((iN << 4) + iQ); + iC--; + + if (!iC) + *pRawo++ = iN; + + } + + if (iC) + *pRawo = (mng_uint8)(iN << iS); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_idx8 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX8, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRawo++ = (mng_uint8)(((mng_uint16)*pRawi + pData->iLevel0) & 0xFF); + + pRawi++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_IDX8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_ga8 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_GA8, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRawo = (mng_uint8)(((mng_uint16)*pRawi + pData->iLevel0) & 0xFF); + *(pRawo+1) = (mng_uint8)(((mng_uint16)*(pRawi+1) + pData->iLevel1) & 0xFF); + + pRawi += 2; + pRawo += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_GA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_ga16 (mng_datap pData) +{ + mng_uint16p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_GA16, MNG_LC_START) +#endif + + pRawi = (mng_uint16p)(pData->pWorkrow + pData->iPixelofs); + pRawo = (mng_uint16p)(pData->pPrevrow + pData->iPixelofs); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRawo = (mng_uint16)(((mng_uint32)*pRawi + (mng_uint32)pData->iLevel0) & 0xFFFF); + *(pRawo+1) = (mng_uint16)(((mng_uint32)*(pRawi+1) + (mng_uint32)pData->iLevel1) & 0xFFFF); + + pRawi += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_GA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_rgba8 (mng_datap pData) +{ + mng_uint8p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGBA8, MNG_LC_START) +#endif + + pRawi = pData->pWorkrow + pData->iPixelofs; + pRawo = pData->pPrevrow + pData->iPixelofs; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *(pRawo+1) = (mng_uint8)(((mng_uint16)*(pRawi+1) + pData->iLevel1) & 0xFF); + *pRawo = (mng_uint8)(((mng_uint16)*pRawi + pData->iLevel0 + + (mng_uint16)*(pRawo+1)) & 0xFF); + *(pRawo+2) = (mng_uint8)(((mng_uint16)*(pRawi+2) + pData->iLevel2 + + (mng_uint16)*(pRawo+1)) & 0xFF); + *(pRawo+3) = (mng_uint8)(((mng_uint16)*(pRawi+3) + pData->iLevel3) & 0xFF); + + pRawi += 4; + pRawo += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGBA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode differ_rgba16 (mng_datap pData) +{ + mng_uint16p pRawi, pRawo; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGBA16, MNG_LC_START) +#endif + + pRawi = (mng_uint16p)(pData->pWorkrow + pData->iPixelofs); + pRawo = (mng_uint16p)(pData->pPrevrow + pData->iPixelofs); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *(pRawo+1) = (mng_uint16)(((mng_uint32)*(pRawi+1) + (mng_uint32)pData->iLevel1) & 0xFFFF); + *pRawo = (mng_uint16)(((mng_uint32)*pRawi + (mng_uint32)pData->iLevel0 + + (mng_uint32)*(pRawo+1)) & 0xFFFF); + *(pRawo+2) = (mng_uint16)(((mng_uint32)*(pRawi+2) + (mng_uint32)pData->iLevel2 + + (mng_uint32)*(pRawo+1)) & 0xFFFF); + *(pRawo+3) = (mng_uint16)(((mng_uint32)*(pRawi+3) + (mng_uint32)pData->iLevel3) & 0xFFFF); + + pRawi += 4; + pRawo += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DIFFER_RGBA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_FILTERS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_filter.h b/freeimage241/Source/LibMNG/libmng_filter.h new file mode 100644 index 0000000..2c8c61d --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_filter.h @@ -0,0 +1,71 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_filter.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Filtering routines (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the filtering routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_filter_h_ +#define _libmng_filter_h_ + +/* ************************************************************************** */ + +mng_retcode filter_a_row (mng_datap pData); + +mng_retcode filter_sub (mng_datap pData); +mng_retcode filter_up (mng_datap pData); +mng_retcode filter_average (mng_datap pData); +mng_retcode filter_paeth (mng_datap pData); + +/* ************************************************************************** */ + +mng_retcode init_rowdiffering (mng_datap pData); + +mng_retcode differ_g1 (mng_datap pData); +mng_retcode differ_g2 (mng_datap pData); +mng_retcode differ_g4 (mng_datap pData); +mng_retcode differ_g8 (mng_datap pData); +mng_retcode differ_g16 (mng_datap pData); +mng_retcode differ_rgb8 (mng_datap pData); +mng_retcode differ_rgb16 (mng_datap pData); +mng_retcode differ_idx1 (mng_datap pData); +mng_retcode differ_idx2 (mng_datap pData); +mng_retcode differ_idx4 (mng_datap pData); +mng_retcode differ_idx8 (mng_datap pData); +mng_retcode differ_ga8 (mng_datap pData); +mng_retcode differ_ga16 (mng_datap pData); +mng_retcode differ_rgba8 (mng_datap pData); +mng_retcode differ_rgba16 (mng_datap pData); + +/* ************************************************************************** */ + +#endif /* _libmng_filter_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_hlapi.c b/freeimage241/Source/LibMNG/libmng_hlapi.c new file mode 100644 index 0000000..9a897ff --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_hlapi.c @@ -0,0 +1,1814 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_hlapi.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : high-level application API (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the high-level function interface * */ +/* * for applications. * */ +/* * * */ +/* * changes : 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - added init of iPLTEcount * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed calling-convention definition * */ +/* * - changed status-handling of display-routines * */ +/* * - added versioning-control routines * */ +/* * - filled the write routine * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added callback error-reporting support * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * 0.5.1 - 05/13/2000 - G.Juyn * */ +/* * - added eMNGma hack (will be removed in 1.0.0 !!!) * */ +/* * - added TERM animation object pointer (easier reference) * */ +/* * 0.5.1 - 05/14/2000 - G.Juyn * */ +/* * - added cleanup of saved-data (SAVE/SEEK processing) * */ +/* * 0.5.1 - 05/16/2000 - G.Juyn * */ +/* * - moved the actual write_graphic functionality from here * */ +/* * to it's appropriate function in the mng_write module * */ +/* * * */ +/* * 0.5.2 - 05/19/2000 - G.Juyn * */ +/* * - cleaned up some code regarding mixed support * */ +/* * - added JNG support * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - moved init of default zlib parms here from "mng_zlib.c" * */ +/* * - added init of default IJG parms * */ +/* * 0.5.2 - 05/29/2000 - G.Juyn * */ +/* * - fixed inconsistancy with freeing global iCCP profile * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added delta-image field initialization * */ +/* * 0.5.2 - 06/06/2000 - G.Juyn * */ +/* * - added initialization of the buffer-suspend parameter * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - added initialization of update-region for refresh * */ +/* * - added initialization of Needrefresh parameter * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - added initialization of Deltaimmediate * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added initialization of Speed * */ +/* * - added initialization of Imagelevel * */ +/* * 0.5.3 - 06/26/2000 - G.Juyn * */ +/* * - changed userdata variable to mng_ptr * */ +/* * 0.5.3 - 06/29/2000 - G.Juyn * */ +/* * - fixed initialization routine for new mng_handle type * */ +/* * * */ +/* * 0.9.1 - 07/06/2000 - G.Juyn * */ +/* * - changed mng_display_resume to allow to be called after * */ +/* * a suspension return with MNG_NEEDMOREDATA * */ +/* * - added returncode MNG_NEEDTIMERWAIT for timer breaks * */ +/* * 0.9.1 - 07/07/2000 - G.Juyn * */ +/* * - implemented support for freeze/reset/resume & go_xxxx * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - added support for improved timing * */ +/* * - added support for improved I/O-suspension * */ +/* * 0.9.1 - 07/14/2000 - G.Juyn * */ +/* * - changed EOF processing behavior * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added callbacks for SAVE/SEEK processing * */ +/* * - added variable for NEEDSECTIONWAIT breaks * */ +/* * - added variable for freeze & reset processing * */ +/* * 0.9.1 - 07/17/2000 - G.Juyn * */ +/* * - added error cleanup processing * */ +/* * - fixed support for mng_display_reset() * */ +/* * - fixed suspension-buffering for 32K+ chunks * */ +/* * * */ +/* * 0.9.2 - 07/29/2000 - G.Juyn * */ +/* * - fixed small bugs in display processing * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - fixed wrapping of suspension parameters * */ +/* * 0.9.2 - 08/04/2000 - G.Juyn * */ +/* * - B111096 - fixed large-buffer read-suspension * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 09/10/2000 - G.Juyn * */ +/* * - fixed DEFI behavior * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added optional support for bKGD for PNG images * */ +/* * - raised initial maximum canvas size * */ +/* * - added support for JDAA * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * - fixed support for delta-images during read() / display() * */ +/* * 0.9.3 - 10/18/2000 - G.Juyn * */ +/* * - added closestream() processing for mng_cleanup() * */ +/* * 0.9.3 - 10/27/2000 - G.Juyn * */ +/* * - fixed seperate read() & display() processing * */ +/* * * */ +/* * 0.9.4 - 11/20/2000 - G.Juyn * */ +/* * - fixed unwanted repetition in mng_readdisplay() * */ +/* * 0.9.4 - 11/24/2000 - G.Juyn * */ +/* * - moved restore of object 0 to libmng_display * */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * 1.0.1 - 02/13/2001 - G.Juyn * */ +/* * - fixed first FRAM_MODE=4 timing problem * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn * */ +/* * - fixed bug with display_reset/display_resume (Thanks G!) * */ +/* * 1.0.1 - 04/22/2001 - G.Juyn * */ +/* * - fixed memory-leak (Thanks Gregg!) * */ +/* * 1.0.1 - 04/23/2001 - G.Juyn * */ +/* * - fixed reset_rundata to drop all objects * */ +/* * 1.0.1 - 04/25/2001 - G.Juyn * */ +/* * - moved mng_clear_cms to libmng_cms * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * - added processterm callback * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - added option to turn off progressive refresh * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_objects.h" +#include "libmng_object_prc.h" +#include "libmng_chunks.h" +#include "libmng_memory.h" +#include "libmng_read.h" +#include "libmng_write.h" +#include "libmng_display.h" +#include "libmng_zlib.h" +#include "libmng_jpeg.h" +#include "libmng_cms.h" +#include "libmng_pixels.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ +/* * * */ +/* * local routines * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) +mng_retcode mng_drop_chunks (mng_datap pData) +{ + mng_chunkp pChunk; + mng_chunkp pNext; + mng_cleanupchunk fCleanup; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_CHUNKS, MNG_LC_START) +#endif + + pChunk = pData->pFirstchunk; /* and get first stored chunk (if any) */ + + while (pChunk) /* more chunks to discard ? */ + { + pNext = ((mng_chunk_headerp)pChunk)->pNext; + /* call appropriate cleanup */ + fCleanup = ((mng_chunk_headerp)pChunk)->fCleanup; + fCleanup (pData, pChunk); + + pChunk = pNext; /* neeeext */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_CHUNKS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode mng_drop_objects (mng_datap pData, + mng_bool bDropaniobj) +{ + mng_objectp pObject; + mng_objectp pNext; + mng_cleanupobject fCleanup; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_OBJECTS, MNG_LC_START) +#endif + + pObject = pData->pFirstimgobj; /* get first stored image-object (if any) */ + + while (pObject) /* more objects to discard ? */ + { + pNext = ((mng_object_headerp)pObject)->pNext; + /* call appropriate cleanup */ + fCleanup = ((mng_object_headerp)pObject)->fCleanup; + fCleanup (pData, pObject); + + pObject = pNext; /* neeeext */ + } + + pData->pFirstimgobj = MNG_NULL; /* clean this up!!! */ + + if (bDropaniobj) /* drop animation objects ? */ + { + pObject = pData->pFirstaniobj; /* get first stored animation-object (if any) */ + + while (pObject) /* more objects to discard ? */ + { + pNext = ((mng_object_headerp)pObject)->pNext; + /* call appropriate cleanup */ + fCleanup = ((mng_object_headerp)pObject)->fCleanup; + fCleanup (pData, pObject); + + pObject = pNext; /* neeeext */ + } + + pData->pFirstaniobj = MNG_NULL; /* clean this up!!! */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_OBJECTS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode mng_drop_savedata (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_SAVEDATA, MNG_LC_START) +#endif + + if (pData->pSavedata) /* sanity check */ + { /* address it more directly */ + mng_savedatap pSave = pData->pSavedata; + + if (pSave->iGlobalProfilesize) /* cleanup the profile ? */ + MNG_FREEX (pData, pSave->pGlobalProfile, pSave->iGlobalProfilesize) + /* cleanup the save structure */ + MNG_FREE (pData, pData->pSavedata, sizeof (mng_savedata)) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_SAVEDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode mng_reset_rundata (mng_datap pData) +{ + drop_invalid_objects (pData); /* drop invalidly stored objects */ + mng_drop_savedata (pData); /* drop stored savedata */ + mng_reset_objzero (pData); /* reset object 0 */ + /* drop stored objects (if any) */ + mng_drop_objects (pData, MNG_FALSE); + + pData->bFramedone = MNG_FALSE; + pData->iFrameseq = 0; /* reset counters & stuff */ + pData->iLayerseq = 0; + pData->iFrametime = 0; + pData->iRequestframe = 0; + pData->iRequestlayer = 0; + pData->iRequesttime = 0; + pData->bSearching = MNG_FALSE; + + pData->iRuntime = 0; + pData->iSynctime = 0; + pData->iStarttime = 0; + pData->iEndtime = 0; + pData->bRunning = MNG_FALSE; + pData->bTimerset = MNG_FALSE; + pData->iBreakpoint = 0; + pData->bSectionwait = MNG_FALSE; + pData->bFreezing = MNG_FALSE; + pData->bResetting = MNG_FALSE; + pData->bNeedrefresh = MNG_FALSE; + + pData->iIterations = 0; + /* start of animation objects! */ + pData->pCurraniobj = MNG_NULL; + + pData->iUpdateleft = 0; /* reset region */ + pData->iUpdateright = 0; + pData->iUpdatetop = 0; + pData->iUpdatebottom = 0; + pData->iPLTEcount = 0; /* reset PLTE data */ + + pData->iDEFIobjectid = 0; /* reset DEFI data */ + pData->bDEFIhasdonotshow = MNG_FALSE; + pData->iDEFIdonotshow = 0; + pData->bDEFIhasconcrete = MNG_FALSE; + pData->iDEFIconcrete = 0; + pData->bDEFIhasloca = MNG_FALSE; + pData->iDEFIlocax = 0; + pData->iDEFIlocay = 0; + pData->bDEFIhasclip = MNG_FALSE; + pData->iDEFIclipl = 0; + pData->iDEFIclipr = 0; + pData->iDEFIclipt = 0; + pData->iDEFIclipb = 0; + + pData->iBACKred = 0; /* reset BACK data */ + pData->iBACKgreen = 0; + pData->iBACKblue = 0; + pData->iBACKmandatory = 0; + pData->iBACKimageid = 0; + pData->iBACKtile = 0; + + pData->iFRAMmode = 1; /* default global FRAM variables */ + pData->iFRAMdelay = 1; + pData->iFRAMtimeout = 0x7fffffffl; + pData->bFRAMclipping = MNG_FALSE; + pData->iFRAMclipl = 0; + pData->iFRAMclipr = 0; + pData->iFRAMclipt = 0; + pData->iFRAMclipb = 0; + + pData->iFramemode = 1; /* again for the current frame */ + pData->iFramedelay = 1; + pData->iFrametimeout = 0x7fffffffl; + pData->bFrameclipping = MNG_FALSE; + pData->iFrameclipl = 0; + pData->iFrameclipr = 0; + pData->iFrameclipt = 0; + pData->iFrameclipb = 0; + + pData->iNextdelay = 1; + + pData->iSHOWmode = 0; /* reset SHOW data */ + pData->iSHOWfromid = 0; + pData->iSHOWtoid = 0; + pData->iSHOWnextid = 0; + pData->iSHOWskip = 0; + + pData->iGlobalPLTEcount = 0; /* reset global PLTE data */ + + pData->iGlobalTRNSrawlen = 0; /* reset global tRNS data */ + + pData->iGlobalGamma = 0; /* reset global gAMA data */ + + pData->iGlobalWhitepointx = 0; /* reset global cHRM data */ + pData->iGlobalWhitepointy = 0; + pData->iGlobalPrimaryredx = 0; + pData->iGlobalPrimaryredy = 0; + pData->iGlobalPrimarygreenx = 0; + pData->iGlobalPrimarygreeny = 0; + pData->iGlobalPrimarybluex = 0; + pData->iGlobalPrimarybluey = 0; + + pData->iGlobalRendintent = 0; /* reset global sRGB data */ + + if (pData->iGlobalProfilesize) /* drop global profile (if any) */ + MNG_FREE (pData, pData->pGlobalProfile, pData->iGlobalProfilesize) + + pData->iGlobalProfilesize = 0; + + pData->iGlobalBKGDred = 0; /* reset global bKGD data */ + pData->iGlobalBKGDgreen = 0; + pData->iGlobalBKGDblue = 0; + /* reset delta-image */ + pData->pDeltaImage = MNG_NULL; + pData->iDeltaImagetype = 0; + pData->iDeltatype = 0; + pData->iDeltaBlockwidth = 0; + pData->iDeltaBlockheight = 0; + pData->iDeltaBlockx = 0; + pData->iDeltaBlocky = 0; + pData->bDeltaimmediate = MNG_FALSE; + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +void cleanup_errors (mng_datap pData) +{ + pData->iErrorcode = MNG_NOERROR; + pData->iSeverity = 0; + pData->iErrorx1 = 0; + pData->iErrorx2 = 0; + pData->zErrortext = MNG_NULL; + + return; +} + +/* ************************************************************************** */ +/* * * */ +/* * Versioning control * */ +/* * * */ +/* ************************************************************************** */ + +mng_pchar MNG_DECL mng_version_text (void) +{ + return MNG_VERSION_TEXT; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_version_so (void) +{ + return MNG_VERSION_SO; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_version_dll (void) +{ + return MNG_VERSION_DLL; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_version_major (void) +{ + return MNG_VERSION_MAJOR; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_version_minor (void) +{ + return MNG_VERSION_MINOR; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_version_release (void) +{ + return MNG_VERSION_RELEASE; +} + +/* ************************************************************************** */ +/* * * */ +/* * HLAPI routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_handle MNG_DECL mng_initialize (mng_ptr pUserdata, + mng_memalloc fMemalloc, + mng_memfree fMemfree, + mng_traceproc fTraceproc) +{ + mng_datap pData; +#ifdef MNG_SUPPORT_DISPLAY + mng_retcode iRetcode; + mng_imagep pImage; +#endif + +#ifdef MNG_INTERNAL_MEMMNGMT /* allocate the main datastruc */ + pData = (mng_datap)calloc (1, sizeof (mng_data)); +#else + pData = (mng_datap)fMemalloc (sizeof (mng_data)); +#endif + + if (!pData) + return MNG_NULL; /* error: out of memory?? */ + /* validate the structure */ + pData->iMagic = MNG_MAGIC; + /* save userdata field */ + pData->pUserdata = pUserdata; + /* remember trace callback */ + pData->fTraceproc = fTraceproc; + +#ifdef MNG_SUPPORT_TRACE + if (mng_trace (pData, MNG_FN_INITIALIZE, MNG_LC_INITIALIZE)) + { + MNG_FREEX (pData, pData, sizeof (mng_data)) + return MNG_NULL; + } +#endif + /* default canvas styles are 8-bit RGB */ + pData->iCanvasstyle = MNG_CANVAS_RGB8; + pData->iBkgdstyle = MNG_CANVAS_RGB8; + + pData->iBGred = 0; /* black */ + pData->iBGgreen = 0; + pData->iBGblue = 0; + + pData->bUseBKGD = MNG_TRUE; + +#ifdef MNG_FULL_CMS + pData->bIssRGB = MNG_TRUE; + pData->hProf1 = 0; /* no profiles yet */ + pData->hProf2 = 0; + pData->hProf3 = 0; + pData->hTrans = 0; +#endif + + pData->dViewgamma = 1.0; + pData->dDisplaygamma = 2.2; + pData->dDfltimggamma = 0.45455; + /* initially remember chunks */ + pData->bStorechunks = MNG_TRUE; + /* no breaks at section-borders */ + pData->bSectionbreaks = MNG_FALSE; + /* initially cache playback info */ + pData->bCacheplayback = MNG_TRUE; + /* progressive refresh for large images */ + pData->bDoProgressive = MNG_TRUE; + /* normal animation-speed ! */ + pData->iSpeed = mng_st_normal; + /* initial image limits */ + pData->iMaxwidth = 10000; + pData->iMaxheight = 10000; + +#ifdef MNG_INTERNAL_MEMMNGMT /* internal management */ + pData->fMemalloc = MNG_NULL; + pData->fMemfree = MNG_NULL; +#else /* keep callbacks */ + pData->fMemalloc = fMemalloc; + pData->fMemfree = fMemfree; +#endif + /* no value (yet) */ + pData->fOpenstream = MNG_NULL; + pData->fClosestream = MNG_NULL; + pData->fReaddata = MNG_NULL; + pData->fWritedata = MNG_NULL; + pData->fErrorproc = MNG_NULL; + pData->fProcessheader = MNG_NULL; + pData->fProcesstext = MNG_NULL; + pData->fProcesssave = MNG_NULL; + pData->fProcessseek = MNG_NULL; + pData->fProcessneed = MNG_NULL; + pData->fProcessmend = MNG_NULL; + pData->fProcessunknown = MNG_NULL; + pData->fProcessterm = MNG_NULL; + pData->fGetcanvasline = MNG_NULL; + pData->fGetbkgdline = MNG_NULL; + pData->fGetalphaline = MNG_NULL; + pData->fRefresh = MNG_NULL; + pData->fGettickcount = MNG_NULL; + pData->fSettimer = MNG_NULL; + pData->fProcessgamma = MNG_NULL; + pData->fProcesschroma = MNG_NULL; + pData->fProcesssrgb = MNG_NULL; + pData->fProcessiccp = MNG_NULL; + pData->fProcessarow = MNG_NULL; + +#if defined(MNG_SUPPORT_DISPLAY) && (defined(MNG_GAMMA_ONLY) || defined(MNG_FULL_CMS)) + pData->dLastgamma = 0; /* lookup table needs first-time calc */ +#endif + +#ifdef MNG_SUPPORT_DISPLAY /* create object 0 */ + iRetcode = create_imageobject (pData, 0, MNG_TRUE, MNG_TRUE, MNG_TRUE, + 0, 0, 0, 0, 0, 0, 0, 0, 0, MNG_FALSE, + 0, 0, 0, 0, &pImage); + + if (iRetcode) /* on error drop out */ + { + MNG_FREEX (pData, pData, sizeof (mng_data)) + return MNG_NULL; + } + + pData->pObjzero = pImage; +#endif + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_INCLUDE_LCMS) + mnglcms_initlibrary (); /* init lcms particulairs */ +#endif + +#ifdef MNG_SUPPORT_READ + pData->bSuspensionmode = MNG_FALSE; + pData->iSuspendbufsize = 0; + pData->pSuspendbuf = MNG_NULL; + pData->pSuspendbufnext = MNG_NULL; + pData->iSuspendbufleft = 0; + pData->iChunklen = 0; + pData->pReadbufnext = MNG_NULL; +#endif + +#ifdef MNG_INCLUDE_ZLIB + mngzlib_initialize (pData); /* initialize zlib structures and such */ + /* default zlib compression parameters */ + pData->iZlevel = MNG_ZLIB_LEVEL; + pData->iZmethod = MNG_ZLIB_METHOD; + pData->iZwindowbits = MNG_ZLIB_WINDOWBITS; + pData->iZmemlevel = MNG_ZLIB_MEMLEVEL; + pData->iZstrategy = MNG_ZLIB_STRATEGY; + /* default maximum IDAT data size */ + pData->iMaxIDAT = MNG_MAX_IDAT_SIZE; +#endif + +#ifdef MNG_INCLUDE_JNG /* default IJG compression parameters */ + pData->eJPEGdctmethod = MNG_JPEG_DCT; + pData->iJPEGquality = MNG_JPEG_QUALITY; + pData->iJPEGsmoothing = MNG_JPEG_SMOOTHING; + pData->bJPEGcompressprogr = MNG_JPEG_PROGRESSIVE; + pData->bJPEGcompressopt = MNG_JPEG_OPTIMIZED; + /* default maximum JDAT data size */ + pData->iMaxJDAT = MNG_MAX_JDAT_SIZE; +#endif + + mng_reset ((mng_handle)pData); + +#ifdef MNG_SUPPORT_TRACE + if (mng_trace (pData, MNG_FN_INITIALIZE, MNG_LC_END)) + { + MNG_FREEX (pData, pData, sizeof (mng_data)) + return MNG_NULL; + } +#endif + + return (mng_handle)pData; /* if we get here, we're in business */ +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_reset (mng_handle hHandle) +{ + mng_datap pData; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_RESET, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)(hHandle)); /* address main structure */ + +#ifdef MNG_SUPPORT_DISPLAY + mng_drop_savedata (pData); /* cleanup saved-data from SAVE/SEEK */ +#endif + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_FULL_CMS) + mng_clear_cms (pData); /* cleanup left-over cms stuff if any */ +#endif + +#ifdef MNG_INCLUDE_JNG + mngjpeg_cleanup (pData); /* cleanup jpeg stuff */ +#endif + +#ifdef MNG_INCLUDE_ZLIB + if (pData->bInflating) /* if we've been inflating */ + { +#ifdef MNG_INCLUDE_DISPLAY_PROCS + cleanup_rowproc (pData); /* cleanup row-processing, */ +#endif + mngzlib_inflatefree (pData); /* cleanup inflate! */ + } +#endif /* MNG_INCLUDE_ZLIB */ + +#ifdef MNG_SUPPORT_READ + if ((pData->bReading) && (!pData->bEOF)) + process_eof (pData); /* cleanup app streaming */ + /* cleanup default read buffers */ + MNG_FREE (pData, pData->pReadbuf, pData->iReadbufsize) + MNG_FREE (pData, pData->pLargebuf, pData->iLargebufsize) + MNG_FREE (pData, pData->pSuspendbuf, pData->iSuspendbufsize) +#endif + +#ifdef MNG_SUPPORT_WRITE /* cleanup default write buffer */ + MNG_FREE (pData, pData->pWritebuf, pData->iWritebufsize) +#endif + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + mng_drop_chunks (pData); /* drop stored chunks (if any) */ +#endif + +#ifdef MNG_SUPPORT_DISPLAY + mng_drop_objects (pData, MNG_TRUE); /* drop stored objects (if any) */ + + if (pData->iGlobalProfilesize) /* drop global profile (if any) */ + MNG_FREEX (pData, pData->pGlobalProfile, pData->iGlobalProfilesize) +#endif + + pData->eSigtype = mng_it_unknown; + pData->eImagetype = mng_it_unknown; + pData->iWidth = 0; /* these are unknown yet */ + pData->iHeight = 0; + pData->iTicks = 0; + pData->iLayercount = 0; + pData->iFramecount = 0; + pData->iPlaytime = 0; + pData->iSimplicity = 0; + pData->iAlphadepth = 16; /* assume the worst! */ + + pData->iImagelevel = 0; /* no image encountered */ + + pData->iMagnify = 0; /* 1-to-1 display */ + pData->iOffsetx = 0; /* no offsets */ + pData->iOffsety = 0; + pData->iCanvaswidth = 0; /* let the app decide during processheader */ + pData->iCanvasheight = 0; + /* so far, so good */ + pData->iErrorcode = MNG_NOERROR; + pData->iSeverity = 0; + pData->iErrorx1 = 0; + pData->iErrorx2 = 0; + pData->zErrortext = MNG_NULL; + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + /* let's assume the best scenario */ + pData->bPreDraft48 = MNG_FALSE; + /* the unknown chunk */ + pData->iChunkname = MNG_UINT_HUH; + pData->iChunkseq = 0; + pData->pFirstchunk = MNG_NULL; + pData->pLastchunk = MNG_NULL; + /* nothing processed yet */ + pData->bHasheader = MNG_FALSE; + pData->bHasMHDR = MNG_FALSE; + pData->bHasIHDR = MNG_FALSE; + pData->bHasBASI = MNG_FALSE; + pData->bHasDHDR = MNG_FALSE; +#ifdef MNG_INCLUDE_JNG + pData->bHasJHDR = MNG_FALSE; + pData->bHasJSEP = MNG_FALSE; + pData->bHasJDAA = MNG_FALSE; + pData->bHasJDAT = MNG_FALSE; +#endif + pData->bHasPLTE = MNG_FALSE; + pData->bHasTRNS = MNG_FALSE; + pData->bHasGAMA = MNG_FALSE; + pData->bHasCHRM = MNG_FALSE; + pData->bHasSRGB = MNG_FALSE; + pData->bHasICCP = MNG_FALSE; + pData->bHasBKGD = MNG_FALSE; + pData->bHasIDAT = MNG_FALSE; + + pData->bHasSAVE = MNG_FALSE; + pData->bHasBACK = MNG_FALSE; + pData->bHasFRAM = MNG_FALSE; + pData->bHasTERM = MNG_FALSE; + pData->bHasLOOP = MNG_FALSE; + /* there's no global stuff yet either */ + pData->bHasglobalPLTE = MNG_FALSE; + pData->bHasglobalTRNS = MNG_FALSE; + pData->bHasglobalGAMA = MNG_FALSE; + pData->bHasglobalCHRM = MNG_FALSE; + pData->bHasglobalSRGB = MNG_FALSE; + pData->bHasglobalICCP = MNG_FALSE; + + pData->iDatawidth = 0; /* no IHDR/BASI/DHDR done yet */ + pData->iDataheight = 0; + pData->iBitdepth = 0; + pData->iColortype = 0; + pData->iCompression = 0; + pData->iFilter = 0; + pData->iInterlace = 0; + +#ifdef MNG_INCLUDE_JNG + pData->iJHDRcolortype = 0; /* no JHDR data */ + pData->iJHDRimgbitdepth = 0; + pData->iJHDRimgcompression = 0; + pData->iJHDRimginterlace = 0; + pData->iJHDRalphabitdepth = 0; + pData->iJHDRalphacompression = 0; + pData->iJHDRalphafilter = 0; + pData->iJHDRalphainterlace = 0; +#endif + +#endif /* MNG_SUPPORT_READ || MNG_SUPPORT_WRITE */ + +#ifdef MNG_SUPPORT_READ /* no reading done */ + pData->bReading = MNG_FALSE; + pData->bHavesig = MNG_FALSE; + pData->bEOF = MNG_FALSE; + pData->iReadbufsize = 0; + pData->pReadbuf = MNG_NULL; + + pData->iLargebufsize = 0; + pData->pLargebuf = MNG_NULL; + + pData->iSuspendtime = 0; + pData->bSuspended = MNG_FALSE; + pData->iSuspendpoint = 0; + + pData->pSuspendbufnext = pData->pSuspendbuf; + pData->iSuspendbufleft = 0; +#endif /* MNG_SUPPORT_READ */ + +#ifdef MNG_SUPPORT_WRITE /* no creating/writing done */ + pData->bCreating = MNG_FALSE; + pData->bWriting = MNG_FALSE; + pData->iFirstchunkadded = 0; + pData->iWritebufsize = 0; + pData->pWritebuf = MNG_NULL; +#endif /* MNG_SUPPORT_WRITE */ + +#ifdef MNG_SUPPORT_DISPLAY /* done nuttin' yet */ + pData->bDisplaying = MNG_FALSE; + pData->iFrameseq = 0; + pData->iLayerseq = 0; + pData->iFrametime = 0; + + pData->iRequestframe = 0; + pData->iRequestlayer = 0; + pData->iRequesttime = 0; + pData->bSearching = MNG_FALSE; + + pData->bRestorebkgd = MNG_FALSE; + + pData->iRuntime = 0; + pData->iSynctime = 0; + pData->iStarttime = 0; + pData->iEndtime = 0; + pData->bRunning = MNG_FALSE; + pData->bTimerset = MNG_FALSE; + pData->iBreakpoint = 0; + pData->bSectionwait = MNG_FALSE; + pData->bFreezing = MNG_FALSE; + pData->bResetting = MNG_FALSE; + pData->bNeedrefresh = MNG_FALSE; + /* these don't exist yet */ + pData->pCurrentobj = MNG_NULL; + pData->pCurraniobj = MNG_NULL; + pData->pTermaniobj = MNG_NULL; + pData->pLastclone = MNG_NULL; + pData->pStoreobj = MNG_NULL; + pData->pStorebuf = MNG_NULL; + pData->pRetrieveobj = MNG_NULL; + /* no saved data ! */ + pData->pSavedata = MNG_NULL; + /* TODO: remove in 1.0.0 !!! */ + pData->bEMNGMAhack = MNG_FALSE; + + pData->iUpdateleft = 0; /* no region updated yet */ + pData->iUpdateright = 0; + pData->iUpdatetop = 0; + pData->iUpdatebottom = 0; + + pData->iPass = -1; /* interlacing stuff and temp buffers */ + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = 0; + pData->iSamplemul = 0; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = 0; + pData->iRowmax = 0; + pData->iFilterofs = 0; + pData->iPixelofs = 1; + pData->iLevel0 = 0; + pData->iLevel1 = 0; + pData->iLevel2 = 0; + pData->iLevel3 = 0; + pData->pWorkrow = MNG_NULL; + pData->pPrevrow = MNG_NULL; + pData->pRGBArow = 0; + pData->bIsRGBA16 = MNG_TRUE; + pData->bIsOpaque = MNG_TRUE; + pData->iFilterbpp = 1; + + pData->iSourcel = 0; /* always initialized just before */ + pData->iSourcer = 0; /* compositing the next layer */ + pData->iSourcet = 0; + pData->iSourceb = 0; + pData->iDestl = 0; + pData->iDestr = 0; + pData->iDestt = 0; + pData->iDestb = 0; + /* lists are empty */ + pData->pFirstimgobj = MNG_NULL; + pData->pLastimgobj = MNG_NULL; + pData->pFirstaniobj = MNG_NULL; + pData->pLastaniobj = MNG_NULL; + /* no processing callbacks */ + pData->fDisplayrow = MNG_NULL; + pData->fRestbkgdrow = MNG_NULL; + pData->fCorrectrow = MNG_NULL; + pData->fRetrieverow = MNG_NULL; + pData->fStorerow = MNG_NULL; + pData->fProcessrow = MNG_NULL; + pData->fDifferrow = MNG_NULL; + pData->fInitrowproc = MNG_NULL; + + pData->iPLTEcount = 0; /* no PLTE data */ + + pData->iDEFIobjectid = 0; /* no DEFI data */ + pData->bDEFIhasdonotshow = MNG_FALSE; + pData->iDEFIdonotshow = 0; + pData->bDEFIhasconcrete = MNG_FALSE; + pData->iDEFIconcrete = 0; + pData->bDEFIhasloca = MNG_FALSE; + pData->iDEFIlocax = 0; + pData->iDEFIlocay = 0; + pData->bDEFIhasclip = MNG_FALSE; + pData->iDEFIclipl = 0; + pData->iDEFIclipr = 0; + pData->iDEFIclipt = 0; + pData->iDEFIclipb = 0; + + pData->iBACKred = 0; /* no BACK data */ + pData->iBACKgreen = 0; + pData->iBACKblue = 0; + pData->iBACKmandatory = 0; + pData->iBACKimageid = 0; + pData->iBACKtile = 0; + + pData->iFRAMmode = 1; /* default global FRAM variables */ + pData->iFRAMdelay = 1; + pData->iFRAMtimeout = 0x7fffffffl; + pData->bFRAMclipping = MNG_FALSE; + pData->iFRAMclipl = 0; + pData->iFRAMclipr = 0; + pData->iFRAMclipt = 0; + pData->iFRAMclipb = 0; + + pData->iFramemode = 1; /* again for the current frame */ + pData->iFramedelay = 1; + pData->iFrametimeout = 0x7fffffffl; + pData->bFrameclipping = MNG_FALSE; + pData->iFrameclipl = 0; + pData->iFrameclipr = 0; + pData->iFrameclipt = 0; + pData->iFrameclipb = 0; + + pData->iNextdelay = 1; + + pData->iSHOWmode = 0; /* no SHOW data */ + pData->iSHOWfromid = 0; + pData->iSHOWtoid = 0; + pData->iSHOWnextid = 0; + pData->iSHOWskip = 0; + + pData->iGlobalPLTEcount = 0; /* no global PLTE data */ + + pData->iGlobalTRNSrawlen = 0; /* no global tRNS data */ + + pData->iGlobalGamma = 0; /* no global gAMA data */ + + pData->iGlobalWhitepointx = 0; /* no global cHRM data */ + pData->iGlobalWhitepointy = 0; + pData->iGlobalPrimaryredx = 0; + pData->iGlobalPrimaryredy = 0; + pData->iGlobalPrimarygreenx = 0; + pData->iGlobalPrimarygreeny = 0; + pData->iGlobalPrimarybluex = 0; + pData->iGlobalPrimarybluey = 0; + + pData->iGlobalRendintent = 0; /* no global sRGB data */ + + pData->iGlobalProfilesize = 0; /* no global iCCP data */ + pData->pGlobalProfile = MNG_NULL; + + pData->iGlobalBKGDred = 0; /* no global bKGD data */ + pData->iGlobalBKGDgreen = 0; + pData->iGlobalBKGDblue = 0; + /* no delta-image */ + pData->pDeltaImage = MNG_NULL; + pData->iDeltaImagetype = 0; + pData->iDeltatype = 0; + pData->iDeltaBlockwidth = 0; + pData->iDeltaBlockheight = 0; + pData->iDeltaBlockx = 0; + pData->iDeltaBlocky = 0; + pData->bDeltaimmediate = MNG_FALSE; +#endif + +#ifdef MNG_INCLUDE_ZLIB + pData->bInflating = 0; /* no inflating or deflating */ + pData->bDeflating = 0; /* going on at the moment */ +#endif + +#ifdef MNG_SUPPORT_DISPLAY /* reset object 0 */ + mng_reset_objzero (pData); +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_RESET, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_cleanup (mng_handle* hHandle) +{ + mng_datap pData; /* local vars */ +#ifndef MNG_INTERNAL_MEMMNGMT + mng_memfree fFree; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)*hHandle), MNG_FN_CLEANUP, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (*hHandle) /* check validity handle */ + pData = ((mng_datap)(*hHandle)); /* and address main structure */ + + mng_reset (*hHandle); /* do an implicit reset to cleanup most stuff */ + +#ifdef MNG_SUPPORT_DISPLAY /* drop object 0 */ + free_imageobject (pData, (mng_imagep)pData->pObjzero); +#endif + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_INCLUDE_LCMS) + if (pData->hProf2) /* output profile defined ? */ + mnglcms_freeprofile (pData->hProf2); + + if (pData->hProf3) /* sRGB profile defined ? */ + mnglcms_freeprofile (pData->hProf3); +#endif /* MNG_SUPPORT_DISPLAY && MNG_INCLUDE_LCMS */ + +#ifdef MNG_INCLUDE_ZLIB + mngzlib_cleanup (pData); /* cleanup zlib stuff */ +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)*hHandle), MNG_FN_CLEANUP, MNG_LC_CLEANUP) +#endif + + pData->iMagic = 0; /* invalidate the actual memory */ + +#ifdef MNG_INTERNAL_MEMMNGMT + free ((void *)*hHandle); /* cleanup the data-structure */ +#else + fFree = ((mng_datap)*hHandle)->fMemfree; + fFree ((mng_ptr)*hHandle, sizeof (mng_data)); +#endif + + *hHandle = 0; /* wipe pointer to inhibit future use */ + + return MNG_NOERROR; /* and we're done */ +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_read (mng_handle hHandle) +{ + mng_datap pData; /* local vars */ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_READ, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle and callbacks */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + +#ifndef MNG_INTERNAL_MEMMNGMT + MNG_VALIDCB (hHandle, fMemalloc) + MNG_VALIDCB (hHandle, fMemfree) +#endif + + MNG_VALIDCB (hHandle, fOpenstream) + MNG_VALIDCB (hHandle, fClosestream) + MNG_VALIDCB (hHandle, fReaddata) + +#ifdef MNG_SUPPORT_DISPLAY /* valid at this point ? */ + if ((pData->bReading) || (pData->bDisplaying)) +#else + if (pData->bReading) +#endif + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + +#ifdef MNG_SUPPORT_WRITE + if ((pData->bWriting) || (pData->bCreating)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) +#endif + + if (!pData->bCacheplayback) /* must store playback info to work!! */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + cleanup_errors (pData); /* cleanup previous errors */ + + pData->bReading = MNG_TRUE; /* read only! */ + + if (!pData->fOpenstream (hHandle)) /* open it and start reading */ + iRetcode = MNG_APPIOERROR; + else + iRetcode = read_graphic (pData); + + if (pData->bEOF) /* already at EOF ? */ + { + pData->bReading = MNG_FALSE; /* then we're no longer reading */ + +#ifdef MNG_SUPPORT_DISPLAY + mng_reset_rundata (pData); /* reset rundata */ +#endif + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bSuspended) /* read suspension ? */ + { + iRetcode = MNG_NEEDMOREDATA; + pData->iSuspendtime = pData->fGettickcount ((mng_handle)pData); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_READ, MNG_LC_END) +#endif + + return iRetcode; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_read_resume (mng_handle hHandle) +{ + mng_datap pData; /* local vars */ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_READ_RESUME, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + /* can we expect this call ? */ + if ((!pData->bReading) || (!pData->bSuspended)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + cleanup_errors (pData); /* cleanup previous errors */ + + pData->bSuspended = MNG_FALSE; /* reset the flag */ + +#ifdef MNG_SUPPORT_DISPLAY /* re-synchronize ? */ + if ((pData->bDisplaying) && (pData->bRunning)) + pData->iSynctime = pData->iSynctime - pData->iSuspendtime + + pData->fGettickcount (hHandle); +#endif + + iRetcode = read_graphic (pData); /* continue reading now */ + + if (pData->bEOF) /* at EOF ? */ + { + pData->bReading = MNG_FALSE; /* then we're no longer reading */ + +#ifdef MNG_SUPPORT_DISPLAY + mng_reset_rundata (pData); /* reset rundata */ +#endif + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bSuspended) /* read suspension ? */ + { + iRetcode = MNG_NEEDMOREDATA; + pData->iSuspendtime = pData->fGettickcount ((mng_handle)pData); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_READ_RESUME, MNG_LC_END) +#endif + + return iRetcode; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_WRITE +mng_retcode MNG_DECL mng_write (mng_handle hHandle) +{ + mng_datap pData; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_WRITE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle and callbacks */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + +#ifndef MNG_INTERNAL_MEMMNGMT + MNG_VALIDCB (hHandle, fMemalloc) + MNG_VALIDCB (hHandle, fMemfree) +#endif + + MNG_VALIDCB (hHandle, fOpenstream) + MNG_VALIDCB (hHandle, fClosestream) + MNG_VALIDCB (hHandle, fWritedata) + +#ifdef MNG_SUPPORT_READ + if (pData->bReading) /* valid at this point ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) +#endif + + if (pData->bCreating) /* can't write while it's still being made! */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + cleanup_errors (pData); /* cleanup previous errors */ + + iRetcode = write_graphic (pData); /* do the write */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_WRITE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_WRITE +mng_retcode MNG_DECL mng_create (mng_handle hHandle) +{ + mng_datap pData; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_CREATE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle and callbacks */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + +#ifndef MNG_INTERNAL_MEMMNGMT + MNG_VALIDCB (hHandle, fMemalloc) + MNG_VALIDCB (hHandle, fMemfree) +#endif + +#ifdef MNG_SUPPORT_READ + if (pData->bReading) /* valid at this point ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) +#endif + + if ((pData->bWriting) || (pData->bCreating)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + cleanup_errors (pData); /* cleanup previous errors */ + + iRetcode = mng_reset (hHandle); /* clear any previous stuff */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + + pData->bCreating = MNG_TRUE; /* indicate we're creating a new file */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_CREATE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_WRITE */ + +/* ************************************************************************** */ + +#if defined(MNG_SUPPORT_DISPLAY) && defined(MNG_SUPPORT_READ) +mng_retcode MNG_DECL mng_readdisplay (mng_handle hHandle) +{ + mng_datap pData; /* local vars */ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_READDISPLAY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle and callbacks */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + +#ifndef MNG_INTERNAL_MEMMNGMT + MNG_VALIDCB (hHandle, fMemalloc) + MNG_VALIDCB (hHandle, fMemfree) +#endif + + MNG_VALIDCB (hHandle, fReaddata) + MNG_VALIDCB (hHandle, fGetcanvasline) + MNG_VALIDCB (hHandle, fRefresh) + MNG_VALIDCB (hHandle, fGettickcount) + MNG_VALIDCB (hHandle, fSettimer) + /* valid at this point ? */ + if ((pData->bReading) || (pData->bDisplaying)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + +#ifdef MNG_SUPPORT_WRITE + if ((pData->bWriting) || (pData->bCreating)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) +#endif + + cleanup_errors (pData); /* cleanup previous errors */ + + pData->bReading = MNG_TRUE; /* read & display! */ + pData->bDisplaying = MNG_TRUE; + pData->bRunning = MNG_TRUE; + pData->iFrameseq = 0; + pData->iLayerseq = 0; + pData->iFrametime = 0; + pData->iRequestframe = 0; + pData->iRequestlayer = 0; + pData->iRequesttime = 0; + pData->bSearching = MNG_FALSE; + pData->iRuntime = 0; + pData->iSynctime = pData->fGettickcount (hHandle); + pData->iSuspendtime = 0; + pData->iStarttime = pData->iSynctime; + pData->iEndtime = 0; + + if (!pData->fOpenstream (hHandle)) /* open it and start reading */ + iRetcode = MNG_APPIOERROR; + else + iRetcode = read_graphic (pData); + + if (pData->bEOF) /* already at EOF ? */ + { + pData->bReading = MNG_FALSE; /* then we're no longer reading */ + drop_invalid_objects (pData); /* drop invalidly stored objects */ + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bSuspended) /* read suspension ? */ + { + iRetcode = MNG_NEEDMOREDATA; + pData->iSuspendtime = pData->fGettickcount ((mng_handle)pData); + } + else + if (pData->bTimerset) /* indicate timer break ? */ + iRetcode = MNG_NEEDTIMERWAIT; + else + if (pData->bSectionwait) /* indicate section break ? */ + iRetcode = MNG_NEEDSECTIONWAIT; + else + pData->bRunning = MNG_FALSE; /* no breaks = end of run */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_READDISPLAY, MNG_LC_END) +#endif + + return iRetcode; +} +#endif /* MNG_SUPPORT_DISPLAY && MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_display (mng_handle hHandle) +{ + mng_datap pData; /* local vars */ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle and callbacks */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + +#ifndef MNG_INTERNAL_MEMMNGMT + MNG_VALIDCB (hHandle, fMemalloc) + MNG_VALIDCB (hHandle, fMemfree) +#endif + + MNG_VALIDCB (hHandle, fGetcanvasline) + MNG_VALIDCB (hHandle, fRefresh) + MNG_VALIDCB (hHandle, fGettickcount) + MNG_VALIDCB (hHandle, fSettimer) + + if (pData->bDisplaying) /* valid at this point ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + +#ifdef MNG_SUPPORT_READ + if (pData->bReading) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) +#endif + +#ifdef MNG_SUPPORT_WRITE + if ((pData->bWriting) || (pData->bCreating)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) +#endif + + cleanup_errors (pData); /* cleanup previous errors */ + + pData->bDisplaying = MNG_TRUE; /* display! */ + pData->bRunning = MNG_TRUE; + pData->iFrameseq = 0; + pData->iLayerseq = 0; + pData->iFrametime = 0; + pData->iRequestframe = 0; + pData->iRequestlayer = 0; + pData->iRequesttime = 0; + pData->bSearching = MNG_FALSE; + pData->iRuntime = 0; + pData->iSynctime = pData->fGettickcount (hHandle); +#ifdef MNG_SUPPORT_READ + pData->iSuspendtime = 0; +#endif + pData->iStarttime = pData->iSynctime; + pData->iEndtime = 0; + pData->pCurraniobj = pData->pFirstaniobj; + + iRetcode = process_display (pData); /* go do it */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bTimerset) /* indicate timer break ? */ + iRetcode = MNG_NEEDTIMERWAIT; + else + pData->bRunning = MNG_FALSE; /* no breaks = end of run */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY, MNG_LC_END) +#endif + + return iRetcode; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_display_resume (mng_handle hHandle) +{ + mng_datap pData; /* local vars */ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_RESUME, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + + if (!pData->bDisplaying) /* can we expect this call ? */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + cleanup_errors (pData); /* cleanup previous errors */ + + if (pData->bRunning) /* was it running ? */ + { /* are we expecting this call ? */ + if ((pData->bTimerset) || (pData->bSuspended) || (pData->bSectionwait)) + { + pData->bTimerset = MNG_FALSE; /* reset the flags */ + pData->bSectionwait = MNG_FALSE; + +#ifdef MNG_SUPPORT_READ + if (pData->bReading) /* set during read&display ? */ + { + if (pData->bSuspended) /* calculate proper synchronization */ + pData->iSynctime = pData->iSynctime - pData->iSuspendtime + + pData->fGettickcount (hHandle); + else + pData->iSynctime = pData->fGettickcount (hHandle); + + pData->bSuspended = MNG_FALSE; /* now reset this flag */ + /* and continue reading */ + iRetcode = read_graphic (pData); + + if (pData->bEOF) /* already at EOF ? */ + { + pData->bReading = MNG_FALSE; /* then we're no longer reading */ + /* drop invalidly stored objects */ + drop_invalid_objects (pData); + } + } + else +#endif /* MNG_SUPPORT_READ */ + { /* synchronize timing */ + pData->iSynctime = pData->fGettickcount (hHandle); + /* resume display processing */ + iRetcode = process_display (pData); + } + } + else + { + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + } + } + else + { /* synchronize timing */ + pData->iSynctime = pData->fGettickcount (hHandle); + pData->bRunning = MNG_TRUE; /* it's restarted again ! */ + /* resume display processing */ + iRetcode = process_display (pData); + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->bSuspended) /* read suspension ? */ + { + iRetcode = MNG_NEEDMOREDATA; + pData->iSuspendtime = pData->fGettickcount ((mng_handle)pData); + } + else + if (pData->bTimerset) /* indicate timer break ? */ + iRetcode = MNG_NEEDTIMERWAIT; + else + if (pData->bSectionwait) /* indicate section break ? */ + iRetcode = MNG_NEEDSECTIONWAIT; + else + { /* no breaks = end of run */ + pData->bRunning = MNG_FALSE; + + if (pData->bFreezing) /* trying to freeze ? */ + { /* then we're there ! */ + pData->bFreezing = MNG_FALSE; + } + + if (pData->bResetting) /* trying to reset as well ? */ + { /* full stop!!! */ + pData->bDisplaying = MNG_FALSE; + + iRetcode = mng_reset_rundata (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_RESUME, MNG_LC_END) +#endif + + return iRetcode; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_display_freeze (mng_handle hHandle) +{ + mng_datap pData; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_FREEZE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + /* can we expect this call ? */ + if ((!pData->bDisplaying) || (pData->bReading)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + cleanup_errors (pData); /* cleanup previous errors */ + + if (pData->bRunning) /* is it running ? */ + { + mng_retcode iRetcode; + + pData->bFreezing = MNG_TRUE; /* indicate we need to freeze */ + /* continue "normal" processing */ + iRetcode = mng_display_resume (hHandle); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_FREEZE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_display_reset (mng_handle hHandle) +{ + mng_datap pData; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_RESET, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + /* can we expect this call ? */ + if ((!pData->bDisplaying) || (pData->bReading)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + if (!pData->bCacheplayback) /* must store playback info to work!! */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + cleanup_errors (pData); /* cleanup previous errors */ + + if (pData->bRunning) /* is it running ? */ + { + pData->bFreezing = MNG_TRUE; /* indicate we need to freeze */ + pData->bResetting = MNG_TRUE; /* indicate we're about to reset too */ + /* continue normal processing ? */ + iRetcode = mng_display_resume (hHandle); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + else + { /* full stop!!! */ + pData->bDisplaying = MNG_FALSE; + + iRetcode = mng_reset_rundata (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_RESET, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_display_goframe (mng_handle hHandle, + mng_uint32 iFramenr) +{ + mng_datap pData; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_GOFRAME, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + + if (pData->eImagetype != mng_it_mng) /* is it an animation ? */ + MNG_ERROR (pData, MNG_NOTANANIMATION); + /* can we expect this call ? */ + if ((!pData->bDisplaying) || (pData->bRunning)) + MNG_ERROR ((mng_datap)hHandle, MNG_FUNCTIONINVALID) + + if (!pData->bCacheplayback) /* must store playback info to work!! */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + if (iFramenr > pData->iFramecount) /* is the parameter within bounds ? */ + MNG_ERROR (pData, MNG_FRAMENRTOOHIGH); + + cleanup_errors (pData); /* cleanup previous errors */ + + pData->iRequestframe = iFramenr; /* go find the requested frame then */ + iRetcode = process_display (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_GOFRAME, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_display_golayer (mng_handle hHandle, + mng_uint32 iLayernr) +{ + mng_datap pData; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_GOLAYER, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + + if (pData->eImagetype != mng_it_mng) /* is it an animation ? */ + MNG_ERROR (pData, MNG_NOTANANIMATION) + /* can we expect this call ? */ + if ((!pData->bDisplaying) || (pData->bRunning)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + if (!pData->bCacheplayback) /* must store playback info to work!! */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + if (iLayernr > pData->iLayercount) /* is the parameter within bounds ? */ + MNG_ERROR (pData, MNG_LAYERNRTOOHIGH) + + cleanup_errors (pData); /* cleanup previous errors */ + + pData->iRequestlayer = iLayernr; /* go find the requested layer then */ + iRetcode = process_display (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_GOLAYER, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_display_gotime (mng_handle hHandle, + mng_uint32 iPlaytime) +{ + mng_datap pData; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_GOTIME, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + + if (pData->eImagetype != mng_it_mng) /* is it an animation ? */ + MNG_ERROR (pData, MNG_NOTANANIMATION) + /* can we expect this call ? */ + if ((!pData->bDisplaying) || (pData->bRunning)) + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + if (!pData->bCacheplayback) /* must store playback info to work!! */ + MNG_ERROR (pData, MNG_FUNCTIONINVALID) + + if (iPlaytime > pData->iPlaytime) /* is the parameter within bounds ? */ + MNG_ERROR (pData, MNG_PLAYTIMETOOHIGH) + + cleanup_errors (pData); /* cleanup previous errors */ + + pData->iRequesttime = iPlaytime; /* go find the requested playtime then */ + iRetcode = process_display (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_DISPLAY_GOTIME, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_getlasterror (mng_handle hHandle, + mng_int8* iSeverity, + mng_chunkid* iChunkname, + mng_uint32* iChunkseq, + mng_int32* iExtra1, + mng_int32* iExtra2, + mng_pchar* zErrortext) +{ + mng_datap pData; /* local vars */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETLASTERROR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) /* check validity handle */ + pData = ((mng_datap)hHandle); /* and make it addressable */ + + *iSeverity = pData->iSeverity; /* return the appropriate fields */ + +#if defined(MNG_SUPPORT_READ) || defined(MNG_SUPPORT_WRITE) + *iChunkname = pData->iChunkname; + *iChunkseq = pData->iChunkseq; +#else + *iChunkname = MNG_UINT_HUH; + *iChunkseq = 0; +#endif + + *iExtra1 = pData->iErrorx1; + *iExtra2 = pData->iErrorx2; + *zErrortext = pData->zErrortext; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GETLASTERROR, MNG_LC_END) +#endif + + return pData->iErrorcode; /* and the errorcode */ +} + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_jpeg.c b/freeimage241/Source/LibMNG/libmng_jpeg.c new file mode 100644 index 0000000..d128adc --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_jpeg.c @@ -0,0 +1,1034 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_jpeg.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : JPEG library interface (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the JPEG library interface * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.5.2 - 05/22/2000 - G.Juyn * */ +/* * - implemented all the JNG routines * */ +/* * * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - added tracing of JPEG calls * */ +/* * 0.5.3 - 06/24/2000 - G.Juyn * */ +/* * - fixed inclusion of IJG read/write code * */ +/* * 0.5.3 - 06/29/2000 - G.Juyn * */ +/* * - fixed some 64-bit warnings * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for JDAA * */ +/* * * */ +/* * 1.0.1 - 04/19/2001 - G.Juyn * */ +/* * - added export of JPEG functions for DLL * */ +/* * 1.0.1 - 04/22/2001 - G.Juyn * */ +/* * - fixed memory-leaks (Thanks Gregg!) * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_memory.h" +#include "libmng_pixels.h" +#include "libmng_jpeg.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG + +/* ************************************************************************** */ +/* * * */ +/* * Local IJG callback routines (source-manager, error-manager and such) * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_IJG6B + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +void MNG_DECL mng_init_source (j_decompress_ptr cinfo) +{ + return; /* nothing needed */ +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +boolean MNG_DECL mng_fill_input_buffer (j_decompress_ptr cinfo) +{ + return FALSE; /* force IJG routine to return to caller */ +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +void MNG_DECL mng_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + if (num_bytes > 0) /* ignore fony calls */ + { /* address my generic structure */ + mng_datap pData = (mng_datap)cinfo->client_data; + /* address source manager */ + mngjpeg_sourcep pSrc = pData->pJPEGdinfo->src; + /* problem scenario ? */ + if (pSrc->bytes_in_buffer < (size_t)num_bytes) + { /* tell the boss we need to skip some data! */ + pData->iJPEGtoskip = (mng_uint32)((size_t)num_bytes - pSrc->bytes_in_buffer); + + pSrc->bytes_in_buffer = 0; /* let the JPEG lib suspend */ + pSrc->next_input_byte = MNG_NULL; + } + else + { /* simply advance in the buffer */ + pSrc->bytes_in_buffer -= num_bytes; + pSrc->next_input_byte += num_bytes; + } + } + + return; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +void MNG_DECL mng_skip_input_data2 (j_decompress_ptr cinfo, long num_bytes) +{ + if (num_bytes > 0) /* ignore fony calls */ + { /* address my generic structure */ + mng_datap pData = (mng_datap)cinfo->client_data; + /* address source manager */ + mngjpeg_sourcep pSrc = pData->pJPEGdinfo2->src; + /* problem scenario ? */ + if (pSrc->bytes_in_buffer < (size_t)num_bytes) + { /* tell the boss we need to skip some data! */ + pData->iJPEGtoskip2 = (mng_uint32)((size_t)num_bytes - pSrc->bytes_in_buffer); + + pSrc->bytes_in_buffer = 0; /* let the JPEG lib suspend */ + pSrc->next_input_byte = MNG_NULL; + } + else + { /* simply advance in the buffer */ + pSrc->bytes_in_buffer -= num_bytes; + pSrc->next_input_byte += num_bytes; + } + } + + return; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +void MNG_DECL mng_term_source (j_decompress_ptr cinfo) +{ + return; /* nothing needed */ +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_USE_SETJMP +void MNG_DECL mng_error_exit (j_common_ptr cinfo) +{ /* address my generic structure */ + mng_datap pData = (mng_datap)cinfo->client_data; + +#ifdef MNG_ERROR_TELLTALE /* fill the message text ??? */ + (*cinfo->err->output_message) (cinfo); +#endif + /* return to the point of no return... */ + longjmp (pData->sErrorbuf, cinfo->err->msg_code); +} +#endif /* MNG_USE_SETJMP */ + +/* ************************************************************************** */ + +#ifdef MNG_USE_SETJMP +void MNG_DECL mng_output_message (j_common_ptr cinfo) +{ + return; /* just do nothing ! */ +} +#endif /* MNG_USE_SETJMP */ + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_IJG6B */ + +/* ************************************************************************** */ +/* * * */ +/* * Global JPEG routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode mngjpeg_initialize (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_INITIALIZE, MNG_LC_START) +#endif + /* allocate space for JPEG structures if necessary */ +#ifdef MNG_INCLUDE_JNG_READ + if (pData->pJPEGderr == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGderr, sizeof (mngjpeg_error )) + if (pData->pJPEGdsrc == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGdsrc, sizeof (mngjpeg_source)) + if (pData->pJPEGdinfo == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGdinfo, sizeof (mngjpeg_decomp)) + /* enable reverse addressing */ + pData->pJPEGdinfo->client_data = pData; + + if (pData->pJPEGderr2 == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGderr2, sizeof (mngjpeg_error )) + if (pData->pJPEGdsrc2 == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGdsrc2, sizeof (mngjpeg_source)) + if (pData->pJPEGdinfo2 == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGdinfo2, sizeof (mngjpeg_decomp)) + /* enable reverse addressing */ + pData->pJPEGdinfo2->client_data = pData; +#endif + +#ifdef MNG_INCLUDE_JNG_WRITE + if (pData->pJPEGcerr == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGcerr, sizeof (mngjpeg_error )) + if (pData->pJPEGcinfo == MNG_NULL) + MNG_ALLOC (pData, pData->pJPEGcinfo, sizeof (mngjpeg_comp )) + /* enable reverse addressing */ + pData->pJPEGcinfo->client_data = pData; +#endif + + if (pData->pJPEGbuf == MNG_NULL) /* initialize temporary buffers */ + { + pData->iJPEGbufmax = MNG_JPEG_MAXBUF; + MNG_ALLOC (pData, pData->pJPEGbuf, pData->iJPEGbufmax) + } + + if (pData->pJPEGbuf2 == MNG_NULL) + { + pData->iJPEGbufmax2 = MNG_JPEG_MAXBUF; + MNG_ALLOC (pData, pData->pJPEGbuf2, pData->iJPEGbufmax2) + } + + pData->pJPEGcurrent = pData->pJPEGbuf; + pData->iJPEGbufremain = 0; + pData->pJPEGrow = MNG_NULL; + pData->iJPEGrowlen = 0; + pData->iJPEGtoskip = 0; + + pData->pJPEGcurrent2 = pData->pJPEGbuf2; + pData->iJPEGbufremain2 = 0; + pData->pJPEGrow2 = MNG_NULL; + pData->iJPEGrowlen2 = 0; + pData->iJPEGtoskip2 = 0; + /* not doing anything yet ! */ + pData->bJPEGcompress = MNG_FALSE; + + pData->bJPEGdecompress = MNG_FALSE; + pData->bJPEGhasheader = MNG_FALSE; + pData->bJPEGdecostarted = MNG_FALSE; + pData->bJPEGscanstarted = MNG_FALSE; + + pData->bJPEGdecompress2 = MNG_FALSE; + pData->bJPEGhasheader2 = MNG_FALSE; + pData->bJPEGdecostarted2 = MNG_FALSE; + pData->bJPEGscanstarted2 = MNG_FALSE; + + pData->iJPEGrow = 0; /* zero input/output lines */ + pData->iJPEGalpharow = 0; + pData->iJPEGrgbrow = 0; + pData->iJPEGdisprow = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_INITIALIZE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode mngjpeg_cleanup (mng_datap pData) +{ +#if defined(MNG_INCLUDE_IJG6B) && defined(MNG_USE_SETJMP) + mng_retcode iRetcode; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_CLEANUP, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_IJG6B +#ifdef MNG_USE_SETJMP + iRetcode = setjmp (pData->sErrorbuf);/* setup local JPEG error-recovery */ + if (iRetcode != 0) /* got here from longjmp ? */ + MNG_ERRORJ (pData, iRetcode) /* then IJG-lib issued an error */ +#endif + +#ifdef MNG_INCLUDE_JNG_READ /* still decompressing something ? */ + if (pData->bJPEGdecompress) + jpeg_destroy_decompress (pData->pJPEGdinfo); + if (pData->bJPEGdecompress2) + jpeg_destroy_decompress (pData->pJPEGdinfo2); +#endif + +#ifdef MNG_INCLUDE_JNG_WRITE + if (pData->bJPEGcompress) /* still compressing something ? */ + jpeg_destroy_compress (pData->pJPEGcinfo); +#endif + +#endif /* MNG_INCLUDE_IJG6B */ + /* cleanup temporary buffers */ + MNG_FREE (pData, pData->pJPEGbuf2, pData->iJPEGbufmax2) + MNG_FREE (pData, pData->pJPEGbuf, pData->iJPEGbufmax) + /* cleanup space for JPEG structures */ +#ifdef MNG_INCLUDE_JNG_WRITE + MNG_FREE (pData, pData->pJPEGcinfo, sizeof (mngjpeg_comp )) + MNG_FREE (pData, pData->pJPEGcerr, sizeof (mngjpeg_error )) +#endif + +#ifdef MNG_INCLUDE_JNG_READ + MNG_FREE (pData, pData->pJPEGdinfo, sizeof (mngjpeg_decomp)) + MNG_FREE (pData, pData->pJPEGdsrc, sizeof (mngjpeg_source)) + MNG_FREE (pData, pData->pJPEGderr, sizeof (mngjpeg_error )) + MNG_FREE (pData, pData->pJPEGdinfo2, sizeof (mngjpeg_decomp)) + MNG_FREE (pData, pData->pJPEGdsrc2, sizeof (mngjpeg_source)) + MNG_FREE (pData, pData->pJPEGderr2, sizeof (mngjpeg_error )) +#endif + + MNG_FREE (pData, pData->pJPEGrow2, pData->iJPEGrowlen2) + MNG_FREE (pData, pData->pJPEGrow, pData->iJPEGrowlen) + /* whatever we were doing ... */ + /* we don't anymore ... */ + pData->bJPEGcompress = MNG_FALSE; + + pData->bJPEGdecompress = MNG_FALSE; + pData->bJPEGhasheader = MNG_FALSE; + pData->bJPEGdecostarted = MNG_FALSE; + pData->bJPEGscanstarted = MNG_FALSE; + + pData->bJPEGdecompress2 = MNG_FALSE; + pData->bJPEGhasheader2 = MNG_FALSE; + pData->bJPEGdecostarted2 = MNG_FALSE; + pData->bJPEGscanstarted2 = MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_CLEANUP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * JPEG decompression routines (JDAT) * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +mng_retcode mngjpeg_decompressinit (mng_datap pData) +{ +#if defined(MNG_INCLUDE_IJG6B) && defined(MNG_USE_SETJMP) + mng_retcode iRetcode; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSINIT, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_IJG6B + /* allocate and initialize a JPEG decompression object */ + pData->pJPEGdinfo->err = jpeg_std_error (pData->pJPEGderr); + +#ifdef MNG_USE_SETJMP /* setup local JPEG error-routines */ + pData->pJPEGderr->error_exit = mng_error_exit; + pData->pJPEGderr->output_message = mng_output_message; + + iRetcode = setjmp (pData->sErrorbuf);/* setup local JPEG error-recovery */ + if (iRetcode != 0) /* got here from longjmp ? */ + MNG_ERRORJ (pData, iRetcode) /* then IJG-lib issued an error */ +#endif /* MNG_USE_SETJMP */ + + /* allocate and initialize a JPEG decompression object (continued) */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSINIT, MNG_LC_JPEG_CREATE_DECOMPRESS) +#endif + jpeg_create_decompress (pData->pJPEGdinfo); + + pData->bJPEGdecompress = MNG_TRUE; /* indicate it's initialized */ + + /* specify the source of the compressed data (eg, a file) */ + /* no, not a file; we have buffered input */ + pData->pJPEGdinfo->src = pData->pJPEGdsrc; + /* use the default handler */ + pData->pJPEGdinfo->src->resync_to_restart = jpeg_resync_to_restart; + /* setup local source routine & parms */ + pData->pJPEGdinfo->src->init_source = mng_init_source; + pData->pJPEGdinfo->src->fill_input_buffer = mng_fill_input_buffer; + pData->pJPEGdinfo->src->skip_input_data = mng_skip_input_data; + pData->pJPEGdinfo->src->term_source = mng_term_source; + pData->pJPEGdinfo->src->next_input_byte = pData->pJPEGcurrent; + pData->pJPEGdinfo->src->bytes_in_buffer = pData->iJPEGbufremain; + +#endif /* MNG_INCLUDE_IJG6B */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSINIT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +mng_retcode mngjpeg_decompressdata (mng_datap pData, + mng_uint32 iRawsize, + mng_uint8p pRawdata) +{ + mng_retcode iRetcode; + mng_uint32 iRemain; + mng_uint8p pWork; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_START) +#endif + +#if defined (MNG_INCLUDE_IJG6B) && defined(MNG_USE_SETJMP) + iRetcode = setjmp (pData->sErrorbuf);/* initialize local JPEG error-recovery */ + if (iRetcode != 0) /* got here from longjmp ? */ + MNG_ERRORJ (pData, iRetcode) /* then IJG-lib issued an error */ +#endif + + pWork = pRawdata; + iRemain = iRawsize; + + if (pData->iJPEGtoskip) /* JPEG-lib told us to skip some more data ? */ + { + if (iRemain > pData->iJPEGtoskip) /* enough data in this buffer ? */ + { + iRemain -= pData->iJPEGtoskip; /* skip enough to access the next byte */ + pWork += pData->iJPEGtoskip; + + pData->iJPEGtoskip = 0; /* no more to skip then */ + } + else + { + pData->iJPEGtoskip -= iRemain; /* skip all data in the buffer */ + iRemain = 0; /* and indicate this accordingly */ + } + /* the skip set current-pointer to NULL ! */ + pData->pJPEGcurrent = pData->pJPEGbuf; + } + + while (iRemain) /* repeat until no more input-bytes */ + { /* need to shift anything ? */ + if ((pData->pJPEGcurrent > pData->pJPEGbuf) && + (pData->pJPEGcurrent - pData->pJPEGbuf + pData->iJPEGbufremain + iRemain > pData->iJPEGbufmax)) + { + if (pData->iJPEGbufremain > 0) /* then do so */ + MNG_COPY (pData->pJPEGbuf, pData->pJPEGcurrent, pData->iJPEGbufremain) + + pData->pJPEGcurrent = pData->pJPEGbuf; + } + /* does the remaining input fit into the buffer ? */ + if (pData->iJPEGbufremain + iRemain <= pData->iJPEGbufmax) + { /* move the lot */ + MNG_COPY ((pData->pJPEGcurrent + pData->iJPEGbufremain), pWork, iRemain) + + pData->iJPEGbufremain += iRemain;/* adjust remaining_bytes counter */ + iRemain = 0; /* and indicate there's no input left */ + } + else + { /* calculate what does fit */ + mng_uint32 iFits = pData->iJPEGbufmax - pData->iJPEGbufremain; + + if (iFits <= 0) /* no space is just bugger 'm all */ + MNG_ERROR (pData, MNG_JPEGBUFTOOSMALL) + /* move that */ + MNG_COPY ((pData->pJPEGcurrent + pData->iJPEGbufremain), pWork, iFits) + + pData->iJPEGbufremain += iFits; /* adjust remain_bytes counter */ + iRemain -= iFits; /* and the input-parms */ + pWork += iFits; + } + +#ifdef MNG_INCLUDE_IJG6B + pData->pJPEGdinfo->src->next_input_byte = pData->pJPEGcurrent; + pData->pJPEGdinfo->src->bytes_in_buffer = pData->iJPEGbufremain; + + if (!pData->bJPEGhasheader) /* haven't got the header yet ? */ + { + /* call jpeg_read_header() to obtain image info */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_READ_HEADER) +#endif + if (jpeg_read_header (pData->pJPEGdinfo, TRUE) != JPEG_SUSPENDED) + { /* indicate the header's oke */ + pData->bJPEGhasheader = MNG_TRUE; + /* let's do some sanity checks ! */ + if ((pData->pJPEGdinfo->image_width != pData->iDatawidth ) || + (pData->pJPEGdinfo->image_height != pData->iDataheight) ) + MNG_ERROR (pData, MNG_JPEGPARMSERR) + + if ( ((pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAY ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA) ) && + (pData->pJPEGdinfo->jpeg_color_space != JCS_GRAYSCALE ) ) + MNG_ERROR (pData, MNG_JPEGPARMSERR) + + if ( ((pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLOR ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) ) && + (pData->pJPEGdinfo->jpeg_color_space != JCS_YCbCr ) ) + MNG_ERROR (pData, MNG_JPEGPARMSERR) + /* indicate whether or not it's progressive */ + pData->bJPEGprogressive = (mng_bool)jpeg_has_multiple_scans (pData->pJPEGdinfo); + /* progressive+alpha can't display "on-the-fly"!! */ + if ((pData->bJPEGprogressive) && + ((pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) )) + pData->fDisplayrow = MNG_NULL; + /* allocate a row of JPEG-samples */ + if (pData->pJPEGdinfo->jpeg_color_space == JCS_YCbCr) + pData->iJPEGrowlen = pData->pJPEGdinfo->image_width * 3; + else + pData->iJPEGrowlen = pData->pJPEGdinfo->image_width; + + MNG_ALLOC (pData, pData->pJPEGrow, pData->iJPEGrowlen) + + pData->iJPEGrgbrow = 0; /* quite empty up to now */ + } + + pData->pJPEGcurrent = (mng_uint8p)pData->pJPEGdinfo->src->next_input_byte; + pData->iJPEGbufremain = (mng_uint32)pData->pJPEGdinfo->src->bytes_in_buffer; + } + /* decompress not started ? */ + if ((pData->bJPEGhasheader) && (!pData->bJPEGdecostarted)) + { + /* set parameters for decompression */ + + if (pData->bJPEGprogressive) /* progressive display ? */ + pData->pJPEGdinfo->buffered_image = TRUE; + + /* jpeg_start_decompress(...); */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_START_DECOMPRESS) +#endif + if (jpeg_start_decompress (pData->pJPEGdinfo) == TRUE) + /* indicate it started */ + pData->bJPEGdecostarted = MNG_TRUE; + + pData->pJPEGcurrent = (mng_uint8p)pData->pJPEGdinfo->src->next_input_byte; + pData->iJPEGbufremain = (mng_uint32)pData->pJPEGdinfo->src->bytes_in_buffer; + } + /* process some scanlines ? */ + if ((pData->bJPEGhasheader) && (pData->bJPEGdecostarted) && + ((!jpeg_input_complete (pData->pJPEGdinfo)) || + (pData->pJPEGdinfo->output_scanline < pData->pJPEGdinfo->output_height))) + { + mng_int32 iLines; + + /* for (each output pass) */ + do + { /* address the row output buffer */ + JSAMPROW pRow = (JSAMPROW)pData->pJPEGrow; + + /* init new pass ? */ + if ((pData->bJPEGprogressive) && + ((!pData->bJPEGscanstarted) || + (pData->pJPEGdinfo->output_scanline >= pData->pJPEGdinfo->output_height))) + { + pData->bJPEGscanstarted = MNG_TRUE; + + /* adjust output decompression parameters if required */ + /* nop */ + + /* start a new output pass */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_START_OUTPUT) +#endif + jpeg_start_output (pData->pJPEGdinfo, pData->pJPEGdinfo->input_scan_number); + + pData->iJPEGrow = 0; /* start at row 0 in the image again */ + } + + /* while (scan lines remain to be read) */ + do + { + /* jpeg_read_scanlines(...); */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_READ_SCANLINES) +#endif + iLines = jpeg_read_scanlines (pData->pJPEGdinfo, (JSAMPARRAY)&pRow, 1); + + pData->pJPEGcurrent = (mng_uint8p)pData->pJPEGdinfo->src->next_input_byte; + pData->iJPEGbufremain = (mng_uint32)pData->pJPEGdinfo->src->bytes_in_buffer; + + if (iLines > 0) /* got something ? */ + { + if (pData->fStorerow2) /* store in object ? */ + { + iRetcode = ((mng_storerow)pData->fStorerow2) (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } + } + } + while ((pData->pJPEGdinfo->output_scanline < pData->pJPEGdinfo->output_height) && + (iLines > 0)); /* until end-of-image or not enough input-data */ + + /* terminate output pass */ + if ((pData->bJPEGprogressive) && + (pData->pJPEGdinfo->output_scanline >= pData->pJPEGdinfo->output_height)) + { +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_FINISH_OUTPUT) +#endif + jpeg_finish_output (pData->pJPEGdinfo); + /* this scan has ended */ + pData->bJPEGscanstarted = MNG_FALSE; + } + } + while ((!jpeg_input_complete (pData->pJPEGdinfo)) && (iLines > 0)); + } + /* end of image ? */ + if ((pData->bJPEGhasheader) && (pData->bJPEGdecostarted) && + (jpeg_input_complete (pData->pJPEGdinfo)) && + (pData->pJPEGdinfo->input_scan_number == pData->pJPEGdinfo->output_scan_number)) + { + /* jpeg_finish_decompress(...); */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_FINISH_DECOMPRESS) +#endif + if (jpeg_finish_decompress (pData->pJPEGdinfo) == TRUE) + { /* indicate it's done */ + pData->bJPEGhasheader = MNG_FALSE; + pData->bJPEGdecostarted = MNG_FALSE; + pData->pJPEGcurrent = (mng_uint8p)pData->pJPEGdinfo->src->next_input_byte; + pData->iJPEGbufremain = (mng_uint32)pData->pJPEGdinfo->src->bytes_in_buffer; + /* remaining fluff is an error ! */ + if ((pData->iJPEGbufremain > 0) || (iRemain > 0)) + MNG_ERROR (pData, MNG_TOOMUCHJDAT) + } + } +#endif /* MNG_INCLUDE_IJG6B */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +mng_retcode mngjpeg_decompressfree (mng_datap pData) +{ +#if defined(MNG_INCLUDE_IJG6B) && defined(MNG_USE_SETJMP) + mng_retcode iRetcode; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSFREE, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_IJG6B +#ifdef MNG_USE_SETJMP + iRetcode = setjmp (pData->sErrorbuf);/* setup local JPEG error-recovery */ + if (iRetcode != 0) /* got here from longjmp ? */ + MNG_ERRORJ (pData, iRetcode) /* then IJG-lib issued an error */ +#endif + /* free the row of JPEG-samples*/ + MNG_FREE (pData, pData->pJPEGrow, pData->iJPEGrowlen) + + /* release the JPEG decompression object */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSFREE, MNG_LC_JPEG_DESTROY_DECOMPRESS) +#endif + jpeg_destroy_decompress (pData->pJPEGdinfo); + + pData->bJPEGdecompress = MNG_FALSE; /* indicate it's done */ + +#endif /* MNG_INCLUDE_IJG6B */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSFREE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ +/* * * */ +/* * JPEG decompression routines (JDAA) * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +mng_retcode mngjpeg_decompressinit2 (mng_datap pData) +{ +#if defined(MNG_INCLUDE_IJG6B) && defined(MNG_USE_SETJMP) + mng_retcode iRetcode; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSINIT, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_IJG6B + /* allocate and initialize a JPEG decompression object */ + pData->pJPEGdinfo2->err = jpeg_std_error (pData->pJPEGderr2); + +#ifdef MNG_USE_SETJMP /* setup local JPEG error-routines */ + pData->pJPEGderr2->error_exit = mng_error_exit; + pData->pJPEGderr2->output_message = mng_output_message; + + iRetcode = setjmp (pData->sErrorbuf);/* setup local JPEG error-recovery */ + if (iRetcode != 0) /* got here from longjmp ? */ + MNG_ERRORJ (pData, iRetcode) /* then IJG-lib issued an error */ +#endif /* MNG_USE_SETJMP */ + + /* allocate and initialize a JPEG decompression object (continued) */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSINIT, MNG_LC_JPEG_CREATE_DECOMPRESS) +#endif + jpeg_create_decompress (pData->pJPEGdinfo2); + + pData->bJPEGdecompress2 = MNG_TRUE; /* indicate it's initialized */ + + /* specify the source of the compressed data (eg, a file) */ + /* no, not a file; we have buffered input */ + pData->pJPEGdinfo2->src = pData->pJPEGdsrc2; + /* use the default handler */ + pData->pJPEGdinfo2->src->resync_to_restart = jpeg_resync_to_restart; + /* setup local source routine & parms */ + pData->pJPEGdinfo2->src->init_source = mng_init_source; + pData->pJPEGdinfo2->src->fill_input_buffer = mng_fill_input_buffer; + pData->pJPEGdinfo2->src->skip_input_data = mng_skip_input_data2; + pData->pJPEGdinfo2->src->term_source = mng_term_source; + pData->pJPEGdinfo2->src->next_input_byte = pData->pJPEGcurrent2; + pData->pJPEGdinfo2->src->bytes_in_buffer = pData->iJPEGbufremain2; + +#endif /* MNG_INCLUDE_IJG6B */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSINIT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +mng_retcode mngjpeg_decompressdata2 (mng_datap pData, + mng_uint32 iRawsize, + mng_uint8p pRawdata) +{ + mng_retcode iRetcode; + mng_uint32 iRemain; + mng_uint8p pWork; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_START) +#endif + +#if defined (MNG_INCLUDE_IJG6B) && defined(MNG_USE_SETJMP) + iRetcode = setjmp (pData->sErrorbuf);/* initialize local JPEG error-recovery */ + if (iRetcode != 0) /* got here from longjmp ? */ + MNG_ERRORJ (pData, iRetcode) /* then IJG-lib issued an error */ +#endif + + pWork = pRawdata; + iRemain = iRawsize; + + if (pData->iJPEGtoskip2) /* JPEG-lib told us to skip some more data ? */ + { + if (iRemain > pData->iJPEGtoskip2) /* enough data in this buffer ? */ + { + iRemain -= pData->iJPEGtoskip2; /* skip enough to access the next byte */ + pWork += pData->iJPEGtoskip2; + + pData->iJPEGtoskip2 = 0; /* no more to skip then */ + } + else + { + pData->iJPEGtoskip2 -= iRemain; /* skip all data in the buffer */ + iRemain = 0; /* and indicate this accordingly */ + } + /* the skip set current-pointer to NULL ! */ + pData->pJPEGcurrent2 = pData->pJPEGbuf2; + } + + while (iRemain) /* repeat until no more input-bytes */ + { /* need to shift anything ? */ + if ((pData->pJPEGcurrent2 > pData->pJPEGbuf2) && + (pData->pJPEGcurrent2 - pData->pJPEGbuf2 + pData->iJPEGbufremain2 + iRemain > pData->iJPEGbufmax2)) + { + if (pData->iJPEGbufremain2 > 0) /* then do so */ + MNG_COPY (pData->pJPEGbuf2, pData->pJPEGcurrent2, pData->iJPEGbufremain2) + + pData->pJPEGcurrent2 = pData->pJPEGbuf2; + } + /* does the remaining input fit into the buffer ? */ + if (pData->iJPEGbufremain2 + iRemain <= pData->iJPEGbufmax2) + { /* move the lot */ + MNG_COPY ((pData->pJPEGcurrent2 + pData->iJPEGbufremain2), pWork, iRemain) + /* adjust remaining_bytes counter */ + pData->iJPEGbufremain2 += iRemain; + iRemain = 0; /* and indicate there's no input left */ + } + else + { /* calculate what does fit */ + mng_uint32 iFits = pData->iJPEGbufmax2 - pData->iJPEGbufremain2; + + if (iFits <= 0) /* no space is just bugger 'm all */ + MNG_ERROR (pData, MNG_JPEGBUFTOOSMALL) + /* move that */ + MNG_COPY ((pData->pJPEGcurrent2 + pData->iJPEGbufremain2), pWork, iFits) + + pData->iJPEGbufremain2 += iFits; /* adjust remain_bytes counter */ + iRemain -= iFits; /* and the input-parms */ + pWork += iFits; + } + +#ifdef MNG_INCLUDE_IJG6B + pData->pJPEGdinfo2->src->next_input_byte = pData->pJPEGcurrent2; + pData->pJPEGdinfo2->src->bytes_in_buffer = pData->iJPEGbufremain2; + + if (!pData->bJPEGhasheader2) /* haven't got the header yet ? */ + { + /* call jpeg_read_header() to obtain image info */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_READ_HEADER) +#endif + if (jpeg_read_header (pData->pJPEGdinfo2, TRUE) != JPEG_SUSPENDED) + { /* indicate the header's oke */ + pData->bJPEGhasheader2 = MNG_TRUE; + /* let's do some sanity checks ! */ + if ((pData->pJPEGdinfo2->image_width != pData->iDatawidth ) || + (pData->pJPEGdinfo2->image_height != pData->iDataheight) ) + MNG_ERROR (pData, MNG_JPEGPARMSERR) + + if (pData->pJPEGdinfo2->jpeg_color_space != JCS_GRAYSCALE) + MNG_ERROR (pData, MNG_JPEGPARMSERR) + /* indicate whether or not it's progressive */ + pData->bJPEGprogressive2 = (mng_bool)jpeg_has_multiple_scans (pData->pJPEGdinfo2); + + if (pData->bJPEGprogressive2) /* progressive alphachannel not allowed !!! */ + MNG_ERROR (pData, MNG_JPEGPARMSERR) + /* allocate a row of JPEG-samples */ + if (pData->pJPEGdinfo2->jpeg_color_space == JCS_YCbCr) + pData->iJPEGrowlen2 = pData->pJPEGdinfo2->image_width * 3; + else + pData->iJPEGrowlen2 = pData->pJPEGdinfo2->image_width; + + MNG_ALLOC (pData, pData->pJPEGrow2, pData->iJPEGrowlen2) + + pData->iJPEGalpharow = 0; /* quite empty up to now */ + } + + pData->pJPEGcurrent2 = (mng_uint8p)pData->pJPEGdinfo2->src->next_input_byte; + pData->iJPEGbufremain2 = (mng_uint32)pData->pJPEGdinfo2->src->bytes_in_buffer; + } + /* decompress not started ? */ + if ((pData->bJPEGhasheader2) && (!pData->bJPEGdecostarted2)) + { + /* set parameters for decompression */ + + if (pData->bJPEGprogressive2) /* progressive display ? */ + pData->pJPEGdinfo2->buffered_image = TRUE; + + /* jpeg_start_decompress(...); */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_START_DECOMPRESS) +#endif + if (jpeg_start_decompress (pData->pJPEGdinfo2) == TRUE) + /* indicate it started */ + pData->bJPEGdecostarted2 = MNG_TRUE; + + pData->pJPEGcurrent2 = (mng_uint8p)pData->pJPEGdinfo2->src->next_input_byte; + pData->iJPEGbufremain2 = (mng_uint32)pData->pJPEGdinfo2->src->bytes_in_buffer; + } + /* process some scanlines ? */ + if ((pData->bJPEGhasheader2) && (pData->bJPEGdecostarted2) && + ((!jpeg_input_complete (pData->pJPEGdinfo2)) || + (pData->pJPEGdinfo2->output_scanline < pData->pJPEGdinfo2->output_height))) + { + mng_int32 iLines; + + /* for (each output pass) */ + do + { /* address the row output buffer */ + JSAMPROW pRow = (JSAMPROW)pData->pJPEGrow2; + + /* init new pass ? */ + if ((pData->bJPEGprogressive2) && + ((!pData->bJPEGscanstarted2) || + (pData->pJPEGdinfo2->output_scanline >= pData->pJPEGdinfo2->output_height))) + { + pData->bJPEGscanstarted2 = MNG_TRUE; + + /* adjust output decompression parameters if required */ + /* nop */ + + /* start a new output pass */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_START_OUTPUT) +#endif + jpeg_start_output (pData->pJPEGdinfo2, pData->pJPEGdinfo2->input_scan_number); + + pData->iJPEGrow = 0; /* start at row 0 in the image again */ + } + + /* while (scan lines remain to be read) */ + do + { + /* jpeg_read_scanlines(...); */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_READ_SCANLINES) +#endif + iLines = jpeg_read_scanlines (pData->pJPEGdinfo2, (JSAMPARRAY)&pRow, 1); + + pData->pJPEGcurrent2 = (mng_uint8p)pData->pJPEGdinfo2->src->next_input_byte; + pData->iJPEGbufremain2 = (mng_uint32)pData->pJPEGdinfo2->src->bytes_in_buffer; + + if (iLines > 0) /* got something ? */ + { + if (pData->fStorerow3) /* store in object ? */ + { + iRetcode = ((mng_storerow)pData->fStorerow3) (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } + } + } + while ((pData->pJPEGdinfo2->output_scanline < pData->pJPEGdinfo2->output_height) && + (iLines > 0)); /* until end-of-image or not enough input-data */ + + /* terminate output pass */ + if ((pData->bJPEGprogressive2) && + (pData->pJPEGdinfo2->output_scanline >= pData->pJPEGdinfo2->output_height)) + { +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_FINISH_OUTPUT) +#endif + jpeg_finish_output (pData->pJPEGdinfo2); + /* this scan has ended */ + pData->bJPEGscanstarted2 = MNG_FALSE; + } + } + while ((!jpeg_input_complete (pData->pJPEGdinfo2)) && (iLines > 0)); + } + /* end of image ? */ + if ((pData->bJPEGhasheader2) && (pData->bJPEGdecostarted2) && + (jpeg_input_complete (pData->pJPEGdinfo2)) && + (pData->pJPEGdinfo2->input_scan_number == pData->pJPEGdinfo2->output_scan_number)) + { + /* jpeg_finish_decompress(...); */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_JPEG_FINISH_DECOMPRESS) +#endif + if (jpeg_finish_decompress (pData->pJPEGdinfo2) == TRUE) + { /* indicate it's done */ + pData->bJPEGhasheader2 = MNG_FALSE; + pData->bJPEGdecostarted2 = MNG_FALSE; + pData->pJPEGcurrent2 = (mng_uint8p)pData->pJPEGdinfo2->src->next_input_byte; + pData->iJPEGbufremain2 = (mng_uint32)pData->pJPEGdinfo2->src->bytes_in_buffer; + /* remaining fluff is an error ! */ + if ((pData->iJPEGbufremain2 > 0) || (iRemain > 0)) + MNG_ERROR (pData, MNG_TOOMUCHJDAT) + } + } +#endif /* MNG_INCLUDE_IJG6B */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG_READ +mng_retcode mngjpeg_decompressfree2 (mng_datap pData) +{ +#if defined(MNG_INCLUDE_IJG6B) && defined(MNG_USE_SETJMP) + mng_retcode iRetcode; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSFREE, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_IJG6B +#ifdef MNG_USE_SETJMP + iRetcode = setjmp (pData->sErrorbuf);/* setup local JPEG error-recovery */ + if (iRetcode != 0) /* got here from longjmp ? */ + MNG_ERRORJ (pData, iRetcode) /* then IJG-lib issued an error */ +#endif + /* free the row of JPEG-samples*/ + MNG_FREE (pData, pData->pJPEGrow2, pData->iJPEGrowlen2) + + /* release the JPEG decompression object */ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSFREE, MNG_LC_JPEG_DESTROY_DECOMPRESS) +#endif + jpeg_destroy_decompress (pData->pJPEGdinfo2); + + pData->bJPEGdecompress2 = MNG_FALSE; /* indicate it's done */ + +#endif /* MNG_INCLUDE_IJG6B */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_JPEG_DECOMPRESSFREE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG_READ */ + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_jpeg.h b/freeimage241/Source/LibMNG/libmng_jpeg.h new file mode 100644 index 0000000..0f1aa6f --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_jpeg.h @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_jpeg.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : JPEG library interface (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the JPEG library interface * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for JDAA * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_jpeg_h_ +#define _libmng_jpeg_h_ + +/* ************************************************************************** */ + +mng_retcode mngjpeg_initialize (mng_datap pData); +mng_retcode mngjpeg_cleanup (mng_datap pData); + +mng_retcode mngjpeg_decompressinit (mng_datap pData); +mng_retcode mngjpeg_decompressdata (mng_datap pData, + mng_uint32 iRawsize, + mng_uint8p pRawdata); +mng_retcode mngjpeg_decompressfree (mng_datap pData); + +mng_retcode mngjpeg_decompressinit2 (mng_datap pData); +mng_retcode mngjpeg_decompressdata2 (mng_datap pData, + mng_uint32 iRawsize, + mng_uint8p pRawdata); +mng_retcode mngjpeg_decompressfree2 (mng_datap pData); + +/* ************************************************************************** */ + +#endif /* _libmng_jpeg_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_memory.h b/freeimage241/Source/LibMNG/libmng_memory.h new file mode 100644 index 0000000..568d324 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_memory.h @@ -0,0 +1,66 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_memory.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Memory management (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of memory management functions * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.5.3 - 06/12/2000 - G.Juyn * */ +/* * - swapped MNG_COPY parameter-names * */ +/* * 0.5.3 - 06/27/2000 - G.Juyn * */ +/* * - changed size parameter to mng_size_t * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_memory_h_ +#define _libmng_memory_h_ + +/* ************************************************************************** */ +/* * * */ +/* * Generic memory manager macros * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INTERNAL_MEMMNGMT +#define MNG_ALLOC(H,P,L) { P = calloc (1, (mng_size_t)(L)); \ + if (P == 0) { MNG_ERROR (H, MNG_OUTOFMEMORY) } } +#define MNG_ALLOCX(H,P,L) { P = calloc (1, (mng_size_t)(L)); } +#define MNG_FREE(H,P,L) { if (P) { free (P); P = 0; } } +#define MNG_FREEX(H,P,L) { if (P) free (P); } +#else +#define MNG_ALLOC(H,P,L) { P = H->fMemalloc ((mng_size_t)(L)); \ + if (P == 0) { MNG_ERROR (H, MNG_OUTOFMEMORY) } } +#define MNG_ALLOCX(H,P,L) { P = H->fMemalloc ((mng_size_t)(L)); } +#define MNG_FREE(H,P,L) { if (P) { H->fMemfree (P, (mng_size_t)(L)); P = 0; } } +#define MNG_FREEX(H,P,L) { if (P) { H->fMemfree (P, (mng_size_t)(L)); } } +#endif /* mng_internal_memmngmt */ + +#define MNG_COPY(D,S,L) { memcpy (D, S, (mng_size_t)(L)); } + +/* ************************************************************************** */ + +#endif /* _libmng_memory_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_object_prc.c b/freeimage241/Source/LibMNG/libmng_object_prc.c new file mode 100644 index 0000000..6915db8 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_object_prc.c @@ -0,0 +1,3828 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_object_prc.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : Object processing routines (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the internal object processing routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - fixed to support JNG objects * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added support for global color-chunks in animation * */ +/* * - added support for global PLTE,tRNS,bKGD in animation * */ +/* * - added SAVE & SEEK animation objects * */ +/* * 0.5.2 - 05/29/2000 - G.Juyn * */ +/* * - added initialization of framenr/layernr/playtime * */ +/* * - changed ani_object create routines not to return the * */ +/* * created object (wasn't necessary) * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added object promotion routine (PROM handling) * */ +/* * - added ani-object routines for delta-image processing * */ +/* * - added compression/filter/interlace fields to * */ +/* * object-buffer for delta-image processing * */ +/* * * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - changed support for delta-image processing * */ +/* * 0.5.3 - 06/20/2000 - G.Juyn * */ +/* * - fixed some small things (as precaution) * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added processing of PLTE/tRNS & color-info for * */ +/* * delta-images in the ani_objects chain * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - added support for PPLT chunk * */ +/* * * */ +/* * 0.9.1 - 07/07/2000 - G.Juyn * */ +/* * - added support for freeze/restart/resume & go_xxxx * */ +/* * 0.9.1 - 07/16/2000 - G.Juyn * */ +/* * - fixed support for mng_display() after mng_read() * */ +/* * * */ +/* * 0.9.2 - 07/29/2000 - G.Juyn * */ +/* * - fixed small bugs in display processing * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/07/2000 - G.Juyn * */ +/* * - B111300 - fixup for improved portability * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/10/2000 - G.Juyn * */ +/* * - fixed DEFI behavior * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added valid-flag to stored objects for read() / display()* */ +/* * - added routine to discard "invalid" objects * */ +/* * 0.9.3 - 10/18/2000 - G.Juyn * */ +/* * - fixed delta-processing behavior * */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - added storage for pixel-/alpha-sampledepth for delta's * */ +/* * * */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - removed "old" MAGN methods 3 & 4 * */ +/* * - added "new" MAGN methods 3, 4 & 5 * */ +/* * * */ +/* * 0.9.5 - 1/22/2001 - G.Juyn * */ +/* * - B129681 - fixed compiler warnings SGI/Irix * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_memory.h" +#include "libmng_objects.h" +#include "libmng_display.h" +#include "libmng_pixels.h" +#include "libmng_object_prc.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_DISPLAY_PROCS + +/* ************************************************************************** */ +/* * * */ +/* * Generic object routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode drop_invalid_objects (mng_datap pData) +{ + mng_objectp pObject; + mng_objectp pNext; + mng_cleanupobject fCleanup; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_INVALID_OBJECTS, MNG_LC_START) +#endif + + pObject = pData->pFirstimgobj; /* get first stored image-object (if any) */ + + while (pObject) /* more objects to check ? */ + { + pNext = ((mng_object_headerp)pObject)->pNext; + /* invalid ? */ + if (!((mng_imagep)pObject)->bValid) + { /* call appropriate cleanup */ + fCleanup = ((mng_object_headerp)pObject)->fCleanup; + fCleanup (pData, pObject); + } + + pObject = pNext; /* neeeext */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DROP_INVALID_OBJECTS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Image-data-object routines * */ +/* * * */ +/* * these handle the "object buffer" as defined by the MNG specification * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode create_imagedataobject (mng_datap pData, + mng_bool bConcrete, + mng_bool bViewable, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_imagedatap *ppObject) +{ + mng_imagedatap pImagedata; + mng_uint32 iSamplesize = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_IMGDATAOBJECT, MNG_LC_START) +#endif + /* get a buffer */ + MNG_ALLOC (pData, pImagedata, sizeof (mng_imagedata)) + /* fill the appropriate fields */ + pImagedata->sHeader.fCleanup = (mng_cleanupobject)free_imagedataobject; + pImagedata->sHeader.fProcess = 0; + pImagedata->iRefcount = 1; + pImagedata->bFrozen = MNG_FALSE; + pImagedata->bConcrete = bConcrete; + pImagedata->bViewable = bViewable; + pImagedata->iWidth = iWidth; + pImagedata->iHeight = iHeight; + pImagedata->iBitdepth = iBitdepth; + pImagedata->iColortype = iColortype; + pImagedata->iCompression = iCompression; + pImagedata->iFilter = iFilter; + pImagedata->iInterlace = iInterlace; + pImagedata->iAlphabitdepth = 0; + pImagedata->iJHDRcompression = 0; + pImagedata->iJHDRinterlace = 0; + pImagedata->iPixelsampledepth = iBitdepth; + pImagedata->iAlphasampledepth = iBitdepth; + /* determine samplesize from color_type/bit_depth */ + switch (iColortype) /* for < 8-bit samples we just reserve 8 bits */ + { + case 0 : ; /* gray */ + case 8 : { /* JPEG gray */ + if (iBitdepth > 8) + iSamplesize = 2; + else + iSamplesize = 1; + + break; + } + case 2 : ; /* rgb */ + case 10 : { /* JPEG rgb */ + if (iBitdepth > 8) + iSamplesize = 6; + else + iSamplesize = 3; + + break; + } + case 3 : { /* indexed */ + iSamplesize = 1; + break; + } + case 4 : ; /* gray+alpha */ + case 12 : { /* JPEG gray+alpha */ + if (iBitdepth > 8) + iSamplesize = 4; + else + iSamplesize = 2; + + break; + } + case 6 : ; /* rgb+alpha */ + case 14 : { /* JPEG rgb+alpha */ + if (iBitdepth > 8) + iSamplesize = 8; + else + iSamplesize = 4; + + break; + } + } + /* make sure we remember all this */ + pImagedata->iSamplesize = iSamplesize; + pImagedata->iRowsize = iSamplesize * iWidth; + pImagedata->iImgdatasize = pImagedata->iRowsize * iHeight; + + if (pImagedata->iImgdatasize) /* need a buffer ? */ + { /* so allocate it */ + MNG_ALLOCX (pData, pImagedata->pImgdata, pImagedata->iImgdatasize) + + if (!pImagedata->pImgdata) /* enough memory ? */ + { + MNG_FREEX (pData, pImagedata, sizeof (mng_imagedata)) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + } + /* check global stuff */ + pImagedata->bHasGAMA = pData->bHasglobalGAMA; + pImagedata->bHasCHRM = pData->bHasglobalCHRM; + pImagedata->bHasSRGB = pData->bHasglobalSRGB; + pImagedata->bHasICCP = pData->bHasglobalICCP; + pImagedata->bHasBKGD = pData->bHasglobalBKGD; + + if (pData->bHasglobalGAMA) /* global gAMA present ? */ + pImagedata->iGamma = pData->iGlobalGamma; + + if (pData->bHasglobalCHRM) /* global cHRM present ? */ + { + pImagedata->iWhitepointx = pData->iGlobalWhitepointx; + pImagedata->iWhitepointy = pData->iGlobalWhitepointy; + pImagedata->iPrimaryredx = pData->iGlobalPrimaryredx; + pImagedata->iPrimaryredy = pData->iGlobalPrimaryredy; + pImagedata->iPrimarygreenx = pData->iGlobalPrimarygreenx; + pImagedata->iPrimarygreeny = pData->iGlobalPrimarygreeny; + pImagedata->iPrimarybluex = pData->iGlobalPrimarybluex; + pImagedata->iPrimarybluey = pData->iGlobalPrimarybluey; + } + + if (pData->bHasglobalSRGB) /* glbal sRGB present ? */ + pImagedata->iRenderingintent = pData->iGlobalRendintent; + + if (pData->bHasglobalICCP) /* glbal iCCP present ? */ + { + pImagedata->iProfilesize = pData->iGlobalProfilesize; + + if (pImagedata->iProfilesize) + { + MNG_ALLOCX (pData, pImagedata->pProfile, pImagedata->iProfilesize) + + if (!pImagedata->pProfile) /* enough memory ? */ + { + MNG_FREEX (pData, pImagedata->pImgdata, pImagedata->iImgdatasize) + MNG_FREEX (pData, pImagedata, sizeof (mng_imagedata)) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + + MNG_COPY (pImagedata->pProfile, pData->pGlobalProfile, pImagedata->iProfilesize) + } + } + + if (pData->bHasglobalBKGD) /* global bKGD present ? */ + { + pImagedata->iBKGDred = pData->iGlobalBKGDred; + pImagedata->iBKGDgreen = pData->iGlobalBKGDgreen; + pImagedata->iBKGDblue = pData->iGlobalBKGDblue; + } + + *ppObject = pImagedata; /* return it */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_IMGDATAOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_imagedataobject (mng_datap pData, + mng_imagedatap pImagedata) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IMGDATAOBJECT, MNG_LC_START) +#endif + + if (pImagedata->iRefcount) /* decrease reference count */ + pImagedata->iRefcount--; + + if (!pImagedata->iRefcount) /* reached zero ? */ + { + if (pImagedata->iProfilesize) /* stored an iCCP profile ? */ + MNG_FREEX (pData, pImagedata->pProfile, pImagedata->iProfilesize) + + if (pImagedata->iImgdatasize) /* sample-buffer present ? */ + MNG_FREEX (pData, pImagedata->pImgdata, pImagedata->iImgdatasize) + /* drop the buffer */ + MNG_FREEX (pData, pImagedata, sizeof (mng_imagedata)) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IMGDATAOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode clone_imagedataobject (mng_datap pData, + mng_bool bConcrete, + mng_imagedatap pSource, + mng_imagedatap *ppClone) +{ + mng_imagedatap pNewdata; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLONE_IMGDATAOBJECT, MNG_LC_START) +#endif + /* get a buffer */ + MNG_ALLOC (pData, pNewdata, sizeof (mng_imagedata)) + /* blatently copy the original buffer */ + MNG_COPY (pNewdata, pSource, sizeof (mng_imagedata)) + + pNewdata->iRefcount = 1; /* only the reference count */ + pNewdata->bConcrete = bConcrete; /* and concrete-flag are different */ + + if (pNewdata->iImgdatasize) /* sample buffer present ? */ + { + MNG_ALLOCX (pData, pNewdata->pImgdata, pNewdata->iImgdatasize) + + if (!pNewdata->pImgdata) /* not enough memory ? */ + { + MNG_FREEX (pData, pNewdata, sizeof (mng_imagedata)) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + /* make a copy */ + MNG_COPY (pNewdata->pImgdata, pSource->pImgdata, pNewdata->iImgdatasize) + } + + if (pNewdata->iProfilesize) /* iCCP profile present ? */ + { + MNG_ALLOCX (pData, pNewdata->pProfile, pNewdata->iProfilesize) + + if (!pNewdata->pProfile) /* enough memory ? */ + { + MNG_FREEX (pData, pNewdata, sizeof (mng_imagedata)) + MNG_ERROR (pData, MNG_OUTOFMEMORY) + } + /* make a copy */ + MNG_COPY (pNewdata->pProfile, pSource->pProfile, pNewdata->iProfilesize) + } + + *ppClone = pNewdata; /* return the clone */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLONE_IMGDATAOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Image-object routines * */ +/* * * */ +/* * these handle the "object" as defined by the MNG specification * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode create_imageobject (mng_datap pData, + mng_uint16 iId, + mng_bool bConcrete, + mng_bool bVisible, + mng_bool bViewable, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_int32 iPosx, + mng_int32 iPosy, + mng_bool bClipped, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb, + mng_imagep *ppObject) +{ + mng_imagep pImage; + mng_imagep pPrev, pNext; + mng_retcode iRetcode; + mng_imagedatap pImgbuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_IMGOBJECT, MNG_LC_START) +#endif + /* get a buffer */ + MNG_ALLOC (pData, pImage, sizeof (mng_image)) + /* now get a new "object buffer" */ + iRetcode = create_imagedataobject (pData, bConcrete, bViewable, + iWidth, iHeight, iBitdepth, iColortype, + iCompression, iFilter, iInterlace, + &pImgbuf); + + if (iRetcode) /* on error bail out */ + { + MNG_FREEX (pData, pImage, sizeof (mng_image)) + return iRetcode; + } + /* fill the appropriate fields */ + pImage->sHeader.fCleanup = (mng_cleanupobject)free_imageobject; + pImage->sHeader.fProcess = 0; + pImage->iId = iId; + pImage->bFrozen = MNG_FALSE; + pImage->bVisible = bVisible; + pImage->bViewable = bViewable; + pImage->bValid = (mng_bool)((pData->bDisplaying) && + (pData->bRunning ) && + (!pData->bFreezing ) ); + pImage->iPosx = iPosx; + pImage->iPosy = iPosy; + pImage->bClipped = bClipped; + pImage->iClipl = iClipl; + pImage->iClipr = iClipr; + pImage->iClipt = iClipt; + pImage->iClipb = iClipb; + pImage->iMAGN_MethodX = 0; + pImage->iMAGN_MethodY = 0; + pImage->iMAGN_MX = 0; + pImage->iMAGN_MY = 0; + pImage->iMAGN_ML = 0; + pImage->iMAGN_MR = 0; + pImage->iMAGN_MT = 0; + pImage->iMAGN_MB = 0; + pImage->pImgbuf = pImgbuf; + + if (iId) /* only if not object 0 ! */ + { /* find previous lower object-id */ + pPrev = (mng_imagep)pData->pLastimgobj; + + while ((pPrev) && (pPrev->iId > iId)) + pPrev = (mng_imagep)pPrev->sHeader.pPrev; + + if (pPrev) /* found it ? */ + { + pImage->sHeader.pPrev = pPrev; /* than link it in place */ + pImage->sHeader.pNext = pPrev->sHeader.pNext; + pPrev->sHeader.pNext = pImage; + } + else /* if not found, it becomes the first ! */ + { + pImage->sHeader.pNext = pData->pFirstimgobj; + pData->pFirstimgobj = pImage; + } + + pNext = (mng_imagep)pImage->sHeader.pNext; + + if (pNext) + pNext->sHeader.pPrev = pImage; + else + pData->pLastimgobj = pImage; + + } + + *ppObject = pImage; /* and return the new buffer */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_IMGOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* okido */ +} + +/* ************************************************************************** */ + +mng_retcode free_imageobject (mng_datap pData, + mng_imagep pImage) +{ + mng_retcode iRetcode; + mng_imagep pPrev = pImage->sHeader.pPrev; + mng_imagep pNext = pImage->sHeader.pNext; + mng_imagedatap pImgbuf = pImage->pImgbuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IMGOBJECT, MNG_LC_START) +#endif + + if (pImage->iId) /* not for object 0 */ + { + if (pPrev) /* unlink from the list first ! */ + pPrev->sHeader.pNext = pImage->sHeader.pNext; + else + pData->pFirstimgobj = pImage->sHeader.pNext; + + if (pNext) + pNext->sHeader.pPrev = pImage->sHeader.pPrev; + else + pData->pLastimgobj = pImage->sHeader.pPrev; + + } + /* unlink the image-data buffer */ + iRetcode = free_imagedataobject (pData, pImgbuf); + /* drop it's own buffer */ + MNG_FREEX (pData, pImage, sizeof (mng_image)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_IMGOBJECT, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +mng_imagep find_imageobject (mng_datap pData, + mng_uint16 iId) +{ + mng_imagep pImage = (mng_imagep)pData->pFirstimgobj; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (pData, MNG_FN_FIND_IMGOBJECT, MNG_LC_START) +#endif + /* look up the right id */ + while ((pImage) && (pImage->iId != iId)) + pImage = (mng_imagep)pImage->sHeader.pNext; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (pData, MNG_FN_FIND_IMGOBJECT, MNG_LC_END) +#endif + + return pImage; +} + +/* ************************************************************************** */ + +mng_retcode clone_imageobject (mng_datap pData, + mng_uint16 iId, + mng_bool bPartial, + mng_bool bVisible, + mng_bool bAbstract, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy, + mng_imagep pSource, + mng_imagep *ppClone) +{ + mng_imagep pNew; + mng_imagep pPrev, pNext; + mng_retcode iRetcode; + mng_imagedatap pImgbuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLONE_IMGOBJECT, MNG_LC_START) +#endif + + if ((pSource->iId) && /* needs magnification ? */ + ((pSource->iMAGN_MethodX) || (pSource->iMAGN_MethodY))) + { + iRetcode = magnify_imageobject (pData, pSource); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + /* get a buffer */ + MNG_ALLOC (pData, pNew, sizeof (mng_image)) + /* fill or copy the appropriate fields */ + pNew->sHeader.fCleanup = (mng_cleanupobject)free_imageobject; + pNew->sHeader.fProcess = 0; + pNew->iId = iId; + pNew->bFrozen = MNG_FALSE; + pNew->bVisible = bVisible; + pNew->bViewable = pSource->bViewable; + + if (bHasloca) /* location info available ? */ + { + if (iLocationtype == 0) /* absolute position ? */ + { + pNew->iPosx = iLocationx; + pNew->iPosy = iLocationy; + } + else /* relative */ + { + pNew->iPosx = pSource->iPosx + iLocationx; + pNew->iPosy = pSource->iPosy + iLocationy; + } + } + else /* copy from source */ + { + pNew->iPosx = pSource->iPosx; + pNew->iPosy = pSource->iPosy; + } + /* copy clipping info */ + pNew->bClipped = pSource->bClipped; + pNew->iClipl = pSource->iClipl; + pNew->iClipr = pSource->iClipr; + pNew->iClipt = pSource->iClipt; + pNew->iClipb = pSource->iClipb; + /* copy magnification info */ + pNew->iMAGN_MethodX = pSource->iMAGN_MethodX; + pNew->iMAGN_MethodY = pSource->iMAGN_MethodY; + pNew->iMAGN_MX = pSource->iMAGN_MX; + pNew->iMAGN_MY = pSource->iMAGN_MY; + pNew->iMAGN_ML = pSource->iMAGN_ML; + pNew->iMAGN_MR = pSource->iMAGN_MR; + pNew->iMAGN_MT = pSource->iMAGN_MT; + pNew->iMAGN_MB = pSource->iMAGN_MB; + + if (iId) /* not for object 0 */ + { /* find previous lower object-id */ + pPrev = (mng_imagep)pData->pLastimgobj; + while ((pPrev) && (pPrev->iId > iId)) + pPrev = (mng_imagep)pPrev->sHeader.pPrev; + + if (pPrev) /* found it ? */ + { + pNew->sHeader.pPrev = pPrev; /* than link it in place */ + pNew->sHeader.pNext = pPrev->sHeader.pNext; + pPrev->sHeader.pNext = pNew; + } + else /* if not found, it becomes the first ! */ + { + pNew->sHeader.pNext = pData->pFirstimgobj; + pData->pFirstimgobj = pNew; + } + + pNext = (mng_imagep)pNew->sHeader.pNext; + + if (pNext) + pNext->sHeader.pPrev = pNew; + else + pData->pLastimgobj = pNew; + + } + + if (bPartial) /* partial clone ? */ + { + pNew->pImgbuf = pSource->pImgbuf; /* use the same object buffer */ + pNew->pImgbuf->iRefcount++; /* and increase the reference count */ + } + else /* create a full clone ! */ + { + mng_bool bConcrete = MNG_FALSE; /* it's abstract by default (?) */ + + if (!bAbstract) /* determine concreteness from source ? */ + bConcrete = pSource->pImgbuf->bConcrete; + /* create a full clone ! */ + iRetcode = clone_imagedataobject (pData, bConcrete, pSource->pImgbuf, &pImgbuf); + + if (iRetcode) /* on error bail out */ + { + MNG_FREEX (pData, pNew, sizeof (mng_image)) + return iRetcode; + } + + pNew->pImgbuf = pImgbuf; /* and remember it */ + } + + *ppClone = pNew; /* return it */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLONE_IMGOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode renum_imageobject (mng_datap pData, + mng_imagep pSource, + mng_uint16 iId, + mng_bool bVisible, + mng_bool bAbstract, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy) +{ + mng_imagep pPrev, pNext; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RENUM_IMGOBJECT, MNG_LC_START) +#endif + + pSource->bVisible = bVisible; /* store the new visibility */ + + if (bHasloca) /* location info available ? */ + { + if (iLocationtype == 0) /* absolute position ? */ + { + pSource->iPosx = iLocationx; + pSource->iPosy = iLocationy; + } + else /* relative */ + { + pSource->iPosx = pSource->iPosx + iLocationx; + pSource->iPosy = pSource->iPosy + iLocationy; + } + } + + if (iId) /* not for object 0 */ + { /* find previous lower object-id */ + pPrev = (mng_imagep)pData->pLastimgobj; + while ((pPrev) && (pPrev->iId > iId)) + pPrev = (mng_imagep)pPrev->sHeader.pPrev; + /* different from current ? */ + if (pPrev != (mng_imagep)pSource->sHeader.pPrev) + { + if (pSource->sHeader.pPrev) /* unlink from current position !! */ + ((mng_imagep)pSource->sHeader.pPrev)->sHeader.pNext = pSource->sHeader.pNext; + else + pData->pFirstimgobj = pSource->sHeader.pNext; + + if (pSource->sHeader.pNext) + ((mng_imagep)pSource->sHeader.pNext)->sHeader.pPrev = pSource->sHeader.pPrev; + else + pData->pLastimgobj = pSource->sHeader.pPrev; + + if (pPrev) /* found the previous ? */ + { /* than link it in place */ + pSource->sHeader.pPrev = pPrev; + pSource->sHeader.pNext = pPrev->sHeader.pNext; + pPrev->sHeader.pNext = pSource; + } + else /* if not found, it becomes the first ! */ + { + pSource->sHeader.pNext = pData->pFirstimgobj; + pData->pFirstimgobj = pSource; + } + + pNext = (mng_imagep)pSource->sHeader.pNext; + + if (pNext) + pNext->sHeader.pPrev = pSource; + else + pData->pLastimgobj = pSource; + + } + } + + pSource->iId = iId; /* now set the new id! */ + + if (bAbstract) /* force it to abstract ? */ + pSource->pImgbuf->bConcrete = MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RENUM_IMGOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode reset_object_details (mng_datap pData, + mng_imagep pImage, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_bool bResetall) +{ + mng_imagedatap pBuf = pImage->pImgbuf; + mng_uint32 iSamplesize = 0; + mng_uint32 iRowsize; + mng_uint32 iImgdatasize; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESET_OBJECTDETAILS, MNG_LC_START) +#endif + + pBuf->iWidth = iWidth; /* set buffer characteristics */ + pBuf->iHeight = iHeight; + pBuf->iBitdepth = iBitdepth; + pBuf->iColortype = iColortype; + pBuf->iCompression = iCompression; + pBuf->iFilter = iFilter; + pBuf->iInterlace = iInterlace; + pBuf->iAlphabitdepth = 0; + /* determine samplesize from color_type/bit_depth */ + switch (iColortype) /* for < 8-bit samples we just reserve 8 bits */ + { + case 0 : ; /* gray */ + case 8 : { /* JPEG gray */ + if (iBitdepth > 8) + iSamplesize = 2; + else + iSamplesize = 1; + + break; + } + case 2 : ; /* rgb */ + case 10 : { /* JPEG rgb */ + if (iBitdepth > 8) + iSamplesize = 6; + else + iSamplesize = 3; + + break; + } + case 3 : { /* indexed */ + iSamplesize = 1; + break; + } + case 4 : ; /* gray+alpha */ + case 12 : { /* JPEG gray+alpha */ + if (iBitdepth > 8) + iSamplesize = 4; + else + iSamplesize = 2; + + break; + } + case 6 : ; /* rgb+alpha */ + case 14 : { /* JPEG rgb+alpha */ + if (iBitdepth > 8) + iSamplesize = 8; + else + iSamplesize = 4; + + break; + } + } + + iRowsize = iSamplesize * iWidth; + iImgdatasize = iRowsize * iHeight; + /* buffer size changed ? */ + if (iImgdatasize != pBuf->iImgdatasize) + { /* drop the old one */ + MNG_FREE (pData, pBuf->pImgdata, pBuf->iImgdatasize) + + if (iImgdatasize) /* allocate new sample-buffer ? */ + MNG_ALLOC (pData, pBuf->pImgdata, iImgdatasize) + } + + pBuf->iSamplesize = iSamplesize; /* remember new sizes */ + pBuf->iRowsize = iRowsize; + pBuf->iImgdatasize = iImgdatasize; + /* dimension set and clipping not ? */ + if ((iWidth) && (iHeight) && (!pImage->bClipped)) + { + pImage->iClipl = 0; /* set clipping to dimension by default */ + pImage->iClipr = iWidth; + pImage->iClipt = 0; + pImage->iClipb = iHeight; + } + + if (pImage->iId) /* reset magnification info ? */ + { + pImage->iMAGN_MethodX = 0; + pImage->iMAGN_MethodY = 0; + pImage->iMAGN_MX = 0; + pImage->iMAGN_MY = 0; + pImage->iMAGN_ML = 0; + pImage->iMAGN_MR = 0; + pImage->iMAGN_MT = 0; + pImage->iMAGN_MB = 0; + } + + if (bResetall) /* reset the other characteristics ? */ + { + pBuf->bHasPLTE = MNG_FALSE; + pBuf->bHasTRNS = MNG_FALSE; + pBuf->bHasGAMA = pData->bHasglobalGAMA; + pBuf->bHasCHRM = pData->bHasglobalCHRM; + pBuf->bHasSRGB = pData->bHasglobalSRGB; + pBuf->bHasICCP = pData->bHasglobalICCP; + pBuf->bHasBKGD = pData->bHasglobalBKGD; + + if (pBuf->iProfilesize) /* drop possibly old ICC profile */ + { + MNG_FREE (pData, pBuf->pProfile, pBuf->iProfilesize) + pBuf->iProfilesize = 0; + } + + if (pData->bHasglobalGAMA) /* global gAMA present ? */ + pBuf->iGamma = pData->iGlobalGamma; + + if (pData->bHasglobalCHRM) /* global cHRM present ? */ + { + pBuf->iWhitepointx = pData->iGlobalWhitepointx; + pBuf->iWhitepointy = pData->iGlobalWhitepointy; + pBuf->iPrimaryredx = pData->iGlobalPrimaryredx; + pBuf->iPrimaryredy = pData->iGlobalPrimaryredy; + pBuf->iPrimarygreenx = pData->iGlobalPrimarygreenx; + pBuf->iPrimarygreeny = pData->iGlobalPrimarygreeny; + pBuf->iPrimarybluex = pData->iGlobalPrimarybluex; + pBuf->iPrimarybluey = pData->iGlobalPrimarybluey; + } + + if (pData->bHasglobalSRGB) /* global sRGB present ? */ + pBuf->iRenderingintent = pData->iGlobalRendintent; + + if (pData->bHasglobalICCP) /* global iCCP present ? */ + { + if (pData->iGlobalProfilesize) + { + MNG_ALLOC (pData, pBuf->pProfile, pData->iGlobalProfilesize) + MNG_COPY (pBuf->pProfile, pData->pGlobalProfile, pData->iGlobalProfilesize) + } + + pBuf->iProfilesize = pData->iGlobalProfilesize; + } + + if (pData->bHasglobalBKGD) /* global bKGD present ? */ + { + pBuf->iBKGDred = pData->iGlobalBKGDred; + pBuf->iBKGDgreen = pData->iGlobalBKGDgreen; + pBuf->iBKGDblue = pData->iGlobalBKGDblue; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESET_OBJECTDETAILS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode promote_imageobject (mng_datap pData, + mng_imagep pImage, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iFilltype) +{ + mng_uint8p pNewbuf; + mng_uint32 iNewbufsize; + mng_uint32 iNewrowsize; + mng_uint32 iNewsamplesize; + mng_uint32 iX, iY; + mng_uint8p pSrcline, pDstline; + mng_uint8 iB; + mng_imagedatap pBuf = pImage->pImgbuf; + mng_uint32 iW = pBuf->iWidth; + mng_uint32 iH = pBuf->iHeight; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROMOTE_IMGOBJECT, MNG_LC_START) +#endif + + if ((pBuf->iColortype == 3) && (iColortype == 2)) + { /* indexed -> rgb */ + iNewsamplesize = 3; + iNewrowsize = iW * iNewsamplesize; + iNewbufsize = iH * iNewrowsize; + + MNG_ALLOC (pData, pNewbuf, iNewbufsize) + + pSrcline = pBuf->pImgdata; + pDstline = pNewbuf; + + for (iY = 0; iY < iH; iY++) + { + for (iX = 0; iX < iW; iX++) + { + iB = *pSrcline; + + if ((mng_uint32)iB < pBuf->iPLTEcount) + { + *pDstline = pBuf->aPLTEentries [iB].iRed; + *(pDstline+1) = pBuf->aPLTEentries [iB].iGreen; + *(pDstline+2) = pBuf->aPLTEentries [iB].iBlue; + } + + pSrcline++; + pDstline += 3; + } + } + + MNG_FREEX (pData, pBuf->pImgdata, pBuf->iImgdatasize) + + pBuf->iBitdepth = iBitdepth; + pBuf->iColortype = iColortype; + pBuf->iSamplesize = iNewsamplesize; + pBuf->iRowsize = iNewrowsize; + pBuf->iImgdatasize = iNewbufsize; + pBuf->pImgdata = pNewbuf; + pBuf->bHasPLTE = MNG_FALSE; + pBuf->bHasTRNS = MNG_FALSE; + } + else + if ((pBuf->iColortype == 3) && (iColortype == 6)) + { /* indexed -> rgba */ + iNewsamplesize = 4; + iNewrowsize = iW * iNewsamplesize; + iNewbufsize = iH * iNewrowsize; + + MNG_ALLOC (pData, pNewbuf, iNewbufsize) + + pSrcline = pBuf->pImgdata; + pDstline = pNewbuf; + + for (iY = 0; iY < iH; iY++) + { + for (iX = 0; iX < iW; iX++) + { + iB = *pSrcline; + + if ((mng_uint32)iB < pBuf->iPLTEcount) + { + *pDstline = pBuf->aPLTEentries [iB].iRed; + *(pDstline+1) = pBuf->aPLTEentries [iB].iGreen; + *(pDstline+2) = pBuf->aPLTEentries [iB].iBlue; + + if ((mng_uint32)iB < pBuf->iTRNScount) + *(pDstline+3) = pBuf->aTRNSentries [iB]; + else + *(pDstline+3) = 255; + } + + pSrcline++; + pDstline += 4; + } + } + + MNG_FREEX (pData, pBuf->pImgdata, pBuf->iImgdatasize) + + pBuf->iBitdepth = iBitdepth; + pBuf->iColortype = iColortype; + pBuf->iSamplesize = iNewsamplesize; + pBuf->iRowsize = iNewrowsize; + pBuf->iImgdatasize = iNewbufsize; + pBuf->pImgdata = pNewbuf; + pBuf->bHasPLTE = MNG_FALSE; + pBuf->bHasTRNS = MNG_FALSE; + } + else + { + + /* TODO: other promotion */ + + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROMOTE_IMGOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_imageobject (mng_datap pData, + mng_imagep pImage) +{ + mng_uint8p pNewdata; + mng_uint8p pSrcline1; + mng_uint8p pSrcline2; + mng_uint8p pTempline; + mng_uint8p pDstline; + mng_uint32 iNewrowsize; + mng_uint32 iNewsize; + mng_uint32 iY; + mng_int32 iS, iM; + mng_retcode iRetcode; + + mng_imagedatap pBuf = pImage->pImgbuf; + mng_uint32 iNewW = pBuf->iWidth; + mng_uint32 iNewH = pBuf->iHeight; + mng_magnify_x fMagnifyX = MNG_NULL; + mng_magnify_y fMagnifyY = MNG_NULL; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_IMGOBJECT, MNG_LC_START) +#endif + + if (pBuf->iColortype == 3) /* indexed color ? */ + { /* concrete buffer ? */ + if ((pBuf->bConcrete) && (pImage->iId)) + MNG_ERROR (pData, MNG_INVALIDCOLORTYPE) + + if (pBuf->iTRNScount) /* with transparency ? */ + iRetcode = promote_imageobject (pData, pImage, 8, 6, 0); + else + iRetcode = promote_imageobject (pData, pImage, 8, 2, 0); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + if (pImage->iMAGN_MethodX) /* determine new width */ + { + if (pImage->iMAGN_MethodX == 1) + { + iNewW = pImage->iMAGN_ML; + if (pBuf->iWidth > 1) + iNewW = iNewW + pImage->iMAGN_MR; + if (pBuf->iWidth > 2) + iNewW = iNewW + (pBuf->iWidth - 2) * (pImage->iMAGN_MX); + } + else + { + iNewW = pBuf->iWidth + pImage->iMAGN_ML - 1; + if (pBuf->iWidth > 2) + iNewW = iNewW + pImage->iMAGN_MR - 1; + if (pBuf->iWidth > 3) + iNewW = iNewW + (pBuf->iWidth - 3) * (pImage->iMAGN_MX - 1); + } + } + + if (pImage->iMAGN_MethodY) /* determine new height */ + { + if (pImage->iMAGN_MethodY == 1) + { + iNewH = pImage->iMAGN_MT; + if (pBuf->iHeight > 1) + iNewH = iNewH + pImage->iMAGN_ML; + if (pBuf->iHeight > 2) + iNewH = iNewH + (pBuf->iHeight - 2) * (pImage->iMAGN_MY); + } + else + { + iNewH = pBuf->iHeight + pImage->iMAGN_MT - 1; + if (pBuf->iHeight > 2) + iNewH = iNewH + pImage->iMAGN_MB - 1; + if (pBuf->iHeight > 3) + iNewH = iNewH + (pBuf->iHeight - 3) * (pImage->iMAGN_MY - 1); + } + } + /* get new buffer */ + iNewrowsize = iNewW * pBuf->iSamplesize; + iNewsize = iNewH * iNewrowsize; + + MNG_ALLOC (pData, pNewdata, iNewsize); + + switch (pBuf->iColortype) /* determine magnification routines */ + { + case 0 : ; + case 8 : { + if (pBuf->iBitdepth <= 8) + { + switch (pImage->iMAGN_MethodX) + { + case 1 : { fMagnifyX = magnify_g8_x1; break; } + case 2 : { fMagnifyX = magnify_g8_x2; break; } + case 3 : { fMagnifyX = magnify_g8_x3; break; } + case 4 : { fMagnifyX = magnify_g8_x2; break; } + case 5 : { fMagnifyX = magnify_g8_x3; break; } + } + + switch (pImage->iMAGN_MethodY) + { + case 1 : { fMagnifyY = magnify_g8_y1; break; } + case 2 : { fMagnifyY = magnify_g8_y2; break; } + case 3 : { fMagnifyY = magnify_g8_y3; break; } + case 4 : { fMagnifyY = magnify_g8_y2; break; } + case 5 : { fMagnifyY = magnify_g8_y3; break; } + } + } + else + { + + /* TODO: magnify 16-bit */ + + } + + break; + } + + case 2 : ; + case 10 : { + if (pBuf->iBitdepth <= 8) + { + switch (pImage->iMAGN_MethodX) + { + case 1 : { fMagnifyX = magnify_rgb8_x1; break; } + case 2 : { fMagnifyX = magnify_rgb8_x2; break; } + case 3 : { fMagnifyX = magnify_rgb8_x3; break; } + case 4 : { fMagnifyX = magnify_rgb8_x2; break; } + case 5 : { fMagnifyX = magnify_rgb8_x3; break; } + } + + switch (pImage->iMAGN_MethodY) + { + case 1 : { fMagnifyY = magnify_rgb8_y1; break; } + case 2 : { fMagnifyY = magnify_rgb8_y2; break; } + case 3 : { fMagnifyY = magnify_rgb8_y3; break; } + case 4 : { fMagnifyY = magnify_rgb8_y2; break; } + case 5 : { fMagnifyY = magnify_rgb8_y3; break; } + } + } + else + { + + /* TODO: magnify 16-bit */ + + } + + break; + } + + case 4 : ; + case 12 : { + if (pBuf->iBitdepth <= 8) + { + switch (pImage->iMAGN_MethodX) + { + case 1 : { fMagnifyX = magnify_ga8_x1; break; } + case 2 : { fMagnifyX = magnify_ga8_x2; break; } + case 3 : { fMagnifyX = magnify_ga8_x3; break; } + case 4 : { fMagnifyX = magnify_ga8_x4; break; } + case 5 : { fMagnifyX = magnify_ga8_x5; break; } + } + + switch (pImage->iMAGN_MethodY) + { + case 1 : { fMagnifyY = magnify_ga8_y1; break; } + case 2 : { fMagnifyY = magnify_ga8_y2; break; } + case 3 : { fMagnifyY = magnify_ga8_y3; break; } + case 4 : { fMagnifyY = magnify_ga8_y4; break; } + case 5 : { fMagnifyY = magnify_ga8_y5; break; } + } + } + else + { + + /* TODO: magnify 16-bit */ + + } + + break; + } + + case 6 : ; + case 14 : { + if (pBuf->iBitdepth <= 8) + { + switch (pImage->iMAGN_MethodX) + { + case 1 : { fMagnifyX = magnify_rgba8_x1; break; } + case 2 : { fMagnifyX = magnify_rgba8_x2; break; } + case 3 : { fMagnifyX = magnify_rgba8_x3; break; } + case 4 : { fMagnifyX = magnify_rgba8_x4; break; } + case 5 : { fMagnifyX = magnify_rgba8_x5; break; } + } + + switch (pImage->iMAGN_MethodY) + { + case 1 : { fMagnifyY = magnify_rgba8_y1; break; } + case 2 : { fMagnifyY = magnify_rgba8_y2; break; } + case 3 : { fMagnifyY = magnify_rgba8_y3; break; } + case 4 : { fMagnifyY = magnify_rgba8_y4; break; } + case 5 : { fMagnifyY = magnify_rgba8_y5; break; } + } + } + else + { + + /* TODO: magnify 16-bit */ + + } + + break; + } + } + + pSrcline1 = pBuf->pImgdata; /* initialize row-loop variables */ + pDstline = pNewdata; + /* allocate temporary row */ + MNG_ALLOC (pData, pTempline, iNewrowsize) + + for (iY = 0; iY < pBuf->iHeight; iY++) + { + pSrcline2 = pSrcline1 + pBuf->iRowsize; + + if (fMagnifyX) /* magnifying in X-direction ? */ + { + iRetcode = fMagnifyX (pData, pImage->iMAGN_MX, + pImage->iMAGN_ML, pImage->iMAGN_MR, + pBuf->iWidth, pSrcline1, pDstline); + + if (iRetcode) /* on error bail out */ + { + MNG_FREEX (pData, pTempline, iNewrowsize) + MNG_FREEX (pData, pNewdata, iNewsize) + return iRetcode; + } + } + else + { + MNG_COPY (pDstline, pSrcline1, iNewrowsize) + } + + pDstline += iNewrowsize; + /* magnifying in Y-direction ? */ + if ((fMagnifyY) && + ((iY < pBuf->iHeight - 1) || (pBuf->iHeight == 1) || (pImage->iMAGN_MethodY == 1))) + { + if (iY == 0) /* first interval ? */ + { + if (pBuf->iHeight == 1) /* single row ? */ + pSrcline2 = MNG_NULL; + + iM = (mng_int32)pImage->iMAGN_MT; + } + else /* last interval ? */ + if (((pImage->iMAGN_MethodY == 1) && (iY == (pBuf->iHeight - 1))) || + ((pImage->iMAGN_MethodY != 1) && (iY == (pBuf->iHeight - 2))) ) + iM = (mng_int32)pImage->iMAGN_MB; + else /* middle interval */ + iM = (mng_int32)pImage->iMAGN_MY; + + for (iS = 1; iS < iM; iS++) + { + iRetcode = fMagnifyY (pData, iS, iM, pBuf->iWidth, + pSrcline1, pSrcline2, pTempline); + + if (iRetcode) /* on error bail out */ + { + MNG_FREEX (pData, pTempline, iNewrowsize) + MNG_FREEX (pData, pNewdata, iNewsize) + return iRetcode; + } + + if (fMagnifyX) /* magnifying in X-direction ? */ + { + iRetcode = fMagnifyX (pData, pImage->iMAGN_MX, + pImage->iMAGN_ML, pImage->iMAGN_MR, + pBuf->iWidth, pTempline, pDstline); + + if (iRetcode) /* on error bail out */ + { + MNG_FREEX (pData, pTempline, iNewrowsize) + MNG_FREEX (pData, pNewdata, iNewsize) + return iRetcode; + } + } + else + { + MNG_COPY (pDstline, pTempline, iNewrowsize) + } + + pDstline += iNewrowsize; + } + } + + pSrcline1 += pBuf->iRowsize; + } + /* drop temporary row */ + MNG_FREEX (pData, pTempline, iNewrowsize) + /* drop old pixel-data */ + MNG_FREEX (pData, pBuf->pImgdata, pBuf->iImgdatasize) + + pBuf->pImgdata = pNewdata; /* save new buffer dimensions */ + pBuf->iRowsize = iNewrowsize; + pBuf->iImgdatasize = iNewsize; + pBuf->iWidth = iNewW; + pBuf->iHeight = iNewH; + + if (pImage->iId) /* real object ? */ + { + pImage->iMAGN_MethodX = 0; /* it's done; don't do it again !!! */ + pImage->iMAGN_MethodY = 0; + pImage->iMAGN_MX = 0; + pImage->iMAGN_MY = 0; + pImage->iMAGN_ML = 0; + pImage->iMAGN_MR = 0; + pImage->iMAGN_MT = 0; + pImage->iMAGN_MB = 0; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_IMGOBJECT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Animation-object routines * */ +/* * * */ +/* * these handle the animation objects used to re-run parts of a MNG. * */ +/* * eg. during LOOP or TERM processing * */ +/* * * */ +/* ************************************************************************** */ + +void add_ani_object (mng_datap pData, + mng_object_headerp pObject) +{ + mng_object_headerp pLast = (mng_object_headerp)pData->pLastaniobj; + + if (pLast) /* link it as last in the chain */ + { + pObject->pPrev = pLast; + pLast->pNext = pObject; + } + else + { + pObject->pPrev = MNG_NULL; /* be on the safe side */ + pData->pFirstaniobj = pObject; + } + + pObject->pNext = MNG_NULL; /* be on the safe side */ + pData->pLastaniobj = pObject; + /* keep track for jumping */ + pObject->iFramenr = pData->iFrameseq; + pObject->iLayernr = pData->iLayerseq; + pObject->iPlaytime = pData->iFrametime; + /* save restart object ? */ + if ((pData->bDisplaying) && (!pData->bRunning) && (!pData->pCurraniobj)) + pData->pCurraniobj = pObject; + + return; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_image (mng_datap pData) +{ + mng_ani_imagep pImage; + mng_imagep pCurrent; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_IMAGE, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + if (pData->bHasDHDR) /* processing delta-image ? */ + pCurrent = (mng_imagep)pData->pObjzero; + else /* get the current object */ + pCurrent = (mng_imagep)pData->pCurrentobj; + + if (!pCurrent) /* otherwise object 0 */ + pCurrent = (mng_imagep)pData->pObjzero; + /* now just clone the object !!! */ + iRetcode = clone_imageobject (pData, 0, MNG_FALSE, pCurrent->bVisible, + MNG_FALSE, MNG_FALSE, 0, 0, 0, pCurrent, &pImage); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + pImage->sHeader.fCleanup = free_ani_image; + pImage->sHeader.fProcess = process_ani_image; + + add_ani_object (pData, (mng_object_headerp)pImage); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_IMAGE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* okido */ +} + +/* ************************************************************************** */ + +mng_retcode free_ani_image (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_imagep pImage = (mng_ani_imagep)pObject; + mng_imagedatap pImgbuf = pImage->pImgbuf; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_IMAGE, MNG_LC_START) +#endif + /* unlink the image-data buffer */ + iRetcode = free_imagedataobject (pData, pImgbuf); + /* drop it's own buffer */ + MNG_FREEX (pData, pImage, sizeof (mng_ani_image)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_IMAGE, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_image (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode = MNG_NOERROR; + mng_ani_imagep pImage = (mng_imagep)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_IMAGE, MNG_LC_START) +#endif + + if (pData->bHasDHDR) /* processing delta-image ? */ + { + mng_imagep pDelta = (mng_imagep)pData->pDeltaImage; + + if (!pData->iBreakpoint) /* only execute if not broken before */ + { /* make sure to process pixels as well */ + pData->bDeltaimmediate = MNG_FALSE; + /* execute the delta process */ + iRetcode = execute_delta_image (pData, pDelta, (mng_imagep)pObject); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + /* now go and shoot it off (if required) */ + if ((pDelta->bVisible) && (pDelta->bViewable)) + iRetcode = display_image (pData, pDelta, MNG_FALSE); + + if (!pData->bTimerset) + pData->bHasDHDR = MNG_FALSE; /* this image signifies IEND !! */ + + } + else + if (pData->pCurrentobj) /* active object ? */ + { + mng_imagep pCurrent = (mng_imagep)pData->pCurrentobj; + mng_imagedatap pBuf = pCurrent->pImgbuf; + + if (!pData->iBreakpoint) /* don't copy it again ! */ + { + if (pBuf->iImgdatasize) /* buffer present in active object ? */ + /* then drop it */ + MNG_FREE (pData, pBuf->pImgdata, pBuf->iImgdatasize) + + if (pBuf->iProfilesize) /* iCCP profile present ? */ + /* then drop it */ + MNG_FREE (pData, pBuf->pProfile, pBuf->iProfilesize) + /* now blatently copy the animation buffer */ + MNG_COPY (pBuf, pImage->pImgbuf, sizeof (mng_imagedata)) + /* copy viewability */ + pCurrent->bViewable = pImage->bViewable; + + if (pBuf->iImgdatasize) /* sample buffer present ? */ + { /* then make a copy */ + MNG_ALLOC (pData, pBuf->pImgdata, pBuf->iImgdatasize) + MNG_COPY (pBuf->pImgdata, pImage->pImgbuf->pImgdata, pBuf->iImgdatasize) + } + + if (pBuf->iProfilesize) /* iCCP profile present ? */ + { /* then make a copy */ + MNG_ALLOC (pData, pBuf->pProfile, pBuf->iProfilesize) + MNG_COPY (pBuf->pProfile, pImage->pImgbuf->pProfile, pBuf->iProfilesize) + } + } + /* now go and shoot it off (if required) */ + if ((pCurrent->bVisible) && (pCurrent->bViewable)) + iRetcode = display_image (pData, pCurrent, MNG_FALSE); + } + else + { + mng_imagep pObjzero = (mng_imagep)pData->pObjzero; + /* overlay with object 0 status */ + pImage->bVisible = pObjzero->bVisible; + pImage->bViewable = pObjzero->bViewable; + pImage->iPosx = pObjzero->iPosx; + pImage->iPosy = pObjzero->iPosy; + pImage->bClipped = pObjzero->bClipped; + pImage->iClipl = pObjzero->iClipl; + pImage->iClipr = pObjzero->iClipr; + pImage->iClipt = pObjzero->iClipt; + pImage->iClipb = pObjzero->iClipb; + /* now this should do the trick */ + if ((pImage->bVisible) && (pImage->bViewable)) + iRetcode = display_image (pData, pImage, MNG_FALSE); + } + + if (!iRetcode) /* all's well ? */ + { + if (pData->bTimerset) /* timer break ? */ + pData->iBreakpoint = 99; /* fictive number; no more processing needed! */ + else + pData->iBreakpoint = 0; /* else clear it */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_IMAGE, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_plte (mng_datap pData, + mng_uint32 iEntrycount, + mng_palette8ep paEntries) +{ + mng_ani_pltep pPLTE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_PLTE, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pPLTE, sizeof (mng_ani_plte)) + + pPLTE->sHeader.fCleanup = free_ani_plte; + pPLTE->sHeader.fProcess = process_ani_plte; + + add_ani_object (pData, (mng_object_headerp)pPLTE); + + pPLTE->iEntrycount = iEntrycount; + + MNG_COPY (pPLTE->aEntries, paEntries, sizeof (pPLTE->aEntries)) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_plte (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_PLTE, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_plte)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_plte (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_pltep pPLTE = (mng_ani_pltep)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_PLTE, MNG_LC_START) +#endif + + pData->bHasglobalPLTE = MNG_TRUE; + pData->iGlobalPLTEcount = pPLTE->iEntrycount; + + MNG_COPY (pData->aGlobalPLTEentries, pPLTE->aEntries, sizeof (pPLTE->aEntries)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_PLTE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_trns (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata) +{ + mng_ani_trnsp pTRNS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_TRNS, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pTRNS, sizeof (mng_ani_trns)) + + pTRNS->sHeader.fCleanup = free_ani_trns; + pTRNS->sHeader.fProcess = process_ani_trns; + + add_ani_object (pData, (mng_object_headerp)pTRNS); + + pTRNS->iRawlen = iRawlen; + + MNG_COPY (pTRNS->aRawdata, pRawdata, sizeof (pTRNS->aRawdata)) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_trns (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_TRNS, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_trns)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_trns (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_trnsp pTRNS = (mng_ani_trnsp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_TRNS, MNG_LC_START) +#endif + + pData->bHasglobalTRNS = MNG_TRUE; + pData->iGlobalTRNSrawlen = pTRNS->iRawlen; + + MNG_COPY (pData->aGlobalTRNSrawdata, pTRNS->aRawdata, sizeof (pTRNS->aRawdata)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_TRNS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_gama (mng_datap pData, + mng_bool bEmpty, + mng_uint32 iGamma) +{ + mng_ani_gamap pGAMA; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_GAMA, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pGAMA, sizeof (mng_ani_gama)) + + pGAMA->sHeader.fCleanup = free_ani_gama; + pGAMA->sHeader.fProcess = process_ani_gama; + + add_ani_object (pData, (mng_object_headerp)pGAMA); + + pGAMA->bEmpty = bEmpty; + pGAMA->iGamma = iGamma; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_gama (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_GAMA, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_gama)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_gama (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_gamap pGAMA = (mng_ani_gamap)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_GAMA, MNG_LC_START) +#endif + + if (pGAMA->bEmpty) /* empty chunk ? */ + { /* clear global gAMA */ + pData->bHasglobalGAMA = MNG_FALSE; + pData->iGlobalGamma = 0; + } + else + { /* set global gAMA */ + pData->bHasglobalGAMA = MNG_TRUE; + pData->iGlobalGamma = pGAMA->iGamma; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_GAMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_chrm (mng_datap pData, + mng_bool bEmpty, + mng_uint32 iWhitepointx, + mng_uint32 iWhitepointy, + mng_uint32 iRedx, + mng_uint32 iRedy, + mng_uint32 iGreenx, + mng_uint32 iGreeny, + mng_uint32 iBluex, + mng_uint32 iBluey) +{ + mng_ani_chrmp pCHRM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_CHRM, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pCHRM, sizeof (mng_ani_chrm)) + + pCHRM->sHeader.fCleanup = free_ani_chrm; + pCHRM->sHeader.fProcess = process_ani_chrm; + + add_ani_object (pData, (mng_object_headerp)pCHRM); + + pCHRM->bEmpty = bEmpty; + pCHRM->iWhitepointx = iWhitepointx; + pCHRM->iWhitepointy = iWhitepointy; + pCHRM->iRedx = iRedx; + pCHRM->iRedy = iRedy; + pCHRM->iGreenx = iGreenx; + pCHRM->iGreeny = iGreeny; + pCHRM->iBluex = iBluex; + pCHRM->iBluey = iBluey; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_chrm (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_CHRM, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_chrm)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_chrm (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_chrmp pCHRM = (mng_ani_chrmp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_CHRM, MNG_LC_START) +#endif + + if (pCHRM->bEmpty) /* empty chunk ? */ + { /* clear global cHRM */ + pData->bHasglobalCHRM = MNG_FALSE; + pData->iGlobalWhitepointx = 0; + pData->iGlobalWhitepointy = 0; + pData->iGlobalPrimaryredx = 0; + pData->iGlobalPrimaryredy = 0; + pData->iGlobalPrimarygreenx = 0; + pData->iGlobalPrimarygreeny = 0; + pData->iGlobalPrimarybluex = 0; + pData->iGlobalPrimarybluey = 0; + } + else + { /* set global cHRM */ + pData->bHasglobalCHRM = MNG_TRUE; + pData->iGlobalWhitepointx = pCHRM->iWhitepointx; + pData->iGlobalWhitepointy = pCHRM->iWhitepointy; + pData->iGlobalPrimaryredx = pCHRM->iRedx; + pData->iGlobalPrimaryredy = pCHRM->iRedy; + pData->iGlobalPrimarygreenx = pCHRM->iGreenx; + pData->iGlobalPrimarygreeny = pCHRM->iGreeny; + pData->iGlobalPrimarybluex = pCHRM->iBluex; + pData->iGlobalPrimarybluey = pCHRM->iBluey; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_CHRM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_srgb (mng_datap pData, + mng_bool bEmpty, + mng_uint8 iRenderingintent) +{ + mng_ani_srgbp pSRGB; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SRGB, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pSRGB, sizeof (mng_ani_srgb)) + + pSRGB->sHeader.fCleanup = free_ani_srgb; + pSRGB->sHeader.fProcess = process_ani_srgb; + + add_ani_object (pData, (mng_object_headerp)pSRGB); + + pSRGB->bEmpty = bEmpty; + pSRGB->iRenderingintent = iRenderingintent; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_srgb (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SRGB, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_srgb)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_srgb (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_srgbp pSRGB = (mng_ani_srgbp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SRGB, MNG_LC_START) +#endif + + if (pSRGB->bEmpty) /* empty chunk ? */ + { /* clear global sRGB */ + pData->bHasglobalSRGB = MNG_FALSE; + pData->iGlobalRendintent = 0; + } + else + { /* set global sRGB */ + pData->bHasglobalSRGB = MNG_TRUE; + pData->iGlobalRendintent = pSRGB->iRenderingintent; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_iccp (mng_datap pData, + mng_bool bEmpty, + mng_uint32 iProfilesize, + mng_ptr pProfile) +{ + mng_ani_iccpp pICCP; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_ICCP, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pICCP, sizeof (mng_ani_iccp)) + + pICCP->sHeader.fCleanup = free_ani_iccp; + pICCP->sHeader.fProcess = process_ani_iccp; + + add_ani_object (pData, (mng_object_headerp)pICCP); + + pICCP->bEmpty = bEmpty; + pICCP->iProfilesize = iProfilesize; + + if (iProfilesize) + { + MNG_ALLOC (pData, pICCP->pProfile, iProfilesize) + MNG_COPY (pICCP->pProfile, pProfile, iProfilesize) + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_iccp (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_iccpp pICCP = (mng_ani_iccpp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_ICCP, MNG_LC_START) +#endif + + if (pICCP->iProfilesize) + MNG_FREEX (pData, pICCP->pProfile, pICCP->iProfilesize) + + MNG_FREEX (pData, pObject, sizeof (mng_ani_iccp)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_iccp (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_iccpp pICCP = (mng_ani_iccpp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_ICCP, MNG_LC_START) +#endif + + if (pICCP->bEmpty) /* empty chunk ? */ + { /* clear global iCCP */ + pData->bHasglobalICCP = MNG_FALSE; + + if (pData->iGlobalProfilesize) + MNG_FREEX (pData, pData->pGlobalProfile, pData->iGlobalProfilesize) + + pData->iGlobalProfilesize = 0; + pData->pGlobalProfile = MNG_NULL; + } + else + { /* set global iCCP */ + pData->bHasglobalICCP = MNG_TRUE; + pData->iGlobalProfilesize = pICCP->iProfilesize; + + if (pICCP->iProfilesize) + { + MNG_ALLOC (pData, pData->pGlobalProfile, pICCP->iProfilesize) + MNG_COPY (pData->pGlobalProfile, pICCP->pProfile, pICCP->iProfilesize) + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_ICCP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_bkgd (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue) +{ + mng_ani_bkgdp pBKGD; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_BKGD, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pBKGD, sizeof (mng_ani_bkgd)) + + pBKGD->sHeader.fCleanup = free_ani_bkgd; + pBKGD->sHeader.fProcess = process_ani_bkgd; + + add_ani_object (pData, (mng_object_headerp)pBKGD); + + pBKGD->iRed = iRed; + pBKGD->iGreen = iGreen; + pBKGD->iBlue = iBlue; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_bkgd (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_BKGD, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_bkgd)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_bkgd (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_bkgdp pBKGD = (mng_ani_bkgdp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_BKGD, MNG_LC_START) +#endif + + pData->bHasglobalBKGD = MNG_TRUE; + pData->iGlobalBKGDred = pBKGD->iRed; + pData->iGlobalBKGDgreen = pBKGD->iGreen; + pData->iGlobalBKGDblue = pBKGD->iBlue; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_loop (mng_datap pData, + mng_uint8 iLevel, + mng_uint32 iRepeatcount, + mng_uint8 iTermcond, + mng_uint32 iItermin, + mng_uint32 iItermax, + mng_uint32 iCount, + mng_uint32p pSignals) +{ + mng_ani_loopp pLOOP; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_LOOP, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pLOOP, sizeof (mng_ani_loop)) + + pLOOP->sHeader.fCleanup = free_ani_loop; + pLOOP->sHeader.fProcess = process_ani_loop; + + add_ani_object (pData, (mng_object_headerp)pLOOP); + + pLOOP->iLevel = iLevel; + pLOOP->iRepeatcount = iRepeatcount; + pLOOP->iTermcond = iTermcond; + pLOOP->iItermin = iItermin; + pLOOP->iItermax = iItermax; + pLOOP->iCount = iCount; + /* running counter starts with repeat_count */ + pLOOP->iRunningcount = iRepeatcount; + + if (iCount) + { + MNG_ALLOC (pData, pLOOP->pSignals, (iCount << 1)) + MNG_COPY (pLOOP->pSignals, pSignals, (iCount << 1)) + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_loop (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_loopp pLOOP = (mng_ani_loopp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_LOOP, MNG_LC_START) +#endif + + if (pLOOP->iCount) /* drop signal buffer ? */ + MNG_FREEX (pData, pLOOP->pSignals, (pLOOP->iCount << 1)) + + MNG_FREEX (pData, pObject, sizeof (mng_ani_loop)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_loop (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_loopp pLOOP = (mng_ani_loopp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_LOOP, MNG_LC_START) +#endif + /* just reset the running counter */ + pLOOP->iRunningcount = pLOOP->iRepeatcount; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_LOOP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_endl (mng_datap pData, + mng_uint8 iLevel) +{ + mng_ani_endlp pENDL; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_ENDL, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pENDL, sizeof (mng_ani_endl)) + + pENDL->sHeader.fCleanup = free_ani_endl; + pENDL->sHeader.fProcess = process_ani_endl; + + add_ani_object (pData, (mng_object_headerp)pENDL); + + pENDL->iLevel = iLevel; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_endl (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_ENDL, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_endl)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_endl (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_endlp pENDL = (mng_ani_endlp)pObject; + mng_ani_loopp pLOOP; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_ENDL, MNG_LC_START) +#endif + + if ((pData->bDisplaying) && (pData->bRunning)) + { + pLOOP = pENDL->pLOOP; /* determine matching LOOP */ + + if (!pLOOP) /* haven't got it yet ? */ + { /* go and look back in the list */ + pLOOP = (mng_ani_loopp)pENDL->sHeader.pPrev; + + while ((pLOOP) && + ((pLOOP->sHeader.fCleanup != free_ani_loop) || + (pLOOP->iLevel != pENDL->iLevel) )) + pLOOP = pLOOP->sHeader.pPrev; + } + /* got it now ? */ + if ((pLOOP) && (pLOOP->iLevel == pENDL->iLevel)) + { + pENDL->pLOOP = pLOOP; /* save for next time ! */ + /* decrease running counter ? */ + if ((pLOOP->iRunningcount) && (pLOOP->iRunningcount < 0x7fffffffL)) + pLOOP->iRunningcount--; + + /* TODO: we're cheating out on the termination_condition, + iteration_min, iteration_max and possible signals; + the code is just not ready for that can of worms.... */ + + if (!pLOOP->iRunningcount) /* reached zero ? */ + { /* was this the outer LOOP ? */ + if (pData->pFirstaniobj == (mng_objectp)pLOOP) + pData->bHasLOOP = MNG_FALSE; + } + else + { + if (pData->pCurraniobj) /* was we processing objects ? */ + pData->pCurraniobj = pLOOP; /* then restart with LOOP */ + else /* else restart behind LOOP !!! */ + pData->pCurraniobj = pLOOP->sHeader.pNext; + } + } + else + { + MNG_ERROR (pData, 1234); + /* TODO: error abort ??? */ + + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_ENDL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_defi (mng_datap pData) +{ + mng_ani_defip pDEFI; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_DEFI, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pDEFI, sizeof (mng_ani_defi)) + + pDEFI->sHeader.fCleanup = free_ani_defi; + pDEFI->sHeader.fProcess = process_ani_defi; + + add_ani_object (pData, (mng_object_headerp)pDEFI); + + pDEFI->iId = pData->iDEFIobjectid; + pDEFI->bHasdonotshow = pData->bDEFIhasdonotshow; + pDEFI->iDonotshow = pData->iDEFIdonotshow; + pDEFI->bHasconcrete = pData->bDEFIhasconcrete; + pDEFI->iConcrete = pData->iDEFIconcrete; + pDEFI->bHasloca = pData->bDEFIhasloca; + pDEFI->iLocax = pData->iDEFIlocax; + pDEFI->iLocay = pData->iDEFIlocay; + pDEFI->bHasclip = pData->bDEFIhasclip; + pDEFI->iClipl = pData->iDEFIclipl; + pDEFI->iClipr = pData->iDEFIclipr; + pDEFI->iClipt = pData->iDEFIclipt; + pDEFI->iClipb = pData->iDEFIclipb; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_defi (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_DEFI, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_defi)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_defi (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_defip pDEFI = (mng_ani_defip)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_DEFI, MNG_LC_START) +#endif + + pData->iDEFIobjectid = pDEFI->iId; + pData->bDEFIhasdonotshow = pDEFI->bHasdonotshow; + pData->iDEFIdonotshow = pDEFI->iDonotshow; + pData->bDEFIhasconcrete = pDEFI->bHasconcrete; + pData->iDEFIconcrete = pDEFI->iConcrete; + pData->bDEFIhasloca = pDEFI->bHasloca; + pData->iDEFIlocax = pDEFI->iLocax; + pData->iDEFIlocay = pDEFI->iLocay; + pData->bDEFIhasclip = pDEFI->bHasclip; + pData->iDEFIclipl = pDEFI->iClipl; + pData->iDEFIclipr = pDEFI->iClipr; + pData->iDEFIclipt = pDEFI->iClipt; + pData->iDEFIclipb = pDEFI->iClipb; + + iRetcode = process_display_defi (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_DEFI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_basi (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_bool bHasalpha, + mng_uint16 iAlpha, + mng_uint8 iViewable) +{ + mng_ani_basip pBASI; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_BASI, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pBASI, sizeof (mng_ani_basi)) + + pBASI->sHeader.fCleanup = free_ani_basi; + pBASI->sHeader.fProcess = process_ani_basi; + + add_ani_object (pData, (mng_object_headerp)pBASI); + + pBASI->iRed = iRed; + pBASI->iGreen = iGreen; + pBASI->iBlue = iBlue; + pBASI->bHasalpha = bHasalpha; + pBASI->iAlpha = iAlpha; + pBASI->iViewable = iViewable; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_basi (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_BASI, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_basi)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_BASI, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_basi (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_basip pBASI = (mng_ani_basip)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_BASI, MNG_LC_START) +#endif + + iRetcode = process_display_basi (pData, pBASI->iRed, pBASI->iGreen, pBASI->iBlue, + pBASI->bHasalpha, pBASI->iAlpha, pBASI->iViewable); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_BASI, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_clon (mng_datap pData, + mng_uint16 iCloneid, + mng_uint16 iSourceid, + mng_uint8 iClonetype, + mng_bool bHasdonotshow, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_uint8 iLocatype, + mng_int32 iLocax, + mng_int32 iLocay) +{ + mng_ani_clonp pCLON; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_CLON, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pCLON, sizeof (mng_ani_clon)) + + pCLON->sHeader.fCleanup = free_ani_clon; + pCLON->sHeader.fProcess = process_ani_clon; + + add_ani_object (pData, (mng_object_headerp)pCLON); + + pCLON->iCloneid = iCloneid; + pCLON->iSourceid = iSourceid; + pCLON->iClonetype = iClonetype; + pCLON->bHasdonotshow = bHasdonotshow; + pCLON->iDonotshow = iDonotshow; + pCLON->iConcrete = iConcrete; + pCLON->bHasloca = bHasloca; + pCLON->iLocatype = iLocatype; + pCLON->iLocax = iLocax; + pCLON->iLocay = iLocay; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_clon (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_CLON, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_clon)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_CLON, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_clon (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_clonp pCLON = (mng_ani_clonp)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_CLON, MNG_LC_START) +#endif + + iRetcode = process_display_clon (pData, pCLON->iCloneid, pCLON->iSourceid, + pCLON->iClonetype, pCLON->bHasdonotshow, + pCLON->iDonotshow, pCLON->iConcrete, + pCLON->bHasloca, pCLON->iLocatype, + pCLON->iLocax, pCLON->iLocay); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_CLON, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_back (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint8 iMandatory, + mng_uint16 iImageid, + mng_uint8 iTile) +{ + mng_ani_backp pBACK; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_BACK, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pBACK, sizeof (mng_ani_back)) + + pBACK->sHeader.fCleanup = free_ani_back; + pBACK->sHeader.fProcess = process_ani_back; + + add_ani_object (pData, (mng_object_headerp)pBACK); + + pBACK->iRed = iRed; + pBACK->iGreen = iGreen; + pBACK->iBlue = iBlue; + pBACK->iMandatory = iMandatory; + pBACK->iImageid = iImageid; + pBACK->iTile = iTile; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_back (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_BACK, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_back)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_back (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_backp pBACK = (mng_ani_backp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_BACK, MNG_LC_START) +#endif + + pData->iBACKred = pBACK->iRed; + pData->iBACKgreen = pBACK->iGreen; + pData->iBACKblue = pBACK->iBlue; + pData->iBACKmandatory = pBACK->iMandatory; + pData->iBACKimageid = pBACK->iImageid; + pData->iBACKtile = pBACK->iTile; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_BACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_fram (mng_datap pData, + mng_uint8 iFramemode, + mng_uint8 iChangedelay, + mng_uint32 iDelay, + mng_uint8 iChangetimeout, + mng_uint32 iTimeout, + mng_uint8 iChangeclipping, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb) +{ + mng_ani_framp pFRAM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_FRAM, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pFRAM, sizeof (mng_ani_fram)) + + pFRAM->sHeader.fCleanup = free_ani_fram; + pFRAM->sHeader.fProcess = process_ani_fram; + + add_ani_object (pData, (mng_object_headerp)pFRAM); + + pFRAM->iFramemode = iFramemode; + pFRAM->iChangedelay = iChangedelay; + pFRAM->iDelay = iDelay; + pFRAM->iChangetimeout = iChangetimeout; + pFRAM->iTimeout = iTimeout; + pFRAM->iChangeclipping = iChangeclipping; + pFRAM->iCliptype = iCliptype; + pFRAM->iClipl = iClipl; + pFRAM->iClipr = iClipr; + pFRAM->iClipt = iClipt; + pFRAM->iClipb = iClipb; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_FRAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_fram (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_FRAM, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_fram)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_FRAM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_fram (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_framp pFRAM = (mng_ani_framp)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_FRAM, MNG_LC_START) +#endif + + if (pData->iBreakpoint) /* previously broken ? */ + { + iRetcode = process_display_fram2 (pData); + pData->iBreakpoint = 0; /* not again */ + } + else + iRetcode = process_display_fram (pData, pFRAM->iFramemode, + pFRAM->iChangedelay, pFRAM->iDelay, + pFRAM->iChangetimeout, pFRAM->iTimeout, + pFRAM->iChangeclipping, pFRAM->iCliptype, + pFRAM->iClipl, pFRAM->iClipr, + pFRAM->iClipt, pFRAM->iClipb); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_FRAM, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_move (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iType, + mng_int32 iLocax, + mng_int32 iLocay) +{ + mng_ani_movep pMOVE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_MOVE, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pMOVE, sizeof (mng_ani_move)) + + pMOVE->sHeader.fCleanup = free_ani_move; + pMOVE->sHeader.fProcess = process_ani_move; + + add_ani_object (pData, (mng_object_headerp)pMOVE); + + pMOVE->iFirstid = iFirstid; + pMOVE->iLastid = iLastid; + pMOVE->iType = iType; + pMOVE->iLocax = iLocax; + pMOVE->iLocay = iLocay; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_move (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_MOVE, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_move)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_MOVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_move (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode; + mng_ani_movep pMOVE = (mng_ani_movep)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_MOVE, MNG_LC_START) +#endif + /* re-process the MOVE chunk */ + iRetcode = process_display_move (pData, pMOVE->iFirstid, pMOVE->iLastid, + pMOVE->iType, + pMOVE->iLocax, pMOVE->iLocay); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_MOVE, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_clip (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iType, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb) +{ + mng_ani_clipp pCLIP; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_CLIP, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pCLIP, sizeof (mng_ani_clip)) + + pCLIP->sHeader.fCleanup = free_ani_clip; + pCLIP->sHeader.fProcess = process_ani_clip; + + add_ani_object (pData, (mng_object_headerp)pCLIP); + + pCLIP->iFirstid = iFirstid; + pCLIP->iLastid = iLastid; + pCLIP->iType = iType; + pCLIP->iClipl = iClipl; + pCLIP->iClipr = iClipr; + pCLIP->iClipt = iClipt; + pCLIP->iClipb = iClipb; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_clip (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_CLIP, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_clip)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_CLIP, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_clip (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode; + mng_ani_clipp pCLIP = (mng_ani_clipp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_CLIP, MNG_LC_START) +#endif + /* re-process the CLIP chunk */ + iRetcode = process_display_clip (pData, pCLIP->iFirstid, pCLIP->iLastid, + pCLIP->iType, + pCLIP->iClipl, pCLIP->iClipr, + pCLIP->iClipt, pCLIP->iClipb); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_CLIP, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_show (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iMode) +{ + mng_ani_showp pSHOW; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SHOW, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pSHOW, sizeof (mng_ani_show)) + + pSHOW->sHeader.fCleanup = free_ani_show; + pSHOW->sHeader.fProcess = process_ani_show; + + add_ani_object (pData, (mng_object_headerp)pSHOW); + + pSHOW->iFirstid = iFirstid; + pSHOW->iLastid = iLastid; + pSHOW->iMode = iMode; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_show (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SHOW, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_show)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SHOW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_show (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode; + mng_ani_showp pSHOW = (mng_ani_showp)pObject; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SHOW, MNG_LC_START) +#endif + + if (pData->iBreakpoint) /* returning from breakpoint ? */ + { + iRetcode = process_display_show (pData); + } + else + { /* "re-run" SHOW chunk */ + pData->iSHOWmode = pSHOW->iMode; + pData->iSHOWfromid = pSHOW->iFirstid; + pData->iSHOWtoid = pSHOW->iLastid; + + iRetcode = process_display_show (pData); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SHOW, MNG_LC_END) +#endif + + return iRetcode; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_term (mng_datap pData, + mng_uint8 iTermaction, + mng_uint8 iIteraction, + mng_uint32 iDelay, + mng_uint32 iItermax) +{ + mng_ani_termp pTERM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_TERM, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pTERM, sizeof (mng_ani_term)) + + pTERM->sHeader.fCleanup = free_ani_term; + pTERM->sHeader.fProcess = process_ani_term; + + add_ani_object (pData, (mng_object_headerp)pTERM); + + pTERM->iTermaction = iTermaction; + pTERM->iIteraction = iIteraction; + pTERM->iDelay = iDelay; + pTERM->iItermax = iItermax; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_term (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_TERM, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_term)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_term (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_TERM, MNG_LC_START) +#endif + + /* dummy: no action required! */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_TERM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_save (mng_datap pData) +{ + mng_ani_savep pSAVE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SAVE, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pSAVE, sizeof (mng_ani_save)) + + pSAVE->sHeader.fCleanup = free_ani_save; + pSAVE->sHeader.fProcess = process_ani_save; + + add_ani_object (pData, (mng_object_headerp)pSAVE); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_save (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SAVE, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_save)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_save (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SAVE, MNG_LC_START) +#endif + + iRetcode = process_display_save (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SAVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_seek (mng_datap pData) +{ + mng_ani_seekp pSEEK; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SEEK, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pSEEK, sizeof (mng_ani_seek)) + + pSEEK->sHeader.fCleanup = free_ani_seek; + pSEEK->sHeader.fProcess = process_ani_seek; + + add_ani_object (pData, (mng_object_headerp)pSEEK); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_seek (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SEEK, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_seek)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_seek (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SEEK, MNG_LC_START) +#endif + + iRetcode = process_display_seek (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_SEEK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_dhdr (mng_datap pData, + mng_uint16 iObjectid, + mng_uint8 iImagetype, + mng_uint8 iDeltatype, + mng_uint32 iBlockwidth, + mng_uint32 iBlockheight, + mng_uint32 iBlockx, + mng_uint32 iBlocky) +{ + mng_ani_dhdrp pDHDR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_DHDR, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pDHDR, sizeof (mng_ani_dhdr)) + + pDHDR->sHeader.fCleanup = free_ani_dhdr; + pDHDR->sHeader.fProcess = process_ani_dhdr; + + pDHDR->iObjectid = iObjectid; + pDHDR->iImagetype = iImagetype; + pDHDR->iDeltatype = iDeltatype; + pDHDR->iBlockwidth = iBlockwidth; + pDHDR->iBlockheight = iBlockheight; + pDHDR->iBlockx = iBlockx; + pDHDR->iBlocky = iBlocky; + + add_ani_object (pData, (mng_object_headerp)pDHDR); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_dhdr (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_DHDR, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_dhdr)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_dhdr (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_dhdrp pDHDR = (mng_ani_dhdrp)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_DHDR, MNG_LC_START) +#endif + + pData->bHasDHDR = MNG_TRUE; /* let everyone know we're inside a DHDR */ + + iRetcode = process_display_dhdr (pData, pDHDR->iObjectid, + pDHDR->iImagetype, pDHDR->iDeltatype, + pDHDR->iBlockwidth, pDHDR->iBlockheight, + pDHDR->iBlockx, pDHDR->iBlocky); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_DHDR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_prom (mng_datap pData, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iFilltype) +{ + mng_ani_promp pPROM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_PROM, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pPROM, sizeof (mng_ani_prom)) + + pPROM->sHeader.fCleanup = free_ani_prom; + pPROM->sHeader.fProcess = process_ani_prom; + + pPROM->iBitdepth = iBitdepth; + pPROM->iColortype = iColortype; + pPROM->iFilltype = iFilltype; + + add_ani_object (pData, (mng_object_headerp)pPROM); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_prom (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_PROM, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_prom)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_prom (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_promp pPROM = (mng_ani_promp)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_PROM, MNG_LC_START) +#endif + + iRetcode = process_display_prom (pData, pPROM->iBitdepth, + pPROM->iColortype, pPROM->iFilltype); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_PROM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_ipng (mng_datap pData) +{ + mng_ani_ipngp pIPNG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_IPNG, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pIPNG, sizeof (mng_ani_ipng)) + + pIPNG->sHeader.fCleanup = free_ani_ipng; + pIPNG->sHeader.fProcess = process_ani_ipng; + + add_ani_object (pData, (mng_object_headerp)pIPNG); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_ipng (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_IPNG, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_ipng)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_ipng (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_IPNG, MNG_LC_START) +#endif + + iRetcode = process_display_ipng (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_IPNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_ijng (mng_datap pData) +{ + mng_ani_ijngp pIJNG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_IJNG, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pIJNG, sizeof (mng_ani_ijng)) + + pIJNG->sHeader.fCleanup = free_ani_ijng; + pIJNG->sHeader.fProcess = process_ani_ijng; + + add_ani_object (pData, (mng_object_headerp)pIJNG); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_ijng (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_IJNG, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_ijng)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_ijng (mng_datap pData, + mng_objectp pObject) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_IJNG, MNG_LC_START) +#endif + + iRetcode = process_display_ijng (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_IJNG, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_pplt (mng_datap pData, + mng_uint8 iType, + mng_uint32 iCount, + mng_palette8ep paIndexentries, + mng_uint8p paAlphaentries, + mng_uint8p paUsedentries) +{ + mng_ani_ppltp pPPLT; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_PPLT, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pPPLT, sizeof (mng_ani_pplt)) + + pPPLT->sHeader.fCleanup = free_ani_pplt; + pPPLT->sHeader.fProcess = process_ani_pplt; + + pPPLT->iType = iType; + pPPLT->iCount = iCount; + + MNG_COPY (pPPLT->aIndexentries, paIndexentries, sizeof (pPPLT->aIndexentries)) + MNG_COPY (pPPLT->aAlphaentries, paAlphaentries, sizeof (pPPLT->aAlphaentries)) + MNG_COPY (pPPLT->aUsedentries, paUsedentries, sizeof (pPPLT->aUsedentries )) + + add_ani_object (pData, (mng_object_headerp)pPPLT); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_pplt (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_PPLT, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_pplt)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_pplt (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_ppltp pPPLT = (mng_ani_ppltp)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_PPLT, MNG_LC_START) +#endif + + iRetcode = process_display_pplt (pData, pPPLT->iType, pPPLT->iCount, + pPPLT->aIndexentries, pPPLT->aAlphaentries, + pPPLT->aUsedentries); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_PPLT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* ************************************************************************** */ + +mng_retcode create_ani_magn (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint16 iMethodX, + mng_uint16 iMX, + mng_uint16 iMY, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint16 iMT, + mng_uint16 iMB, + mng_uint16 iMethodY) +{ + mng_ani_magnp pMAGN; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_MAGN, MNG_LC_START) +#endif + + if (pData->bCacheplayback) /* caching playback info ? */ + { + MNG_ALLOC (pData, pMAGN, sizeof (mng_ani_magn)) + + pMAGN->sHeader.fCleanup = free_ani_magn; + pMAGN->sHeader.fProcess = process_ani_magn; + + pMAGN->iFirstid = iFirstid; + pMAGN->iLastid = iLastid; + pMAGN->iMethodX = iMethodX; + pMAGN->iMX = iMX; + pMAGN->iMY = iMY; + pMAGN->iML = iML; + pMAGN->iMR = iMR; + pMAGN->iMT = iMT; + pMAGN->iMB = iMB; + pMAGN->iMethodY = iMethodY; + + add_ani_object (pData, (mng_object_headerp)pMAGN); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CREATE_ANI_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode free_ani_magn (mng_datap pData, + mng_objectp pObject) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_MAGN, MNG_LC_START) +#endif + + MNG_FREEX (pData, pObject, sizeof (mng_ani_magn)) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_FREE_ANI_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ani_magn (mng_datap pData, + mng_objectp pObject) +{ + mng_ani_magnp pMAGN = (mng_ani_magnp)pObject; + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_MAGN, MNG_LC_START) +#endif + + iRetcode = process_display_magn (pData, pMAGN->iFirstid, pMAGN->iLastid, + pMAGN->iMethodX, pMAGN->iMX, pMAGN->iMY, + pMAGN->iML, pMAGN->iMR, pMAGN->iMT, pMAGN->iMB, + pMAGN->iMethodY); + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_ANI_MAGN, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_DISPLAY_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_object_prc.h b/freeimage241/Source/LibMNG/libmng_object_prc.h new file mode 100644 index 0000000..7a1c786 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_object_prc.h @@ -0,0 +1,432 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_object_prc.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Object processing routines (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the internal object processing routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added support for global color-chunks in animation * */ +/* * - added support for global PLTE,tRNS,bKGD in animation * */ +/* * - added SAVE & SEEK animation objects * */ +/* * 0.5.2 - 05/29/2000 - G.Juyn * */ +/* * - changed ani_object create routines not to return the * */ +/* * created object (wasn't necessary) * */ +/* * - added compression/filter/interlace fields to * */ +/* * object-buffer for delta-image processing * */ +/* * * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - added support for PPLT chunk * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added routine to discard "invalid" objects * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_object_prc_h_ +#define _libmng_object_prc_h_ + +/* ************************************************************************** */ + +mng_retcode drop_invalid_objects (mng_datap pData); + +/* ************************************************************************** */ + +mng_retcode create_imagedataobject (mng_datap pData, + mng_bool bConcrete, + mng_bool bViewable, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_imagedatap *ppObject); + +mng_retcode free_imagedataobject (mng_datap pData, + mng_imagedatap pImagedata); + +mng_retcode clone_imagedataobject (mng_datap pData, + mng_bool bConcrete, + mng_imagedatap pSource, + mng_imagedatap *ppClone); + +/* ************************************************************************** */ + +mng_retcode create_imageobject (mng_datap pData, + mng_uint16 iId, + mng_bool bConcrete, + mng_bool bVisible, + mng_bool bViewable, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_int32 iPosx, + mng_int32 iPosy, + mng_bool bClipped, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb, + mng_imagep *ppObject); + +mng_retcode free_imageobject (mng_datap pData, + mng_imagep pImage); + +mng_imagep find_imageobject (mng_datap pData, + mng_uint16 iId); + +mng_retcode clone_imageobject (mng_datap pData, + mng_uint16 iId, + mng_bool bPartial, + mng_bool bVisible, + mng_bool bAbstract, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy, + mng_imagep pSource, + mng_imagep *ppClone); + +mng_retcode renum_imageobject (mng_datap pData, + mng_imagep pSource, + mng_uint16 iId, + mng_bool bVisible, + mng_bool bAbstract, + mng_bool bHasloca, + mng_uint8 iLocationtype, + mng_int32 iLocationx, + mng_int32 iLocationy); + +mng_retcode reset_object_details (mng_datap pData, + mng_imagep pImage, + mng_uint32 iWidth, + mng_uint32 iHeight, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iCompression, + mng_uint8 iFilter, + mng_uint8 iInterlace, + mng_bool bResetall); + +mng_retcode promote_imageobject (mng_datap pData, + mng_imagep pImage, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iFilltype); + +mng_retcode magnify_imageobject (mng_datap pData, + mng_imagep pImage); + +/* ************************************************************************** */ + +mng_retcode create_ani_image (mng_datap pData); + +mng_retcode create_ani_plte (mng_datap pData, + mng_uint32 iEntrycount, + mng_palette8ep paEntries); + +mng_retcode create_ani_trns (mng_datap pData, + mng_uint32 iRawlen, + mng_uint8p pRawdata); + +mng_retcode create_ani_gama (mng_datap pData, + mng_bool bEmpty, + mng_uint32 iGamma); + +mng_retcode create_ani_chrm (mng_datap pData, + mng_bool bEmpty, + mng_uint32 iWhitepointx, + mng_uint32 iWhitepointy, + mng_uint32 iRedx, + mng_uint32 iRedy, + mng_uint32 iGreenx, + mng_uint32 iGreeny, + mng_uint32 iBluex, + mng_uint32 iBluey); + +mng_retcode create_ani_srgb (mng_datap pData, + mng_bool bEmpty, + mng_uint8 iRenderinginent); + +mng_retcode create_ani_iccp (mng_datap pData, + mng_bool bEmpty, + mng_uint32 iProfilesize, + mng_ptr pProfile); + +mng_retcode create_ani_bkgd (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue); + +mng_retcode create_ani_loop (mng_datap pData, + mng_uint8 iLevel, + mng_uint32 iRepeatcount, + mng_uint8 iTermcond, + mng_uint32 iItermin, + mng_uint32 iItermax, + mng_uint32 iCount, + mng_uint32p pSignals); + +mng_retcode create_ani_endl (mng_datap pData, + mng_uint8 iLevel); + +mng_retcode create_ani_defi (mng_datap pData); + +mng_retcode create_ani_basi (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_bool bHasalpha, + mng_uint16 iAlpha, + mng_uint8 iViewable); + +mng_retcode create_ani_clon (mng_datap pData, + mng_uint16 iCloneid, + mng_uint16 iSourceid, + mng_uint8 iClonetype, + mng_bool bHasdonotshow, + mng_uint8 iDonotshow, + mng_uint8 iConcrete, + mng_bool bHasloca, + mng_uint8 iLocatype, + mng_int32 iLocax, + mng_int32 iLocay); + +mng_retcode create_ani_back (mng_datap pData, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue, + mng_uint8 iMandatory, + mng_uint16 iImageid, + mng_uint8 iTile); + +mng_retcode create_ani_fram (mng_datap pData, + mng_uint8 iFramemode, + mng_uint8 iChangedelay, + mng_uint32 iDelay, + mng_uint8 iChangetimeout, + mng_uint32 iTimeout, + mng_uint8 iChangeclipping, + mng_uint8 iCliptype, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb); + +mng_retcode create_ani_move (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iType, + mng_int32 iLocax, + mng_int32 iLocay); + +mng_retcode create_ani_clip (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iType, + mng_int32 iClipl, + mng_int32 iClipr, + mng_int32 iClipt, + mng_int32 iClipb); + +mng_retcode create_ani_show (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint8 iMode); + +mng_retcode create_ani_term (mng_datap pData, + mng_uint8 iTermaction, + mng_uint8 iIteraction, + mng_uint32 iDelay, + mng_uint32 iItermax); + +mng_retcode create_ani_save (mng_datap pData); +mng_retcode create_ani_seek (mng_datap pData); + +mng_retcode create_ani_dhdr (mng_datap pData, + mng_uint16 iObjectid, + mng_uint8 iImagetype, + mng_uint8 iDeltatype, + mng_uint32 iBlockwidth, + mng_uint32 iBlockheight, + mng_uint32 iBlockx, + mng_uint32 iBlocky); + +mng_retcode create_ani_prom (mng_datap pData, + mng_uint8 iBitdepth, + mng_uint8 iColortype, + mng_uint8 iFilltype); + +mng_retcode create_ani_ipng (mng_datap pData); +mng_retcode create_ani_ijng (mng_datap pData); + +mng_retcode create_ani_pplt (mng_datap pData, + mng_uint8 iType, + mng_uint32 iCount, + mng_palette8ep paIndexentries, + mng_uint8p paAlphaentries, + mng_uint8p paUsedentries); + +mng_retcode create_ani_magn (mng_datap pData, + mng_uint16 iFirstid, + mng_uint16 iLastid, + mng_uint16 iMethodX, + mng_uint16 iMX, + mng_uint16 iMY, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint16 iMT, + mng_uint16 iMB, + mng_uint16 iMethodY); + +/* ************************************************************************** */ + +mng_retcode free_ani_image (mng_datap pData, + mng_objectp pObject); + +mng_retcode free_ani_plte (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_trns (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_gama (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_chrm (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_srgb (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_iccp (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_bkgd (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_loop (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_endl (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_defi (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_basi (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_clon (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_back (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_fram (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_move (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_clip (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_show (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_term (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_save (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_seek (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_dhdr (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_prom (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_ipng (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_ijng (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_pplt (mng_datap pData, + mng_objectp pObject); +mng_retcode free_ani_magn (mng_datap pData, + mng_objectp pObject); + +/* ************************************************************************** */ + +mng_retcode process_ani_image (mng_datap pData, + mng_objectp pObject); + +mng_retcode process_ani_plte (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_trns (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_gama (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_chrm (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_srgb (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_iccp (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_bkgd (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_loop (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_endl (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_defi (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_basi (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_clon (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_back (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_fram (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_move (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_clip (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_show (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_term (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_save (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_seek (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_dhdr (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_prom (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_ipng (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_ijng (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_pplt (mng_datap pData, + mng_objectp pObject); +mng_retcode process_ani_magn (mng_datap pData, + mng_objectp pObject); + +/* ************************************************************************** */ + +#endif /* _libmng_object_prc_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_objects.h b/freeimage241/Source/LibMNG/libmng_objects.h new file mode 100644 index 0000000..67647f3 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_objects.h @@ -0,0 +1,509 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_objects.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Internal object structures (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the internal object structures * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - changed inclusion to DISPLAY_PROCS * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added global color-chunks for animations * */ +/* * - added global PLTE,tRNS,bKGD chunks for animation * */ +/* * - added SAVE & SEEK animation objects * */ +/* * 0.5.2 - 05/29/2000 - G.Juyn * */ +/* * - added framenr/layernr/playtime to object header * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added ani-objects for delta-image processing * */ +/* * - added compression/filter/interlace fields to * */ +/* * object-buffer for delta-image processing * */ +/* * * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - changed definition of aTRNSentries * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - added definition for PPLT animation-processing * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/10/2000 - G.Juyn * */ +/* * - fixed DEFI behavior * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for delta-JNG * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added valid-flag to stored objects for read() / display()* */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - added storage for pixel-/alpha-sampledepth for delta's * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_objects_h_ +#define _libmng_objects_h_ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_DISPLAY_PROCS + +/* ************************************************************************** */ + +typedef mng_retcode (*mng_cleanupobject) (mng_datap pData, + mng_objectp pHeader); + +typedef mng_retcode (*mng_processobject) (mng_datap pData, + mng_objectp pHeader); + +/* ************************************************************************** */ + +typedef struct { + mng_cleanupobject fCleanup; + mng_processobject fProcess; + mng_objectp pNext; /* for double-linked list */ + mng_objectp pPrev; + mng_uint32 iFramenr; + mng_uint32 iLayernr; + mng_uint32 iPlaytime; + } mng_object_header; +typedef mng_object_header * mng_object_headerp; + +/* ************************************************************************** */ + +typedef struct { /* MNG specification "object-buffer" */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint32 iRefcount; /* reference counter */ + mng_bool bFrozen; /* frozen flag */ + mng_bool bConcrete; /* concrete flag */ + mng_bool bViewable; /* viewable flag */ + mng_uint32 iWidth; /* image specifics */ + mng_uint32 iHeight; + mng_uint8 iBitdepth; + mng_uint8 iColortype; + mng_uint8 iCompression; + mng_uint8 iFilter; + mng_uint8 iInterlace; + + mng_uint8 iAlphabitdepth; /* used only for JNG images */ + mng_uint8 iJHDRcompression; + mng_uint8 iJHDRinterlace; + + mng_uint8 iPixelsampledepth; /* used with delta-images */ + mng_uint8 iAlphasampledepth; + + mng_bool bHasPLTE; /* PLTE chunk present */ + mng_bool bHasTRNS; /* tRNS chunk present */ + mng_bool bHasGAMA; /* gAMA chunk present */ + mng_bool bHasCHRM; /* cHRM chunk present */ + mng_bool bHasSRGB; /* sRGB chunk present */ + mng_bool bHasICCP; /* iCCP chunk present */ + mng_bool bHasBKGD; /* bKGD chunk present */ + + mng_uint32 iPLTEcount; /* PLTE fields */ + mng_rgbpaltab aPLTEentries; + + mng_uint16 iTRNSgray; /* tRNS fields */ + mng_uint16 iTRNSred; + mng_uint16 iTRNSgreen; + mng_uint16 iTRNSblue; + mng_uint32 iTRNScount; + mng_uint8arr aTRNSentries; + + mng_uint32 iGamma; /* gAMA fields */ + + mng_uint32 iWhitepointx; /* cHRM fields */ + mng_uint32 iWhitepointy; + mng_uint32 iPrimaryredx; + mng_uint32 iPrimaryredy; + mng_uint32 iPrimarygreenx; + mng_uint32 iPrimarygreeny; + mng_uint32 iPrimarybluex; + mng_uint32 iPrimarybluey; + + mng_uint8 iRenderingintent; /* sRGB fields */ + + mng_uint32 iProfilesize; /* iCCP fields */ + mng_ptr pProfile; + + mng_uint8 iBKGDindex; /* bKGD fields */ + mng_uint16 iBKGDgray; + mng_uint16 iBKGDred; + mng_uint16 iBKGDgreen; + mng_uint16 iBKGDblue; + + mng_uint32 iSamplesize; /* size of a sample */ + mng_uint32 iRowsize; /* size of a row of samples */ + mng_uint32 iImgdatasize; /* size of the sample data buffer */ + mng_uint8p pImgdata; /* actual sample data buffer */ + + } mng_imagedata; +typedef mng_imagedata * mng_imagedatap; + +/* ************************************************************************** */ + +typedef struct { /* MNG specification "object" */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iId; /* object-id */ + mng_bool bFrozen; /* frozen flag */ + mng_bool bVisible; /* potential visibility flag */ + mng_bool bViewable; /* viewable flag */ + mng_bool bValid; /* marks invalid when only reading */ + mng_int32 iPosx; /* location fields */ + mng_int32 iPosy; + mng_bool bClipped; /* clipping fields */ + mng_int32 iClipl; + mng_int32 iClipr; + mng_int32 iClipt; + mng_int32 iClipb; + mng_uint16 iMAGN_MethodX; /* magnification (MAGN) */ + mng_uint16 iMAGN_MethodY; + mng_uint16 iMAGN_MX; + mng_uint16 iMAGN_MY; + mng_uint16 iMAGN_ML; + mng_uint16 iMAGN_MR; + mng_uint16 iMAGN_MT; + mng_uint16 iMAGN_MB; + mng_imagedatap pImgbuf; /* the image-data buffer */ + } mng_image; +typedef mng_image * mng_imagep; + +/* ************************************************************************** */ + + /* "on-the-fly" image (= object 0) */ +typedef mng_image mng_ani_image; /* let's (ab)use the general "object" */ +typedef mng_ani_image * mng_ani_imagep; /* that's actualy crucial, so don't change it! */ + +/* ************************************************************************** */ + +typedef struct { /* global PLTE object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint32 iEntrycount; + mng_rgbpaltab aEntries; + } mng_ani_plte; +typedef mng_ani_plte * mng_ani_pltep; + +/* ************************************************************************** */ + +typedef struct { /* global tRNS object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint32 iRawlen; + mng_uint8arr aRawdata; + } mng_ani_trns; +typedef mng_ani_trns * mng_ani_trnsp; + +/* ************************************************************************** */ + +typedef struct { /* global gAMA object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_bool bEmpty; + mng_uint32 iGamma; + } mng_ani_gama; +typedef mng_ani_gama * mng_ani_gamap; + +/* ************************************************************************** */ + +typedef struct { /* global gCRM object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_bool bEmpty; + mng_uint32 iWhitepointx; + mng_uint32 iWhitepointy; + mng_uint32 iRedx; + mng_uint32 iRedy; + mng_uint32 iGreenx; + mng_uint32 iGreeny; + mng_uint32 iBluex; + mng_uint32 iBluey; + } mng_ani_chrm; +typedef mng_ani_chrm * mng_ani_chrmp; + +/* ************************************************************************** */ + +typedef struct { /* global sRGB object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_bool bEmpty; + mng_uint8 iRenderingintent; + } mng_ani_srgb; +typedef mng_ani_srgb * mng_ani_srgbp; + +/* ************************************************************************** */ + +typedef struct { /* global iCCP object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_bool bEmpty; + mng_uint32 iProfilesize; + mng_ptr pProfile; + } mng_ani_iccp; +typedef mng_ani_iccp * mng_ani_iccpp; + +/* ************************************************************************** */ + +typedef struct { /* global bKGD object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iRed; + mng_uint16 iGreen; + mng_uint16 iBlue; + } mng_ani_bkgd; +typedef mng_ani_bkgd * mng_ani_bkgdp; + +/* ************************************************************************** */ + +typedef struct { /* LOOP object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint8 iLevel; + mng_uint32 iRepeatcount; + mng_uint8 iTermcond; + mng_uint32 iItermin; + mng_uint32 iItermax; + mng_uint32 iCount; + mng_uint32p pSignals; + + mng_uint32 iRunningcount; /* running counter */ + } mng_ani_loop; +typedef mng_ani_loop * mng_ani_loopp; + +/* ************************************************************************** */ + +typedef struct { /* ENDL object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint8 iLevel; + + mng_ani_loopp pLOOP; /* matching LOOP */ + } mng_ani_endl; +typedef mng_ani_endl * mng_ani_endlp; + +/* ************************************************************************** */ + +typedef struct { /* DEFI object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iId; + mng_bool bHasdonotshow; + mng_uint8 iDonotshow; + mng_bool bHasconcrete; + mng_uint8 iConcrete; + mng_bool bHasloca; + mng_int32 iLocax; + mng_int32 iLocay; + mng_bool bHasclip; + mng_int32 iClipl; + mng_int32 iClipr; + mng_int32 iClipt; + mng_int32 iClipb; + } mng_ani_defi; +typedef mng_ani_defi * mng_ani_defip; + +/* ************************************************************************** */ + +typedef struct { /* BASI object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iRed; + mng_uint16 iGreen; + mng_uint16 iBlue; + mng_bool bHasalpha; + mng_uint16 iAlpha; + mng_uint8 iViewable; + } mng_ani_basi; +typedef mng_ani_basi * mng_ani_basip; + +/* ************************************************************************** */ + +typedef struct { /* CLON object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iCloneid; + mng_uint16 iSourceid; + mng_uint8 iClonetype; + mng_bool bHasdonotshow; + mng_uint8 iDonotshow; + mng_uint8 iConcrete; + mng_bool bHasloca; + mng_uint8 iLocatype; + mng_int32 iLocax; + mng_int32 iLocay; + } mng_ani_clon; +typedef mng_ani_clon * mng_ani_clonp; + +/* ************************************************************************** */ + +typedef struct { /* BACK object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iRed; + mng_uint16 iGreen; + mng_uint16 iBlue; + mng_uint8 iMandatory; + mng_uint16 iImageid; + mng_uint8 iTile; + } mng_ani_back; +typedef mng_ani_back * mng_ani_backp; + +/* ************************************************************************** */ + +typedef struct { /* FRAM object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint8 iFramemode; + mng_uint8 iChangedelay; + mng_uint32 iDelay; + mng_uint8 iChangetimeout; + mng_uint32 iTimeout; + mng_uint8 iChangeclipping; + mng_uint8 iCliptype; + mng_int32 iClipl; + mng_int32 iClipr; + mng_int32 iClipt; + mng_int32 iClipb; + } mng_ani_fram; +typedef mng_ani_fram * mng_ani_framp; + +/* ************************************************************************** */ + +typedef struct { /* MOVE object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint8 iType; + mng_int32 iLocax; + mng_int32 iLocay; + } mng_ani_move; +typedef mng_ani_move * mng_ani_movep; + +/* ************************************************************************** */ + +typedef struct { /* CLIP object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint8 iType; + mng_int32 iClipl; + mng_int32 iClipr; + mng_int32 iClipt; + mng_int32 iClipb; + } mng_ani_clip; +typedef mng_ani_clip * mng_ani_clipp; + +/* ************************************************************************** */ + +typedef struct { /* SHOW object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint8 iMode; + } mng_ani_show; +typedef mng_ani_show * mng_ani_showp; + +/* ************************************************************************** */ + +typedef struct { /* TERM object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint8 iTermaction; + mng_uint8 iIteraction; + mng_uint32 iDelay; + mng_uint32 iItermax; + } mng_ani_term; +typedef mng_ani_term * mng_ani_termp; + +/* ************************************************************************** */ + +typedef struct { /* SAVE object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + } mng_ani_save; +typedef mng_ani_save * mng_ani_savep; + +/* ************************************************************************** */ + +typedef struct { /* SEEK object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + } mng_ani_seek; +typedef mng_ani_seek * mng_ani_seekp; + +/* ************************************************************************** */ + +typedef struct { /* DHDR object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iObjectid; + mng_uint8 iImagetype; + mng_uint8 iDeltatype; + mng_uint32 iBlockwidth; + mng_uint32 iBlockheight; + mng_uint32 iBlockx; + mng_uint32 iBlocky; + } mng_ani_dhdr; +typedef mng_ani_dhdr * mng_ani_dhdrp; + +/* ************************************************************************** */ + +typedef struct { /* PROM object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint8 iBitdepth; + mng_uint8 iColortype; + mng_uint8 iFilltype; + } mng_ani_prom; +typedef mng_ani_prom * mng_ani_promp; + +/* ************************************************************************** */ + +typedef struct { /* IPNG object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + } mng_ani_ipng; +typedef mng_ani_ipng * mng_ani_ipngp; + +/* ************************************************************************** */ + +typedef struct { /* IJNG object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + } mng_ani_ijng; +typedef mng_ani_ijng * mng_ani_ijngp; + +/* ************************************************************************** */ + +typedef struct { /* PPLT object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint8 iType; + mng_uint32 iCount; + mng_rgbpaltab aIndexentries; + mng_uint8arr aAlphaentries; + mng_uint8arr aUsedentries; + } mng_ani_pplt; +typedef mng_ani_pplt * mng_ani_ppltp; + +/* ************************************************************************** */ + +typedef struct { /* MAGN object */ + mng_object_header sHeader; /* default header (DO NOT REMOVE) */ + mng_uint16 iFirstid; + mng_uint16 iLastid; + mng_uint16 iMethodX; + mng_uint16 iMX; + mng_uint16 iMY; + mng_uint16 iML; + mng_uint16 iMR; + mng_uint16 iMT; + mng_uint16 iMB; + mng_uint16 iMethodY; + } mng_ani_magn; +typedef mng_ani_magn * mng_ani_magnp; + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_DISPLAY_PROCS */ + +/* ************************************************************************** */ + +#endif /* _libmng_objects_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_pixels.c b/freeimage241/Source/LibMNG/libmng_pixels.c new file mode 100644 index 0000000..cddffb7 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_pixels.c @@ -0,0 +1,10837 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_pixels.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : Pixel-row management routines (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the pixel-row management routines * */ +/* * * */ +/* * the dual alpha-composing for RGBA/BGRA/etc output-canvas' * */ +/* * is based on the Note on Compositing chapter of the * */ +/* * DOH-3 draft, noted to me by Adam M. Costello * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added callback error-reporting support * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.5.2 - 05/22/2000 - G.Juyn * */ +/* * - added JNG support * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - fixed minor bugs 16-bit pixel-handling * */ +/* * - added delta-image row-processing routines * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - fixed endian support (hopefully) * */ +/* * 0.5.2 - 06/03/2000 - G.Juyn * */ +/* * - fixed makeup for Linux gcc compile * */ +/* * 0.5.2 - 06/05/2000 - G.Juyn * */ +/* * - implemented app bkgd restore routines * */ +/* * - implemented RGBA8, ARGB8, BGRA8 & ABGR8 display routines * */ +/* * - added support for RGB8_A8 canvasstyle * */ +/* * 0.5.2 - 06/09/2000 - G.Juyn * */ +/* * - fixed alpha-handling for alpha canvasstyles * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - changed progressive-display processing * */ +/* * 0.5.3 - 06/17/2000 - G.Juyn * */ +/* * - changed to support delta-images * */ +/* * - optimized some store_xxx routines * */ +/* * 0.5.3 - 06/20/2000 - G.Juyn * */ +/* * - fixed nasty bug with embedded PNG after delta-image * */ +/* * 0.5.3 - 06/24/2000 - G.Juyn * */ +/* * - fixed problem with 16-bit GA format * */ +/* * 0.5.3 - 06/25/2000 - G.Juyn * */ +/* * - fixed problem with cheap transparency for 4-bit gray * */ +/* * - fixed display_xxxx routines for interlaced images * */ +/* * 0.5.3 - 06/28/2000 - G.Juyn * */ +/* * - fixed compiler-warning for non-initialized iB variable * */ +/* * * */ +/* * 0.9.1 - 07/05/2000 - G.Juyn * */ +/* * - fixed mandatory BACK color to be opaque * */ +/* * * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - B110547 - fixed bug in interlace code * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/20/2000 - G.Juyn * */ +/* * - fixed app-supplied background restore * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 09/30/2000 - G.Juyn * */ +/* * - fixed MAGN rounding errors (thanks Matthias!) * */ +/* * 0.9.3 - 10/10/2000 - G.Juyn * */ +/* * - fixed alpha-blending for RGBA canvasstyle * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - fixed alpha-blending for other alpha-canvasstyles * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added optional support for bKGD for PNG images * */ +/* * - added support for JDAA * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - fixed support for bKGD * */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - implemented delayed delta-processing * */ +/* * 0.9.3 - 10/28/2000 - G.Juyn * */ +/* * - fixed tRNS processing for gray-image < 8-bits * */ +/* * * */ +/* * 0.9.4 - 12/16/2000 - G.Juyn * */ +/* * - fixed mixup of data- & function-pointers (thanks Dimitri)* */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - removed "old" MAGN methods 3 & 4 * */ +/* * - added "new" MAGN methods 3, 4 & 5 * */ +/* * - removed test filter-methods 1 & 65 * */ +/* * * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn (code by G.Kelly) * */ +/* * - added BGRA8 canvas with premultiplied alpha * */ +/* * 1.0.1 - 04/25/2001 - G.Juyn * */ +/* * - moved mng_clear_cms to libmng_cms * */ +/* * * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - added option to turn off progressive refresh * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_objects.h" +#include "libmng_memory.h" +#include "libmng_cms.h" +#include "libmng_filter.h" +#include "libmng_pixels.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_DISPLAY_PROCS + +/* TODO: magnification & canvas-positioning/-clipping */ + +/* TODO: major optimization of pixel-loops by using assembler (?) */ + +/* ************************************************************************** */ +/* * * */ +/* * Interlace tables * */ +/* * * */ +/* ************************************************************************** */ + +mng_uint32 const interlace_row [7] = { 0, 0, 4, 0, 2, 0, 1 }; +mng_uint32 const interlace_rowskip [7] = { 8, 8, 8, 4, 4, 2, 2 }; +mng_uint32 const interlace_col [7] = { 0, 4, 0, 2, 0, 1, 0 }; +mng_uint32 const interlace_colskip [7] = { 8, 8, 4, 4, 2, 2, 1 }; +mng_uint32 const interlace_roundoff [7] = { 7, 7, 3, 3, 1, 1, 0 }; +mng_uint32 const interlace_divider [7] = { 3, 3, 2, 2, 1, 1, 0 }; + +/* ************************************************************************** */ +/* * * */ +/* * Alpha composing macros * */ +/* * the code below is slightly modified from the libpng package * */ +/* * the original was last optimized by Greg Roelofs & Mark Adler * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_COMPOSE8(RET,FG,ALPHA,BG) { \ + mng_uint16 iH = (mng_uint16)((mng_uint16)(FG) * (mng_uint16)(ALPHA) \ + + (mng_uint16)(BG)*(mng_uint16)(255 - \ + (mng_uint16)(ALPHA)) + (mng_uint16)128); \ + (RET) = (mng_uint8)((iH + (iH >> 8)) >> 8); } + +#define MNG_COMPOSE16(RET,FG,ALPHA,BG) { \ + mng_uint32 iH = (mng_uint32)((mng_uint32)(FG) * (mng_uint32)(ALPHA) \ + + (mng_uint32)(BG)*(mng_uint32)(65535L - \ + (mng_uint32)(ALPHA)) + (mng_uint32)32768L); \ + (RET) = (mng_uint16)((iH + (iH >> 16)) >> 16); } + +/* ************************************************************************** */ +/* * * */ +/* * Alpha blending macros * */ +/* * this code is based on Adam Costello's "Note on Compositing" from the * */ +/* * mng-list which gives the following formula: * */ +/* * * */ +/* * top pixel = (Rt, Gt, Bt, At) * */ +/* * bottom pixel = (Rb, Gb, Bb, Ab) * */ +/* * composite pixel = (Rc, Gc, Bc, Ac) * */ +/* * * */ +/* * all values in the range 0..1 * */ +/* * * */ +/* * Ac = 1 - (1 - At)(1 - Ab) * */ +/* * s = At / Ac * */ +/* * t = (1 - At) Ab / Ac * */ +/* * Rc = s Rt + t Rb * */ +/* * Gc = s Gt + t Gb * */ +/* * Bc = s Bt + t Bb * */ +/* * * */ +/* * (I just hope I coded it correctly in integer arithmetic...) * */ +/* * * */ +/* ************************************************************************** */ + +#define MNG_BLEND8(RT, GT, BT, AT, RB, GB, BB, AB, RC, GC, BC, AC) { \ + mng_uint32 S, T; \ + (AC) = (mng_uint8)((mng_uint32)255 - \ + ((((mng_uint32)255 - (mng_uint32)(AT)) * \ + ((mng_uint32)255 - (mng_uint32)(AB)) ) >> 8)); \ + S = (mng_uint32)(((mng_uint32)(AT) << 8) / \ + (mng_uint32)(AC)); \ + T = (mng_uint32)(((mng_uint32)255 - (mng_uint32)(AT)) * \ + (mng_uint32)(AB) / (mng_uint32)(AC)); \ + (RC) = (mng_uint8)((S * (mng_uint32)(RT) + \ + T * (mng_uint32)(RB) + (mng_uint32)127) >> 8); \ + (GC) = (mng_uint8)((S * (mng_uint32)(GT) + \ + T * (mng_uint32)(GB) + (mng_uint32)127) >> 8); \ + (BC) = (mng_uint8)((S * (mng_uint32)(BT) + \ + T * (mng_uint32)(BB) + (mng_uint32)127) >> 8); } + +#define MNG_BLEND16(RT, GT, BT, AT, RB, GB, BB, AB, RC, GC, BC, AC) { \ + mng_uint32 S, T; \ + (AC) = (mng_uint16)((mng_uint32)65525 - \ + ((((mng_uint32)65535 - (mng_uint32)(AT)) * \ + ((mng_uint32)65535 - (mng_uint32)(AB)) ) >> 16)); \ + S = (mng_uint32)(((mng_uint32)(AT) << 16) / \ + (mng_uint32)(AC)); \ + T = (mng_uint32)(((mng_uint32)65535 - (mng_uint32)(AT)) * \ + (mng_uint32)(AB) / (mng_uint32)(AC)); \ + (RC) = (mng_uint16)((S * (mng_uint32)(RT) + \ + T * (mng_uint32)(RB) + (mng_uint32)32767) >> 16); \ + (GC) = (mng_uint16)((S * (mng_uint32)(GT) + \ + T * (mng_uint32)(GB) + (mng_uint32)32767) >> 16); \ + (BC) = (mng_uint16)((S * (mng_uint32)(BT) + \ + T * (mng_uint32)(BB) + (mng_uint32)32767) >> 16); } + +/* ************************************************************************** */ + +/* note a good optimizing compiler will optimize this */ +#define DIV255B8(x) (mng_uint8)(((x) + 127) / 255) +#define DIV255B16(x) (mng_uint16)(((x) + 32767) / 65535) + +/* ************************************************************************** */ +/* * * */ +/* * Progressive display check - checks to see if progressive display is * */ +/* * in order & indicates so * */ +/* * * */ +/* * The routine is called after a call to one of the display_xxx routines * */ +/* * if appropriate * */ +/* * * */ +/* * The refresh is warrented in the read_chunk routine (mng_read.c) * */ +/* * and only during read&display processing, since there's not much point * */ +/* * doing it from memory! * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode display_progressive_check (mng_datap pData) +{ + if ((pData->bDoProgressive) && /* need progressive display? */ + ((pData->eImagetype != mng_it_mng) || (pData->iDataheight > 300)) && + (pData->iDestb - pData->iDestt > 50) && (!pData->pCurraniobj)) + { + mng_int32 iC = pData->iRow + pData->iDestt - pData->iSourcet; + + if (iC % 20 == 0) /* every 20th line */ + pData->bNeedrefresh = MNG_TRUE; + + } + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Display routines - convert rowdata (which is already color-corrected) * */ +/* * to the output canvas, respecting the opacity information * */ +/* * * */ +/* ************************************************************************** */ + +void check_update_region (mng_datap pData) +{ /* determine actual canvas row */ + mng_int32 iRow = pData->iRow + pData->iDestt - pData->iSourcet; + /* check for change in update-region */ + if ((pData->iDestl < (mng_int32)pData->iUpdateleft) || (pData->iUpdateright == 0)) + pData->iUpdateleft = pData->iDestl; + + if (pData->iDestr > (mng_int32)pData->iUpdateright) + pData->iUpdateright = pData->iDestr; + + if ((iRow < (mng_int32)pData->iUpdatetop) || (pData->iUpdatebottom == 0)) + pData->iUpdatetop = iRow; + + if (iRow+1 > (mng_int32)pData->iUpdatebottom) + pData->iUpdatebottom = iRow+1; + + return; +} + +/* ************************************************************************** */ + +mng_retcode display_rgb8 (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint16 iA16; + mng_uint16 iFGr16, iFGg16, iFGb16; + mng_uint16 iBGr16, iBGg16, iBGb16; + mng_uint8 iA8; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_RGB8, MNG_LC_START) +#endif + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination row */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination row starting-point */ + pScanline = pScanline + (pData->iCol * 3) + (pData->iDestl * 3); + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 3); + else + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 2); + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+4); + + pScanline += (pData->iColinc * 3); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *(pDataline+2); + + pScanline += (pData->iColinc * 3); + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iA16 = mng_get_uint16 (pDataline+6); + + if (iA16) /* any opacity at all ? */ + { + if (iA16 == 0xFFFF) /* fully opaque ? */ + { /* scale down by dropping the LSB */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+4); + } + else + { /* get the proper values */ + iFGr16 = mng_get_uint16 (pDataline ); + iFGg16 = mng_get_uint16 (pDataline+2); + iFGb16 = mng_get_uint16 (pDataline+4); + /* scale background up */ + iBGr16 = (mng_uint16)(*pScanline ); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*(pScanline+2)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* now compose */ + MNG_COMPOSE16(iFGr16, iFGr16, iA16, iBGr16) + MNG_COMPOSE16(iFGg16, iFGg16, iA16, iBGg16) + MNG_COMPOSE16(iFGb16, iFGb16, iA16, iBGb16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iFGr16 >> 8); + *(pScanline+1) = (mng_uint8)(iFGg16 >> 8); + *(pScanline+2) = (mng_uint8)(iFGb16 >> 8); + } + } + + pScanline += (pData->iColinc * 3); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iA8 = *(pDataline+3); /* get alpha value */ + + if (iA8) /* any opacity at all ? */ + { + if (iA8 == 0xFF) /* fully opaque ? */ + { /* then simply copy the values */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *(pDataline+2); + } + else + { /* do alpha composing */ + MNG_COMPOSE8 (*pScanline, *pDataline, iA8, *pScanline ) + MNG_COMPOSE8 (*(pScanline+1), *(pDataline+1), iA8, *(pScanline+1)) + MNG_COMPOSE8 (*(pScanline+2), *(pDataline+2), iA8, *(pScanline+2)) + } + } + + pScanline += (pData->iColinc * 3); + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_rgba8 (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint16 iFGa16, iBGa16, iCa16; + mng_uint8 iFGa8, iBGa8, iCa8; + mng_uint16 iFGr16, iFGg16, iFGb16; + mng_uint16 iBGr16, iBGg16, iBGb16; + mng_uint16 iCr16, iCg16, iCb16; + mng_uint8 iCr8, iCg8, iCb8; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_RGBA8, MNG_LC_START) +#endif + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination row */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination row starting-point */ + pScanline = pScanline + (pData->iCol << 2) + (pData->iDestl << 2); + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 3); + else + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 2); + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+4); + *(pScanline+3) = *(pDataline+6); + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *(pDataline+2); + *(pScanline+3) = *(pDataline+3); + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* get alpha values */ + iFGa16 = mng_get_uint16 (pDataline+6); + iBGa16 = (mng_uint16)(*(pScanline+3)); + iBGa16 = (mng_uint16)(iBGa16 << 8) | iBGa16; + + if (iFGa16) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa16 == 0xFFFF) || (iBGa16 == 0)) + { /* plain copy it */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+4); + *(pScanline+3) = *(pDataline+6); + } + else + { + if (iBGa16 == 0xFFFF) /* background fully opaque ? */ + { /* get the proper values */ + iFGr16 = mng_get_uint16 (pDataline ); + iFGg16 = mng_get_uint16 (pDataline+2); + iFGb16 = mng_get_uint16 (pDataline+4); + /* scale background up */ + iBGr16 = (mng_uint16)(*pScanline ); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*(pScanline+2)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* now compose */ + MNG_COMPOSE16(iFGr16, iFGr16, iFGa16, iBGr16) + MNG_COMPOSE16(iFGg16, iFGg16, iFGa16, iBGg16) + MNG_COMPOSE16(iFGb16, iFGb16, iFGa16, iBGb16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iFGr16 >> 8); + *(pScanline+1) = (mng_uint8)(iFGg16 >> 8); + *(pScanline+2) = (mng_uint8)(iFGb16 >> 8); + /* alpha remains fully opaque !!! */ + } + else + { /* scale background up */ + iBGr16 = (mng_uint16)(*pScanline ); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*(pScanline+2)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* let's blend */ + MNG_BLEND16 (mng_get_uint16 (pDataline ), + mng_get_uint16 (pDataline+2), + mng_get_uint16 (pDataline+4), iFGa16, + iBGr16, iBGg16, iBGb16, iBGa16, + iCr16, iCg16, iCb16, iCa16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iCr16 >> 8); + *(pScanline+1) = (mng_uint8)(iCg16 >> 8); + *(pScanline+2) = (mng_uint8)(iCb16 >> 8); + *(pScanline+3) = (mng_uint8)(iCa16 >> 8); + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iFGa8 = *(pDataline+3); /* get alpha values */ + iBGa8 = *(pScanline+3); + + if (iFGa8) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa8 == 0xFF) || (iBGa8 == 0)) + { /* then simply copy the values */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *(pDataline+2); + *(pScanline+3) = *(pDataline+3); + } + else + { + if (iBGa8 == 0xFF) /* background fully opaque ? */ + { /* do alpha composing */ + MNG_COMPOSE8 (*pScanline, *pDataline, iFGa8, *pScanline ) + MNG_COMPOSE8 (*(pScanline+1), *(pDataline+1), iFGa8, *(pScanline+1)) + MNG_COMPOSE8 (*(pScanline+2), *(pDataline+2), iFGa8, *(pScanline+2)) + /* alpha remains fully opaque !!! */ + } + else + { /* now blend */ + MNG_BLEND8 (*pDataline, *(pDataline+1), *(pDataline+2), iFGa8, + *pScanline, *(pScanline+1), *(pScanline+2), iBGa8, + iCr8, iCg8, iCb8, iCa8) + /* and return the composed values */ + *pScanline = iCr8; + *(pScanline+1) = iCg8; + *(pScanline+2) = iCb8; + *(pScanline+3) = iCa8; + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_RGBA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_argb8 (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint16 iFGa16, iBGa16, iCa16; + mng_uint8 iFGa8, iBGa8, iCa8; + mng_uint16 iFGr16, iFGg16, iFGb16; + mng_uint16 iBGr16, iBGg16, iBGb16; + mng_uint16 iCr16, iCg16, iCb16; + mng_uint8 iCr8, iCg8, iCb8; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_ARGB8, MNG_LC_START) +#endif + + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination row */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination row starting-point */ + pScanline = pScanline + (pData->iCol << 2) + (pData->iDestl << 2); + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 3); + else + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 2); + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + *pScanline = *(pDataline+6); + *(pScanline+1) = *pDataline; + *(pScanline+2) = *(pDataline+2); + *(pScanline+3) = *(pDataline+4); + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values */ + *pScanline = *(pDataline+2); + *(pScanline+1) = *pDataline; + *(pScanline+2) = *(pDataline+1); + *(pScanline+3) = *(pDataline+2); + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* get alpha values */ + iFGa16 = mng_get_uint16 (pDataline+6); + iBGa16 = (mng_uint16)(*pScanline); + iBGa16 = (mng_uint16)(iBGa16 << 8) | iBGa16; + + if (iFGa16) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa16 == 0xFFFF) || (iBGa16 == 0)) + { /* plain copy it */ + *pScanline = *(pDataline+6); + *(pScanline+1) = *pDataline; + *(pScanline+2) = *(pDataline+2); + *(pScanline+3) = *(pDataline+4); + } + else + { + if (iBGa16 == 0xFFFF) /* background fully opaque ? */ + { /* get the proper values */ + iFGr16 = mng_get_uint16 (pDataline ); + iFGg16 = mng_get_uint16 (pDataline+2); + iFGb16 = mng_get_uint16 (pDataline+4); + /* scale background up */ + iBGr16 = (mng_uint16)(*(pScanline+1)); + iBGg16 = (mng_uint16)(*(pScanline+2)); + iBGb16 = (mng_uint16)(*(pScanline+3)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* now compose */ + MNG_COMPOSE16(iFGr16, iFGr16, iFGa16, iBGr16) + MNG_COMPOSE16(iFGg16, iFGg16, iFGa16, iBGg16) + MNG_COMPOSE16(iFGb16, iFGb16, iFGa16, iBGb16) + /* and return the composed values */ + /* alpha remains fully opaque !!! */ + *(pScanline+1) = (mng_uint8)(iFGr16 >> 8); + *(pScanline+2) = (mng_uint8)(iFGg16 >> 8); + *(pScanline+3) = (mng_uint8)(iFGb16 >> 8); + } + else + { /* scale background up */ + iBGr16 = (mng_uint16)(*(pScanline+1)); + iBGg16 = (mng_uint16)(*(pScanline+2)); + iBGb16 = (mng_uint16)(*(pScanline+3)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* let's blend */ + MNG_BLEND16 (mng_get_uint16 (pDataline ), + mng_get_uint16 (pDataline+2), + mng_get_uint16 (pDataline+4), iFGa16, + iBGr16, iBGg16, iBGb16, iBGa16, + iCr16, iCg16, iCb16, iCa16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iCa16 >> 8); + *(pScanline+1) = (mng_uint8)(iCr16 >> 8); + *(pScanline+2) = (mng_uint8)(iCg16 >> 8); + *(pScanline+3) = (mng_uint8)(iCb16 >> 8); + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iFGa8 = *(pDataline+3); /* get alpha values */ + iBGa8 = *pScanline; + + if (iFGa8) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa8 == 0xFF) || (iBGa8 == 0)) + { /* then simply copy the values */ + *pScanline = *(pDataline+3); + *(pScanline+1) = *pDataline; + *(pScanline+2) = *(pDataline+1); + *(pScanline+3) = *(pDataline+2); + } + else + { + if (iBGa8 == 0xFF) /* background fully opaque ? */ + { /* do simple alpha composing */ + /* alpha itself remains fully opaque !!! */ + MNG_COMPOSE8 (*(pScanline+1), *pDataline, iFGa8, *(pScanline+1)) + MNG_COMPOSE8 (*(pScanline+2), *(pDataline+1), iFGa8, *(pScanline+2)) + MNG_COMPOSE8 (*(pScanline+3), *(pDataline+2), iFGa8, *(pScanline+3)) + } + else + { /* now blend */ + MNG_BLEND8 (*pDataline, *(pDataline+1), *(pDataline+2), iFGa8, + *(pScanline+1), *(pScanline+2), *(pScanline+3), iBGa8, + iCr8, iCg8, iCb8, iCa8) + /* and return the composed values */ + *pScanline = iCa8; + *(pScanline+1) = iCr8; + *(pScanline+2) = iCg8; + *(pScanline+3) = iCb8; + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_ARGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_rgb8_a8 (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pAlphaline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint16 iFGa16, iBGa16, iCa16; + mng_uint8 iFGa8, iBGa8, iCa8; + mng_uint16 iFGr16, iFGg16, iFGb16; + mng_uint16 iBGr16, iBGg16, iBGb16; + mng_uint16 iCr16, iCg16, iCb16; + mng_uint8 iCr8, iCg8, iCb8; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_RGB8_A8, MNG_LC_START) +#endif + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination rows */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + pAlphaline = (mng_uint8p)pData->fGetalphaline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination rows starting-point */ + pScanline = pScanline + (pData->iCol * 3) + (pData->iDestl * 3); + pAlphaline = pAlphaline + pData->iCol + pData->iDestl; + + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 3); + else + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 2); + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+4); + *pAlphaline = *(pDataline+6); + + pScanline += (pData->iColinc * 3); + pAlphaline += pData->iColinc; + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *(pDataline+2); + *pAlphaline = *(pDataline+3); + + pScanline += (pData->iColinc * 3); + pAlphaline += pData->iColinc; + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* get alpha values */ + iFGa16 = mng_get_uint16 (pDataline+6); + iBGa16 = (mng_uint16)(*pAlphaline); + iBGa16 = (mng_uint16)(iBGa16 << 8) | iBGa16; + + if (iFGa16) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa16 == 0xFFFF) || (iBGa16 == 0)) + { /* plain copy it */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+4); + *pAlphaline = *(pDataline+6); + } + else + { + if (iBGa16 == 0xFFFF) /* background fully opaque ? */ + { /* get the proper values */ + iFGr16 = mng_get_uint16 (pDataline ); + iFGg16 = mng_get_uint16 (pDataline+2); + iFGb16 = mng_get_uint16 (pDataline+4); + /* scale background up */ + iBGr16 = (mng_uint16)(*pScanline ); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*(pScanline+2)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* now compose */ + MNG_COMPOSE16(iFGr16, iFGr16, iFGa16, iBGr16) + MNG_COMPOSE16(iFGg16, iFGg16, iFGa16, iBGg16) + MNG_COMPOSE16(iFGb16, iFGb16, iFGa16, iBGb16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iFGr16 >> 8); + *(pScanline+1) = (mng_uint8)(iFGg16 >> 8); + *(pScanline+2) = (mng_uint8)(iFGb16 >> 8); + /* alpha remains fully opaque !!! */ + } + else + { /* scale background up */ + iBGr16 = (mng_uint16)(*pScanline ); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*(pScanline+2)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* let's blend */ + MNG_BLEND16 (mng_get_uint16 (pDataline ), + mng_get_uint16 (pDataline+2), + mng_get_uint16 (pDataline+4), iFGa16, + iBGr16, iBGg16, iBGb16, iBGa16, + iCr16, iCg16, iCb16, iCa16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iCr16 >> 8); + *(pScanline+1) = (mng_uint8)(iCg16 >> 8); + *(pScanline+2) = (mng_uint8)(iCb16 >> 8); + *pAlphaline = (mng_uint8)(iCa16 >> 8); + } + } + } + + pScanline += (pData->iColinc * 3); + pAlphaline += pData->iColinc; + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iFGa8 = *(pDataline+3); /* get alpha values */ + iBGa8 = *(pScanline+3); + + if (iFGa8) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa8 == 0xFF) || (iBGa8 == 0)) + { /* then simply copy the values */ + *pScanline = *pDataline; + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *(pDataline+2); + *pAlphaline = *(pDataline+3); + } + else + { + if (iBGa8 == 0xFF) /* background fully opaque ? */ + { /* do alpha composing */ + MNG_COMPOSE8 (*pScanline, *pDataline, iFGa8, *pScanline ) + MNG_COMPOSE8 (*(pScanline+1), *(pDataline+1), iFGa8, *(pScanline+1)) + MNG_COMPOSE8 (*(pScanline+2), *(pDataline+2), iFGa8, *(pScanline+2)) + /* alpha remains fully opaque !!! */ + } + else + { /* now blend */ + MNG_BLEND8 (*pDataline, *(pDataline+1), *(pDataline+2), iFGa8, + *pScanline, *(pScanline+1), *(pScanline+2), iBGa8, + iCr8, iCg8, iCb8, iCa8) + /* and return the composed values */ + *pScanline = iCr8; + *(pScanline+1) = iCg8; + *(pScanline+2) = iCb8; + *pAlphaline = iCa8; + } + } + } + + pScanline += (pData->iColinc * 3); + pAlphaline += pData->iColinc; + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_RGB8_A8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_bgr8 (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint16 iA16; + mng_uint16 iFGr16, iFGg16, iFGb16; + mng_uint16 iBGr16, iBGg16, iBGb16; + mng_uint8 iA8; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_BGR8, MNG_LC_START) +#endif + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination row */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination row starting-point */ + pScanline = pScanline + (pData->iCol * 3) + (pData->iDestl * 3); + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + (pData->iSourcel / pData->iColinc) * 8; + else + pDataline = pDataline + (pData->iSourcel / pData->iColinc) * 4; + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + *pScanline = *(pDataline+4); + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *pDataline; + + pScanline += (pData->iColinc * 3); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values */ + *pScanline = *(pDataline+2); + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *pDataline; + + pScanline += (pData->iColinc * 3); + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* get alpha value */ + iA16 = mng_get_uint16 (pDataline+6); + + if (iA16) /* any opacity at all ? */ + { + if (iA16 == 0xFFFF) /* fully opaque ? */ + { /* scale down by dropping the LSB */ + *pScanline = *(pDataline+4); + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *pDataline; + } + else + { /* get the proper values */ + iFGr16 = mng_get_uint16 (pDataline ); + iFGg16 = mng_get_uint16 (pDataline+2); + iFGb16 = mng_get_uint16 (pDataline+4); + /* scale background up */ + iBGr16 = (mng_uint16)(*(pScanline+2)); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*pScanline ); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* now compose */ + MNG_COMPOSE16(iFGr16, iFGr16, iA16, iBGr16) + MNG_COMPOSE16(iFGg16, iFGg16, iA16, iBGg16) + MNG_COMPOSE16(iFGb16, iFGb16, iA16, iBGb16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iFGb16 >> 8); + *(pScanline+1) = (mng_uint8)(iFGg16 >> 8); + *(pScanline+2) = (mng_uint8)(iFGr16 >> 8); + } + } + + pScanline += (pData->iColinc * 3); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iA8 = *(pDataline+3); /* get alpha value */ + + if (iA8) /* any opacity at all ? */ + { + if (iA8 == 0xFF) /* fully opaque ? */ + { /* then simply copy the values */ + *pScanline = *(pDataline+2); + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *pDataline; + } + else + { /* do alpha composing */ + MNG_COMPOSE8 (*pScanline, *(pDataline+2), iA8, *pScanline ) + MNG_COMPOSE8 (*(pScanline+1), *(pDataline+1), iA8, *(pScanline+1)) + MNG_COMPOSE8 (*(pScanline+2), *pDataline, iA8, *(pScanline+2)) + } + } + + pScanline += (pData->iColinc * 3); + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_BGR8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_bgra8 (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint16 iFGa16, iBGa16, iCa16; + mng_uint8 iFGa8, iBGa8, iCa8; + mng_uint16 iFGr16, iFGg16, iFGb16; + mng_uint16 iBGr16, iBGg16, iBGb16; + mng_uint16 iCr16, iCg16, iCb16; + mng_uint8 iCr8, iCg8, iCb8; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_BGRA8, MNG_LC_START) +#endif + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination row */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination row starting-point */ + pScanline = pScanline + (pData->iCol << 2) + (pData->iDestl << 2); + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 3); + else + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 2); + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + *pScanline = *(pDataline+4); + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *pDataline; + *(pScanline+3) = *(pDataline+6); + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values */ + *pScanline = *(pDataline+2); + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *pDataline; + *(pScanline+3) = *(pDataline+3); + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* get alpha values */ + iFGa16 = mng_get_uint16 (pDataline+6); + iBGa16 = (mng_uint16)(*(pScanline+3)); + iBGa16 = (mng_uint16)(iBGa16 << 8) | iBGa16; + + if (iFGa16) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa16 == 0xFFFF) || (iBGa16 == 0)) + { /* plain copy it */ + *pScanline = *(pDataline+4); + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *pDataline; + *(pScanline+3) = *(pDataline+6); + } + else + { + if (iBGa16 == 0xFFFF) /* background fully opaque ? */ + { /* get the proper values */ + iFGr16 = mng_get_uint16 (pDataline ); + iFGg16 = mng_get_uint16 (pDataline+2); + iFGb16 = mng_get_uint16 (pDataline+4); + /* scale background up */ + iBGr16 = (mng_uint16)(*(pScanline+2)); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*pScanline ); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* now compose */ + MNG_COMPOSE16(iFGr16, iFGr16, iFGa16, iBGr16) + MNG_COMPOSE16(iFGg16, iFGg16, iFGa16, iBGg16) + MNG_COMPOSE16(iFGb16, iFGb16, iFGa16, iBGb16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iFGb16 >> 8); + *(pScanline+1) = (mng_uint8)(iFGg16 >> 8); + *(pScanline+2) = (mng_uint8)(iFGr16 >> 8); + /* alpha remains fully opaque !!! */ + } + else + { /* scale background up */ + iBGr16 = (mng_uint16)(*(pScanline+2)); + iBGg16 = (mng_uint16)(*(pScanline+1)); + iBGb16 = (mng_uint16)(*pScanline ); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* let's blend */ + MNG_BLEND16 (mng_get_uint16 (pDataline ), + mng_get_uint16 (pDataline+2), + mng_get_uint16 (pDataline+4), iFGa16, + iBGr16, iBGg16, iBGb16, iBGa16, + iCr16, iCg16, iCb16, iCa16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iCb16 >> 8); + *(pScanline+1) = (mng_uint8)(iCg16 >> 8); + *(pScanline+2) = (mng_uint8)(iCr16 >> 8); + *(pScanline+3) = (mng_uint8)(iCa16 >> 8); + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iFGa8 = *(pDataline+3); /* get alpha values */ + iBGa8 = *(pScanline+3); + + if (iFGa8) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa8 == 0xFF) || (iBGa8 == 0)) + { /* then simply copy the values */ + *pScanline = *(pDataline+2); + *(pScanline+1) = *(pDataline+1); + *(pScanline+2) = *pDataline; + *(pScanline+3) = *(pDataline+3); + } + else + { + if (iBGa8 == 0xFF) /* background fully opaque ? */ + { /* do alpha composing */ + MNG_COMPOSE8 (*pScanline, *(pDataline+2), iFGa8, *pScanline ) + MNG_COMPOSE8 (*(pScanline+1), *(pDataline+1), iFGa8, *(pScanline+1)) + MNG_COMPOSE8 (*(pScanline+2), *pDataline, iFGa8, *(pScanline+2)) + /* alpha remains fully opaque !!! */ + } + else + { /* now blend */ + MNG_BLEND8 (*pDataline, *(pDataline+1), *(pDataline+2), iFGa8, + *(pScanline+2), *(pScanline+1), *pScanline, iBGa8, + iCr8, iCg8, iCb8, iCa8) + /* and return the composed values */ + *pScanline = iCb8; + *(pScanline+1) = iCg8; + *(pScanline+2) = iCr8; + *(pScanline+3) = iCa8; + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_BGRA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_bgra8_pm (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint32 s, t; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_BGRA8PM, MNG_LC_START) +#endif + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination row */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination row starting-point */ + pScanline = pScanline + (pData->iCol << 2) + (pData->iDestl << 2); + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 3); + else + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 2); + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + if ((s = pDataline[6]) == 0) + *(mng_uint32*) pScanline = 0; /* set all components = 0 */ + else + { + if (s == 255) + { + pScanline[0] = pDataline[4]; + pScanline[1] = pDataline[2]; + pScanline[2] = pDataline[0]; + pScanline[3] = 255; + } + else + { + pScanline[0] = DIV255B8(s * pDataline[4]); + pScanline[1] = DIV255B8(s * pDataline[2]); + pScanline[2] = DIV255B8(s * pDataline[0]); + pScanline[3] = (mng_uint8)s; + } + } + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values and premultiply */ + if ((s = pDataline[3]) == 0) + *(mng_uint32*) pScanline = 0; /* set all components = 0 */ + else + { + if (s == 255) + { + pScanline[0] = pDataline[2]; + pScanline[1] = pDataline[1]; + pScanline[2] = pDataline[0]; + pScanline[3] = 255; + } + else + { + pScanline[0] = DIV255B8(s * pDataline[2]); + pScanline[1] = DIV255B8(s * pDataline[1]); + pScanline[2] = DIV255B8(s * pDataline[0]); + pScanline[3] = (mng_uint8)s; + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* get alpha values */ + if ((s = pDataline[6]) != 0) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if (s == 255) + { /* plain copy it */ + pScanline[0] = pDataline[4]; + pScanline[1] = pDataline[2]; + pScanline[2] = pDataline[0]; + pScanline[3] = 255; + } + else + { /* now blend (premultiplied) */ + t = 255 - s; + pScanline[0] = DIV255B8(s * pDataline[4] + t * pScanline[0]); + pScanline[1] = DIV255B8(s * pDataline[2] + t * pScanline[1]); + pScanline[2] = DIV255B8(s * pDataline[0] + t * pScanline[2]); + pScanline[3] = (mng_uint8)(255 - DIV255B8(t * (255 - pScanline[3]))); + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + if ((s = pDataline[3]) != 0) /* any opacity at all ? */ + { /* fully opaque ? */ + if (s == 255) + { /* then simply copy the values */ + pScanline[0] = pDataline[2]; + pScanline[1] = pDataline[1]; + pScanline[2] = pDataline[0]; + pScanline[3] = 255; + } + else + { /* now blend (premultiplied) */ + t = 255 - s; + pScanline[0] = DIV255B8(s * pDataline[2] + t * pScanline[0]); + pScanline[1] = DIV255B8(s * pDataline[1] + t * pScanline[1]); + pScanline[2] = DIV255B8(s * pDataline[0] + t * pScanline[2]); + pScanline[3] = (mng_uint8)(255 - DIV255B8(t * (255 - pScanline[3]))); + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_BGRA8PM, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode display_abgr8 (mng_datap pData) +{ + mng_uint8p pScanline; + mng_uint8p pDataline; + mng_int32 iX; + mng_uint16 iFGa16, iBGa16, iCa16; + mng_uint8 iFGa8, iBGa8, iCa8; + mng_uint16 iFGr16, iFGg16, iFGb16; + mng_uint16 iBGr16, iBGg16, iBGb16; + mng_uint16 iCr16, iCg16, iCb16; + mng_uint8 iCr8, iCg8, iCb8; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_ABGR8, MNG_LC_START) +#endif + /* viewable row ? */ + if ((pData->iRow >= pData->iSourcet) && (pData->iRow < pData->iSourceb)) + { /* address destination row */ + pScanline = (mng_uint8p)pData->fGetcanvasline (((mng_handle)pData), + pData->iRow + pData->iDestt - + pData->iSourcet); + /* adjust destination row starting-point */ + pScanline = pScanline + (pData->iCol << 2) + (pData->iDestl << 2); + pDataline = pData->pRGBArow; /* address source row */ + + if (pData->bIsRGBA16) /* adjust source row starting-point */ + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 3); + else + pDataline = pDataline + ((pData->iSourcel / pData->iColinc) << 2); + + if (pData->bIsOpaque) /* forget about transparency ? */ + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* scale down by dropping the LSB */ + *pScanline = *(pDataline+6); + *(pScanline+1) = *(pDataline+4); + *(pScanline+2) = *(pDataline+2); + *(pScanline+3) = *pDataline; + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* copy the values */ + *pScanline = *(pDataline+3); + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+1); + *(pScanline+3) = *pDataline; + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + else + { + if (pData->bIsRGBA16) /* 16-bit input row ? */ + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { /* get alpha values */ + iFGa16 = mng_get_uint16 (pDataline+6); + iBGa16 = (mng_uint16)(*pScanline); + iBGa16 = (mng_uint16)(iBGa16 << 8) | iBGa16; + + if (iFGa16) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa16 == 0xFFFF) || (iBGa16 == 0)) + { /* plain copy it */ + *pScanline = *(pDataline+6); + *(pScanline+1) = *(pDataline+4); + *(pScanline+2) = *(pDataline+2); + *(pScanline+3) = *pDataline; + } + else + { + if (iBGa16 == 0xFFFF) /* background fully opaque ? */ + { /* get the proper values */ + iFGr16 = mng_get_uint16 (pDataline ); + iFGg16 = mng_get_uint16 (pDataline+2); + iFGb16 = mng_get_uint16 (pDataline+4); + /* scale background up */ + iBGr16 = (mng_uint16)(*(pScanline+3)); + iBGg16 = (mng_uint16)(*(pScanline+2)); + iBGb16 = (mng_uint16)(*(pScanline+1)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* now compose */ + MNG_COMPOSE16(iFGr16, iFGr16, iFGa16, iBGr16) + MNG_COMPOSE16(iFGg16, iFGg16, iFGa16, iBGg16) + MNG_COMPOSE16(iFGb16, iFGb16, iFGa16, iBGb16) + /* and return the composed values */ + /* alpha itself remains fully opaque !!! */ + *(pScanline+1) = (mng_uint8)(iFGb16 >> 8); + *(pScanline+2) = (mng_uint8)(iFGg16 >> 8); + *(pScanline+3) = (mng_uint8)(iFGr16 >> 8); + } + else + { /* scale background up */ + iBGr16 = (mng_uint16)(*(pScanline+3)); + iBGg16 = (mng_uint16)(*(pScanline+2)); + iBGb16 = (mng_uint16)(*(pScanline+1)); + iBGr16 = (mng_uint16)((mng_uint32)iBGr16 << 8) | iBGr16; + iBGg16 = (mng_uint16)((mng_uint32)iBGg16 << 8) | iBGg16; + iBGb16 = (mng_uint16)((mng_uint32)iBGb16 << 8) | iBGb16; + /* let's blend */ + MNG_BLEND16 (mng_get_uint16 (pDataline ), + mng_get_uint16 (pDataline+2), + mng_get_uint16 (pDataline+4), iFGa16, + iBGr16, iBGg16, iBGb16, iBGa16, + iCr16, iCg16, iCb16, iCa16) + /* and return the composed values */ + *pScanline = (mng_uint8)(iCa16 >> 8); + *(pScanline+1) = (mng_uint8)(iCb16 >> 8); + *(pScanline+2) = (mng_uint8)(iCg16 >> 8); + *(pScanline+3) = (mng_uint8)(iCr16 >> 8); + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 8; + } + } + else + { + for (iX = pData->iSourcel + pData->iCol; iX < pData->iSourcer; iX += pData->iColinc) + { + iFGa8 = *(pDataline+3); /* get alpha values */ + iBGa8 = *pScanline; + + if (iFGa8) /* any opacity at all ? */ + { /* fully opaque or background fully transparent ? */ + if ((iFGa8 == 0xFF) || (iBGa8 == 0)) + { /* then simply copy the values */ + *pScanline = *(pDataline+3); + *(pScanline+1) = *(pDataline+2); + *(pScanline+2) = *(pDataline+1); + *(pScanline+3) = *pDataline; + } + else + { + if (iBGa8 == 0xFF) /* background fully opaque ? */ + { /* do simple alpha composing */ + /* alpha itself remains fully opaque !!! */ + MNG_COMPOSE8 (*(pScanline+1), *(pDataline+2), iFGa8, *(pScanline+1)) + MNG_COMPOSE8 (*(pScanline+2), *(pDataline+1), iFGa8, *(pScanline+2)) + MNG_COMPOSE8 (*(pScanline+3), *pDataline, iFGa8, *(pScanline+3)) + } + else + { /* now blend */ + MNG_BLEND8 (*pDataline, *(pDataline+1), *(pDataline+2), iFGa8, + *(pScanline+3), *(pScanline+2), *(pScanline+1), iBGa8, + iCr8, iCg8, iCb8, iCa8) + /* and return the composed values */ + *pScanline = iCa8; + *(pScanline+1) = iCb8; + *(pScanline+2) = iCg8; + *(pScanline+3) = iCr8; + } + } + } + + pScanline += (pData->iColinc << 2); + pDataline += 4; + } + } + } + } + + check_update_region (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_ABGR8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Background restore routines - restore the background with info from * */ +/* * the BACK and/or bKGD chunk or the app's background canvas * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode restore_bkgd_backimage (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BACKIMAGE, MNG_LC_START) +#endif + /* make it easy on yourself */ + iRetcode = restore_bkgd_backcolor (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + + /* TODO: loading the background-image */ + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BACKIMAGE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode restore_bkgd_backcolor (mng_datap pData) +{ + mng_int32 iX; + mng_uint8p pWork = pData->pRGBArow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BACKCOLOR, MNG_LC_START) +#endif + + for (iX = pData->iSourcel; iX < pData->iSourcer; iX++) + { /* ok; drop the background-color in there */ + *pWork = (mng_uint8)(pData->iBACKred >> 8); + *(pWork+1) = (mng_uint8)(pData->iBACKgreen >> 8); + *(pWork+2) = (mng_uint8)(pData->iBACKblue >> 8); + *(pWork+3) = 0xFF; /* opaque! it's mandatory */ + + pWork += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BACKCOLOR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode restore_bkgd_bkgd (mng_datap pData) +{ + mng_int32 iX; + mng_uint8p pWork = pData->pRGBArow; + mng_imagep pImage; + mng_imagedatap pBuf; + mng_uint8 iRed = 0; + mng_uint8 iGreen = 0; + mng_uint8 iBlue = 0; + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BKGD, MNG_LC_START) +#endif + /* determine the correct image buffer */ + pImage = (mng_imagep)pData->pCurrentobj; + + if (!pImage) + pImage = (mng_imagep)pData->pObjzero; + + pBuf = pImage->pImgbuf; + + switch (pBuf->iColortype) + { + case 0 : ; /* gray types */ + case 4 : { + mng_uint8 iGray; + + if (pBuf->iBitdepth > 8) + iGray = (mng_uint8)(pBuf->iBKGDgray >> 8); + else + { + iGray = (mng_uint8)pBuf->iBKGDgray; + /* please note how tricky the next code is !! */ + switch (pBuf->iBitdepth) + { + case 1 : iGray = (mng_uint8)((iGray << 1) + iGray); + case 2 : iGray = (mng_uint8)((iGray << 2) + iGray); + case 4 : iGray = (mng_uint8)((iGray << 4) + iGray); + } + } + + iRed = iGray; + iGreen = iGray; + iBlue = iGray; + + break; + } + + case 3 : { /* indexed type */ + iRed = pBuf->aPLTEentries [pBuf->iBKGDindex].iRed; + iGreen = pBuf->aPLTEentries [pBuf->iBKGDindex].iGreen; + iBlue = pBuf->aPLTEentries [pBuf->iBKGDindex].iBlue; + + break; + } + + case 2 : ; /* rgb types */ + case 6 : { + if (pBuf->iBitdepth > 8) + { + iRed = (mng_uint8)(pBuf->iBKGDred >> 8); + iGreen = (mng_uint8)(pBuf->iBKGDgreen >> 8); + iBlue = (mng_uint8)(pBuf->iBKGDblue >> 8); + } + else + { + iRed = (mng_uint8)(pBuf->iBKGDred ); + iGreen = (mng_uint8)(pBuf->iBKGDgreen); + iBlue = (mng_uint8)(pBuf->iBKGDblue ); + } + + break; + } + } + + for (iX = pData->iSourcel; iX < pData->iSourcer; iX++) + { + *pWork = iRed; + *(pWork+1) = iGreen; + *(pWork+2) = iBlue; + *(pWork+3) = 0x00; /* transparant for alpha-canvasses */ + + pWork += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode restore_bkgd_bgcolor (mng_datap pData) +{ + mng_int32 iX; + mng_uint8p pWork = pData->pRGBArow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BGCOLOR, MNG_LC_START) +#endif + + for (iX = pData->iSourcel; iX < pData->iSourcer; iX++) + { /* ok; drop the background-color in there */ + *pWork = (mng_uint8)(pData->iBGred >> 8); + *(pWork+1) = (mng_uint8)(pData->iBGgreen >> 8); + *(pWork+2) = (mng_uint8)(pData->iBGblue >> 8); + *(pWork+3) = 0x00; /* transparant for alpha-canvasses */ + + pWork += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BGCOLOR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode restore_bkgd_rgb8 (mng_datap pData) +{ + mng_int32 iX; + mng_uint8p pBkgd; + mng_uint8p pWork = pData->pRGBArow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_RGB8, MNG_LC_START) +#endif + + if (pData->fGetbkgdline) /* can we access the background ? */ + { /* point to the right pixel then */ + pBkgd = (mng_uint8p)pData->fGetbkgdline ((mng_handle)pData, + pData->iRow + pData->iDestt) + + (3 * pData->iDestl); + + for (iX = pData->iSourcel; iX < pData->iSourcer; iX++) + { + *pWork = *pBkgd; /* ok; copy the pixel */ + *(pWork+1) = *(pBkgd+1); + *(pWork+2) = *(pBkgd+2); + *(pWork+3) = 0x00; /* transparant for alpha-canvasses */ + + pWork += 4; + pBkgd += 3; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode restore_bkgd_bgr8 (mng_datap pData) +{ + mng_int32 iX; + mng_uint8p pBkgd; + mng_uint8p pWork = pData->pRGBArow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BGR8, MNG_LC_START) +#endif + + if (pData->fGetbkgdline) /* can we access the background ? */ + { /* point to the right pixel then */ + pBkgd = (mng_uint8p)pData->fGetbkgdline ((mng_handle)pData, + pData->iRow + pData->iDestt) + + (3 * pData->iDestl); + + for (iX = pData->iSourcel; iX < pData->iSourcer; iX++) + { + *pWork = *(pBkgd+2); /* ok; copy the pixel */ + *(pWork+1) = *(pBkgd+1); + *(pWork+2) = *pBkgd; + *(pWork+3) = 0x00; /* transparant for alpha-canvasses */ + + pWork += 4; + pBkgd += 3; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RESTORE_BGR8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Row retrieval routines - retrieve processed & uncompressed row-data * */ +/* * from the current "object" * */ +/* * * */ +/* ************************************************************************** */ + +/* TODO: a serious optimization is to retrieve only those pixels that will + actually be displayed; this would require changes in + the "display_image" routine (in mng_display.c) & + all the "retrieve_xxx" routines below & + the "display_xxx" routines above !!!!! + NOTE that "correct_xxx" routines would not require modification */ + +mng_retcode retrieve_g8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_G8, MNG_LC_START) +#endif + + pRGBArow = pData->pRGBArow; /* temporary work pointers */ + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + + if (pBuf->bHasTRNS) /* tRNS in buffer ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iG = *pWorkrow; /* get the gray-value */ + /* is it transparent ? */ + if ((mng_uint16)iG == pBuf->iTRNSgray) + { + *pRGBArow = 0x00; /* nuttin to display */ + *(pRGBArow+1) = 0x00; + *(pRGBArow+2) = 0x00; + *(pRGBArow+3) = 0x00; + } + else + { + switch (pBuf->iBitdepth) /* LBR to 8-bits ! */ + { + case 1 : iG = (mng_uint8)((iG << 1) + iG); + case 2 : iG = (mng_uint8)((iG << 2) + iG); + case 4 : iG = (mng_uint8)((iG << 4) + iG); + } + + *pRGBArow = iG; /* put in intermediate row */ + *(pRGBArow+1) = iG; + *(pRGBArow+2) = iG; + *(pRGBArow+3) = 0xFF; + } + + pWorkrow++; /* next pixel */ + pRGBArow += 4; + } + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iG = *pWorkrow; /* get the gray-value */ + + switch (pBuf->iBitdepth) /* LBR to 8-bits ! */ + { + case 1 : iG = (mng_uint8)((iG << 1) + iG); + case 2 : iG = (mng_uint8)((iG << 2) + iG); + case 4 : iG = (mng_uint8)((iG << 4) + iG); + } + + *pRGBArow = iG; /* put in intermediate row */ + *(pRGBArow+1) = iG; + *(pRGBArow+2) = iG; + *(pRGBArow+3) = 0xFF; + + pWorkrow++; /* next pixel */ + pRGBArow += 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_G8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_g16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint16 iG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_G16, MNG_LC_START) +#endif + /* temporary work pointers */ + pRGBArow = pData->pRGBArow; + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + + if (pBuf->bHasTRNS) /* tRNS in buffer ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iG = mng_get_uint16 (pWorkrow); /* get the gray-value */ + /* is it transparent ? */ + if (iG == pBuf->iTRNSgray) + { /* nuttin to display */ + mng_put_uint16 (pRGBArow, 0x0000); + mng_put_uint16 (pRGBArow+2, 0x0000); + mng_put_uint16 (pRGBArow+4, 0x0000); + mng_put_uint16 (pRGBArow+6, 0x0000); + } + else + { /* put in intermediate row */ + mng_put_uint16 (pRGBArow, iG); + mng_put_uint16 (pRGBArow+2, iG); + mng_put_uint16 (pRGBArow+4, iG); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + } + + pWorkrow += 2; /* next pixel */ + pRGBArow += 8; + } + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iG = mng_get_uint16 (pWorkrow); /* get the gray-value */ + + mng_put_uint16 (pRGBArow, iG); /* and put in intermediate row */ + mng_put_uint16 (pRGBArow+2, iG); + mng_put_uint16 (pRGBArow+4, iG); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + + pWorkrow += 2; /* next pixel */ + pRGBArow += 8; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_G16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_rgb8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iR, iG, iB; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGB8, MNG_LC_START) +#endif + + pRGBArow = pData->pRGBArow; /* temporary work pointers */ + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + + if (pBuf->bHasTRNS) /* tRNS in buffer ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iR = *pWorkrow; /* get the rgb-values */ + iG = *(pWorkrow+1); + iB = *(pWorkrow+2); + /* is it transparent ? */ + if (((mng_uint16)iR == pBuf->iTRNSred ) && + ((mng_uint16)iG == pBuf->iTRNSgreen) && + ((mng_uint16)iB == pBuf->iTRNSblue ) ) + { + *pRGBArow = 0x00; /* nothing to display */ + *(pRGBArow+1) = 0x00; + *(pRGBArow+2) = 0x00; + *(pRGBArow+3) = 0x00; + } + else + { + *pRGBArow = iR; /* put in intermediate row */ + *(pRGBArow+1) = iG; + *(pRGBArow+2) = iB; + *(pRGBArow+3) = 0xFF; + } + + pWorkrow += 3; /* next pixel */ + pRGBArow += 4; + } + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRGBArow = *pWorkrow; /* just copy the pixel */ + *(pRGBArow+1) = *(pWorkrow+1); + *(pRGBArow+2) = *(pWorkrow+2); + *(pRGBArow+3) = 0xFF; + + pWorkrow += 3; /* next pixel */ + pRGBArow += 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_rgb16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint16 iR, iG, iB; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGB16, MNG_LC_START) +#endif + /* temporary work pointers */ + pRGBArow = pData->pRGBArow; + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + + if (pBuf->bHasTRNS) /* tRNS in buffer ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iR = mng_get_uint16 (pWorkrow); /* get the rgb-values */ + iG = mng_get_uint16 (pWorkrow+2); + iB = mng_get_uint16 (pWorkrow+4); + /* is it transparent ? */ + if ((iR == pBuf->iTRNSred ) && + (iG == pBuf->iTRNSgreen) && + (iB == pBuf->iTRNSblue ) ) + { /* nothing to display */ + mng_put_uint16 (pRGBArow, 0x0000); + mng_put_uint16 (pRGBArow+2, 0x0000); + mng_put_uint16 (pRGBArow+4, 0x0000); + mng_put_uint16 (pRGBArow+6, 0x0000); + } + else + { /* put in intermediate row */ + mng_put_uint16 (pRGBArow, iR); + mng_put_uint16 (pRGBArow+2, iG); + mng_put_uint16 (pRGBArow+4, iB); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + } + + pWorkrow += 6; /* next pixel */ + pRGBArow += 8; + } + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* just copy the pixel */ + mng_put_uint16 (pRGBArow, mng_get_uint16 (pWorkrow )); + mng_put_uint16 (pRGBArow+2, mng_get_uint16 (pWorkrow+2)); + mng_put_uint16 (pRGBArow+4, mng_get_uint16 (pWorkrow+4)); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + + pWorkrow += 6; /* next pixel */ + pRGBArow += 8; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGB16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_idx8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_IDX8, MNG_LC_START) +#endif + + pRGBArow = pData->pRGBArow; /* temporary work pointers */ + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + + if (pBuf->bHasTRNS) /* tRNS in buffer ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iQ = *pWorkrow; /* get the index */ + /* is it valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + *pRGBArow = pBuf->aPLTEentries [iQ].iRed; + *(pRGBArow+1) = pBuf->aPLTEentries [iQ].iGreen; + *(pRGBArow+2) = pBuf->aPLTEentries [iQ].iBlue; + /* transparency for this index ? */ + if ((mng_uint32)iQ < pBuf->iTRNScount) + *(pRGBArow+3) = pBuf->aTRNSentries [iQ]; + else + *(pRGBArow+3) = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pWorkrow++; /* next pixel */ + pRGBArow += 4; + } + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iQ = *pWorkrow; /* get the index */ + /* is it valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + *pRGBArow = pBuf->aPLTEentries [iQ].iRed; + *(pRGBArow+1) = pBuf->aPLTEentries [iQ].iGreen; + *(pRGBArow+2) = pBuf->aPLTEentries [iQ].iBlue; + *(pRGBArow+3) = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pWorkrow++; /* next pixel */ + pRGBArow += 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_IDX8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_ga8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_GA8, MNG_LC_START) +#endif + + pRGBArow = pData->pRGBArow; /* temporary work pointers */ + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iG = *pWorkrow; /* get the gray-value */ + *pRGBArow = iG; /* put in intermediate row */ + *(pRGBArow+1) = iG; + *(pRGBArow+2) = iG; + *(pRGBArow+3) = *(pWorkrow+1); + + pWorkrow += 2; /* next pixel */ + pRGBArow += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_GA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_ga16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint16 iG; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_GA16, MNG_LC_START) +#endif + /* temporary work pointers */ + pRGBArow = pData->pRGBArow; + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iG = mng_get_uint16 (pWorkrow); /* get the gray-value */ + + mng_put_uint16 (pRGBArow, iG); /* and put in intermediate row */ + mng_put_uint16 (pRGBArow+2, iG); + mng_put_uint16 (pRGBArow+4, iG); + mng_put_uint16 (pRGBArow+6, mng_get_uint16 (pWorkrow+2)); + + pWorkrow += 4; /* next pixel */ + pRGBArow += 8; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_GA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_rgba8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGBA8, MNG_LC_START) +#endif + + pRGBArow = pData->pRGBArow; /* temporary work pointers */ + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + /* can't be easier than this ! */ + MNG_COPY (pRGBArow, pWorkrow, pBuf->iRowsize) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGBA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode retrieve_rgba16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pRetrieveobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGBA16, MNG_LC_START) +#endif + /* temporary work pointers */ + pRGBArow = pData->pRGBArow; + pWorkrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize); + /* can't be easier than this ! */ + MNG_COPY (pRGBArow, pWorkrow, pBuf->iRowsize) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_RETRIEVE_RGBA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Row storage routines - store processed & uncompressed row-data * */ +/* * into the current "object" * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode store_g1 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G1, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* is it white ? */ + *pOutrow = 0x01; /* white */ + else + *pOutrow = 0x00; /* black */ + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 1; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_g2 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G2, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + + iQ = (mng_uint8)((iB & iM) >> iS); /* get the gray level */ + *pOutrow = iQ; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 2; + iS -= 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_g4 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G4, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + + iQ = (mng_uint8)((iB & iM) >> iS); /* get the gray level */ + *pOutrow = iQ; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 4; + iS -= 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_g8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_g16 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* copy into object buffer */ + mng_put_uint16 (pOutrow, mng_get_uint16 (pWorkrow)); + + pOutrow += (pData->iColinc << 1); /* next pixel */ + pWorkrow += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_G16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_rgb8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGB8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* copy the RGB bytes */ + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + + pWorkrow += 3; /* next pixel */ + pOutrow += (pData->iColinc * 3); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_rgb16 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGB16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + MNG_COPY (pOutrow, pWorkrow, 6) /* copy the RGB bytes */ + + pWorkrow += 6; /* next pixel */ + pOutrow += (pData->iColinc * 6); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGB16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_idx1 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX1, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* store the index */ + *pOutrow = 0x01; + else + *pOutrow = 0x00; + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 1; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_idx2 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX2, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + /* store the index */ + *pOutrow = (mng_uint8)((iB & iM) >> iS); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 2; + iS -= 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_idx4 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX4, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* store the index */ + *pOutrow = (mng_uint8)((iB & iM) >> iS); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 4; + iS -= 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_idx8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_IDX8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_ga8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_GA8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* copy the GA bytes */ + *(pOutrow+1) = *(pWorkrow+1); + + pWorkrow += 2; /* next pixel */ + pOutrow += (pData->iColinc << 1); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_GA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_ga16 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_GA16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + MNG_COPY (pOutrow, pWorkrow, 4) /* copy the GA bytes */ + + pWorkrow += 4; /* next pixel */ + pOutrow += (pData->iColinc << 2); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_GA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_rgba8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGBA8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* copy the RGBA bytes */ + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + *(pOutrow+3) = *(pWorkrow+3); + + pWorkrow += 4; /* next pixel */ + pOutrow += (pData->iColinc << 2); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGBA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode store_rgba16 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGBA16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + MNG_COPY (pOutrow, pWorkrow, 8) /* copy the RGBA bytes */ + + pWorkrow += 8; /* next pixel */ + pOutrow += (pData->iColinc << 3); + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_RGBA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Row storage routines (JPEG) - store processed & uncompressed row-data * */ +/* * into the current "object" * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8, MNG_LC_START) +#endif + + pWorkrow = pData->pJPEGrow; /* temporary work pointers */ + pOutrow = pBuf->pImgdata + (pData->iJPEGrow * pBuf->iRowsize); + /* easy as pie ... */ + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8, MNG_LC_END) +#endif + + return next_jpeg_row (pData); /* we've got one more row of gray-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgb8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8, MNG_LC_START) +#endif + + pWorkrow = pData->pJPEGrow; /* temporary work pointers */ + pOutrow = pBuf->pImgdata + (pData->iJPEGrow * pBuf->iRowsize); + /* easy as pie ... */ + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples * 3) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8, MNG_LC_END) +#endif + + return next_jpeg_row (pData); /* we've got one more row of rgb-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_ga8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_GA8, MNG_LC_START) +#endif + + pWorkrow = pData->pJPEGrow; /* temporary work pointers */ + pOutrow = pBuf->pImgdata + (pData->iJPEGrow * pBuf->iRowsize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* copy into object buffer */ + + pOutrow += 2; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_GA8, MNG_LC_END) +#endif + + return next_jpeg_row (pData); /* we've got one more row of gray-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgba8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGBA8, MNG_LC_START) +#endif + + pWorkrow = pData->pJPEGrow; /* temporary work pointers */ + pOutrow = pBuf->pImgdata + (pData->iJPEGrow * pBuf->iRowsize); + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* copy pixel into object buffer */ + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + + pOutrow += 4; /* next pixel */ + pWorkrow += 3; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGBA8, MNG_LC_END) +#endif + + return next_jpeg_row (pData); /* we've got one more row of rgb-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8_alpha (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_ALPHA, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pJPEGrow2; + pOutrow = pBuf->pImgdata + (pData->iJPEGalpharow * pBuf->iRowsize) + 1; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + + pOutrow += 2; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_ALPHA, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgb8_alpha (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_ALPHA, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pJPEGrow2; + pOutrow = pBuf->pImgdata + (pData->iJPEGalpharow * pBuf->iRowsize) + 3; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + + pOutrow += 4; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_ALPHA, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8_a1 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A1, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 1; + iM = 0; /* start at pixel 0 */ + iB = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* is it opaque ? */ + *pOutrow = 0xFF; /* opaque */ + else + *pOutrow = 0x00; /* transparent */ + + pOutrow += 2; /* next pixel */ + iM >>= 1; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A1, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8_a2 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A2, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 1; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + + switch ((iB & iM) >> iS) /* determine the alpha level */ + { + case 0x03 : { *pOutrow = 0xFF; break; } + case 0x02 : { *pOutrow = 0xAA; break; } + case 0x01 : { *pOutrow = 0x55; break; } + default : { *pOutrow = 0x00; } + } + + pOutrow += 2; /* next pixel */ + iM >>= 2; + iS -= 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A2, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8_a4 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A4, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 1; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the alpha level */ + iQ = (mng_uint8)((iB & iM) >> iS); + iQ = (mng_uint8)(iQ + (iQ << 4)); /* expand to 8-bit by replication */ + + *pOutrow = iQ; /* put in object buffer */ + + pOutrow += 2; /* next pixel */ + iM >>= 4; + iS -= 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A4, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8_a8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 1; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + + pOutrow += 2; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A8, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8_a16 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 1; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* only high-order byte! */ + + pOutrow += 2; /* next pixel */ + pWorkrow += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G8_A16, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgb8_a1 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A1, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 3; + iM = 0; /* start at pixel 0 */ + iB = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* is it opaque ? */ + *pOutrow = 0xFF; /* opaque */ + else + *pOutrow = 0x00; /* transparent */ + + pOutrow += 4; /* next pixel */ + iM >>= 1; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A1, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgb8_a2 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A2, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 3; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + + switch ((iB & iM) >> iS) /* determine the alpha level */ + { + case 0x03 : { *pOutrow = 0xFF; break; } + case 0x02 : { *pOutrow = 0xAA; break; } + case 0x01 : { *pOutrow = 0x55; break; } + default : { *pOutrow = 0x00; } + } + + pOutrow += 4; /* next pixel */ + iM >>= 2; + iS -= 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A2, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgb8_a4 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A4, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 3; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the alpha level */ + iQ = (mng_uint8)((iB & iM) >> iS); + iQ = (mng_uint8)(iQ + (iQ << 4)); /* expand to 8-bit by replication */ + + *pOutrow = iQ; /* put in object buffer */ + + pOutrow += 4; /* next pixel */ + iM >>= 4; + iS -= 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A4, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgb8_a8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 3; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in buffer */ + + pOutrow += 4; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A8, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_rgb8_a16 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 3; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* only high-order byte */ + + pOutrow += 4; /* next pixel */ + pWorkrow += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_RGB8_A16, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g12_a1 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A1, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 2; + iM = 0; /* start at pixel 0 */ + iB = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* opaque ? */ + mng_put_uint16 (pOutrow, 0xFFFF);/* opaque */ + else + mng_put_uint16 (pOutrow, 0x0000);/* transparent */ + + pOutrow += 4; /* next pixel */ + iM >>= 1; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A1, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g12_a2 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A2, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 2; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + + switch ((iB & iM) >> iS) /* determine the gray level */ + { + case 0x03 : { mng_put_uint16 (pOutrow, 0xFFFF); break; } + case 0x02 : { mng_put_uint16 (pOutrow, 0xAAAA); break; } + case 0x01 : { mng_put_uint16 (pOutrow, 0x5555); break; } + default : { mng_put_uint16 (pOutrow, 0x0000); } + } + + pOutrow += 4; /* next pixel */ + iM >>= 2; + iS -= 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A2, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g12_a4 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint16 iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A4, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 2; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the gray level */ + iQ = (mng_uint16)((iB & iM) >> iS); + iQ = (mng_uint16)(iQ + (iQ << 4)); /* expand to 16-bit by replication */ + iQ = (mng_uint16)(iQ + (iQ << 8)); + /* put in object buffer */ + mng_put_uint16 (pOutrow, iQ); + + pOutrow += 4; /* next pixel */ + iM >>= 4; + iS -= 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A4, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g12_a8 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint16 iW; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 2; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iW = (mng_uint16)(*pWorkrow); /* get input byte */ + iW = (mng_uint16)(iW + (iW << 8)); /* expand to 16-bit by replication */ + + mng_put_uint16 (pOutrow, iW); /* put in object buffer */ + + pOutrow += 4; /* next pixel */ + pWorkrow++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A8, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +mng_retcode store_jpeg_g12_a16 (mng_datap pData) +{ + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 2; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* copy it */ + mng_put_uint16 (pOutrow, mng_get_uint16 (pWorkrow)); + + pOutrow += 4; /* next pixel */ + pWorkrow += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_STORE_JPEG_G12_A16, MNG_LC_END) +#endif + + return next_jpeg_alpharow (pData); /* we've got one more row of alpha-samples */ +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ +/* * * */ +/* * Delta-image row routines - apply the processed & uncompressed row-data * */ +/* * onto the target "object" * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode delta_g1 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G1, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* is it white ? */ + *pOutrow = 0xFF; /* white */ + else + *pOutrow = 0x00; /* black */ + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 1; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* invert if it is white ? */ + *pOutrow = (mng_uint8)(*pOutrow ^ 0xFF); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 1; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G1, MNG_LC_END) +#endif + + return store_g1 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_g2 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G2, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + + switch ((iB & iM) >> iS) /* determine the gray level */ + { + case 0x03 : { *pOutrow = 0xFF; break; } + case 0x02 : { *pOutrow = 0xAA; break; } + case 0x01 : { *pOutrow = 0x55; break; } + default : { *pOutrow = 0x00; } + } + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 2; + iS -= 2; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + /* determine the gray level */ + switch (((*pOutrow >> 6) + ((iB & iM) >> iS)) & 0x03) + { + case 0x03 : { *pOutrow = 0xFF; break; } + case 0x02 : { *pOutrow = 0xAA; break; } + case 0x01 : { *pOutrow = 0x55; break; } + default : { *pOutrow = 0x00; } + } + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 2; + iS -= 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G2, MNG_LC_END) +#endif + + return store_g2 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_g4 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G4, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the gray level */ + iQ = (mng_uint8)((iB & iM) >> iS); + /* expand to 8-bit by replication */ + iQ = (mng_uint8)(iQ + (iQ << 4)); + + *pOutrow = iQ; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 4; + iS -= 4; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the gray level */ + iQ = (mng_uint8)(((*pOutrow >> 4) + ((iB & iM) >> iS)) & 0x0F); + /* expand to 8-bit by replication */ + iQ = (mng_uint8)(iQ + (iQ << 4)); + + *pOutrow = iQ; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 4; + iS -= 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G4, MNG_LC_END) +#endif + + return store_g4 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_g8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + pWorkrow++; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + *pOutrow = (mng_uint8)(*pOutrow + *pWorkrow); + + pOutrow += pData->iColinc; /* next pixel */ + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G8, MNG_LC_END) +#endif + + return store_g8 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_g16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + *(pOutrow+1) = *(pWorkrow+1); + /* next pixel */ + pOutrow += (pData->iColinc << 1); + pWorkrow += 2; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + mng_put_uint16 (pOutrow, (mng_uint16)(mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow) )); + /* next pixel */ + pOutrow += (pData->iColinc << 1); + pWorkrow += 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G16, MNG_LC_END) +#endif + + return store_g16 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_rgb8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + /* next pixel */ + pOutrow += (pData->iColinc * 3); + pWorkrow += 3; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + *pOutrow = (mng_uint8)(*pOutrow + *pWorkrow ); + *(pOutrow+1) = (mng_uint8)(*(pOutrow+1) + *(pWorkrow+1)); + *(pOutrow+2) = (mng_uint8)(*(pOutrow+2) + *(pWorkrow+2)); + /* next pixel */ + pOutrow += (pData->iColinc * 3); + pWorkrow += 3; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB8, MNG_LC_END) +#endif + + return store_rgb8 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_rgb16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + *(pOutrow+3) = *(pWorkrow+3); + *(pOutrow+4) = *(pWorkrow+4); + *(pOutrow+5) = *(pWorkrow+5); + /* next pixel */ + pOutrow += (pData->iColinc * 6); + pWorkrow += 6; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + mng_put_uint16 (pOutrow, (mng_uint16)(mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow ) )); + mng_put_uint16 (pOutrow+2, (mng_uint16)(mng_get_uint16 (pOutrow+2 ) + + mng_get_uint16 (pWorkrow+2) )); + mng_put_uint16 (pOutrow+4, (mng_uint16)(mng_get_uint16 (pOutrow+4 ) + + mng_get_uint16 (pWorkrow+4) )); + /* next pixel */ + pOutrow += (pData->iColinc * 6); + pWorkrow += 6; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB16, MNG_LC_END) +#endif + + return store_rgb16 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_idx1 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX1, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* put the right index value */ + *pOutrow = 1; + else + *pOutrow = 0; + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 1; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* invert if it is non-zero index */ + *pOutrow = (mng_uint8)(*pOutrow ^ 0x01); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 1; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX1, MNG_LC_END) +#endif + + return store_idx1 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_idx2 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX2, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + /* put the index */ + *pOutrow = (mng_uint8)((iB & iM) >> iS); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 2; + iS -= 2; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + /* calculate the index */ + *pOutrow = (mng_uint8)((*pOutrow + ((iB & iM) >> iS)) & 0x03); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 2; + iS -= 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX2, MNG_LC_END) +#endif + + return store_idx2 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_idx4 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX4, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* put the index */ + *pOutrow = (mng_uint8)((iB & iM) >> iS); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 4; + iS -= 4; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* calculate the index */ + *pOutrow = (mng_uint8)((*pOutrow + ((iB & iM) >> iS)) & 0x0F); + + pOutrow += pData->iColinc; /* next pixel */ + iM >>= 4; + iS -= 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX4, MNG_LC_END) +#endif + + return store_idx4 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_idx8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + + pOutrow += pData->iColinc; /* next pixel */ + pWorkrow++; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + *pOutrow = (mng_uint8)(*pOutrow + *pWorkrow); + + pOutrow += pData->iColinc; /* next pixel */ + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_IDX8, MNG_LC_END) +#endif + + return store_idx8 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_ga8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + *(pOutrow+1) = *(pWorkrow+1); + /* next pixel */ + pOutrow += (pData->iColinc << 1); + pWorkrow += 2; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + *pOutrow = (mng_uint8)(*pOutrow + *pWorkrow ); + *(pOutrow+1) = (mng_uint8)(*(pOutrow+1) + *(pWorkrow+1)); + /* next pixel */ + pOutrow += (pData->iColinc << 1); + pWorkrow += 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8, MNG_LC_END) +#endif + + return store_ga8 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_ga16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + *(pOutrow+3) = *(pWorkrow+3); + /* next pixel */ + pOutrow += (pData->iColinc << 2); + pWorkrow += 4; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + mng_put_uint16 (pOutrow, (mng_uint16)(mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow ) )); + mng_put_uint16 (pOutrow+2, (mng_uint16)(mng_get_uint16 (pOutrow+2 ) + + mng_get_uint16 (pWorkrow+2) )); + /* next pixel */ + pOutrow += (pData->iColinc << 2); + pWorkrow += 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16, MNG_LC_END) +#endif + + return store_ga16 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; /* put in object buffer */ + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + *(pOutrow+3) = *(pWorkrow+3); + /* next pixel */ + pOutrow += (pData->iColinc << 2); + pWorkrow += 4; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + *pOutrow = (mng_uint8)(*pOutrow + *pWorkrow ); + *(pOutrow+1) = (mng_uint8)(*(pOutrow+1) + *(pWorkrow+1)); + *(pOutrow+2) = (mng_uint8)(*(pOutrow+2) + *(pWorkrow+2)); + *(pOutrow+3) = (mng_uint8)(*(pOutrow+3) + *(pWorkrow+3)); + /* next pixel */ + pOutrow += (pData->iColinc << 2); + pWorkrow += 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8, MNG_LC_END) +#endif + + return store_rgba8 (pData); +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pDeltaImage)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iDeltaBlocky * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + + (pData->iDeltaBlockx * pBuf->iSamplesize); + /* pixel replace ? */ + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + MNG_COPY (pOutrow, pWorkrow, 8) /* put in object buffer */ + /* next pixel */ + pOutrow += (pData->iColinc << 3); + pWorkrow += 8; + } + } + else + { /* pixel add ! */ + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* add to object buffer */ + mng_put_uint16 (pOutrow, (mng_uint16)(mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow ) )); + mng_put_uint16 (pOutrow+2, (mng_uint16)(mng_get_uint16 (pOutrow+2 ) + + mng_get_uint16 (pWorkrow+2) )); + mng_put_uint16 (pOutrow+4, (mng_uint16)(mng_get_uint16 (pOutrow+4 ) + + mng_get_uint16 (pWorkrow+4) )); + mng_put_uint16 (pOutrow+6, (mng_uint16)(mng_get_uint16 (pOutrow+6 ) + + mng_get_uint16 (pWorkrow+6) )); + /* next pixel */ + pOutrow += (pData->iColinc << 3); + pWorkrow += 8; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16, MNG_LC_END) +#endif + + return store_rgba16 (pData); +} + +/* ************************************************************************** */ +/* * * */ +/* * Delta-image row routines - apply the source row onto the target * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode delta_g1_g1 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G1_G1, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0x01); + + pOutrow++; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G1_G1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_g2_g2 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G2_G2, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0x03); + + pOutrow++; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G2_G2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_g4_g4 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G4_G4, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0x0F); + + pOutrow++; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G4_G4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_g8_g8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G8_G8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0xFF); + + pOutrow++; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G8_G8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_g16_g16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G16_G16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, (pData->iRowsamples << 1)) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, (mng_uint16)((mng_get_uint16 (pOutrow) + + mng_get_uint16 (pWorkrow)) & 0xFFFF)); + + pOutrow += 2; + pWorkrow += 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_G16_G16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgb8_rgb8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB8_RGB8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples * 3) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < (pData->iRowsamples * 3); iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0xFF); + + pOutrow++; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB8_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgb16_rgb16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB16_RGB16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, (pData->iRowsamples * 6)) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, (mng_uint16)((mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow )) & 0xFFFF)); + mng_put_uint16 (pOutrow+2, (mng_uint16)((mng_get_uint16 (pOutrow+2) + + mng_get_uint16 (pWorkrow+2)) & 0xFFFF)); + mng_put_uint16 (pOutrow+4, (mng_uint16)((mng_get_uint16 (pOutrow+4) + + mng_get_uint16 (pWorkrow+4)) & 0xFFFF)); + + pOutrow += 6; + pWorkrow += 6; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGB16_RGB16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_ga8_ga8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8_GA8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples << 1) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < (pData->iRowsamples << 1); iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0xFF); + + pOutrow++; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8_GA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_ga8_g8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8_G8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; + + pOutrow += 2; + pWorkrow++; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0xFF); + + pOutrow += 2; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8_G8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_ga8_a8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8_A8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 1; + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; + + pOutrow += 2; + pWorkrow++; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0xFF); + + pOutrow += 2; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA8_A8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_ga16_ga16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16_GA16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, (pData->iRowsamples << 2)) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, (mng_uint16)((mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow )) & 0xFFFF)); + mng_put_uint16 (pOutrow+2, (mng_uint16)((mng_get_uint16 (pOutrow+2) + + mng_get_uint16 (pWorkrow+2)) & 0xFFFF)); + + pOutrow += 4; + pWorkrow += 4; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16_GA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_ga16_g16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16_A16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, mng_get_uint16 (pWorkrow)); + + pOutrow += 4; + pWorkrow += 2; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, (mng_uint16)((mng_get_uint16 (pOutrow) + + mng_get_uint16 (pWorkrow)) & 0xFFFF)); + + pOutrow += 4; + pWorkrow += 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16_A16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_ga16_a16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16_G16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow+2, mng_get_uint16 (pWorkrow)); + + pOutrow += 4; + pWorkrow += 2; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow+2, (mng_uint16)((mng_get_uint16 (pOutrow+2) + + mng_get_uint16 (pWorkrow)) & 0xFFFF)); + + pOutrow += 4; + pWorkrow += 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_GA16_G16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba8_rgba8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8_RGBA8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, pData->iRowsamples << 2) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < (pData->iRowsamples << 2); iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0xFF); + + pOutrow++; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8_RGBA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba8_rgb8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8_RGB8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; + *(pOutrow+1) = *(pWorkrow+1); + *(pOutrow+2) = *(pWorkrow+2); + + pOutrow += 4; + pWorkrow += 3; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow ) & 0xFF); + *(pOutrow+1) = (mng_uint8)(((mng_uint16)*(pOutrow+1) + + (mng_uint16)*(pWorkrow+1)) & 0xFF); + *(pOutrow+2) = (mng_uint8)(((mng_uint16)*(pOutrow+2) + + (mng_uint16)*(pWorkrow+2)) & 0xFF); + + pOutrow += 4; + pWorkrow += 3; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba8_a8 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8_A8, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize) + 3; + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = *pWorkrow; + + pOutrow += 4; + pWorkrow++; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pOutrow = (mng_uint8)(((mng_uint16)*pOutrow + + (mng_uint16)*pWorkrow) & 0xFF); + + pOutrow += 4; + pWorkrow++; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA8_A8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba16_rgba16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16_RGBA16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + MNG_COPY (pOutrow, pWorkrow, (pData->iRowsamples << 3)) + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, (mng_uint16)((mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow )) & 0xFFFF)); + mng_put_uint16 (pOutrow+2, (mng_uint16)((mng_get_uint16 (pOutrow+2) + + mng_get_uint16 (pWorkrow+2)) & 0xFFFF)); + mng_put_uint16 (pOutrow+4, (mng_uint16)((mng_get_uint16 (pOutrow+4) + + mng_get_uint16 (pWorkrow+4)) & 0xFFFF)); + mng_put_uint16 (pOutrow+6, (mng_uint16)((mng_get_uint16 (pOutrow+6) + + mng_get_uint16 (pWorkrow+6)) & 0xFFFF)); + + pOutrow += 8; + pWorkrow += 8; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16_RGBA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba16_rgb16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16_RGB16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, mng_get_uint16 (pWorkrow )); + mng_put_uint16 (pOutrow+2, mng_get_uint16 (pWorkrow+2)); + mng_put_uint16 (pOutrow+4, mng_get_uint16 (pWorkrow+4)); + + pOutrow += 8; + pWorkrow += 6; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow, (mng_uint16)((mng_get_uint16 (pOutrow ) + + mng_get_uint16 (pWorkrow )) & 0xFFFF)); + mng_put_uint16 (pOutrow+2, (mng_uint16)((mng_get_uint16 (pOutrow+2) + + mng_get_uint16 (pWorkrow+2)) & 0xFFFF)); + mng_put_uint16 (pOutrow+4, (mng_uint16)((mng_get_uint16 (pOutrow+4) + + mng_get_uint16 (pWorkrow+4)) & 0xFFFF)); + + pOutrow += 8; + pWorkrow += 6; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16_RGB16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode delta_rgba16_a16 (mng_datap pData) +{ + mng_imagedatap pBuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + mng_uint8p pWorkrow; + mng_uint8p pOutrow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16_A16, MNG_LC_START) +#endif + + pWorkrow = pData->pRGBArow; + pOutrow = pBuf->pImgdata + (pData->iRow * pBuf->iRowsize ) + + (pData->iCol * pBuf->iSamplesize); + + if ((pData->iDeltatype == MNG_DELTATYPE_REPLACE ) || + (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELREPLACE) ) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow+6, mng_get_uint16 (pWorkrow)); + + pOutrow += 8; + pWorkrow += 2; + } + } + else + if (pData->iDeltatype == MNG_DELTATYPE_BLOCKPIXELADD) + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + mng_put_uint16 (pOutrow+6, (mng_uint16)((mng_get_uint16 (pOutrow+6) + + mng_get_uint16 (pWorkrow)) & 0xFFFF)); + + pOutrow += 8; + pWorkrow += 2; + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DELTA_RGBA16_A16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Delta-image row routines - scale the source to bitdepth of target * */ +/* * * */ +/* ************************************************************************** */ + + + +/* ************************************************************************** */ +/* * * */ +/* * Row processing routines - convert uncompressed data from zlib to * */ +/* * managable row-data which serves as input to the color-management * */ +/* * routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode process_g1 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G1, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + iM = 0; /* start at pixel 0 */ + iB = 0; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + if (pBuf->iTRNSgray) /* white transparent ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* is it white ? */ + /* transparent ! */ + mng_put_uint32 (pRGBArow, 0x00000000); + else /* opaque black */ + mng_put_uint32 (pRGBArow, 0x000000FF); + + pRGBArow += 4; /* next pixel */ + iM >>= 1; + } + } + else /* black transparent */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* is it white ? */ + /* opaque white */ + mng_put_uint32 (pRGBArow, 0xFFFFFFFF); + else /* transparent */ + mng_put_uint32 (pRGBArow, 0x00000000); + + pRGBArow += 4; /* next pixel */ + iM >>= 1; + } + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else /* no transparency */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + } + + if (iB & iM) /* is it white ? */ + /* opaque white */ + mng_put_uint32 (pRGBArow, 0xFFFFFFFF); + else /* opaque black */ + mng_put_uint32 (pRGBArow, 0x000000FF); + + pRGBArow += 4; /* next pixel */ + iM >>= 1; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_g2 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G2, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + /* determine gray level */ + iQ = (mng_uint8)((iB & iM) >> iS); + + if (iQ == pBuf->iTRNSgray) /* transparent ? */ + mng_put_uint32 (pRGBArow, 0x00000000); + else + { + switch (iQ) /* determine the gray level */ + { + case 0x03 : { mng_put_uint32 (pRGBArow, 0xFFFFFFFF); break; } + case 0x02 : { mng_put_uint32 (pRGBArow, 0xAAAAAAFF); break; } + case 0x01 : { mng_put_uint32 (pRGBArow, 0x555555FF); break; } + default : { mng_put_uint32 (pRGBArow, 0x000000FF); } + } + } + + pRGBArow += 4; /* next pixel */ + iM >>= 2; + iS -= 2; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + + switch ((iB & iM) >> iS) /* determine the gray level */ + { + case 0x03 : { mng_put_uint32 (pRGBArow, 0xFFFFFFFF); break; } + case 0x02 : { mng_put_uint32 (pRGBArow, 0xAAAAAAFF); break; } + case 0x01 : { mng_put_uint32 (pRGBArow, 0x555555FF); break; } + default : { mng_put_uint32 (pRGBArow, 0x000000FF); } + } + + pRGBArow += 4; /* next pixel */ + iM >>= 2; + iS -= 2; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_g4 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G4, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the gray level */ + iQ = (mng_uint8)((iB & iM) >> iS); + + if (iQ == pBuf->iTRNSgray) /* transparent ? */ + { + *pRGBArow = 0; /* put in intermediate row */ + *(pRGBArow+1) = 0; + *(pRGBArow+2) = 0; + *(pRGBArow+3) = 0; + } + else + { /* expand to 8-bit by replication */ + iQ = (mng_uint8)(iQ + (iQ << 4)); + + *pRGBArow = iQ; /* put in intermediate row */ + *(pRGBArow+1) = iQ; + *(pRGBArow+2) = iQ; + *(pRGBArow+3) = 0xFF; + } + + pRGBArow += 4; /* next pixel */ + iM >>= 4; + iS -= 4; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the gray level */ + iQ = (mng_uint8)((iB & iM) >> iS); + iQ = (mng_uint8)(iQ + (iQ << 4));/* expand to 8-bit by replication */ + + *pRGBArow = iQ; /* put in intermediate row */ + *(pRGBArow+1) = iQ; + *(pRGBArow+2) = iQ; + *(pRGBArow+3) = 0xFF; + + pRGBArow += 4; /* next pixel */ + iM >>= 4; + iS -= 4; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_g8 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iB; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G8, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iB = *pWorkrow; /* get next input-byte */ + + if (iB == pBuf->iTRNSgray) /* transparent ? */ + { + *pRGBArow = 0; /* put in intermediate row */ + *(pRGBArow+1) = 0; + *(pRGBArow+2) = 0; + *(pRGBArow+3) = 0; + } + else + { + *pRGBArow = iB; /* put in intermediate row */ + *(pRGBArow+1) = iB; + *(pRGBArow+2) = iB; + *(pRGBArow+3) = 0xFF; + } + + pRGBArow += 4; /* next pixel */ + pWorkrow++; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iB = *pWorkrow; /* get next input-byte */ + + *pRGBArow = iB; /* put in intermediate row */ + *(pRGBArow+1) = iB; + *(pRGBArow+2) = iB; + *(pRGBArow+3) = 0xFF; + + pRGBArow += 4; /* next pixel */ + pWorkrow++; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_g16 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint16 iW; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G16, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iW = mng_get_uint16 (pWorkrow); /* get input */ + + if (iW == pBuf->iTRNSgray) /* transparent ? */ + { /* put in intermediate row */ + mng_put_uint16 (pRGBArow, 0); + mng_put_uint16 (pRGBArow+2, 0); + mng_put_uint16 (pRGBArow+4, 0); + mng_put_uint16 (pRGBArow+6, 0); + } + else + { /* put in intermediate row */ + mng_put_uint16 (pRGBArow, iW); + mng_put_uint16 (pRGBArow+2, iW); + mng_put_uint16 (pRGBArow+4, iW); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + } + + pRGBArow += 8; /* next pixel */ + pWorkrow += 2; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iW = mng_get_uint16 (pWorkrow); /* get input */ + + mng_put_uint16 (pRGBArow, iW); /* and put in intermediate row */ + mng_put_uint16 (pRGBArow+2, iW); + mng_put_uint16 (pRGBArow+4, iW); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + + pRGBArow += 8; /* next pixel */ + pWorkrow += 2; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_G16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_rgb8 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iR, iG, iB; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGB8, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iR = *pWorkrow; /* get the RGB values */ + iG = *(pWorkrow+1); + iB = *(pWorkrow+2); + /* transparent ? */ + if ((iR == pBuf->iTRNSred) && (iG == pBuf->iTRNSgreen) && + (iB == pBuf->iTRNSblue)) + { + *pRGBArow = 0; /* this pixel is transparent ! */ + *(pRGBArow+1) = 0; + *(pRGBArow+2) = 0; + *(pRGBArow+3) = 0; + } + else + { + *pRGBArow = iR; /* copy the RGB values */ + *(pRGBArow+1) = iG; + *(pRGBArow+2) = iB; + *(pRGBArow+3) = 0xFF; /* this one isn't transparent */ + } + + pWorkrow += 3; /* next pixel */ + pRGBArow += 4; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRGBArow = *pWorkrow; /* copy the RGB bytes */ + *(pRGBArow+1) = *(pWorkrow+1); + *(pRGBArow+2) = *(pWorkrow+2); + *(pRGBArow+3) = 0xFF; /* no alpha; so always fully opaque */ + + pWorkrow += 3; /* next pixel */ + pRGBArow += 4; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGB8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_rgb16 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint16 iR, iG, iB; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGB16, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iR = mng_get_uint16 (pWorkrow); /* get the RGB values */ + iG = mng_get_uint16 (pWorkrow+2); + iB = mng_get_uint16 (pWorkrow+4); + /* transparent ? */ + if ((iR == pBuf->iTRNSred) && (iG == pBuf->iTRNSgreen) && + (iB == pBuf->iTRNSblue)) + { /* transparent then */ + mng_put_uint16 (pRGBArow, 0); + mng_put_uint16 (pRGBArow+2, 0); + mng_put_uint16 (pRGBArow+4, 0); + mng_put_uint16 (pRGBArow+6, 0); + } + else + { /* put in intermediate row */ + mng_put_uint16 (pRGBArow, iR); + mng_put_uint16 (pRGBArow+2, iG); + mng_put_uint16 (pRGBArow+4, iB); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + } + + pWorkrow += 6; /* next pixel */ + pRGBArow += 8; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { /* copy the RGB values */ + mng_put_uint16 (pRGBArow, mng_get_uint16 (pWorkrow )); + mng_put_uint16 (pRGBArow+2, mng_get_uint16 (pWorkrow+2)); + mng_put_uint16 (pRGBArow+4, mng_get_uint16 (pWorkrow+4)); + mng_put_uint16 (pRGBArow+6, 0xFFFF); + + pWorkrow += 6; /* next pixel */ + pRGBArow += 8; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGB16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_idx1 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX1, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + iS = 7; + } + /* get the index */ + iQ = (mng_uint8)((iB & iM) >> iS); + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + *pRGBArow = pBuf->aPLTEentries [iQ].iRed; + *(pRGBArow+1) = pBuf->aPLTEentries [iQ].iGreen; + *(pRGBArow+2) = pBuf->aPLTEentries [iQ].iBlue; + /* transparency for this index ? */ + if ((mng_uint32)iQ < pBuf->iTRNScount) + *(pRGBArow+3) = pBuf->aTRNSentries [iQ]; + else + *(pRGBArow+3) = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + iM >>= 1; + iS -= 1; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0x80; + iS = 7; + } + /* get the index */ + iQ = (mng_uint8)((iB & iM) >> iS); + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + *pRGBArow = pBuf->aPLTEentries [iQ].iRed; + *(pRGBArow+1) = pBuf->aPLTEentries [iQ].iGreen; + *(pRGBArow+2) = pBuf->aPLTEentries [iQ].iBlue; + *(pRGBArow+3) = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + iM >>= 1; + iS -= 1; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_idx2 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX2, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + /* get the index */ + iQ = (mng_uint8)((iB & iM) >> iS); + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + *pRGBArow = pBuf->aPLTEentries [iQ].iRed; + *(pRGBArow+1) = pBuf->aPLTEentries [iQ].iGreen; + *(pRGBArow+2) = pBuf->aPLTEentries [iQ].iBlue; + /* transparency for this index ? */ + if ((mng_uint32)iQ < pBuf->iTRNScount) + *(pRGBArow+3) = pBuf->aTRNSentries [iQ]; + else + *(pRGBArow+3) = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + iM >>= 2; + iS -= 2; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = *pWorkrow; /* get next input-byte */ + pWorkrow++; + iM = 0xC0; + iS = 6; + } + /* get the index */ + iQ = (mng_uint8)((iB & iM) >> iS); + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + *pRGBArow = pBuf->aPLTEentries [iQ].iRed; + *(pRGBArow+1) = pBuf->aPLTEentries [iQ].iGreen; + *(pRGBArow+2) = pBuf->aPLTEentries [iQ].iBlue; + *(pRGBArow+3) = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + iM >>= 2; + iS -= 2; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_idx4 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iB; + mng_uint8 iM; + mng_uint32 iS; + mng_uint8 iQ; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX4, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + iM = 0; /* start at pixel 0 */ + iB = 0; + iS = 0; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = pWorkrow [0]; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the index */ + iQ = (mng_uint8)((iB & iM) >> iS); + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + pRGBArow [0] = pBuf->aPLTEentries [iQ].iRed; + pRGBArow [1] = pBuf->aPLTEentries [iQ].iGreen; + pRGBArow [2] = pBuf->aPLTEentries [iQ].iBlue; + /* transparency for this index ? */ + if ((mng_uint32)iQ < pBuf->iTRNScount) + pRGBArow [3] = pBuf->aTRNSentries [iQ]; + else + pRGBArow [3] = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + iM >>= 4; + iS -= 4; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + if (!iM) /* mask underflow ? */ + { + iB = pWorkrow [0]; /* get next input-byte */ + pWorkrow++; + iM = 0xF0; + iS = 4; + } + /* get the index */ + iQ = (mng_uint8)((iB & iM) >> iS); + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + pRGBArow [0] = pBuf->aPLTEentries [iQ].iRed; + pRGBArow [1] = pBuf->aPLTEentries [iQ].iGreen; + pRGBArow [2] = pBuf->aPLTEentries [iQ].iBlue; + pRGBArow [3] = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + iM >>= 4; + iS -= 4; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_idx8 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint8 iQ; + mng_imagedatap pBuf = (mng_imagedatap)pData->pStorebuf; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX8, MNG_LC_START) +#endif + + if (!pBuf) /* no object? then use obj 0 */ + pBuf = ((mng_imagep)pData->pObjzero)->pImgbuf; + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + + if (pBuf->bHasTRNS) /* tRNS encountered ? */ + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iQ = *pWorkrow; /* get input byte */ + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + pRGBArow [0] = pBuf->aPLTEentries [iQ].iRed; + pRGBArow [1] = pBuf->aPLTEentries [iQ].iGreen; + pRGBArow [2] = pBuf->aPLTEentries [iQ].iBlue; + /* transparency for this index ? */ + if ((mng_uint32)iQ < pBuf->iTRNScount) + pRGBArow [3] = pBuf->aTRNSentries [iQ]; + else + pRGBArow [3] = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + pWorkrow++; + } + + pData->bIsOpaque = MNG_FALSE; /* it's not fully opaque */ + } + else + { + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iQ = *pWorkrow; /* get input byte */ + /* index valid ? */ + if ((mng_uint32)iQ < pBuf->iPLTEcount) + { /* put in intermediate row */ + pRGBArow [0] = pBuf->aPLTEentries [iQ].iRed; + pRGBArow [1] = pBuf->aPLTEentries [iQ].iGreen; + pRGBArow [2] = pBuf->aPLTEentries [iQ].iBlue; + pRGBArow [3] = 0xFF; + } + else + MNG_ERROR (pData, MNG_PLTEINDEXERROR) + + pRGBArow += 4; /* next pixel */ + pWorkrow++; + } + + pData->bIsOpaque = MNG_TRUE; /* it's fully opaque */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_IDX8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ga8 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_GA8, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + *pRGBArow = *pWorkrow; /* copy the gray value */ + *(pRGBArow+1) = *pWorkrow; + *(pRGBArow+2) = *pWorkrow; + *(pRGBArow+3) = *(pWorkrow+1); /* copy the alpha value */ + + pWorkrow += 2; /* next pixel */ + pRGBArow += 4; + } + + pData->bIsOpaque = MNG_FALSE; /* it's definitely not fully opaque */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_GA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_ga16 (mng_datap pData) +{ + mng_uint8p pWorkrow; + mng_uint8p pRGBArow; + mng_int32 iX; + mng_uint16 iW; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_GA16, MNG_LC_START) +#endif + /* temporary work pointers */ + pWorkrow = pData->pWorkrow + pData->iPixelofs; + pRGBArow = pData->pRGBArow; + + for (iX = 0; iX < pData->iRowsamples; iX++) + { + iW = mng_get_uint16 (pWorkrow); /* copy the gray value */ + mng_put_uint16 (pRGBArow, iW); + mng_put_uint16 (pRGBArow+2, iW); + mng_put_uint16 (pRGBArow+4, iW); + /* copy the alpha value */ + mng_put_uint16 (pRGBArow+6, mng_get_uint16 (pWorkrow+2)); + + pWorkrow += 4; /* next pixel */ + pRGBArow += 8; + } + + pData->bIsOpaque = MNG_FALSE; /* it's definitely not fully opaque */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_GA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_rgba8 (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGBA8, MNG_LC_START) +#endif + /* this is the easiest transform */ + MNG_COPY (pData->pRGBArow, pData->pWorkrow + pData->iPixelofs, pData->iRowsize) + + pData->bIsOpaque = MNG_FALSE; /* it's definitely not fully opaque */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGBA8, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_rgba16 (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGBA16, MNG_LC_START) +#endif + /* this is the easiest transform */ + MNG_COPY (pData->pRGBArow, pData->pWorkrow + pData->iPixelofs, pData->iRowsize) + + pData->bIsOpaque = MNG_FALSE; /* it's definitely not fully opaque */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RGBA16, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ +/* * * */ +/* * Row processing initialization routines - set up the variables needed * */ +/* * to process uncompressed row-data * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode init_g1_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G1_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g1; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g1; + else + pData->fStorerow = (mng_fptr)store_g1; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g1; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 7; + pData->iSamplediv = 3; + pData->iRowsize = (pData->iRowsamples + 7) >> 3; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G1_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g1_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G1_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g1; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g1; + else + pData->fStorerow = (mng_fptr)store_g1; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g1; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 7; + pData->iSamplediv = 3; + pData->iRowsize = ((pData->iRowsamples + 7) >> 3); + pData->iRowmax = ((pData->iDatawidth + 7) >> 3) + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G1_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g2_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G2_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g2; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g2; + else + pData->fStorerow = (mng_fptr)store_g2; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g2; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 3; + pData->iSamplediv = 2; + pData->iRowsize = (pData->iRowsamples + 3) >> 2; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G2_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g2_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G2_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g2; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g2; + else + pData->fStorerow = (mng_fptr)store_g2; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g2; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 3; + pData->iSamplediv = 2; + pData->iRowsize = ((pData->iRowsamples + 3) >> 2); + pData->iRowmax = ((pData->iDatawidth + 3) >> 2) + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G2_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g4_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G4_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g4; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g4; + else + pData->fStorerow = (mng_fptr)store_g4; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g4; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 1; + pData->iSamplediv = 1; + pData->iRowsize = (pData->iRowsamples + 1) >> 1; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G4_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g4_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G4_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g4; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g4; + else + pData->fStorerow = (mng_fptr)store_g4; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g4; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 1; + pData->iSamplediv = 1; + pData->iRowsize = ((pData->iRowsamples + 1) >> 1); + pData->iRowmax = ((pData->iDatawidth + 1) >> 1) + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G4_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g8_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G8_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g8; + else + pData->fStorerow = (mng_fptr)store_g8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g8; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G8_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g8_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G8_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g8; + else + pData->fStorerow = (mng_fptr)store_g8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g8; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples; + pData->iRowmax = pData->iDatawidth + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G8_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g16_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G16_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g16; + else + pData->fStorerow = (mng_fptr)store_g16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g16; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 2; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 1; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 2; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G16_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_g16_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G16_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_g16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_g16; + else + pData->fStorerow = (mng_fptr)store_g16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g16; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 2; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 1; + pData->iRowmax = (pData->iDatawidth << 1) + pData->iPixelofs; + pData->iFilterbpp = 2; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_G16_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgb8_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB8_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgb8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgb8; + else + pData->fStorerow = (mng_fptr)store_rgb8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgb8; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 3; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples * 3; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 3; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB8_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgb8_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB8_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgb8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgb8; + else + pData->fStorerow = (mng_fptr)store_rgb8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgb8; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 3; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples * 3; + pData->iRowmax = (pData->iDatawidth * 3) + pData->iPixelofs; + pData->iFilterbpp = 3; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB8_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgb16_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB16_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgb16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgb16; + else + pData->fStorerow = (mng_fptr)store_rgb16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgb16; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 6; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples * 6; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 6; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB16_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgb16_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB16_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgb16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgb16; + else + pData->fStorerow = (mng_fptr)store_rgb16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgb16; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 6; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples * 6; + pData->iRowmax = (pData->iDatawidth * 6) + pData->iPixelofs; + pData->iFilterbpp = 6; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGB16_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx1_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX1_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx1; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx1; + else + pData->fStorerow = (mng_fptr)store_idx1; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx1; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 7; + pData->iSamplediv = 3; + pData->iRowsize = (pData->iRowsamples + 7) >> 3; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX1_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx1_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX1_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx1; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx1; + else + pData->fStorerow = (mng_fptr)store_idx1; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx1; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 7; + pData->iSamplediv = 3; + pData->iRowsize = (pData->iRowsamples + 7) >> 3; + pData->iRowmax = ((pData->iDatawidth + 7) >> 3) + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX1_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx2_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX2_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx2; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx2; + else + pData->fStorerow = (mng_fptr)store_idx2; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx2; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 3; + pData->iSamplediv = 2; + pData->iRowsize = (pData->iRowsamples + 3) >> 2; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX2_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx2_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX2_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx2; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx2; + else + pData->fStorerow = (mng_fptr)store_idx2; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx2; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 3; + pData->iSamplediv = 2; + pData->iRowsize = (pData->iRowsamples + 3) >> 2; + pData->iRowmax = ((pData->iDatawidth + 3) >> 2) + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX2_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx4_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX4_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx4; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx4; + else + pData->fStorerow = (mng_fptr)store_idx4; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx4; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 1; + pData->iSamplediv = 1; + pData->iRowsize = (pData->iRowsamples + 1) >> 1; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX4_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx4_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX4_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx4; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx4; + else + pData->fStorerow = (mng_fptr)store_idx4; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx4; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 1; + pData->iSamplediv = 1; + pData->iRowsize = (pData->iRowsamples + 1) >> 1; + pData->iRowmax = ((pData->iDatawidth + 1) >> 1) + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX4_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx8_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX8_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx8; + else + pData->fStorerow = (mng_fptr)store_idx8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx8; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX8_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_idx8_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX8_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_idx8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_idx8; + else + pData->fStorerow = (mng_fptr)store_idx8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_idx8; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 1; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples; + pData->iRowmax = pData->iDatawidth + pData->iPixelofs; + pData->iFilterbpp = 1; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_IDX8_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_ga8_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA8_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_ga8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_ga8; + else + pData->fStorerow = (mng_fptr)store_ga8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_ga8; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 2; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 1; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 2; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA8_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_ga8_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA8_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_ga8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_ga8; + else + pData->fStorerow = (mng_fptr)store_ga8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_ga8; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 2; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 1; + pData->iRowmax = (pData->iDatawidth << 1) + pData->iPixelofs; + pData->iFilterbpp = 2; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA8_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_ga16_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA16_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_ga16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_ga16; + else + pData->fStorerow = (mng_fptr)store_ga16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_ga16; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 4; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 2; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 4; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA16_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_ga16_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA16_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_ga16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_ga16; + else + pData->fStorerow = (mng_fptr)store_ga16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_ga16; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 4; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 2; + pData->iRowmax = (pData->iDatawidth << 2) + pData->iPixelofs; + pData->iFilterbpp = 4; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_GA16_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgba8_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA8_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgba8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgba8; + else + pData->fStorerow = (mng_fptr)store_rgba8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgba8; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 4; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 2; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 4; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA8_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgba8_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA8_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgba8; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgba8; + else + pData->fStorerow = (mng_fptr)store_rgba8; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgba8; + + pData->iPass = 0; /* from 0..6; is 1..7 in specifications */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 4; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 2; + pData->iRowmax = (pData->iDatawidth << 2) + pData->iPixelofs; + pData->iFilterbpp = 4; + pData->bIsRGBA16 = MNG_FALSE; /* intermediate row is 8-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA8_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgba16_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA16_NI, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgba16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgba16; + else + pData->fStorerow = (mng_fptr)store_rgba16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgba16; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 8; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 3; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 8; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA16_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_rgba16_i (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA16_I, MNG_LC_START) +#endif + + if (pData->fDisplayrow) + pData->fProcessrow = (mng_fptr)process_rgba16; + + if (pData->pStoreobj) /* store in object too ? */ + { /* immediate delta ? */ + if ((pData->bHasDHDR) && (pData->bDeltaimmediate)) + pData->fStorerow = (mng_fptr)delta_rgba16; + else + pData->fStorerow = (mng_fptr)store_rgba16; + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_rgba16; + + pData->iPass = 0; /* from 0..6; (1..7 in specification) */ + pData->iRow = interlace_row [0]; + pData->iRowinc = interlace_rowskip [0]; + pData->iCol = interlace_col [0]; + pData->iColinc = interlace_colskip [0]; + pData->iRowsamples = (pData->iDatawidth + interlace_roundoff [0]) >> interlace_divider [0]; + pData->iSamplemul = 8; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 3; + pData->iRowmax = (pData->iDatawidth << 3) + pData->iPixelofs; + pData->iFilterbpp = 8; + pData->bIsRGBA16 = MNG_TRUE; /* intermediate row is 16-bit deep */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_RGBA16_I, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ +/* * * */ +/* * Row processing initialization routines (JPEG) - set up the variables * */ +/* * needed to process uncompressed row-data * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG + +/* ************************************************************************** */ + +mng_retcode init_jpeg_a1_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A1_NI, MNG_LC_START) +#endif + + if (pData->pStoreobj) /* store in object too ? */ + { + if (pData->iJHDRimgbitdepth == 8) + { + switch (pData->iJHDRcolortype) + { + case 12 : { pData->fStorerow = (mng_fptr)store_jpeg_g8_a1; break; } + case 14 : { pData->fStorerow = (mng_fptr)store_jpeg_rgb8_a1; break; } + } + } + + /* TODO: bitdepth 12 & 20 */ + + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g1; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 7; + pData->iSamplediv = 3; + pData->iRowsize = (pData->iRowsamples + 7) >> 3; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A1_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_jpeg_a2_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A2_NI, MNG_LC_START) +#endif + + if (pData->pStoreobj) /* store in object too ? */ + { + if (pData->iJHDRimgbitdepth == 8) + { + switch (pData->iJHDRcolortype) + { + case 12 : { pData->fStorerow = (mng_fptr)store_jpeg_g8_a2; break; } + case 14 : { pData->fStorerow = (mng_fptr)store_jpeg_rgb8_a2; break; } + } + } + + /* TODO: bitdepth 12 & 20 */ + + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g2; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 3; + pData->iSamplediv = 2; + pData->iRowsize = (pData->iRowsamples + 3) >> 2; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A2_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_jpeg_a4_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A4_NI, MNG_LC_START) +#endif + + if (pData->pStoreobj) /* store in object too ? */ + { + if (pData->iJHDRimgbitdepth == 8) + { + switch (pData->iJHDRcolortype) + { + case 12 : { pData->fStorerow = (mng_fptr)store_jpeg_g8_a4; break; } + case 14 : { pData->fStorerow = (mng_fptr)store_jpeg_rgb8_a4; break; } + } + } + + /* TODO: bitdepth 12 & 20 */ + + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g4; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 1; + pData->iSamplediv = 1; + pData->iRowsize = (pData->iRowsamples + 1) >> 1; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A4_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_jpeg_a8_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A8_NI, MNG_LC_START) +#endif + + if (pData->pStoreobj) /* store in object too ? */ + { + if (pData->iJHDRimgbitdepth == 8) + { + switch (pData->iJHDRcolortype) + { + case 12 : { pData->fStorerow = (mng_fptr)store_jpeg_g8_a8; break; } + case 14 : { pData->fStorerow = (mng_fptr)store_jpeg_rgb8_a8; break; } + } + } + + /* TODO: bitdepth 12 & 20 */ + + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g8; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 1; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 1; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A8_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +mng_retcode init_jpeg_a16_ni (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A16_NI, MNG_LC_START) +#endif + + if (pData->pStoreobj) /* store in object too ? */ + { + if (pData->iJHDRimgbitdepth == 8) + { + switch (pData->iJHDRcolortype) + { + case 12 : { pData->fStorerow = (mng_fptr)store_jpeg_g8_a16; break; } + case 14 : { pData->fStorerow = (mng_fptr)store_jpeg_rgb8_a16; break; } + } + } + + /* TODO: bitdepth 12 & 20 */ + + } + + if (pData->iFilter & 0x40) /* leveling & differing ? */ + pData->fDifferrow = (mng_fptr)differ_g16; + + pData->iPass = -1; + pData->iRow = 0; + pData->iRowinc = 1; + pData->iCol = 0; + pData->iColinc = 1; + pData->iRowsamples = pData->iDatawidth; + pData->iSamplemul = 2; + pData->iSampleofs = 0; + pData->iSamplediv = 0; + pData->iRowsize = pData->iRowsamples << 1; + pData->iRowmax = pData->iRowsize + pData->iPixelofs; + pData->iFilterbpp = 2; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_JPEG_A16_NI, MNG_LC_END) +#endif + + return init_rowproc (pData); +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ +/* * * */ +/* * Generic row processing initialization & cleanup routines * */ +/* * - initialize the buffers used by the row processing routines * */ +/* * - cleanup the buffers used by the row processing routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode init_rowproc (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ROWPROC, MNG_LC_START) +#endif + + if (pData->pStoreobj) /* storage object selected ? */ + { + pData->pStorebuf = ((mng_imagep)pData->pStoreobj)->pImgbuf; + /* and so it becomes viewable ! */ + ((mng_imagep)pData->pStoreobj)->bViewable = MNG_TRUE; + ((mng_imagedatap)pData->pStorebuf)->bViewable = MNG_TRUE; + } + + /* allocate the buffers; the individual init routines have already + calculated the required maximum size; except in the case of a JNG + without alpha!!! */ + if (pData->iRowmax) + { + MNG_ALLOC (pData, pData->pWorkrow, pData->iRowmax) + MNG_ALLOC (pData, pData->pPrevrow, pData->iRowmax) + } + + /* allocate an RGBA16 row for intermediate processing */ + MNG_ALLOC (pData, pData->pRGBArow, (pData->iDatawidth << 3)); + +#ifndef MNG_NO_CMS + if (pData->fDisplayrow) /* display "on-the-fly" ? */ + { +#if defined(MNG_FULL_CMS) /* determine color-management initialization */ + mng_retcode iRetcode = init_full_cms (pData); +#elif defined(MNG_GAMMA_ONLY) + mng_retcode iRetcode = init_gamma_only (pData); +#elif defined(MNG_APP_CMS) + mng_retcode iRetcode = init_app_cms (pData); +#endif + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif /* !MNG_NO_CMS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_INIT_ROWPROC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode next_row (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_ROW, MNG_LC_START) +#endif + + pData->iRow += pData->iRowinc; /* increase the row counter */ + + if (pData->iPass >= 0) /* interlaced ? */ + { + while ((pData->iPass < 7) && /* went 'outside' the image ? */ + ((pData->iRow >= (mng_int32)pData->iDataheight) || + (pData->iCol >= (mng_int32)pData->iDatawidth ) )) + { + pData->iPass++; /* next pass ! */ + + if (pData->iPass < 7) /* there's only 7 passes ! */ + { + pData->iRow = interlace_row [pData->iPass]; + pData->iRowinc = interlace_rowskip [pData->iPass]; + pData->iCol = interlace_col [pData->iPass]; + pData->iColinc = interlace_colskip [pData->iPass]; + pData->iRowsamples = (pData->iDatawidth - pData->iCol + interlace_roundoff [pData->iPass]) + >> interlace_divider [pData->iPass]; + + if (pData->iSamplemul > 1) /* recalculate row dimension */ + pData->iRowsize = pData->iRowsamples * pData->iSamplemul; + else + if (pData->iSamplediv > 0) + pData->iRowsize = (pData->iRowsamples + pData->iSampleofs) >> pData->iSamplediv; + else + pData->iRowsize = pData->iRowsamples; + + } + + if ((pData->iPass < 7) && /* reset previous row to zeroes ? */ + (pData->iRow < (mng_int32)pData->iDataheight) && + (pData->iCol < (mng_int32)pData->iDatawidth ) ) + { /* making sure the filters will work properly! */ + mng_int32 iX; + mng_uint8p pTemp = pData->pPrevrow; + + for (iX = 0; iX < pData->iRowsize; iX++) + { + *pTemp = 0; + pTemp++; + } + } + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_ROW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode cleanup_rowproc (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLEANUP_ROWPROC, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_LCMS /* cleanup cms profile/transform */ + mng_retcode iRetcode = mng_clear_cms (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; +#endif /* MNG_INCLUDE_LCMS */ + + if (pData->pWorkrow) /* cleanup buffer for working row */ + MNG_FREE (pData, pData->pWorkrow, pData->iRowmax) + + if (pData->pPrevrow) /* cleanup buffer for previous row */ + MNG_FREE (pData, pData->pPrevrow, pData->iRowmax) + + if (pData->pRGBArow) /* cleanup buffer for intermediate row */ + MNG_FREE (pData, pData->pRGBArow, (pData->iDatawidth << 3)) + + pData->pWorkrow = 0; /* propogate uninitialized buffers */ + pData->pPrevrow = 0; + pData->pRGBArow = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_CLEANUP_ROWPROC, MNG_LC_END) +#endif + + return MNG_NOERROR; /* woohiii */ +} + +/* ************************************************************************** */ +/* * * */ +/* * Generic row processing routines for JNG * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG + +/* ************************************************************************** */ + +mng_retcode display_jpeg_rows (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_JPEG_ROWS, MNG_LC_START) +#endif + /* any completed rows ? */ + if ((pData->iJPEGrow > pData->iJPEGdisprow) && + (pData->iJPEGalpharow > pData->iJPEGdisprow) ) + { + mng_uint32 iX, iMax; + mng_uint32 iSaverow = pData->iRow; /* save alpha decompression row-count */ + /* determine the highest complete(!) row */ + if (pData->iJPEGrow > pData->iJPEGalpharow) + iMax = pData->iJPEGalpharow; + else + iMax = pData->iJPEGrow; + /* display the rows */ + for (iX = pData->iJPEGdisprow; iX < iMax; iX++) + { + pData->iRow = iX; /* make sure we all know which row to handle */ + /* makeup an intermediate row from the buffer */ + iRetcode = ((mng_retrieverow)pData->fRetrieverow) (pData); + /* color-correct it if necessary */ + if ((!iRetcode) && (pData->fCorrectrow)) + iRetcode = ((mng_correctrow)pData->fCorrectrow) (pData); + + if (!iRetcode) /* and display it */ + { + iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData); + + if (!iRetcode) /* check progressive display refresh */ + iRetcode = display_progressive_check (pData); + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + pData->iJPEGdisprow = iMax; /* keep track of the last displayed row */ + pData->iRow = iSaverow; /* restore alpha decompression row-count */ + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_DISPLAY_JPEG_ROWS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode next_jpeg_alpharow (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_JPEG_ALPHAROW, MNG_LC_START) +#endif + + pData->iJPEGalpharow++; /* count the row */ + + if (pData->fDisplayrow) /* display "on-the-fly" ? */ + { /* try to display what you can */ + iRetcode = display_jpeg_rows (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_JPEG_ALPHAROW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode next_jpeg_row (mng_datap pData) +{ + mng_retcode iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_JPEG_ROW, MNG_LC_START) +#endif + + pData->iJPEGrow++; /* increase the row-counter */ + + if (pData->fDisplayrow) /* display "on-the-fly" ? */ + { /* has alpha channel ? */ + if ((pData->iJHDRcolortype == MNG_COLORTYPE_JPEGGRAYA ) || + (pData->iJHDRcolortype == MNG_COLORTYPE_JPEGCOLORA) ) + { /* try to display what you can */ + iRetcode = display_jpeg_rows (pData); + } + else + { /* make sure we all know which row to handle */ + pData->iRow = pData->iJPEGrow - 1; + /* makeup an intermediate row from the buffer */ + iRetcode = ((mng_retrieverow)pData->fRetrieverow) (pData); + /* color-correct it if necessary */ + if ((!iRetcode) && (pData->fCorrectrow)) + iRetcode = ((mng_correctrow)pData->fCorrectrow) (pData); + + if (!iRetcode) /* and display it */ + { + iRetcode = ((mng_displayrow)pData->fDisplayrow) (pData); + + if (!iRetcode) /* check progressive display refresh */ + iRetcode = display_progressive_check (pData); + } + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + } + + /* surpassed last filled row ? */ + if (pData->iJPEGrow > pData->iJPEGrgbrow) + pData->iJPEGrgbrow = pData->iJPEGrow; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_NEXT_JPEG_ROW, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +mng_retcode magnify_g8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX, iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_X1, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + + if (iX == 0) /* first interval ? */ + iM = iML; + else + if (iX == (iWidth - 1)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + + for (iS = 1; iS < iM; iS++) /* fill interval */ + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + } + + pTempsrc1++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_X1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_g8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_X2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 1; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { /* is it same as first ? */ + if (*pTempsrc1 == *pTempsrc2) + { + for (iS = 1; iS < iM; iS++) /* then just repeat the first */ + { + *pTempdst = *pTempsrc1; + pTempdst++; + } + } + else + { + for (iS = 1; iS < iM; iS++) /* calculate the distances */ + { + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + pTempdst++; + } + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + } + } + } + + pTempsrc1++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_X2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_g8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_X3, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 1; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { /* is it same as first ? */ + if (*pTempsrc1 == *pTempsrc2) + { + for (iS = 1; iS < iM; iS++) /* then just repeat the first */ + { + *pTempdst = *pTempsrc1; + pTempdst++; + } + } + else + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* replicate first half */ + { + *pTempdst = *pTempsrc1; + pTempdst++; + } + + for (iS = iH; iS < iM; iS++) /* replicate second half */ + { + *pTempdst = *pTempsrc2; + pTempdst++; + } + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + } + } + } + + pTempsrc1++; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_X3, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgb8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX, iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_X1, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + + if (iX == 0) /* first interval ? */ + iM = iML; + else + if (iX == (iWidth - 1)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + + for (iS = 1; iS < iM; iS++) /* fill interval */ + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + } + + pTempsrc1 += 3; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_X1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgb8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_X2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 3; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = (mng_int32)iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = (mng_int32)iMR; + else + iM = (mng_int32)iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + for (iS = 1; iS < iM; iS++) + { + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; /* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + + if (*(pTempsrc1+1) == *(pTempsrc2+1)) + *pTempdst = *(pTempsrc1+1); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+1)) - + (mng_int32)(*(pTempsrc1+1)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+1)) ); + + pTempdst++; + + if (*(pTempsrc1+2) == *(pTempsrc2+2)) + *pTempdst = *(pTempsrc1+2); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+2)) - + (mng_int32)(*(pTempsrc1+2)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+2)) ); + + pTempdst++; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + } + } + } + + pTempsrc1 += 3; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_X2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgb8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_X3, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 3; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = (mng_int32)iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = (mng_int32)iMR; + else + iM = (mng_int32)iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* replicate first half */ + { + *pTempdst = *pTempsrc1; + *(pTempdst+1) = *(pTempsrc1+1); + *(pTempdst+2) = *(pTempsrc1+2); + + pTempdst += 3; + } + + for (iS = iH; iS < iM; iS++) /* replicate second half */ + { + *pTempdst = *pTempsrc2; + *(pTempdst+1) = *(pTempsrc2+1); + *(pTempdst+2) = *(pTempsrc2+2); + + pTempdst += 3; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + } + } + } + + pTempsrc1 += 3; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_X3, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX, iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X1, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + + if (iX == 0) /* first interval ? */ + iM = iML; + else + if (iX == (iWidth - 1)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + + for (iS = 1; iS < iM; iS++) /* fill interval */ + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + } + + pTempsrc1 += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 2; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + for (iS = 1; iS < iM; iS++) + { + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; /* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + + if (*(pTempsrc1+1) == *(pTempsrc2+1)) + *pTempdst = *(pTempsrc1+1); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+1)) - + (mng_int32)(*(pTempsrc1+1)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+1)) ); + + pTempdst++; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + } + } + } + + pTempsrc1 += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X3, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 2; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* replicate first half */ + { + *pTempdst = *pTempsrc1; + *(pTempdst+1) = *(pTempsrc1+1); + + pTempdst += 2; + } + + for (iS = iH; iS < iM; iS++) /* replicate second half */ + { + *pTempdst = *pTempsrc2; + *(pTempdst+1) = *(pTempsrc2+1); + + pTempdst += 2; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + } + } + } + + pTempsrc1 += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X3, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_x4 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X4, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 2; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* first half */ + { + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; /* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + + *pTempdst = *(pTempsrc1+1); /* replicate alpha from left */ + + pTempdst++; + } + + for (iS = iH; iS < iM; iS++) /* second half */ + { + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; /* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + + *pTempdst = *(pTempsrc2+1); /* replicate alpha from right */ + + pTempdst++; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + } + } + } + + pTempsrc1 += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_x5 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X5, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 2; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* first half */ + { + *pTempdst = *pTempsrc1; /* replicate gray from left */ + + pTempdst++; + + if (*(pTempsrc1+1) == *(pTempsrc2+1)) + *pTempdst = *(pTempsrc1+1);/* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+1)) - + (mng_int32)(*(pTempsrc1+1)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+1)) ); + + pTempdst++; + } + + for (iS = iH; iS < iM; iS++) /* second half */ + { + *pTempdst = *pTempsrc2; /* replicate gray from right */ + + pTempdst++; + + if (*(pTempsrc1+1) == *(pTempsrc2+1)) + *pTempdst = *(pTempsrc1+1);/* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+1)) - + (mng_int32)(*(pTempsrc1+1)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+1)) ); + + pTempdst++; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + } + } + } + + pTempsrc1 += 2; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_X5, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX, iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X1, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + + if (iX == 0) /* first interval ? */ + iM = iML; + else + if (iX == (iWidth - 1)) /* last interval ? */ + iM = iMR; + else + iM = iMX; + + for (iS = 1; iS < iM; iS++) /* fill interval */ + { + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + } + + pTempsrc1 += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 4; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = (mng_int32)iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = (mng_int32)iMR; + else + iM = (mng_int32)iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + for (iS = 1; iS < iM; iS++) + { + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; /* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + + if (*(pTempsrc1+1) == *(pTempsrc2+1)) + *pTempdst = *(pTempsrc1+1); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+1)) - + (mng_int32)(*(pTempsrc1+1)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+1)) ); + + pTempdst++; + + if (*(pTempsrc1+2) == *(pTempsrc2+2)) + *pTempdst = *(pTempsrc1+2); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+2)) - + (mng_int32)(*(pTempsrc1+2)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+2)) ); + + pTempdst++; + + if (*(pTempsrc1+3) == *(pTempsrc2+3)) + *pTempdst = *(pTempsrc1+3); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+3)) - + (mng_int32)(*(pTempsrc1+3)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+3)) ); + + pTempdst++; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + } + } + } + + pTempsrc1 += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X3, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 4; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = (mng_int32)iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = (mng_int32)iMR; + else + iM = (mng_int32)iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* replicate first half */ + { + *pTempdst = *pTempsrc1; + *(pTempdst+1) = *(pTempsrc1+1); + *(pTempdst+2) = *(pTempsrc1+2); + *(pTempdst+3) = *(pTempsrc1+3); + + pTempdst += 4; + } + + for (iS = iH; iS < iM; iS++) /* replicate second half */ + { + *pTempdst = *pTempsrc2; + *(pTempdst+1) = *(pTempsrc2+1); + *(pTempdst+2) = *(pTempsrc2+2); + *(pTempdst+3) = *(pTempsrc2+3); + + pTempdst += 4; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + } + } + } + + pTempsrc1 += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X3, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_x4 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X4, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 4; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = (mng_int32)iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = (mng_int32)iMR; + else + iM = (mng_int32)iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* first half */ + { + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; /* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + + if (*(pTempsrc1+1) == *(pTempsrc2+1)) + *pTempdst = *(pTempsrc1+1); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+1)) - + (mng_int32)(*(pTempsrc1+1)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+1)) ); + + pTempdst++; + + if (*(pTempsrc1+2) == *(pTempsrc2+2)) + *pTempdst = *(pTempsrc1+2); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+2)) - + (mng_int32)(*(pTempsrc1+2)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+2)) ); + + pTempdst++; + /* replicate alpha from left */ + *pTempdst = *(pTempsrc1+3); + + pTempdst++; + } + + for (iS = iH; iS < iM; iS++) /* second half */ + { + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; /* just repeat the first */ + else /* calculate the distance */ + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2)) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + + if (*(pTempsrc1+1) == *(pTempsrc2+1)) + *pTempdst = *(pTempsrc1+1); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+1)) - + (mng_int32)(*(pTempsrc1+1)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+1)) ); + + pTempdst++; + + if (*(pTempsrc1+2) == *(pTempsrc2+2)) + *pTempdst = *(pTempsrc1+2); + else + *pTempdst = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+2)) - + (mng_int32)(*(pTempsrc1+2)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+2)) ); + + pTempdst++; + /* replicate alpha from right */ + *pTempdst = *(pTempsrc2+3); + + pTempdst++; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + } + } + } + + pTempsrc1 += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_x5 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_int32 iS, iM, iH; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X5, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline; /* initialize pixel-loop */ + pTempdst = pDstline; + + for (iX = 0; iX < iWidth; iX++) + { + pTempsrc2 = pTempsrc1 + 4; + + *pTempdst = *pTempsrc1; /* copy original source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + + if (iX == 0) /* first interval ? */ + { + if (iWidth == 1) /* single pixel ? */ + pTempsrc2 = MNG_NULL; + + iM = (mng_int32)iML; + } + else + if (iX == (iWidth - 2)) /* last interval ? */ + iM = (mng_int32)iMR; + else + iM = (mng_int32)iMX; + /* fill interval ? */ + if ((iX < iWidth - 1) || (iWidth == 1)) + { + if (pTempsrc2) /* do we have the second pixel ? */ + { + iH = (iM+1) / 2; /* calculate halfway point */ + + for (iS = 1; iS < iH; iS++) /* first half */ + { + *pTempdst = *pTempsrc1; /* replicate color from left */ + *(pTempdst+1) = *(pTempsrc1+1); + *(pTempdst+2) = *(pTempsrc1+2); + + if (*(pTempsrc1+3) == *(pTempsrc2+3)) + *(pTempdst+3) = *(pTempsrc1+3); + else + *(pTempdst+3) = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+3)) - + (mng_int32)(*(pTempsrc1+3)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+3)) ); + + pTempdst += 4; + } + + for (iS = iH; iS < iM; iS++) /* second half */ + { + *pTempdst = *pTempsrc2; /* replicate color from right */ + *(pTempdst+1) = *(pTempsrc2+1); + *(pTempdst+2) = *(pTempsrc2+2); + + if (*(pTempsrc1+3) == *(pTempsrc2+3)) + *(pTempdst+3) = *(pTempsrc1+3); + else + *(pTempdst+3) = (mng_uint8)(((2 * iS * ( (mng_int32)(*(pTempsrc2+3)) - + (mng_int32)(*(pTempsrc1+3)) ) + iM) / + (iM * 2)) + (mng_int32)(*(pTempsrc1+3)) ); + + pTempdst += 4; + } + } + else + { + for (iS = 1; iS < iM; iS++) + { + *pTempdst = *pTempsrc1; /* repeat first source pixel */ + pTempdst++; + *pTempdst = *(pTempsrc1+1); + pTempdst++; + *pTempdst = *(pTempsrc1+2); + pTempdst++; + *pTempdst = *(pTempsrc1+3); + pTempdst++; + } + } + } + + pTempsrc1 += 4; + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_X4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_g8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_Y1, MNG_LC_START) +#endif + + MNG_COPY (pDstline, pSrcline1, iWidth) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_Y1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_g8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_Y2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_Y2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_g8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_Y3, MNG_LC_START) +#endif + + if (pSrcline2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + MNG_COPY (pDstline, pSrcline1, iWidth) + else + MNG_COPY (pDstline, pSrcline2, iWidth) + } + else + { /* just repeat the entire line */ + MNG_COPY (pDstline, pSrcline1, iWidth) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_G8_Y3, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgb8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_Y1, MNG_LC_START) +#endif + + MNG_COPY (pDstline, pSrcline1, iWidth * 3) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_Y1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgb8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_Y2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth * 3) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_Y2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgb8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_Y3, MNG_LC_START) +#endif + + if (pSrcline2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + MNG_COPY (pDstline, pSrcline1, iWidth * 3) + else + MNG_COPY (pDstline, pSrcline2, iWidth * 3) + } + else + { /* just repeat the entire line */ + MNG_COPY (pDstline, pSrcline1, iWidth * 3) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGB8_Y3, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y1, MNG_LC_START) +#endif + + MNG_COPY (pDstline, pSrcline1, iWidth << 1) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth << 1) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y3, MNG_LC_START) +#endif + + if (pSrcline2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + MNG_COPY (pDstline, pSrcline1, iWidth << 1) + else + MNG_COPY (pDstline, pSrcline2, iWidth << 1) + } + else + { /* just repeat the entire line */ + MNG_COPY (pDstline, pSrcline1, iWidth << 1) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_y4 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y4, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2 += 2; + + *pTempdst++ = *pTempsrc1++; /* replicate alpha from top */ + } + } + else + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1 += 2; + pTempsrc2++; + + *pTempdst++ = *pTempsrc2++; /* replicate alpha from bottom */ + } + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth << 1) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_ga8_y5 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y5, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + { + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst = *pTempsrc1; /* replicate gray from top */ + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) /* calculate the distances */ + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + else + { + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst = *pTempsrc2; /* replicate gray from bottom */ + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) /* calculate the distances */ + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth << 1) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_GA8_Y5, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y1, MNG_LC_START) +#endif + + MNG_COPY (pDstline, pSrcline1, iWidth << 2) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y1, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y2, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth << 2) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y3, MNG_LC_START) +#endif + + if (pSrcline2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + MNG_COPY (pDstline, pSrcline1, iWidth << 2) + else + MNG_COPY (pDstline, pSrcline2, iWidth << 2) + } + else + { /* just repeat the entire line */ + MNG_COPY (pDstline, pSrcline1, iWidth << 2) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_y4 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y4, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2 += 2; + + *pTempdst++ = *pTempsrc1++; /* replicate alpha from top */ + } + } + else + { + for (iX = 0; iX < iWidth; iX++) + { /* calculate the distances */ + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + + if (*pTempsrc1 == *pTempsrc2) + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1 += 2; + pTempsrc2++; + + *pTempdst++ = *pTempsrc2++; /* replicate alpha from bottom */ + } + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth << 2) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y4, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode magnify_rgba8_y5 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline) +{ + mng_uint32 iX; + mng_uint8p pTempsrc1; + mng_uint8p pTempsrc2; + mng_uint8p pTempdst; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y5, MNG_LC_START) +#endif + + pTempsrc1 = pSrcline1; /* initialize pixel-loop */ + pTempsrc2 = pSrcline2; + pTempdst = pDstline; + + if (pTempsrc2) /* do we have a second line ? */ + { + if (iS < (iM+1) / 2) /* top half ? */ + { + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst++ = *pTempsrc1++; /* replicate color from top */ + *pTempdst++ = *pTempsrc1++; + *pTempdst++ = *pTempsrc1++; + + pTempsrc2 += 3; + + if (*pTempsrc1 == *pTempsrc2) /* calculate the distances */ + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + else + { + for (iX = 0; iX < iWidth; iX++) + { + *pTempdst++ = *pTempsrc2++; /* replicate color from bottom */ + *pTempdst++ = *pTempsrc2++; + *pTempdst++ = *pTempsrc2++; + + pTempsrc1 += 3; + + if (*pTempsrc1 == *pTempsrc2) /* calculate the distances */ + *pTempdst = *pTempsrc1; + else + *pTempdst = (mng_uint8)( ( (2 * iS * ( (mng_int32)(*pTempsrc2) - + (mng_int32)(*pTempsrc1) ) + iM) / + (iM * 2) ) + (mng_int32)(*pTempsrc1) ); + + pTempdst++; + pTempsrc1++; + pTempsrc2++; + } + } + } + else + { /* just repeat the entire line */ + MNG_COPY (pTempdst, pTempsrc1, iWidth << 2) + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_MAGNIFY_RGBA8_Y5, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_DISPLAY_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_pixels.h b/freeimage241/Source/LibMNG/libmng_pixels.h new file mode 100644 index 0000000..aa97c70 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_pixels.h @@ -0,0 +1,570 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_pixels.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.1 * */ +/* * * */ +/* * purpose : Pixel-row management routines (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the pixel-row management routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.5.2 - 05/22/2000 - G.Juyn * */ +/* * - added some JNG definitions * */ +/* * - added delta-image row-processing routines * */ +/* * 0.5.2 - 06/05/2000 - G.Juyn * */ +/* * - added support for RGB8_A8 canvasstyle * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - changed progressive-display processing * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN support * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added optional support for bKGD for PNG images * */ +/* * - added support for JDAA * */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - implemented delayed delta-processing * */ +/* * * */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - added "new" MAGN methods 3, 4 & 5 * */ +/* * * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn (code by G.Kelly) * */ +/* * - added BGRA8 canvas with premultiplied alpha * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_pixels_h_ +#define _libmng_pixels_h_ + +/* ************************************************************************** */ +/* * * */ +/* * Progressive display check - checks to see if progressive display is * */ +/* * in order & indicates so * */ +/* * * */ +/* * The routine is called after a call to one of the display_xxx routines * */ +/* * if appropriate * */ +/* * * */ +/* * The refresh is warrented in the read_chunk routine (mng_read.c) * */ +/* * and only during read&display processing, since there's not much point * */ +/* * doing it from memory! * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode display_progressive_check (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Display routines - convert rowdata (which is already color-corrected) * */ +/* * to the output canvas, respecting any transparency information * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode display_rgb8 (mng_datap pData); +mng_retcode display_rgba8 (mng_datap pData); +mng_retcode display_argb8 (mng_datap pData); +mng_retcode display_rgb8_a8 (mng_datap pData); +mng_retcode display_bgr8 (mng_datap pData); +mng_retcode display_bgra8 (mng_datap pData); +mng_retcode display_bgra8_pm (mng_datap pData); +mng_retcode display_abgr8 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Background restore routines - restore the background with info from * */ +/* * the BACK and/or bKGD chunk and/or the app's background canvas * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode restore_bkgd_backimage (mng_datap pData); +mng_retcode restore_bkgd_backcolor (mng_datap pData); +mng_retcode restore_bkgd_bkgd (mng_datap pData); +mng_retcode restore_bkgd_bgcolor (mng_datap pData); +mng_retcode restore_bkgd_rgb8 (mng_datap pData); +mng_retcode restore_bkgd_bgr8 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Row retrieval routines - retrieve processed & uncompressed row-data * */ +/* * from the current "object" * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode retrieve_g8 (mng_datap pData); +mng_retcode retrieve_g16 (mng_datap pData); +mng_retcode retrieve_rgb8 (mng_datap pData); +mng_retcode retrieve_rgb16 (mng_datap pData); +mng_retcode retrieve_idx8 (mng_datap pData); +mng_retcode retrieve_ga8 (mng_datap pData); +mng_retcode retrieve_ga16 (mng_datap pData); +mng_retcode retrieve_rgba8 (mng_datap pData); +mng_retcode retrieve_rgba16 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Row storage routines - store processed & uncompressed row-data * */ +/* * into the current "object" * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode store_g1 (mng_datap pData); +mng_retcode store_g2 (mng_datap pData); +mng_retcode store_g4 (mng_datap pData); +mng_retcode store_g8 (mng_datap pData); +mng_retcode store_g16 (mng_datap pData); +mng_retcode store_rgb8 (mng_datap pData); +mng_retcode store_rgb16 (mng_datap pData); +mng_retcode store_idx1 (mng_datap pData); +mng_retcode store_idx2 (mng_datap pData); +mng_retcode store_idx4 (mng_datap pData); +mng_retcode store_idx8 (mng_datap pData); +mng_retcode store_ga8 (mng_datap pData); +mng_retcode store_ga16 (mng_datap pData); +mng_retcode store_rgba8 (mng_datap pData); +mng_retcode store_rgba16 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Row storage routines (JPEG) - store processed & uncompressed row-data * */ +/* * into the current "object" * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode store_jpeg_g8 (mng_datap pData); +mng_retcode store_jpeg_rgb8 (mng_datap pData); +mng_retcode store_jpeg_ga8 (mng_datap pData); +mng_retcode store_jpeg_rgba8 (mng_datap pData); + +mng_retcode store_jpeg_g12 (mng_datap pData); +mng_retcode store_jpeg_rgb12 (mng_datap pData); +mng_retcode store_jpeg_ga12 (mng_datap pData); +mng_retcode store_jpeg_rgba12 (mng_datap pData); + +mng_retcode store_jpeg_g8_alpha (mng_datap pData); +mng_retcode store_jpeg_rgb8_alpha (mng_datap pData); + +mng_retcode store_jpeg_g8_a1 (mng_datap pData); +mng_retcode store_jpeg_g8_a2 (mng_datap pData); +mng_retcode store_jpeg_g8_a4 (mng_datap pData); +mng_retcode store_jpeg_g8_a8 (mng_datap pData); +mng_retcode store_jpeg_g8_a16 (mng_datap pData); + +mng_retcode store_jpeg_rgb8_a1 (mng_datap pData); +mng_retcode store_jpeg_rgb8_a2 (mng_datap pData); +mng_retcode store_jpeg_rgb8_a4 (mng_datap pData); +mng_retcode store_jpeg_rgb8_a8 (mng_datap pData); +mng_retcode store_jpeg_rgb8_a16 (mng_datap pData); + +mng_retcode store_jpeg_g12_a1 (mng_datap pData); +mng_retcode store_jpeg_g12_a2 (mng_datap pData); +mng_retcode store_jpeg_g12_a4 (mng_datap pData); +mng_retcode store_jpeg_g12_a8 (mng_datap pData); +mng_retcode store_jpeg_g12_a16 (mng_datap pData); + +mng_retcode store_jpeg_rgb12_a1 (mng_datap pData); +mng_retcode store_jpeg_rgb12_a2 (mng_datap pData); +mng_retcode store_jpeg_rgb12_a4 (mng_datap pData); +mng_retcode store_jpeg_rgb12_a8 (mng_datap pData); +mng_retcode store_jpeg_rgb12_a16 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Delta-image row routines - apply the processed & uncompressed row-data * */ +/* * onto the target "object" * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode delta_g1 (mng_datap pData); +mng_retcode delta_g2 (mng_datap pData); +mng_retcode delta_g4 (mng_datap pData); +mng_retcode delta_g8 (mng_datap pData); +mng_retcode delta_g16 (mng_datap pData); +mng_retcode delta_rgb8 (mng_datap pData); +mng_retcode delta_rgb16 (mng_datap pData); +mng_retcode delta_idx1 (mng_datap pData); +mng_retcode delta_idx2 (mng_datap pData); +mng_retcode delta_idx4 (mng_datap pData); +mng_retcode delta_idx8 (mng_datap pData); +mng_retcode delta_ga8 (mng_datap pData); +mng_retcode delta_ga16 (mng_datap pData); +mng_retcode delta_rgba8 (mng_datap pData); +mng_retcode delta_rgba16 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Delta-image row routines - apply the source row onto the target * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode delta_g1_g1 (mng_datap pData); +mng_retcode delta_g2_g2 (mng_datap pData); +mng_retcode delta_g4_g4 (mng_datap pData); +mng_retcode delta_g8_g8 (mng_datap pData); +mng_retcode delta_g16_g16 (mng_datap pData); +mng_retcode delta_rgb8_rgb8 (mng_datap pData); +mng_retcode delta_rgb16_rgb16 (mng_datap pData); +mng_retcode delta_ga8_ga8 (mng_datap pData); +mng_retcode delta_ga8_g8 (mng_datap pData); +mng_retcode delta_ga8_a8 (mng_datap pData); +mng_retcode delta_ga16_ga16 (mng_datap pData); +mng_retcode delta_ga16_g16 (mng_datap pData); +mng_retcode delta_ga16_a16 (mng_datap pData); +mng_retcode delta_rgba8_rgba8 (mng_datap pData); +mng_retcode delta_rgba8_rgb8 (mng_datap pData); +mng_retcode delta_rgba8_a8 (mng_datap pData); +mng_retcode delta_rgba16_rgba16 (mng_datap pData); +mng_retcode delta_rgba16_rgb16 (mng_datap pData); +mng_retcode delta_rgba16_a16 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Delta-image row routines - scale the source to bitdepth of target * */ +/* * * */ +/* ************************************************************************** */ + + + +/* ************************************************************************** */ +/* * * */ +/* * Row processing routines - convert uncompressed data from zlib to * */ +/* * managable row-data which serves as input to the color-management * */ +/* * routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode process_g1 (mng_datap pData); +mng_retcode process_g2 (mng_datap pData); +mng_retcode process_g4 (mng_datap pData); +mng_retcode process_g8 (mng_datap pData); +mng_retcode process_g16 (mng_datap pData); +mng_retcode process_rgb8 (mng_datap pData); +mng_retcode process_rgb16 (mng_datap pData); +mng_retcode process_idx1 (mng_datap pData); +mng_retcode process_idx2 (mng_datap pData); +mng_retcode process_idx4 (mng_datap pData); +mng_retcode process_idx8 (mng_datap pData); +mng_retcode process_ga8 (mng_datap pData); +mng_retcode process_ga16 (mng_datap pData); +mng_retcode process_rgba8 (mng_datap pData); +mng_retcode process_rgba16 (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Row processing initialization routines - set up the variables needed * */ +/* * to process uncompressed row-data * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode init_g1_ni (mng_datap pData); +mng_retcode init_g1_i (mng_datap pData); +mng_retcode init_g2_ni (mng_datap pData); +mng_retcode init_g2_i (mng_datap pData); +mng_retcode init_g4_ni (mng_datap pData); +mng_retcode init_g4_i (mng_datap pData); +mng_retcode init_g8_ni (mng_datap pData); +mng_retcode init_g8_i (mng_datap pData); +mng_retcode init_g16_ni (mng_datap pData); +mng_retcode init_g16_i (mng_datap pData); +mng_retcode init_rgb8_ni (mng_datap pData); +mng_retcode init_rgb8_i (mng_datap pData); +mng_retcode init_rgb16_ni (mng_datap pData); +mng_retcode init_rgb16_i (mng_datap pData); +mng_retcode init_idx1_ni (mng_datap pData); +mng_retcode init_idx1_i (mng_datap pData); +mng_retcode init_idx2_ni (mng_datap pData); +mng_retcode init_idx2_i (mng_datap pData); +mng_retcode init_idx4_ni (mng_datap pData); +mng_retcode init_idx4_i (mng_datap pData); +mng_retcode init_idx8_ni (mng_datap pData); +mng_retcode init_idx8_i (mng_datap pData); +mng_retcode init_ga8_ni (mng_datap pData); +mng_retcode init_ga8_i (mng_datap pData); +mng_retcode init_ga16_ni (mng_datap pData); +mng_retcode init_ga16_i (mng_datap pData); +mng_retcode init_rgba8_ni (mng_datap pData); +mng_retcode init_rgba8_i (mng_datap pData); +mng_retcode init_rgba16_ni (mng_datap pData); +mng_retcode init_rgba16_i (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Row processing initialization routines (JPEG) - set up the variables * */ +/* * needed to process uncompressed row-data * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode init_jpeg_a1_ni (mng_datap pData); +mng_retcode init_jpeg_a2_ni (mng_datap pData); +mng_retcode init_jpeg_a4_ni (mng_datap pData); +mng_retcode init_jpeg_a8_ni (mng_datap pData); +mng_retcode init_jpeg_a16_ni (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * General row processing routines * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode init_rowproc (mng_datap pData); +mng_retcode next_row (mng_datap pData); +mng_retcode next_jpeg_alpharow (mng_datap pData); +mng_retcode next_jpeg_row (mng_datap pData); +mng_retcode cleanup_rowproc (mng_datap pData); + +/* ************************************************************************** */ +/* * * */ +/* * Magnification row routines - apply magnification transforms * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode magnify_g8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_g8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_g8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgb8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgb8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgb8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_ga8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_ga8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_ga8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_ga8_x4 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_ga8_x5 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_x1 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_x2 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_x3 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_x4 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_x5 (mng_datap pData, + mng_uint16 iMX, + mng_uint16 iML, + mng_uint16 iMR, + mng_uint32 iWidth, + mng_uint8p pSrcline, + mng_uint8p pDstline); + +mng_retcode magnify_g8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_g8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_g8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgb8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgb8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgb8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_ga8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_ga8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_ga8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_ga8_y4 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_ga8_y5 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_y1 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_y2 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_y3 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_y4 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); +mng_retcode magnify_rgba8_y5 (mng_datap pData, + mng_int32 iS, + mng_int32 iM, + mng_uint32 iWidth, + mng_uint8p pSrcline1, + mng_uint8p pSrcline2, + mng_uint8p pDstline); + +/* ************************************************************************** */ + +#endif /* _libmng_pixels_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_prop_xs.c b/freeimage241/Source/LibMNG/libmng_prop_xs.c new file mode 100644 index 0000000..8ff252e --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_prop_xs.c @@ -0,0 +1,2322 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_prop_xs.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : property get/set interface (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the property get/set functions * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - fixed calling convention * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added set_outputprofile2 & set_srgbprofile2 * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - changed inclusion of cms-routines * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added support for get/set default zlib/IJG parms * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - fixed up punctuation (contribution by Tim Rowley) * */ +/* * 0.5.2 - 06/05/2000 - G.Juyn * */ +/* * - added support for RGB8_A8 canvasstyle * */ +/* * * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added get/set for speedtype to facilitate testing * */ +/* * - added get for imagelevel during processtext callback * */ +/* * 0.5.3 - 06/26/2000 - G.Juyn * */ +/* * - changed userdata variable to mng_ptr * */ +/* * 0.5.3 - 06/29/2000 - G.Juyn * */ +/* * - fixed incompatible return-types * */ +/* * * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - added get routines for internal display variables * */ +/* * - added get/set routines for suspensionmode variable * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added get/set routines for sectionbreak variable * */ +/* * * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - added status_xxxx functions * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 10/10/2000 - G.Juyn * */ +/* * - added support for alpha-depth prediction * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added functions to retrieve PNG/JNG specific header-info * */ +/* * 0.9.3 - 10/20/2000 - G.Juyn * */ +/* * - added get/set for bKGD preference setting * */ +/* * 0.9.3 - 10/21/2000 - G.Juyn * */ +/* * - added get function for interlace/progressive display * */ +/* * * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn (code by G.Kelly) * */ +/* * - added BGRA8 canvas with premultiplied alpha * */ +/* * 1.0.1 - 05/02/2001 - G.Juyn * */ +/* * - added "default" sRGB generation (Thanks Marti!) * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - added option to turn off progressive refresh * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_cms.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ +/* * * */ +/* * Property set functions * */ +/* * * */ +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_userdata (mng_handle hHandle, + mng_ptr pUserdata) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_USERDATA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->pUserdata = pUserdata; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_USERDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_canvasstyle (mng_handle hHandle, + mng_uint32 iStyle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_CANVASSTYLE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + + switch (iStyle) + { + case MNG_CANVAS_RGB8 : break; + case MNG_CANVAS_RGBA8 : break; + case MNG_CANVAS_ARGB8 : break; + case MNG_CANVAS_RGB8_A8 : break; + case MNG_CANVAS_BGR8 : break; + case MNG_CANVAS_BGRA8 : break; + case MNG_CANVAS_BGRA8PM : break; + case MNG_CANVAS_ABGR8 : break; +/* case MNG_CANVAS_RGB16 : break; */ +/* case MNG_CANVAS_RGBA16 : break; */ +/* case MNG_CANVAS_ARGB16 : break; */ +/* case MNG_CANVAS_BGR16 : break; */ +/* case MNG_CANVAS_BGRA16 : break; */ +/* case MNG_CANVAS_ABGR16 : break; */ +/* case MNG_CANVAS_INDEX8 : break; */ +/* case MNG_CANVAS_INDEXA8 : break; */ +/* case MNG_CANVAS_AINDEX8 : break; */ +/* case MNG_CANVAS_GRAY8 : break; */ +/* case MNG_CANVAS_GRAY16 : break; */ +/* case MNG_CANVAS_GRAYA8 : break; */ +/* case MNG_CANVAS_GRAYA16 : break; */ +/* case MNG_CANVAS_AGRAY8 : break; */ +/* case MNG_CANVAS_AGRAY16 : break; */ +/* case MNG_CANVAS_DX15 : break; */ +/* case MNG_CANVAS_DX16 : break; */ + default : { MNG_ERROR (((mng_datap)hHandle), MNG_INVALIDCNVSTYLE) } + } + + ((mng_datap)hHandle)->iCanvasstyle = iStyle; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_CANVASSTYLE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_bkgdstyle (mng_handle hHandle, + mng_uint32 iStyle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_BKGDSTYLE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + + switch (iStyle) /* alpha-modes not supported */ + { + case MNG_CANVAS_RGB8 : break; + case MNG_CANVAS_BGR8 : break; +/* case MNG_CANVAS_RGB16 : break; */ +/* case MNG_CANVAS_BGR16 : break; */ +/* case MNG_CANVAS_INDEX8 : break; */ +/* case MNG_CANVAS_GRAY8 : break; */ +/* case MNG_CANVAS_GRAY16 : break; */ +/* case MNG_CANVAS_DX15 : break; */ +/* case MNG_CANVAS_DX16 : break; */ + default : MNG_ERROR (((mng_datap)hHandle), MNG_INVALIDCNVSTYLE) + } + + ((mng_datap)hHandle)->iBkgdstyle = iStyle; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_BKGDSTYLE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_bgcolor (mng_handle hHandle, + mng_uint16 iRed, + mng_uint16 iGreen, + mng_uint16 iBlue) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_BGCOLOR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iBGred = iRed; + ((mng_datap)hHandle)->iBGgreen = iGreen; + ((mng_datap)hHandle)->iBGblue = iBlue; + ((mng_datap)hHandle)->bUseBKGD = MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_BGCOLOR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_usebkgd (mng_handle hHandle, + mng_bool bUseBKGD) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_USEBKGD, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->bUseBKGD = bUseBKGD; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_USEBKGD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_storechunks (mng_handle hHandle, + mng_bool bStorechunks) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_STORECHUNKS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->bStorechunks = bStorechunks; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_STORECHUNKS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_sectionbreaks (mng_handle hHandle, + mng_bool bSectionbreaks) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SECTIONBREAKS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->bSectionbreaks = bSectionbreaks; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SECTIONBREAKS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_cacheplayback (mng_handle hHandle, + mng_bool bCacheplayback) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_CACHEPLAYBACK, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + + if (((mng_datap)hHandle)->bHasheader) + MNG_ERROR (((mng_datap)hHandle), MNG_FUNCTIONINVALID) + + ((mng_datap)hHandle)->bCacheplayback = bCacheplayback; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_CACHEPLAYBACK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_doprogressive (mng_handle hHandle, + mng_bool bDoProgressive) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DOPROGRESSIVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + + ((mng_datap)hHandle)->bDoProgressive = bDoProgressive; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DOPROGRESSIVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_set_srgb (mng_handle hHandle, + mng_bool bIssRGB) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGB, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->bIssRGB = bIssRGB; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_set_outputprofile (mng_handle hHandle, + mng_pchar zFilename) +{ +#ifdef MNG_INCLUDE_LCMS + mng_datap pData; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_OUTPUTPROFILE, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_LCMS + MNG_VALIDHANDLE (hHandle) + + pData = (mng_datap)hHandle; /* address the structure */ + + if (pData->hProf2) /* previously defined ? */ + mnglcms_freeprofile (pData->hProf2); + /* allocate new CMS profile handle */ + pData->hProf2 = mnglcms_createfileprofile (zFilename); + + if (!pData->hProf2) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) +#endif /* MNG_INCLUDE_LCMS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_OUTPUTPROFILE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_set_outputprofile2 (mng_handle hHandle, + mng_uint32 iProfilesize, + mng_ptr pProfile) +{ +#ifdef MNG_INCLUDE_LCMS + mng_datap pData; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_OUTPUTPROFILE2, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_LCMS + MNG_VALIDHANDLE (hHandle) + + pData = (mng_datap)hHandle; /* address the structure */ + + if (pData->hProf2) /* previously defined ? */ + mnglcms_freeprofile (pData->hProf2); + /* allocate new CMS profile handle */ + pData->hProf2 = mnglcms_creatememprofile (iProfilesize, pProfile); + + if (!pData->hProf2) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) +#endif /* MNG_INCLUDE_LCMS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_OUTPUTPROFILE2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_outputsrgb (mng_handle hHandle) +{ +#ifdef MNG_INCLUDE_LCMS + mng_datap pData; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_OUTPUTSRGB, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_LCMS + MNG_VALIDHANDLE (hHandle) + + pData = (mng_datap)hHandle; /* address the structure */ + + if (pData->hProf2) /* previously defined ? */ + mnglcms_freeprofile (pData->hProf2); + /* allocate new CMS profile handle */ + pData->hProf2 = mnglcms_createsrgbprofile (); + + if (!pData->hProf2) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) +#endif /* MNG_INCLUDE_LCMS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_OUTPUTSRGB, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_set_srgbprofile (mng_handle hHandle, + mng_pchar zFilename) +{ +#ifdef MNG_INCLUDE_LCMS + mng_datap pData; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGBPROFILE2, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_LCMS + MNG_VALIDHANDLE (hHandle) + + pData = (mng_datap)hHandle; /* address the structure */ + + if (pData->hProf3) /* previously defined ? */ + mnglcms_freeprofile (pData->hProf3); + /* allocate new CMS profile handle */ + pData->hProf3 = mnglcms_createfileprofile (zFilename); + + if (!pData->hProf3) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) +#endif /* MNG_INCLUDE_LCMS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGBPROFILE2, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_set_srgbprofile2 (mng_handle hHandle, + mng_uint32 iProfilesize, + mng_ptr pProfile) +{ +#ifdef MNG_INCLUDE_LCMS + mng_datap pData; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGBPROFILE, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_LCMS + MNG_VALIDHANDLE (hHandle) + + pData = (mng_datap)hHandle; /* address the structure */ + + if (pData->hProf3) /* previously defined ? */ + mnglcms_freeprofile (pData->hProf3); + /* allocate new CMS profile handle */ + pData->hProf3 = mnglcms_creatememprofile (iProfilesize, pProfile); + + if (!pData->hProf3) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) +#endif /* MNG_INCLUDE_LCMS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGBPROFILE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_srgbimplicit (mng_handle hHandle) +{ +#ifdef MNG_INCLUDE_LCMS + mng_datap pData; +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGBIMPLICIT, MNG_LC_START) +#endif + +#ifdef MNG_INCLUDE_LCMS + MNG_VALIDHANDLE (hHandle) + + pData = (mng_datap)hHandle; /* address the structure */ + + if (pData->hProf3) /* previously defined ? */ + mnglcms_freeprofile (pData->hProf3); + /* allocate new CMS profile handle */ + pData->hProf3 = mnglcms_createsrgbprofile (); + + if (!pData->hProf3) /* handle error ? */ + MNG_ERRORL (pData, MNG_LCMS_NOHANDLE) +#endif /* MNG_INCLUDE_LCMS */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SRGBIMPLICIT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_viewgamma (mng_handle hHandle, + mng_float dGamma) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_VIEWGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->dViewgamma = dGamma; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_VIEWGAMMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_displaygamma (mng_handle hHandle, + mng_float dGamma) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DISPLAYGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->dDisplaygamma = dGamma; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DISPLAYGAMMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_dfltimggamma (mng_handle hHandle, + mng_float dGamma) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DFLTIMGGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->dDfltimggamma = dGamma; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DFLTIMGGAMMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_viewgammaint (mng_handle hHandle, + mng_uint32 iGamma) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_VIEWGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->dViewgamma = (mng_float)iGamma / 100000; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_VIEWGAMMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_displaygammaint (mng_handle hHandle, + mng_uint32 iGamma) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DISPLAYGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->dDisplaygamma = (mng_float)iGamma / 100000; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DISPLAYGAMMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_dfltimggammaint (mng_handle hHandle, + mng_uint32 iGamma) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DFLTIMGGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->dDfltimggamma = (mng_float)iGamma / 100000; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_DFLTIMGGAMMA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_maxcanvaswidth (mng_handle hHandle, + mng_uint32 iMaxwidth) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_MAXCANVASWIDTH, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iMaxwidth = iMaxwidth; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_MAXCANVASWIDTH, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_maxcanvasheight (mng_handle hHandle, + mng_uint32 iMaxheight) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_MAXCANVASHEIGHT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iMaxheight = iMaxheight; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_MAXCANVASHEIGHT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_set_maxcanvassize (mng_handle hHandle, + mng_uint32 iMaxwidth, + mng_uint32 iMaxheight) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_MAXCANVASSIZE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iMaxwidth = iMaxwidth; + ((mng_datap)hHandle)->iMaxheight = iMaxheight; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_MAXCANVASSIZE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_retcode MNG_DECL mng_set_zlib_level (mng_handle hHandle, + mng_int32 iZlevel) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_LEVEL, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iZlevel = iZlevel; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_LEVEL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_retcode MNG_DECL mng_set_zlib_method (mng_handle hHandle, + mng_int32 iZmethod) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_METHOD, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iZmethod = iZmethod; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_METHOD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_retcode MNG_DECL mng_set_zlib_windowbits (mng_handle hHandle, + mng_int32 iZwindowbits) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_WINDOWBITS, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iZwindowbits = iZwindowbits; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_WINDOWBITS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_retcode MNG_DECL mng_set_zlib_memlevel (mng_handle hHandle, + mng_int32 iZmemlevel) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_MEMLEVEL, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iZmemlevel = iZmemlevel; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_MEMLEVEL, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_retcode MNG_DECL mng_set_zlib_strategy (mng_handle hHandle, + mng_int32 iZstrategy) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_STRATEGY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iZstrategy = iZstrategy; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_STRATEGY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_retcode MNG_DECL mng_set_zlib_maxidat (mng_handle hHandle, + mng_uint32 iMaxIDAT) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_MAXIDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iMaxIDAT = iMaxIDAT; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_ZLIB_MAXIDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode MNG_DECL mng_set_jpeg_dctmethod (mng_handle hHandle, + mngjpeg_dctmethod eJPEGdctmethod) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_DCTMETHOD, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->eJPEGdctmethod = eJPEGdctmethod; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_DCTMETHOD, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode MNG_DECL mng_set_jpeg_quality (mng_handle hHandle, + mng_int32 iJPEGquality) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_QUALITY, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iJPEGquality = iJPEGquality; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_QUALITY, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode MNG_DECL mng_set_jpeg_smoothing (mng_handle hHandle, + mng_int32 iJPEGsmoothing) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_SMOOTHING, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iJPEGsmoothing = iJPEGsmoothing; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_SMOOTHING, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode MNG_DECL mng_set_jpeg_progressive (mng_handle hHandle, + mng_bool bJPEGprogressive) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_PROGRESSIVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->bJPEGcompressprogr = bJPEGprogressive; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_PROGRESSIVE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode MNG_DECL mng_set_jpeg_optimized (mng_handle hHandle, + mng_bool bJPEGoptimized) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_OPTIMIZED, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->bJPEGcompressopt = bJPEGoptimized; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_OPTIMIZED, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_retcode MNG_DECL mng_set_jpeg_maxjdat (mng_handle hHandle, + mng_uint32 iMaxJDAT) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_MAXJDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iMaxJDAT = iMaxJDAT; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_JPEG_MAXJDAT, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_retcode MNG_DECL mng_set_suspensionmode (mng_handle hHandle, + mng_bool bSuspensionmode) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SUSPENSIONMODE, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + + if (((mng_datap)hHandle)->bReading) /* we must NOT be reading !!! */ + MNG_ERROR ((mng_datap)hHandle, MNG_FUNCTIONINVALID) + + ((mng_datap)hHandle)->bSuspensionmode = bSuspensionmode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SUSPENSIONMODE, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode MNG_DECL mng_set_speed (mng_handle hHandle, + mng_speedtype iSpeed) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SPEED, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + ((mng_datap)hHandle)->iSpeed = iSpeed; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_SET_SPEED, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ +/* * * */ +/* * Property get functions * */ +/* * * */ +/* ************************************************************************** */ + +mng_ptr MNG_DECL mng_get_userdata (mng_handle hHandle) +{ /* no tracing in here to prevent recursive calls */ + MNG_VALIDHANDLEX (hHandle) + return ((mng_datap)hHandle)->pUserdata; +} + +/* ************************************************************************** */ + +mng_imgtype MNG_DECL mng_get_sigtype (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SIGTYPE, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_it_unknown; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SIGTYPE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->eSigtype; +} + +/* ************************************************************************** */ + +mng_imgtype MNG_DECL mng_get_imagetype (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGETYPE, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_it_unknown; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGETYPE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->eImagetype; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_imagewidth (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGEWIDTH, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGEWIDTH, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iWidth; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_imageheight (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGEWIDTH, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGEHEIGHT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iHeight; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_ticks (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_TICKS, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_TICKS, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iTicks; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_framecount (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_FRAMECOUNT, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_FRAMECOUNT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iFramecount; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_layercount (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_LAYERCOUNT, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_LAYERCOUNT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iLayercount; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_playtime (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_PLAYTIME, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_PLAYTIME, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iPlaytime; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_simplicity (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SIMPLICITY, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SIMPLICITY, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iSimplicity; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_bitdepth (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_BITDEPTH, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_png) + iRslt = ((mng_datap)hHandle)->iBitdepth; + else + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRimgbitdepth; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_BITDEPTH, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_colortype (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_COLORTYPE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_png) + iRslt = ((mng_datap)hHandle)->iColortype; + else + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRcolortype; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_COLORTYPE, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_compression (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_COMPRESSION, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_png) + iRslt = ((mng_datap)hHandle)->iCompression; + else + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRimgcompression; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_COMPRESSION, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_filter (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_FILTER, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_png) + iRslt = ((mng_datap)hHandle)->iFilter; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_FILTER, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_interlace (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_INTERLACE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_png) + iRslt = ((mng_datap)hHandle)->iInterlace; + else + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRimginterlace; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_INTERLACE, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_alphabitdepth (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHABITDEPTH, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRalphabitdepth; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHABITDEPTH, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_refreshpass (mng_handle hHandle) +{ + mng_uint8 iRslt; + mng_datap pData; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_REFRESHPASS, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + pData = (mng_datap)hHandle; + /* for PNG we know the exact pass */ + if ((pData->eImagetype == mng_it_png) && (pData->iPass >= 0)) + iRslt = pData->iPass; +#ifdef MNG_INCLUDE_JNG + else /* for JNG we'll fake it... */ + if ((pData->eImagetype == mng_it_jng) && + (pData->bJPEGhasheader) && (pData->bJPEGdecostarted) && + (pData->bJPEGprogressive)) + { + if (pData->pJPEGdinfo->input_scan_number <= 1) + iRslt = 0; /* first pass (I think...) */ + else + if (jpeg_input_complete (pData->pJPEGdinfo)) + iRslt = 7; /* input complete; aka final pass */ + else + iRslt = 3; /* anything between 0 and 7 will do */ + + } +#endif + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_REFRESHPASS, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_alphacompression (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHACOMPRESSION, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRalphacompression; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHACOMPRESSION, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_alphafilter (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHAFILTER, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRalphafilter; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHAFILTER, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_alphainterlace (mng_handle hHandle) +{ + mng_uint8 iRslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHAINTERLACE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + + if (((mng_datap)hHandle)->eImagetype == mng_it_jng) + iRslt = ((mng_datap)hHandle)->iJHDRalphainterlace; + else + iRslt = 0; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHAINTERLACE, MNG_LC_END) +#endif + + return iRslt; +} + +/* ************************************************************************** */ + +mng_uint8 MNG_DECL mng_get_alphadepth (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHADEPTH, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ALPHADEPTH, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iAlphadepth; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_canvasstyle (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CANVASSTYLE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CANVASSTYLE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iCanvasstyle; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_bkgdstyle (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_BKGDSTYLE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_BKGDSTYLE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iBkgdstyle; +} + +/* ************************************************************************** */ + +mng_retcode MNG_DECL mng_get_bgcolor (mng_handle hHandle, + mng_uint16* iRed, + mng_uint16* iGreen, + mng_uint16* iBlue) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GET_BGCOLOR, MNG_LC_START) +#endif + + MNG_VALIDHANDLE (hHandle) + *iRed = ((mng_datap)hHandle)->iBGred; + *iGreen = ((mng_datap)hHandle)->iBGgreen; + *iBlue = ((mng_datap)hHandle)->iBGblue; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (((mng_datap)hHandle), MNG_FN_GET_BGCOLOR, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_bool MNG_DECL mng_get_usebkgd (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_USEBKGD, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_USEBKGD, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bUseBKGD; +} + +/* ************************************************************************** */ + +mng_bool MNG_DECL mng_get_storechunks (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_STORECHUNKS, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_STORECHUNKS, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bStorechunks; +} + +/* ************************************************************************** */ + +mng_bool MNG_DECL mng_get_sectionbreaks (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_SECTIONBREAKS, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_SECTIONBREAKS, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bSectionbreaks; +} + +/* ************************************************************************** */ + +mng_bool MNG_DECL mng_get_cacheplayback (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_CACHEPLAYBACK, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_CACHEPLAYBACK, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bCacheplayback; +} + +/* ************************************************************************** */ + +mng_bool MNG_DECL mng_get_doprogressive (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_DOPROGRESSIVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_DOPROGRESSIVE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bDoProgressive; +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_bool MNG_DECL mng_get_srgb (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_SRGB, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEB (((mng_datap)hHandle), MNG_FN_GET_SRGB, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bIssRGB; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +mng_float MNG_DECL mng_get_viewgamma (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_VIEWGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_VIEWGAMMA, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->dViewgamma; +} + +/* ************************************************************************** */ + +mng_float MNG_DECL mng_get_displaygamma (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DISPLAYGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DISPLAYGAMMA, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->dDisplaygamma; +} + +/* ************************************************************************** */ + +mng_float MNG_DECL mng_get_dfltimggamma (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DFLTIMGGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DFLTIMGGAMMA, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->dDfltimggamma; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_viewgammaint (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_VIEWGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_VIEWGAMMA, MNG_LC_END) +#endif + + return (mng_uint32)(((mng_datap)hHandle)->dViewgamma * 100000); +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_displaygammaint (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DISPLAYGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DISPLAYGAMMA, MNG_LC_END) +#endif + + return (mng_uint32)(((mng_datap)hHandle)->dDisplaygamma * 100000); +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_dfltimggammaint (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DFLTIMGGAMMA, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_DFLTIMGGAMMA, MNG_LC_END) +#endif + + return (mng_uint32)(((mng_datap)hHandle)->dDfltimggamma * 100000); +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_maxcanvaswidth (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_MAXCANVASWIDTH, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_MAXCANVASWIDTH, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iMaxwidth; +} + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_maxcanvasheight (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_MAXCANVASHEIGHT, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_MAXCANVASHEIGHT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iMaxheight; +} + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_int32 MNG_DECL mng_get_zlib_level (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_LEVEL, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_LEVEL, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iZlevel; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_int32 MNG_DECL mng_get_zlib_method (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_METHOD, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_METHOD, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iZmethod; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_int32 MNG_DECL mng_get_zlib_windowbits (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_WINDOWBITS, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_WINDOWBITS, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iZwindowbits; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_int32 MNG_DECL mng_get_zlib_memlevel (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_MEMLEVEL, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_MEMLEVEL, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iZmemlevel; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_int32 MNG_DECL mng_get_zlib_strategy (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_STRATEGY, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_STRATEGY, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iZstrategy; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB +mng_uint32 MNG_DECL mng_get_zlib_maxidat (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_MAXIDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_ZLIB_MAXIDAT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iMaxIDAT; +} +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mngjpeg_dctmethod MNG_DECL mng_get_jpeg_dctmethod (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_DCTMETHOD, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return JDCT_ISLOW; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_DCTMETHOD, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->eJPEGdctmethod; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_int32 MNG_DECL mng_get_jpeg_quality (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_QUALITY, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_QUALITY, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iJPEGquality; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_int32 MNG_DECL mng_get_jpeg_smoothing (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_SMOOTHING, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_SMOOTHING, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iJPEGsmoothing; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_bool MNG_DECL mng_get_jpeg_progressive (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_PROGRESSIVE, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_PROGRESSIVE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bJPEGcompressprogr; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_bool MNG_DECL mng_get_jpeg_optimized (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_OPTIMIZED, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_OPTIMIZED, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bJPEGcompressopt; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG +mng_uint32 MNG_DECL mng_get_jpeg_maxjdat (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_MAXJDAT, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_JPEG_MAXJDAT, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iMaxJDAT; +} +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_bool MNG_DECL mng_get_suspensionmode (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SUSPENSIONMODE, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_st_normal; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SUSPENSIONMODE, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bSuspensionmode; +} +#endif /* MNG_SUPPORT_READ */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_speedtype MNG_DECL mng_get_speed (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SPEED, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_st_normal; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_SPEED, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iSpeed; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +mng_uint32 MNG_DECL mng_get_imagelevel (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGELEVEL, MNG_LC_START) +#endif + + MNG_VALIDHANDLEX (hHandle) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_IMAGELEVEL, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iImagelevel; +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_uint32 MNG_DECL mng_get_starttime (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_STARTTIME, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_st_normal; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_STARTTIME, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iStarttime; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_uint32 MNG_DECL mng_get_runtime (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_RUNTIME, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_st_normal; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_RUNTIME, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iRuntime; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_uint32 MNG_DECL mng_get_currentframe (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CURRENTFRAME, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_st_normal; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CURRENTFRAME, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iFrameseq; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_uint32 MNG_DECL mng_get_currentlayer (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CURRENTLAYER, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_st_normal; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CURRENTLAYER, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iLayerseq; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_uint32 MNG_DECL mng_get_currentplaytime (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CURRENTPLAYTIME, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return mng_st_normal; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_GET_CURRENTPLAYTIME, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->iFrametime; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +mng_bool MNG_DECL mng_status_error (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_ERROR, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_ERROR, MNG_LC_END) +#endif + + return (mng_bool)((mng_datap)hHandle)->iErrorcode; +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_bool MNG_DECL mng_status_reading (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_READING, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_READING, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bReading; +} +#endif + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_READ +mng_bool MNG_DECL mng_status_suspendbreak (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_SUSPENDBREAK, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_SUSPENDBREAK, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bSuspended; +} +#endif + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_WRITE +mng_bool MNG_DECL mng_status_creating (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_CREATING, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_CREATING, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bCreating; +} +#endif + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_WRITE +mng_bool MNG_DECL mng_status_writing (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_WRITING, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_WRITING, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bWriting; +} +#endif + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_bool MNG_DECL mng_status_displaying (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_DISPLAYING, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_DISPLAYING, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bDisplaying; +} +#endif + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_bool MNG_DECL mng_status_running (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_RUNNING, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_RUNNING, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bRunning; +} +#endif + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_bool MNG_DECL mng_status_timerbreak (mng_handle hHandle) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_TIMERBREAK, MNG_LC_START) +#endif + + if ((hHandle == 0) || (((mng_datap)hHandle)->iMagic != MNG_MAGIC)) + return MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACEX (((mng_datap)hHandle), MNG_FN_STATUS_TIMERBREAK, MNG_LC_END) +#endif + + return ((mng_datap)hHandle)->bTimerset; +} +#endif + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_read.c b/freeimage241/Source/LibMNG/libmng_read.c new file mode 100644 index 0000000..61c0e9c --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_read.c @@ -0,0 +1,693 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_read.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Read logic (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the high-level read logic * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - added callback error-reporting support * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.5.2 - 05/19/2000 - G.Juyn * */ +/* * - cleaned up some code regarding mixed support * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - added support for JNG * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - fixed up punctuation (contribution by Tim Rowley) * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - changed progressive-display processing * */ +/* * * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - changed read-processing for improved I/O-suspension * */ +/* * 0.9.1 - 07/14/2000 - G.Juyn * */ +/* * - changed EOF processing behavior * */ +/* * 0.9.1 - 07/14/2000 - G.Juyn * */ +/* * - changed default readbuffer size from 1024 to 4200 * */ +/* * * */ +/* * 0.9.2 - 07/27/2000 - G.Juyn * */ +/* * - B110320 - fixed GCC warning about mix-sized pointer math * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - B110546 - fixed for improperly returning UNEXPECTEDEOF * */ +/* * 0.9.2 - 08/04/2000 - G.Juyn * */ +/* * - B111096 - fixed large-buffer read-suspension * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - removed test-MaGN * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added support for JDAA * */ +/* * * */ +/* * 0.9.5 - 1/23/2001 - G.Juyn * */ +/* * - fixed timing-problem with switching framing_modes * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_memory.h" +#include "libmng_objects.h" +#include "libmng_object_prc.h" +#include "libmng_chunks.h" +#include "libmng_chunk_prc.h" +#include "libmng_chunk_io.h" +#include "libmng_display.h" +#include "libmng_read.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_READ_PROCS + +/* ************************************************************************** */ + +mng_retcode process_eof (mng_datap pData) +{ + if (!pData->bEOF) /* haven't closed the stream yet ? */ + { + pData->bEOF = MNG_TRUE; /* now we do! */ + + if (!pData->fClosestream ((mng_handle)pData)) + MNG_ERROR (pData, MNG_APPIOERROR) + } + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode read_databuffer (mng_datap pData, + mng_uint8p pBuf, + mng_uint32 iSize, + mng_uint32 * iRead) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DATABUFFER, MNG_LC_START) +#endif + + if (pData->bSuspensionmode) + { + mng_uint8p pTemp; + mng_uint32 iTemp; + + *iRead = 0; /* let's be negative about the outcome */ + + if (!pData->pSuspendbuf) /* need to create a suspension buffer ? */ + { + pData->iSuspendbufsize = MNG_SUSPENDBUFFERSIZE; + /* so, create it */ + MNG_ALLOC (pData, pData->pSuspendbuf, pData->iSuspendbufsize) + + pData->iSuspendbufleft = 0; /* make sure to fill it first time */ + pData->pSuspendbufnext = pData->pSuspendbuf; + } + /* more than our buffer can hold ? */ + if (iSize > pData->iSuspendbufsize) + { + mng_uint32 iRemain; + + if (!pData->pReadbufnext) /* first time ? */ + { + if (pData->iSuspendbufleft) /* do we have some data left ? */ + { /* then copy it */ + MNG_COPY (pBuf, pData->pSuspendbufnext, pData->iSuspendbufleft) + /* fixup variables */ + pData->pReadbufnext = pBuf + pData->iSuspendbufleft; + pData->pSuspendbufnext = pData->pSuspendbuf; + pData->iSuspendbufleft = 0; + } + else + { + pData->pReadbufnext = pBuf; + } + } + /* calculate how much to get */ + iRemain = iSize - (mng_uint32)(pData->pReadbufnext - pBuf); + /* let's go get it */ + if (!pData->fReaddata (((mng_handle)pData), pData->pReadbufnext, iRemain, &iTemp)) + MNG_ERROR (pData, MNG_APPIOERROR); + /* first read after suspension return 0 means EOF */ + if ((pData->iSuspendpoint) && (iTemp == 0)) + { /* that makes it final */ + mng_retcode iRetcode = process_eof (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + /* indicate the source is depleted */ + *iRead = iSize - iRemain + iTemp; + } + else + { + if (iTemp < iRemain) /* suspension required ? */ + { + pData->pReadbufnext = pData->pReadbufnext + iTemp; + pData->bSuspended = MNG_TRUE; + } + else + { + *iRead = iSize; /* got it all now ! */ + } + } + } + else + { /* need to read some more ? */ + while ((!pData->bSuspended) && (!pData->bEOF) && (iSize > pData->iSuspendbufleft)) + { /* not enough space left in buffer ? */ + if (pData->iSuspendbufsize - pData->iSuspendbufleft - + (mng_uint32)(pData->pSuspendbufnext - pData->pSuspendbuf) < + MNG_SUSPENDREQUESTSIZE) + { + if (pData->iSuspendbufleft) /* then lets shift (if there's anything left) */ + MNG_COPY (pData->pSuspendbuf, pData->pSuspendbufnext, pData->iSuspendbufleft) + /* adjust running pointer */ + pData->pSuspendbufnext = pData->pSuspendbuf; + } + /* still not enough room ? */ + if (pData->iSuspendbufsize - pData->iSuspendbufleft < MNG_SUSPENDREQUESTSIZE) + MNG_ERROR (pData, MNG_INTERNALERROR) + /* now read some more data */ + pTemp = pData->pSuspendbufnext + pData->iSuspendbufleft; + + if (!pData->fReaddata (((mng_handle)pData), pTemp, MNG_SUSPENDREQUESTSIZE, &iTemp)) + MNG_ERROR (pData, MNG_APPIOERROR); + /* adjust fill-counter */ + pData->iSuspendbufleft += iTemp; + /* first read after suspension returning 0 means EOF */ + if ((pData->iSuspendpoint) && (iTemp == 0)) + { /* that makes it final */ + mng_retcode iRetcode = process_eof (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if (pData->iSuspendbufleft) /* return the leftover scraps */ + MNG_COPY (pBuf, pData->pSuspendbufnext, pData->iSuspendbufleft) + /* and indicate so */ + *iRead = pData->iSuspendbufleft; + pData->pSuspendbufnext = pData->pSuspendbuf; + pData->iSuspendbufleft = 0; + } + else + { /* suspension required ? */ + if ((iSize > pData->iSuspendbufleft) && (iTemp < MNG_SUSPENDREQUESTSIZE)) + pData->bSuspended = MNG_TRUE; + + } + + pData->iSuspendpoint = 0; /* reset it here in case we loop back */ + } + + if ((!pData->bSuspended) && (!pData->bEOF)) + { /* return the data ! */ + MNG_COPY (pBuf, pData->pSuspendbufnext, iSize) + + *iRead = iSize; /* returned it all */ + /* adjust suspension-buffer variables */ + pData->pSuspendbufnext += iSize; + pData->iSuspendbufleft -= iSize; + } + } + } + else + { + if (!pData->fReaddata (((mng_handle)pData), (mng_ptr)pBuf, iSize, iRead)) + { + if (iRead == 0) /* suspension required ? */ + pData->bSuspended = MNG_TRUE; + else + MNG_ERROR (pData, MNG_APPIOERROR); + } + } + + pData->iSuspendpoint = 0; /* safely reset it here ! */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_DATABUFFER, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode process_raw_chunk (mng_datap pData, + mng_uint8p pBuf, + mng_uint32 iBuflen) +{ + /* the table-idea & binary search code was adapted from + libpng 1.1.0 (pngread.c) */ + /* NOTE1: the table must remain sorted by chunkname, otherwise the binary + search will break !!! */ + /* NOTE2: the layout must remain equal to the header part of all the + chunk-structures (yes, that means even the pNext and pPrev fields; + it's wasting a bit of space, but hey, the code is a lot easier) */ + + mng_chunk_header chunk_unknown = {MNG_UINT_HUH, init_unknown, free_unknown, + read_unknown, write_unknown, 0, 0}; + + mng_chunk_header chunk_table [] = + { + {MNG_UINT_BACK, init_back, free_back, read_back, write_back, 0, 0}, + {MNG_UINT_BASI, init_basi, free_basi, read_basi, write_basi, 0, 0}, + {MNG_UINT_CLIP, init_clip, free_clip, read_clip, write_clip, 0, 0}, + {MNG_UINT_CLON, init_clon, free_clon, read_clon, write_clon, 0, 0}, + {MNG_UINT_DBYK, init_dbyk, free_dbyk, read_dbyk, write_dbyk, 0, 0}, + {MNG_UINT_DEFI, init_defi, free_defi, read_defi, write_defi, 0, 0}, + {MNG_UINT_DHDR, init_dhdr, free_dhdr, read_dhdr, write_dhdr, 0, 0}, + {MNG_UINT_DISC, init_disc, free_disc, read_disc, write_disc, 0, 0}, + {MNG_UINT_DROP, init_drop, free_drop, read_drop, write_drop, 0, 0}, + {MNG_UINT_ENDL, init_endl, free_endl, read_endl, write_endl, 0, 0}, + {MNG_UINT_FRAM, init_fram, free_fram, read_fram, write_fram, 0, 0}, + {MNG_UINT_IDAT, init_idat, free_idat, read_idat, write_idat, 0, 0}, /* 12-th element! */ + {MNG_UINT_IEND, init_iend, free_iend, read_iend, write_iend, 0, 0}, + {MNG_UINT_IHDR, init_ihdr, free_ihdr, read_ihdr, write_ihdr, 0, 0}, + {MNG_UINT_IJNG, init_ijng, free_ijng, read_ijng, write_ijng, 0, 0}, + {MNG_UINT_IPNG, init_ipng, free_ipng, read_ipng, write_ipng, 0, 0}, +#ifdef MNG_INCLUDE_JNG + {MNG_UINT_JDAA, init_jdaa, free_jdaa, read_jdaa, write_jdaa, 0, 0}, + {MNG_UINT_JDAT, init_jdat, free_jdat, read_jdat, write_jdat, 0, 0}, + {MNG_UINT_JHDR, init_jhdr, free_jhdr, read_jhdr, write_jhdr, 0, 0}, + {MNG_UINT_JSEP, init_jsep, free_jsep, read_jsep, write_jsep, 0, 0}, + {MNG_UINT_JdAA, init_jdaa, free_jdaa, read_jdaa, write_jdaa, 0, 0}, +#endif + {MNG_UINT_LOOP, init_loop, free_loop, read_loop, write_loop, 0, 0}, + {MNG_UINT_MAGN, init_magn, free_magn, read_magn, write_magn, 0, 0}, + {MNG_UINT_MEND, init_mend, free_mend, read_mend, write_mend, 0, 0}, + {MNG_UINT_MHDR, init_mhdr, free_mhdr, read_mhdr, write_mhdr, 0, 0}, + {MNG_UINT_MOVE, init_move, free_move, read_move, write_move, 0, 0}, + {MNG_UINT_ORDR, init_ordr, free_ordr, read_ordr, write_ordr, 0, 0}, + {MNG_UINT_PAST, init_past, free_past, read_past, write_past, 0, 0}, + {MNG_UINT_PLTE, init_plte, free_plte, read_plte, write_plte, 0, 0}, + {MNG_UINT_PPLT, init_pplt, free_pplt, read_pplt, write_pplt, 0, 0}, + {MNG_UINT_PROM, init_prom, free_prom, read_prom, write_prom, 0, 0}, + {MNG_UINT_SAVE, init_save, free_save, read_save, write_save, 0, 0}, + {MNG_UINT_SEEK, init_seek, free_seek, read_seek, write_seek, 0, 0}, + {MNG_UINT_SHOW, init_show, free_show, read_show, write_show, 0, 0}, + {MNG_UINT_TERM, init_term, free_term, read_term, write_term, 0, 0}, + {MNG_UINT_bKGD, init_bkgd, free_bkgd, read_bkgd, write_bkgd, 0, 0}, + {MNG_UINT_cHRM, init_chrm, free_chrm, read_chrm, write_chrm, 0, 0}, + {MNG_UINT_eXPI, init_expi, free_expi, read_expi, write_expi, 0, 0}, + {MNG_UINT_fPRI, init_fpri, free_fpri, read_fpri, write_fpri, 0, 0}, + {MNG_UINT_gAMA, init_gama, free_gama, read_gama, write_gama, 0, 0}, + {MNG_UINT_hIST, init_hist, free_hist, read_hist, write_hist, 0, 0}, + {MNG_UINT_iCCP, init_iccp, free_iccp, read_iccp, write_iccp, 0, 0}, + {MNG_UINT_iTXt, init_itxt, free_itxt, read_itxt, write_itxt, 0, 0}, + {MNG_UINT_nEED, init_need, free_need, read_need, write_need, 0, 0}, +/* TODO: {MNG_UINT_oFFs, 0, 0, 0, 0, 0, 0}, */ +/* TODO: {MNG_UINT_pCAL, 0, 0, 0, 0, 0, 0}, */ + {MNG_UINT_pHYg, init_phyg, free_phyg, read_phyg, write_phyg, 0, 0}, + {MNG_UINT_pHYs, init_phys, free_phys, read_phys, write_phys, 0, 0}, + {MNG_UINT_sBIT, init_sbit, free_sbit, read_sbit, write_sbit, 0, 0}, +/* TODO: {MNG_UINT_sCAL, 0, 0, 0, 0, 0, 0}, */ + {MNG_UINT_sPLT, init_splt, free_splt, read_splt, write_splt, 0, 0}, + {MNG_UINT_sRGB, init_srgb, free_srgb, read_srgb, write_srgb, 0, 0}, + {MNG_UINT_tEXt, init_text, free_text, read_text, write_text, 0, 0}, + {MNG_UINT_tIME, init_time, free_time, read_time, write_time, 0, 0}, + {MNG_UINT_tRNS, init_trns, free_trns, read_trns, write_trns, 0, 0}, + {MNG_UINT_zTXt, init_ztxt, free_ztxt, read_ztxt, write_ztxt, 0, 0}, + }; + /* binary search variables */ + mng_int32 iTop, iLower, iUpper, iMiddle; + mng_chunk_headerp pEntry; /* pointer to found entry */ + mng_chunkid iChunkname; /* the chunk's tag */ + mng_chunkp pChunk; /* chunk structure (if #define MNG_STORE_CHUNKS) */ + mng_retcode iRetcode; /* temporary error-code */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RAW_CHUNK, MNG_LC_START) +#endif + /* get the chunkname */ + iChunkname = (mng_chunkid)(mng_get_uint32 (pBuf)); + + pBuf += sizeof (mng_chunkid); /* adjust the buffer */ + iBuflen -= sizeof (mng_chunkid); + /* determine max index of table */ + iTop = (sizeof (chunk_table) / sizeof (chunk_table [0])) - 1; + + /* binary search; with 52 chunks, worst-case is 7 comparisons */ + iLower = 0; + iMiddle = 11; /* start with the IDAT entry */ + iUpper = iTop; + pEntry = 0; /* no goods yet! */ + pChunk = 0; + + do /* the binary search itself */ + { + if (chunk_table [iMiddle].iChunkname < iChunkname) + iLower = iMiddle + 1; + else if (chunk_table [iMiddle].iChunkname > iChunkname) + iUpper = iMiddle - 1; + else + { + pEntry = &chunk_table [iMiddle]; + break; + } + + iMiddle = (iLower + iUpper) >> 1; + } + while (iLower <= iUpper); + + if (!pEntry) /* unknown chunk ? */ + pEntry = &chunk_unknown; /* make it so! */ + + pData->iChunkname = iChunkname; /* keep track of where we are */ + pData->iChunkseq++; + + if (pEntry->fRead) /* read-callback available ? */ + { + iRetcode = pEntry->fRead (pData, pEntry, iBuflen, (mng_ptr)pBuf, &pChunk); + + if (!iRetcode) /* everything oke ? */ + { /* remember unknown chunk's id */ + if ((pChunk) && (pEntry == &chunk_unknown)) + ((mng_chunk_headerp)pChunk)->iChunkname = iChunkname; + } + } + else + iRetcode = MNG_NOERROR; + + if (pChunk) /* store this chunk ? */ + add_chunk (pData, pChunk); /* do it */ + +#ifdef MNG_INCLUDE_JNG /* implicit EOF ? */ + if ((!pData->bHasMHDR) && (!pData->bHasIHDR) && (!pData->bHasJHDR)) +#else + if ((!pData->bHasMHDR) && (!pData->bHasIHDR)) +#endif + iRetcode = process_eof (pData); /* then do some EOF processing */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_PROCESS_RAW_CHUNK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode read_chunk (mng_datap pData) +{ + mng_uint32 iBufmax = pData->iReadbufsize; + mng_uint8p pBuf = pData->pReadbuf; + mng_uint32 iBuflen = 0; /* number of bytes requested */ + mng_uint32 iRead = 0; /* number of bytes read */ + mng_uint32 iCrc; /* calculated CRC */ + mng_retcode iRetcode = MNG_NOERROR; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CHUNK, MNG_LC_START) +#endif + +#ifdef MNG_SUPPORT_DISPLAY + if (pData->pCurraniobj) /* processing an animation object ? */ + { + do /* process it then */ + { + iRetcode = ((mng_object_headerp)pData->pCurraniobj)->fProcess (pData, pData->pCurraniobj); + /* refresh needed ? */ +/* if ((!iRetcode) && (!pData->bTimerset) && (pData->bNeedrefresh)) + iRetcode = display_progressive_refresh (pData, 1); */ + /* can we advance to next object ? */ + if ((!iRetcode) && (pData->pCurraniobj) && + (!pData->bTimerset) && (!pData->bSectionwait)) + { + pData->pCurraniobj = ((mng_object_headerp)pData->pCurraniobj)->pNext; + /* TERM processing to be done ? */ + if ((!pData->pCurraniobj) && (pData->bHasTERM) && (!pData->bHasMHDR)) + iRetcode = process_display_mend (pData); + } + } /* until error or a break or no more objects */ + while ((!iRetcode) && (pData->pCurraniobj) && + (!pData->bTimerset) && (!pData->bSectionwait) && (!pData->bFreezing)); + } + else + { + if (pData->iBreakpoint) /* do we need to finish something first ? */ + { + switch (pData->iBreakpoint) /* return to broken display routine */ + { + case 1 : { iRetcode = process_display_fram2 (pData); break; } + case 2 : { iRetcode = process_display_ihdr (pData); break; } + case 3 : ; /* same as 4 !!! */ + case 4 : { iRetcode = process_display_show (pData); break; } + case 5 : { iRetcode = process_display_clon2 (pData); break; } +#ifdef MNG_INCLUDE_JNG + case 7 : { iRetcode = process_display_jhdr (pData); break; } +#endif + case 6 : ; /* same as 8 !!! */ + case 8 : { iRetcode = process_display_iend (pData); break; } + case 9 : { iRetcode = process_display_magn2 (pData); break; } + } + } + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + +#endif /* MNG_SUPPORT_DISPLAY */ + /* can we continue processing now, or do we */ + /* need to wait for the timer to finish (again) ? */ +#ifdef MNG_SUPPORT_DISPLAY + if ((!pData->bTimerset) && (!pData->bSectionwait) && (!pData->bEOF)) +#else + if (!pData->bEOF) +#endif + { /* freezing in progress ? */ + if ((pData->bFreezing) && (pData->iSuspendpoint == 0)) + pData->bRunning = MNG_FALSE; /* then this is the right moment to do it */ + + if (pData->iSuspendpoint <= 2) + { + iBuflen = sizeof (mng_uint32); /* read length */ + iRetcode = read_databuffer (pData, pBuf, iBuflen, &iRead); + + if (iRetcode) /* bail on errors */ + return iRetcode; + + if (pData->bSuspended) /* suspended ? */ + pData->iSuspendpoint = 2; + else /* save the length */ + pData->iChunklen = mng_get_uint32 (pBuf); + + } + + if (!pData->bSuspended) /* still going ? */ + { /* previously suspended or not eof ? */ + if ((pData->iSuspendpoint > 2) || (iRead == iBuflen)) + { /* determine length chunkname + data + crc */ + iBuflen = pData->iChunklen + (mng_uint32)(sizeof (mng_chunkid) + sizeof (iCrc)); + + if (iBuflen < iBufmax) /* does it fit in default buffer ? */ + { /* note that we don't use the full size + so there's always a zero-byte at the + very end !!! */ + iRetcode = read_databuffer (pData, pBuf, iBuflen, &iRead); + + if (iRetcode) /* bail on errors */ + return iRetcode; + + if (pData->bSuspended) /* suspended ? */ + pData->iSuspendpoint = 3; + else + { + if (iRead != iBuflen) /* did we get all the data ? */ + iRetcode = MNG_UNEXPECTEDEOF; + else + { + mng_uint32 iL = iBuflen - (mng_uint32)(sizeof (iCrc)); + /* calculate the crc */ + iCrc = crc (pData, pBuf, iL); + /* and check it */ + if (!(iCrc == mng_get_uint32 (pBuf + iL))) + iRetcode = MNG_INVALIDCRC; + else + iRetcode = process_raw_chunk (pData, pBuf, iL); + } + } + } + else + { + if (!pData->iSuspendpoint) /* create additional large buffer ? */ + { /* again reserve space for the last zero-byte */ + pData->iLargebufsize = iBuflen + 1; + MNG_ALLOC (pData, pData->pLargebuf, pData->iLargebufsize) + } + + iRetcode = read_databuffer (pData, pData->pLargebuf, iBuflen, &iRead); + + if (iRetcode) + return iRetcode; + + if (pData->bSuspended) /* suspended ? */ + pData->iSuspendpoint = 4; + else + { + if (iRead != iBuflen) /* did we get all the data ? */ + iRetcode = MNG_UNEXPECTEDEOF; + else + { + mng_uint32 iL = iBuflen - (mng_uint32)(sizeof (iCrc)); + /* calculate the crc */ + iCrc = crc (pData, pData->pLargebuf, iL); + /* and check it */ + if (!(iCrc == mng_get_uint32 (pData->pLargebuf + iL))) + iRetcode = MNG_INVALIDCRC; + else + iRetcode = process_raw_chunk (pData, pData->pLargebuf, iL); + } + /* cleanup additional large buffer */ + MNG_FREE (pData, pData->pLargebuf, pData->iLargebufsize) + } + } + + if (iRetcode) /* on error bail out */ + return iRetcode; + + } + else + { /* that's final */ + iRetcode = process_eof (pData); + + if (iRetcode) /* on error bail out */ + return iRetcode; + + if ((iRead != 0) || /* did we get an unexpected eof ? */ +#ifdef MNG_INCLUDE_JNG + (pData->bHasIHDR || pData->bHasMHDR || pData->bHasJHDR)) +#else + (pData->bHasIHDR || pData->bHasMHDR)) +#endif + MNG_ERROR (pData, MNG_UNEXPECTEDEOF); + } + } + } + +#ifdef MNG_SUPPORT_DISPLAY /* refresh needed ? */ + if ((!pData->bTimerset) && (!pData->bSuspended) && (pData->bNeedrefresh)) + { + iRetcode = display_progressive_refresh (pData, 1); + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#endif + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_CHUNK, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode read_graphic (mng_datap pData) +{ + mng_uint32 iBuflen; /* number of bytes requested */ + mng_uint32 iRead; /* number of bytes read */ + mng_retcode iRetcode; /* temporary error-code */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_GRAPHIC, MNG_LC_START) +#endif + + if (!pData->pReadbuf) /* buffer allocated ? */ + { + pData->iReadbufsize = 4200; /* allocate a default read buffer */ + MNG_ALLOC (pData, pData->pReadbuf, pData->iReadbufsize) + } + /* haven't processed the signature ? */ + if ((!pData->bHavesig) || (pData->iSuspendpoint == 1)) + { + iBuflen = 2 * sizeof (mng_uint32); /* read signature */ + + iRetcode = read_databuffer (pData, pData->pReadbuf, iBuflen, &iRead); + + if (iRetcode) + return iRetcode; + + if (pData->bSuspended) /* input suspension ? */ + pData->iSuspendpoint = 1; + else + { + if (iRead != iBuflen) /* full signature received ? */ + MNG_ERROR (pData, MNG_UNEXPECTEDEOF); + /* is it a valid signature ? */ + if (mng_get_uint32 (pData->pReadbuf) == PNG_SIG) + pData->eSigtype = mng_it_png; + else + if (mng_get_uint32 (pData->pReadbuf) == JNG_SIG) + pData->eSigtype = mng_it_jng; + else + if (mng_get_uint32 (pData->pReadbuf) == MNG_SIG) + pData->eSigtype = mng_it_mng; + else + MNG_ERROR (pData, MNG_INVALIDSIG); + /* all of it ? */ + if (mng_get_uint32 (pData->pReadbuf+4) != POST_SIG) + MNG_ERROR (pData, MNG_INVALIDSIG); + + pData->bHavesig = MNG_TRUE; + } + } + + if (!pData->bSuspended) /* still going ? */ + { + do + { + iRetcode = read_chunk (pData); /* process a chunk */ + + if (iRetcode) /* on error bail out */ + return iRetcode; + } +#ifdef MNG_SUPPORT_DISPLAY /* until EOF or a break-request */ + while (((!pData->bEOF) || (pData->pCurraniobj)) && (!pData->bSuspended) && + (!pData->bTimerset) && (!pData->bSectionwait)); +#else + while ((!pData->bEOF) && (!pData->bSuspended)); +#endif + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_READ_GRAPHIC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_READ_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_read.h b/freeimage241/Source/LibMNG/libmng_read.h new file mode 100644 index 0000000..280043d --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_read.h @@ -0,0 +1,45 @@ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_read.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Read management (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the read management routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 10/18/2000 - G.Juyn * */ +/* * - added closestream() processing for mng_cleanup() * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_read_h_ +#define _libmng_read_h_ + +/* ************************************************************************** */ + +mng_retcode process_eof (mng_datap pData); + +mng_retcode read_graphic (mng_datap pData); + +/* ************************************************************************** */ + +#endif /* _libmng_read_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_trace.c b/freeimage241/Source/LibMNG/libmng_trace.c new file mode 100644 index 0000000..acf44a4 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_trace.c @@ -0,0 +1,1170 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_trace.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : Trace functions (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the trace functions * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - added callback error-reporting support * */ +/* * * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - added trace telltale reporting * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added tracestrings for global animation color-chunks * */ +/* * - added tracestrings for get/set of default ZLIB/IJG parms * */ +/* * - added tracestrings for global PLTE,tRNS,bKGD * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added tracestrings for image-object promotion * */ +/* * - added tracestrings for delta-image processing * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - added tracestrings for getalphaline callback * */ +/* * 0.5.2 - 06/05/2000 - G.Juyn * */ +/* * - added tracestring for RGB8_A8 canvasstyle * */ +/* * 0.5.2 - 06/06/2000 - G.Juyn * */ +/* * - added tracestring for mng_read_resume HLAPI function * */ +/* * * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added tracestrings for get/set speedtype * */ +/* * - added tracestring for get imagelevel * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - added tracestring for delta-image processing * */ +/* * - added tracestrings for PPLT chunk processing * */ +/* * * */ +/* * 0.9.1 - 07/07/2000 - G.Juyn * */ +/* * - added tracecodes for special display processing * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - added tracestring for get/set suspensionmode * */ +/* * - added tracestrings for get/set display variables * */ +/* * - added tracecode for read_databuffer (I/O-suspension) * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added tracestrings for SAVE/SEEK callbacks * */ +/* * - added tracestrings for get/set sectionbreaks * */ +/* * - added tracestring for special error routine * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - added tracestring for updatemngheader * */ +/* * * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - added tracestrings for status_xxxxx functions * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * - added tracestring for updatemngsimplicity * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 10/10/2000 - G.Juyn * */ +/* * - added support for alpha-depth prediction * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - added JDAA chunk * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added functions to retrieve PNG/JNG specific header-info * */ +/* * - added optional support for bKGD for PNG images * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * - added routine to discard "invalid" objects * */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - implemented delayed delta-processing * */ +/* * 0.9.3 - 10/20/2000 - G.Juyn * */ +/* * - added get/set for bKGD preference setting * */ +/* * 0.9.3 - 10/21/2000 - G.Juyn * */ +/* * - added get function for interlace/progressive display * */ +/* * * */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - added "new" MAGN methods 3, 4 & 5 * */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn (code by G.Kelly) * */ +/* * - added BGRA8 canvas with premultiplied alpha * */ +/* * 1.0.1 - 05/02/2001 - G.Juyn * */ +/* * - added "default" sRGB generation (Thanks Marti!) * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * - added processterm callback * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - added option to turn off progressive refresh * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_TRACE_PROCS + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_TRACE_STRINGS + mng_trace_entry trace_table [] = + { + {MNG_FN_INITIALIZE, "initialize"}, + {MNG_FN_RESET, "reset"}, + {MNG_FN_CLEANUP, "cleanup"}, + {MNG_FN_READ, "read"}, + {MNG_FN_WRITE, "write"}, + {MNG_FN_CREATE, "create"}, + {MNG_FN_READDISPLAY, "readdisplay"}, + {MNG_FN_DISPLAY, "display"}, + {MNG_FN_DISPLAY_RESUME, "display_resume"}, + {MNG_FN_DISPLAY_FREEZE, "display_freeze"}, + {MNG_FN_DISPLAY_RESET, "display_reset"}, + {MNG_FN_DISPLAY_GOFRAME, "display_goframe"}, + {MNG_FN_DISPLAY_GOLAYER, "display_golayer"}, + {MNG_FN_DISPLAY_GOTIME, "display_gotime"}, + {MNG_FN_GETLASTERROR, "getlasterror"}, + {MNG_FN_READ_RESUME, "read_resume"}, + + {MNG_FN_SETCB_MEMALLOC, "setcb_memalloc"}, + {MNG_FN_SETCB_MEMFREE, "setcb_memfree"}, + {MNG_FN_SETCB_READDATA, "setcb_readdata"}, + {MNG_FN_SETCB_WRITEDATA, "setcb_writedata"}, + {MNG_FN_SETCB_ERRORPROC, "setcb_errorproc"}, + {MNG_FN_SETCB_TRACEPROC, "setcb_traceproc"}, + {MNG_FN_SETCB_PROCESSHEADER, "setcb_processheader"}, + {MNG_FN_SETCB_PROCESSTEXT, "setcb_processtext"}, + {MNG_FN_SETCB_GETCANVASLINE, "setcb_getcanvasline"}, + {MNG_FN_SETCB_GETBKGDLINE, "setcb_getbkgdline"}, + {MNG_FN_SETCB_REFRESH, "setcb_refresh"}, + {MNG_FN_SETCB_GETTICKCOUNT, "setcb_gettickcount"}, + {MNG_FN_SETCB_SETTIMER, "setcb_settimer"}, + {MNG_FN_SETCB_PROCESSGAMMA, "setcb_processgamma"}, + {MNG_FN_SETCB_PROCESSCHROMA, "setcb_processchroma"}, + {MNG_FN_SETCB_PROCESSSRGB, "setcb_processsrgb"}, + {MNG_FN_SETCB_PROCESSICCP, "setcb_processiccp"}, + {MNG_FN_SETCB_PROCESSAROW, "setcb_processarow"}, + {MNG_FN_SETCB_OPENSTREAM, "setcb_openstream"}, + {MNG_FN_SETCB_CLOSESTREAM, "setcb_closestream"}, + {MNG_FN_SETCB_GETALPHALINE, "setcb_getalphaline"}, + {MNG_FN_SETCB_PROCESSSAVE, "setcb_processsave"}, + {MNG_FN_SETCB_PROCESSSEEK, "setcb_processseek"}, + {MNG_FN_SETCB_PROCESSNEED, "setcb_processneed"}, + {MNG_FN_SETCB_PROCESSUNKNOWN, "setcb_processunknown"}, + {MNG_FN_SETCB_PROCESSMEND, "setcb_processmend"}, + {MNG_FN_SETCB_PROCESSTERM, "setcb_processterm"}, + + {MNG_FN_GETCB_MEMALLOC, "getcb_memalloc"}, + {MNG_FN_GETCB_MEMFREE, "getcb_memfree"}, + {MNG_FN_GETCB_READDATA, "getcb_readdata,"}, + {MNG_FN_GETCB_WRITEDATA, "getcb_writedata"}, + {MNG_FN_GETCB_ERRORPROC, "getcb_errorproc"}, + {MNG_FN_GETCB_TRACEPROC, "getcb_traceproc"}, + {MNG_FN_GETCB_PROCESSHEADER, "getcb_processheader"}, + {MNG_FN_GETCB_PROCESSTEXT, "getcb_processtext"}, + {MNG_FN_GETCB_GETCANVASLINE, "getcb_getcanvasline"}, + {MNG_FN_GETCB_GETBKGDLINE, "getcb_getbkgdline"}, + {MNG_FN_GETCB_REFRESH, "getcb_refresh"}, + {MNG_FN_GETCB_GETTICKCOUNT, "getcb_gettickcount"}, + {MNG_FN_GETCB_SETTIMER, "getcb_settimer"}, + {MNG_FN_GETCB_PROCESSGAMMA, "getcb_processgamma"}, + {MNG_FN_GETCB_PROCESSCHROMA, "getcb_processchroma"}, + {MNG_FN_GETCB_PROCESSSRGB, "getcb_processsrgb"}, + {MNG_FN_GETCB_PROCESSICCP, "getcb_processiccp"}, + {MNG_FN_GETCB_PROCESSAROW, "getcb_processarow"}, + {MNG_FN_GETCB_OPENSTREAM, "getcb_openstream"}, + {MNG_FN_GETCB_CLOSESTREAM, "getcb_closestream"}, + {MNG_FN_GETCB_GETALPHALINE, "getcb_getalphaline"}, + {MNG_FN_GETCB_PROCESSSAVE, "getcb_processsave"}, + {MNG_FN_GETCB_PROCESSSEEK, "getcb_processseek"}, + {MNG_FN_GETCB_PROCESSNEED, "getcb_processneed"}, + {MNG_FN_GETCB_PROCESSUNKNOWN, "getcb_processunknown"}, + {MNG_FN_GETCB_PROCESSMEND, "getcb_processmend"}, + {MNG_FN_GETCB_PROCESSTERM, "getcb_processterm"}, + + {MNG_FN_SET_USERDATA, "set_userdata"}, + {MNG_FN_SET_CANVASSTYLE, "set_canvasstyle"}, + {MNG_FN_SET_BKGDSTYLE, "set_bkgdstyle"}, + {MNG_FN_SET_BGCOLOR, "set_bgcolor"}, + {MNG_FN_SET_STORECHUNKS, "set_storechunks"}, + {MNG_FN_SET_VIEWGAMMA, "set_viewgamma"}, + {MNG_FN_SET_DISPLAYGAMMA, "set_displaygamma"}, + {MNG_FN_SET_DFLTIMGGAMMA, "set_dfltimggamma"}, + {MNG_FN_SET_SRGB, "set_srgb"}, + {MNG_FN_SET_OUTPUTPROFILE, "set_outputprofile"}, + {MNG_FN_SET_SRGBPROFILE, "set_srgbprofile"}, + {MNG_FN_SET_MAXCANVASWIDTH, "set_maxcanvaswidth"}, + {MNG_FN_SET_MAXCANVASHEIGHT, "set_maxcanvasheight"}, + {MNG_FN_SET_MAXCANVASSIZE, "set_maxcanvassize"}, + {MNG_FN_SET_ZLIB_LEVEL, "set_zlib_level"}, + {MNG_FN_SET_ZLIB_METHOD, "set_zlib_method"}, + {MNG_FN_SET_ZLIB_WINDOWBITS, "set_zlib_windowbits"}, + {MNG_FN_SET_ZLIB_MEMLEVEL, "set_zlib_memlevel"}, + {MNG_FN_SET_ZLIB_STRATEGY, "set_zlib_strategy"}, + {MNG_FN_SET_ZLIB_MAXIDAT, "set_zlib_maxidat"}, + {MNG_FN_SET_JPEG_DCTMETHOD, "set_jpeg_dctmethod"}, + {MNG_FN_SET_JPEG_QUALITY, "set_jpeg_quality"}, + {MNG_FN_SET_JPEG_SMOOTHING, "set_jpeg_smoothing"}, + {MNG_FN_SET_JPEG_PROGRESSIVE, "set_jpeg_progressive"}, + {MNG_FN_SET_JPEG_OPTIMIZED, "set_jpeg_optimized"}, + {MNG_FN_SET_JPEG_MAXJDAT, "set_jpeg_maxjdat"}, + {MNG_FN_SET_SPEED, "set_speed"}, + {MNG_FN_SET_SUSPENSIONMODE, "set_suspensionmode"}, + {MNG_FN_SET_SECTIONBREAKS, "set_sectionbreaks"}, + {MNG_FN_SET_USEBKGD, "set_usebkgd"}, + {MNG_FN_SET_OUTPUTPROFILE2, "set_outputprofile2"}, + {MNG_FN_SET_SRGBPROFILE2, "set_srgbprofile2"}, + {MNG_FN_SET_OUTPUTSRGB, "set_outputsrgb"}, + {MNG_FN_SET_SRGBIMPLICIT, "set_srgbimplicit"}, + {MNG_FN_SET_CACHEPLAYBACK, "set_cacheplayback"}, + {MNG_FN_SET_DOPROGRESSIVE, "set_doprogressive"}, + + {MNG_FN_GET_USERDATA, "get_userdata"}, + {MNG_FN_GET_SIGTYPE, "get_sigtype"}, + {MNG_FN_GET_IMAGETYPE, "get_imagetype"}, + {MNG_FN_GET_IMAGEWIDTH, "get_imagewidth"}, + {MNG_FN_GET_IMAGEHEIGHT, "get_imageheight"}, + {MNG_FN_GET_TICKS, "get_ticks"}, + {MNG_FN_GET_FRAMECOUNT, "get_framecount"}, + {MNG_FN_GET_LAYERCOUNT, "get_layercount"}, + {MNG_FN_GET_PLAYTIME, "get_playtime"}, + {MNG_FN_GET_SIMPLICITY, "get_simplicity"}, + {MNG_FN_GET_CANVASSTYLE, "get_canvasstyle"}, + {MNG_FN_GET_BKGDSTYLE, "get_bkgdstyle"}, + {MNG_FN_GET_BGCOLOR, "get_bgcolor"}, + {MNG_FN_GET_STORECHUNKS, "get_storechunks"}, + {MNG_FN_GET_VIEWGAMMA, "get_viewgamma"}, + {MNG_FN_GET_DISPLAYGAMMA, "get_displaygamma"}, + {MNG_FN_GET_DFLTIMGGAMMA, "get_dfltimggamma"}, + {MNG_FN_GET_SRGB, "get_srgb"}, + {MNG_FN_GET_MAXCANVASWIDTH, "get_maxcanvaswidth"}, + {MNG_FN_GET_MAXCANVASHEIGHT, "get_maxcanvasheight"}, + {MNG_FN_GET_ZLIB_LEVEL, "get_zlib_level"}, + {MNG_FN_GET_ZLIB_METHOD, "get_zlib_method"}, + {MNG_FN_GET_ZLIB_WINDOWBITS, "get_zlib_windowbits"}, + {MNG_FN_GET_ZLIB_MEMLEVEL, "get_zlib_memlevel"}, + {MNG_FN_GET_ZLIB_STRATEGY, "get_zlib_strategy"}, + {MNG_FN_GET_ZLIB_MAXIDAT, "get_zlib_maxidat"}, + {MNG_FN_GET_JPEG_DCTMETHOD, "get_jpeg_dctmethod"}, + {MNG_FN_GET_JPEG_QUALITY, "get_jpeg_quality"}, + {MNG_FN_GET_JPEG_SMOOTHING, "get_jpeg_smoothing"}, + {MNG_FN_GET_JPEG_PROGRESSIVE, "get_jpeg_progressive"}, + {MNG_FN_GET_JPEG_OPTIMIZED, "get_jpeg_optimized"}, + {MNG_FN_GET_JPEG_MAXJDAT, "get_jpeg_maxjdat"}, + {MNG_FN_GET_SPEED, "get_speed"}, + {MNG_FN_GET_IMAGELEVEL, "get_imagelevel"}, + {MNG_FN_GET_SUSPENSIONMODE, "get_speed"}, + {MNG_FN_GET_STARTTIME, "get_starttime"}, + {MNG_FN_GET_RUNTIME, "get_runtime"}, + {MNG_FN_GET_CURRENTFRAME, "get_currentframe"}, + {MNG_FN_GET_CURRENTLAYER, "get_currentlayer"}, + {MNG_FN_GET_CURRENTPLAYTIME, "get_currentplaytime"}, + {MNG_FN_GET_SECTIONBREAKS, "get_sectionbreaks"}, + {MNG_FN_GET_ALPHADEPTH, "get_alphadepth"}, + {MNG_FN_GET_BITDEPTH, "get_bitdepth"}, + {MNG_FN_GET_COLORTYPE, "get_colortype"}, + {MNG_FN_GET_COMPRESSION, "get_compression"}, + {MNG_FN_GET_FILTER, "get_filter"}, + {MNG_FN_GET_INTERLACE, "get_interlace"}, + {MNG_FN_GET_ALPHABITDEPTH, "get_alphabitdepth"}, + {MNG_FN_GET_ALPHACOMPRESSION, "get_alphacompression"}, + {MNG_FN_GET_ALPHAFILTER, "get_alphafilter"}, + {MNG_FN_GET_ALPHAINTERLACE, "get_alphainterlace"}, + {MNG_FN_GET_USEBKGD, "get_usebkgd"}, + {MNG_FN_GET_REFRESHPASS, "get_refreshpass"}, + {MNG_FN_GET_CACHEPLAYBACK, "get_cacheplayback"}, + {MNG_FN_GET_DOPROGRESSIVE, "get_doprogressive"}, + + {MNG_FN_STATUS_ERROR, "status_error"}, + {MNG_FN_STATUS_READING, "status_reading"}, + {MNG_FN_STATUS_SUSPENDBREAK, "status_suspendbreak"}, + {MNG_FN_STATUS_CREATING, "status_creating"}, + {MNG_FN_STATUS_WRITING, "status_writing"}, + {MNG_FN_STATUS_DISPLAYING, "status_displaying"}, + {MNG_FN_STATUS_RUNNING, "status_running"}, + {MNG_FN_STATUS_TIMERBREAK, "status_timerbreak"}, + + {MNG_FN_ITERATE_CHUNKS, "iterate_chunks"}, + + {MNG_FN_GETCHUNK_IHDR, "getchunk_ihdr"}, + {MNG_FN_GETCHUNK_PLTE, "getchunk_plte"}, + {MNG_FN_GETCHUNK_IDAT, "getchunk_idat"}, + {MNG_FN_GETCHUNK_IEND, "getchunk_iend"}, + {MNG_FN_GETCHUNK_TRNS, "getchunk_trns"}, + {MNG_FN_GETCHUNK_GAMA, "getchunk_gama"}, + {MNG_FN_GETCHUNK_CHRM, "getchunk_chrm"}, + {MNG_FN_GETCHUNK_SRGB, "getchunk_srgb"}, + {MNG_FN_GETCHUNK_ICCP, "getchunk_iccp"}, + {MNG_FN_GETCHUNK_TEXT, "getchunk_text"}, + {MNG_FN_GETCHUNK_ZTXT, "getchunk_ztxt"}, + {MNG_FN_GETCHUNK_ITXT, "getchunk_itxt"}, + {MNG_FN_GETCHUNK_BKGD, "getchunk_bkgd"}, + {MNG_FN_GETCHUNK_PHYS, "getchunk_phys"}, + {MNG_FN_GETCHUNK_SBIT, "getchunk_sbit"}, + {MNG_FN_GETCHUNK_SPLT, "getchunk_splt"}, + {MNG_FN_GETCHUNK_HIST, "getchunk_hist"}, + {MNG_FN_GETCHUNK_TIME, "getchunk_time"}, + {MNG_FN_GETCHUNK_MHDR, "getchunk_mhdr"}, + {MNG_FN_GETCHUNK_MEND, "getchunk_mend"}, + {MNG_FN_GETCHUNK_LOOP, "getchunk_loop"}, + {MNG_FN_GETCHUNK_ENDL, "getchunk_endl"}, + {MNG_FN_GETCHUNK_DEFI, "getchunk_defi"}, + {MNG_FN_GETCHUNK_BASI, "getchunk_basi"}, + {MNG_FN_GETCHUNK_CLON, "getchunk_clon"}, + {MNG_FN_GETCHUNK_PAST, "getchunk_past"}, + {MNG_FN_GETCHUNK_DISC, "getchunk_disc"}, + {MNG_FN_GETCHUNK_BACK, "getchunk_back"}, + {MNG_FN_GETCHUNK_FRAM, "getchunk_fram"}, + {MNG_FN_GETCHUNK_MOVE, "getchunk_move"}, + {MNG_FN_GETCHUNK_CLIP, "getchunk_clip"}, + {MNG_FN_GETCHUNK_SHOW, "getchunk_show"}, + {MNG_FN_GETCHUNK_TERM, "getchunk_term"}, + {MNG_FN_GETCHUNK_SAVE, "getchunk_save"}, + {MNG_FN_GETCHUNK_SEEK, "getchunk_seek"}, + {MNG_FN_GETCHUNK_EXPI, "getchunk_expi"}, + {MNG_FN_GETCHUNK_FPRI, "getchunk_fpri"}, + {MNG_FN_GETCHUNK_NEED, "getchunk_need"}, + {MNG_FN_GETCHUNK_PHYG, "getchunk_phyg"}, + {MNG_FN_GETCHUNK_JHDR, "getchunk_jhdr"}, + {MNG_FN_GETCHUNK_JDAT, "getchunk_jdat"}, + {MNG_FN_GETCHUNK_JSEP, "getchunk_jsep"}, + {MNG_FN_GETCHUNK_DHDR, "getchunk_dhdr"}, + {MNG_FN_GETCHUNK_PROM, "getchunk_prom"}, + {MNG_FN_GETCHUNK_IPNG, "getchunk_ipng"}, + {MNG_FN_GETCHUNK_PPLT, "getchunk_pplt"}, + {MNG_FN_GETCHUNK_IJNG, "getchunk_ijng"}, + {MNG_FN_GETCHUNK_DROP, "getchunk_drop"}, + {MNG_FN_GETCHUNK_DBYK, "getchunk_dbyk"}, + {MNG_FN_GETCHUNK_ORDR, "getchunk_ordr"}, + {MNG_FN_GETCHUNK_UNKNOWN, "getchunk_unknown"}, + {MNG_FN_GETCHUNK_MAGN, "getchunk_magn"}, + {MNG_FN_GETCHUNK_JDAA, "getchunk_jdaa"}, + + {MNG_FN_GETCHUNK_PAST_SRC, "getchunk_past_src"}, + {MNG_FN_GETCHUNK_SAVE_ENTRY, "getchunk_save_entry"}, + {MNG_FN_GETCHUNK_PPLT_ENTRY, "getchunk_pplt_entry"}, + {MNG_FN_GETCHUNK_ORDR_ENTRY, "getchunk_ordr_entry"}, + + {MNG_FN_PUTCHUNK_IHDR, "putchunk_ihdr"}, + {MNG_FN_PUTCHUNK_PLTE, "putchunk_plte"}, + {MNG_FN_PUTCHUNK_IDAT, "putchunk_idat"}, + {MNG_FN_PUTCHUNK_IEND, "putchunk_iend"}, + {MNG_FN_PUTCHUNK_TRNS, "putchunk_trns"}, + {MNG_FN_PUTCHUNK_GAMA, "putchunk_gama"}, + {MNG_FN_PUTCHUNK_CHRM, "putchunk_chrm"}, + {MNG_FN_PUTCHUNK_SRGB, "putchunk_srgb"}, + {MNG_FN_PUTCHUNK_ICCP, "putchunk_iccp"}, + {MNG_FN_PUTCHUNK_TEXT, "putchunk_text"}, + {MNG_FN_PUTCHUNK_ZTXT, "putchunk_ztxt"}, + {MNG_FN_PUTCHUNK_ITXT, "putchunk_itxt"}, + {MNG_FN_PUTCHUNK_BKGD, "putchunk_bkgd"}, + {MNG_FN_PUTCHUNK_PHYS, "putchunk_phys"}, + {MNG_FN_PUTCHUNK_SBIT, "putchunk_sbit"}, + {MNG_FN_PUTCHUNK_SPLT, "putchunk_splt"}, + {MNG_FN_PUTCHUNK_HIST, "putchunk_hist"}, + {MNG_FN_PUTCHUNK_TIME, "putchunk_time"}, + {MNG_FN_PUTCHUNK_MHDR, "putchunk_mhdr"}, + {MNG_FN_PUTCHUNK_MEND, "putchunk_mend"}, + {MNG_FN_PUTCHUNK_LOOP, "putchunk_loop"}, + {MNG_FN_PUTCHUNK_ENDL, "putchunk_endl"}, + {MNG_FN_PUTCHUNK_DEFI, "putchunk_defi"}, + {MNG_FN_PUTCHUNK_BASI, "putchunk_basi"}, + {MNG_FN_PUTCHUNK_CLON, "putchunk_clon"}, + {MNG_FN_PUTCHUNK_PAST, "putchunk_past"}, + {MNG_FN_PUTCHUNK_DISC, "putchunk_disc"}, + {MNG_FN_PUTCHUNK_BACK, "putchunk_back"}, + {MNG_FN_PUTCHUNK_FRAM, "putchunk_fram"}, + {MNG_FN_PUTCHUNK_MOVE, "putchunk_move"}, + {MNG_FN_PUTCHUNK_CLIP, "putchunk_clip"}, + {MNG_FN_PUTCHUNK_SHOW, "putchunk_show"}, + {MNG_FN_PUTCHUNK_TERM, "putchunk_term"}, + {MNG_FN_PUTCHUNK_SAVE, "putchunk_save"}, + {MNG_FN_PUTCHUNK_SEEK, "putchunk_seek"}, + {MNG_FN_PUTCHUNK_EXPI, "putchunk_expi"}, + {MNG_FN_PUTCHUNK_FPRI, "putchunk_fpri"}, + {MNG_FN_PUTCHUNK_NEED, "putchunk_need"}, + {MNG_FN_PUTCHUNK_PHYG, "putchunk_phyg"}, + {MNG_FN_PUTCHUNK_JHDR, "putchunk_jhdr"}, + {MNG_FN_PUTCHUNK_JDAT, "putchunk_jdat"}, + {MNG_FN_PUTCHUNK_JSEP, "putchunk_jsep"}, + {MNG_FN_PUTCHUNK_DHDR, "putchunk_dhdr"}, + {MNG_FN_PUTCHUNK_PROM, "putchunk_prom"}, + {MNG_FN_PUTCHUNK_IPNG, "putchunk_ipng"}, + {MNG_FN_PUTCHUNK_PPLT, "putchunk_pplt"}, + {MNG_FN_PUTCHUNK_IJNG, "putchunk_ijng"}, + {MNG_FN_PUTCHUNK_DROP, "putchunk_drop"}, + {MNG_FN_PUTCHUNK_DBYK, "putchunk_dbyk"}, + {MNG_FN_PUTCHUNK_ORDR, "putchunk_ordr"}, + {MNG_FN_PUTCHUNK_UNKNOWN, "putchunk_unknown"}, + {MNG_FN_PUTCHUNK_MAGN, "putchunk_magn"}, + {MNG_FN_PUTCHUNK_JDAA, "putchunk_jdaa"}, + + {MNG_FN_PUTCHUNK_PAST_SRC, "putchunk_past_src"}, + {MNG_FN_PUTCHUNK_SAVE_ENTRY, "putchunk_save_entry"}, + {MNG_FN_PUTCHUNK_PPLT_ENTRY, "putchunk_pplt_entry"}, + {MNG_FN_PUTCHUNK_ORDR_ENTRY, "putchunk_ordr_entry"}, + + {MNG_FN_GETIMGDATA_SEQ, "getimgdata_seq"}, + {MNG_FN_GETIMGDATA_CHUNKSEQ, "getimgdata_chunkseq"}, + {MNG_FN_GETIMGDATA_CHUNK, "getimgdata_chunk"}, + + {MNG_FN_PUTIMGDATA_IHDR, "putimgdata_ihdr"}, + {MNG_FN_PUTIMGDATA_JHDR, "putimgdata_jhdr"}, + {MNG_FN_PUTIMGDATA_BASI, "putimgdata_basi"}, + {MNG_FN_PUTIMGDATA_DHDR, "putimgdata_dhdr"}, + + {MNG_FN_UPDATEMNGHEADER, "updatemngheader"}, + {MNG_FN_UPDATEMNGSIMPLICITY, "updatemngsimplicity"}, + + {MNG_FN_PROCESS_RAW_CHUNK, "process_raw_chunk"}, + {MNG_FN_READ_GRAPHIC, "read_graphic"}, + {MNG_FN_DROP_CHUNKS, "drop_chunks"}, + {MNG_FN_PROCESS_ERROR, "process_error"}, + {MNG_FN_CLEAR_CMS, "clear_cms"}, + {MNG_FN_DROP_OBJECTS, "drop_objects"}, + {MNG_FN_READ_CHUNK, "read_chunk"}, + {MNG_FN_LOAD_BKGDLAYER, "load_bkgdlayer"}, + {MNG_FN_NEXT_FRAME, "next_frame"}, + {MNG_FN_NEXT_LAYER, "next_layer"}, + {MNG_FN_INTERFRAME_DELAY, "interframe_delay"}, + {MNG_FN_DISPLAY_IMAGE, "display_image"}, + {MNG_FN_DROP_IMGOBJECTS, "drop_imgobjects"}, + {MNG_FN_DROP_ANIOBJECTS, "drop_aniobjects"}, + {MNG_FN_INFLATE_BUFFER, "inflate_buffer"}, + {MNG_FN_DEFLATE_BUFFER, "deflate_buffer"}, + {MNG_FN_WRITE_RAW_CHUNK, "write_raw_chunk"}, + {MNG_FN_WRITE_GRAPHIC, "write_graphic"}, + {MNG_FN_SAVE_STATE, "save_state"}, + {MNG_FN_RESTORE_STATE, "restore_state"}, + {MNG_FN_DROP_SAVEDATA, "drop_savedata"}, + {MNG_FN_EXECUTE_DELTA_IMAGE, "execute_delta_image"}, + {MNG_FN_PROCESS_DISPLAY, "process_display"}, + {MNG_FN_CLEAR_CANVAS, "clear_canvas"}, + {MNG_FN_READ_DATABUFFER, "read_databuffer"}, + {MNG_FN_STORE_ERROR, "store_error"}, + {MNG_FN_DROP_INVALID_OBJECTS, "drop_invalid_objects"}, + + {MNG_FN_DISPLAY_RGB8, "display_rgb8"}, + {MNG_FN_DISPLAY_RGBA8, "display_rgba8"}, + {MNG_FN_DISPLAY_ARGB8, "display_argb8"}, + {MNG_FN_DISPLAY_BGR8, "display_bgr8"}, + {MNG_FN_DISPLAY_BGRA8, "display_bgra8"}, + {MNG_FN_DISPLAY_ABGR8, "display_abgr8"}, + {MNG_FN_DISPLAY_RGB16, "display_rgb16"}, + {MNG_FN_DISPLAY_RGBA16, "display_rgba16"}, + {MNG_FN_DISPLAY_ARGB16, "display_argb16"}, + {MNG_FN_DISPLAY_BGR16, "display_bgr16"}, + {MNG_FN_DISPLAY_BGRA16, "display_bgra16"}, + {MNG_FN_DISPLAY_ABGR16, "display_abgr16"}, + {MNG_FN_DISPLAY_INDEX8, "display_index8"}, + {MNG_FN_DISPLAY_INDEXA8, "display_indexa8"}, + {MNG_FN_DISPLAY_AINDEX8, "display_aindex8"}, + {MNG_FN_DISPLAY_GRAY8, "display_gray8"}, + {MNG_FN_DISPLAY_GRAY16, "display_gray16"}, + {MNG_FN_DISPLAY_GRAYA8, "display_graya8"}, + {MNG_FN_DISPLAY_GRAYA16, "display_graya16"}, + {MNG_FN_DISPLAY_AGRAY8, "display_agray8"}, + {MNG_FN_DISPLAY_AGRAY16, "display_agray16"}, + {MNG_FN_DISPLAY_DX15, "display_dx15"}, + {MNG_FN_DISPLAY_DX16, "display_dx16"}, + {MNG_FN_DISPLAY_RGB8_A8, "display_rgb8_a8"}, + {MNG_FN_DISPLAY_BGRA8PM, "display_bgra8_pm"}, + + {MNG_FN_INIT_FULL_CMS, "init_full_cms"}, + {MNG_FN_CORRECT_FULL_CMS, "correct_full_cms"}, + {MNG_FN_INIT_GAMMA_ONLY, "init_gamma_only"}, + {MNG_FN_CORRECT_GAMMA_ONLY, "correct_gamma_only"}, + {MNG_FN_CORRECT_APP_CMS, "correct_app_cms"}, + {MNG_FN_INIT_FULL_CMS_OBJ, "init_full_cms_obj"}, + {MNG_FN_INIT_GAMMA_ONLY_OBJ, "init_gamma_only_obj"}, + {MNG_FN_INIT_APP_CMS, "init_app_cms"}, + {MNG_FN_INIT_APP_CMS_OBJ, "init_app_cms_obj"}, + + {MNG_FN_PROCESS_G1, "process_g1"}, + {MNG_FN_PROCESS_G2, "process_g2"}, + {MNG_FN_PROCESS_G4, "process_g4"}, + {MNG_FN_PROCESS_G8, "process_g8"}, + {MNG_FN_PROCESS_G16, "process_g16"}, + {MNG_FN_PROCESS_RGB8, "process_rgb8"}, + {MNG_FN_PROCESS_RGB16, "process_rgb16"}, + {MNG_FN_PROCESS_IDX1, "process_idx1"}, + {MNG_FN_PROCESS_IDX2, "process_idx2"}, + {MNG_FN_PROCESS_IDX4, "process_idx4"}, + {MNG_FN_PROCESS_IDX8, "process_idx8"}, + {MNG_FN_PROCESS_GA8, "process_ga8"}, + {MNG_FN_PROCESS_GA16, "process_ga16"}, + {MNG_FN_PROCESS_RGBA8, "process_rgba8"}, + {MNG_FN_PROCESS_RGBA16, "process_rgba16"}, + + {MNG_FN_INIT_G1_NI, "init_g1_ni"}, + {MNG_FN_INIT_G1_I, "init_g1_i"}, + {MNG_FN_INIT_G2_NI, "init_g2_ni"}, + {MNG_FN_INIT_G2_I, "init_g2_i"}, + {MNG_FN_INIT_G4_NI, "init_g4_ni"}, + {MNG_FN_INIT_G4_I, "init_g4_i"}, + {MNG_FN_INIT_G8_NI, "init_g8_ni"}, + {MNG_FN_INIT_G8_I, "init_g8_i"}, + {MNG_FN_INIT_G16_NI, "init_g16_ni"}, + {MNG_FN_INIT_G16_I, "init_g16_i"}, + {MNG_FN_INIT_RGB8_NI, "init_rgb8_ni"}, + {MNG_FN_INIT_RGB8_I, "init_rgb8_i"}, + {MNG_FN_INIT_RGB16_NI, "init_rgb16_ni"}, + {MNG_FN_INIT_RGB16_I, "init_rgb16_i"}, + {MNG_FN_INIT_IDX1_NI, "init_idx1_ni"}, + {MNG_FN_INIT_IDX1_I, "init_idx1_i"}, + {MNG_FN_INIT_IDX2_NI, "init_idx2_ni"}, + {MNG_FN_INIT_IDX2_I, "init_idx2_i"}, + {MNG_FN_INIT_IDX4_NI, "init_idx4_ni"}, + {MNG_FN_INIT_IDX4_I, "init_idx4_i"}, + {MNG_FN_INIT_IDX8_NI, "init_idx8_ni"}, + {MNG_FN_INIT_IDX8_I, "init_idx8_i"}, + {MNG_FN_INIT_GA8_NI, "init_ga8_ni"}, + {MNG_FN_INIT_GA8_I, "init_ga8_i"}, + {MNG_FN_INIT_GA16_NI, "init_ga16_ni"}, + {MNG_FN_INIT_GA16_I, "init_ga16_i"}, + {MNG_FN_INIT_RGBA8_NI, "init_rgba8_ni"}, + {MNG_FN_INIT_RGBA8_I, "init_rgba8_i"}, + {MNG_FN_INIT_RGBA16_NI, "init_rgba16_ni"}, + {MNG_FN_INIT_RGBA16_I, "init_rgba16_i"}, + + {MNG_FN_INIT_ROWPROC, "init_rowproc"}, + {MNG_FN_NEXT_ROW, "next_row"}, + {MNG_FN_CLEANUP_ROWPROC, "cleanup_rowproc"}, + + {MNG_FN_FILTER_A_ROW, "filter_a_row"}, + {MNG_FN_FILTER_SUB, "filter_sub"}, + {MNG_FN_FILTER_UP, "filter_up"}, + {MNG_FN_FILTER_AVERAGE, "filter_average"}, + {MNG_FN_FILTER_PAETH, "filter_paeth"}, + + {MNG_FN_INIT_ROWDIFFERING, "init_rowdiffering"}, + {MNG_FN_DIFFER_G1, "differ_g1"}, + {MNG_FN_DIFFER_G2, "differ_g2"}, + {MNG_FN_DIFFER_G4, "differ_g4"}, + {MNG_FN_DIFFER_G8, "differ_g8"}, + {MNG_FN_DIFFER_G16, "differ_g16"}, + {MNG_FN_DIFFER_RGB8, "differ_rgb8"}, + {MNG_FN_DIFFER_RGB16, "differ_rgb16"}, + {MNG_FN_DIFFER_IDX1, "differ_idx1"}, + {MNG_FN_DIFFER_IDX2, "differ_idx2"}, + {MNG_FN_DIFFER_IDX4, "differ_idx4"}, + {MNG_FN_DIFFER_IDX8, "differ_idx8"}, + {MNG_FN_DIFFER_GA8, "differ_ga8"}, + {MNG_FN_DIFFER_GA16, "differ_ga16"}, + {MNG_FN_DIFFER_RGBA8, "differ_rgba8"}, + {MNG_FN_DIFFER_RGBA16, "differ_rgba16"}, + + {MNG_FN_CREATE_IMGDATAOBJECT, "create_imgdataobject"}, + {MNG_FN_FREE_IMGDATAOBJECT, "free_imgdataobject"}, + {MNG_FN_CLONE_IMGDATAOBJECT, "clone_imgdataobject"}, + {MNG_FN_CREATE_IMGOBJECT, "create_imgobject"}, + {MNG_FN_FREE_IMGOBJECT, "free_imgobject"}, + {MNG_FN_FIND_IMGOBJECT, "find_imgobject"}, + {MNG_FN_CLONE_IMGOBJECT, "clone_imgobject"}, + {MNG_FN_RESET_OBJECTDETAILS, "reset_objectdetails"}, + {MNG_FN_RENUM_IMGOBJECT, "renum_imgobject"}, + {MNG_FN_PROMOTE_IMGOBJECT, "promote_imgobject"}, + {MNG_FN_MAGNIFY_IMGOBJECT, "magnify_imgobject"}, + + {MNG_FN_STORE_G1, "store_g1"}, + {MNG_FN_STORE_G2, "store_g2"}, + {MNG_FN_STORE_G4, "store_g4"}, + {MNG_FN_STORE_G8, "store_g8"}, + {MNG_FN_STORE_G16, "store_g16"}, + {MNG_FN_STORE_RGB8, "store_rgb8"}, + {MNG_FN_STORE_RGB16, "store_rgb16"}, + {MNG_FN_STORE_IDX1, "store_idx1"}, + {MNG_FN_STORE_IDX2, "store_idx2"}, + {MNG_FN_STORE_IDX4, "store_idx4"}, + {MNG_FN_STORE_IDX8, "store_idx8"}, + {MNG_FN_STORE_GA8, "store_ga8"}, + {MNG_FN_STORE_GA16, "store_ga16"}, + {MNG_FN_STORE_RGBA8, "store_rgba8"}, + {MNG_FN_STORE_RGBA16, "store_rgba16"}, + + {MNG_FN_RETRIEVE_G8, "retrieve_g8"}, + {MNG_FN_RETRIEVE_G16, "retrieve_g16"}, + {MNG_FN_RETRIEVE_RGB8, "retrieve_rgb8"}, + {MNG_FN_RETRIEVE_RGB16, "retrieve_rgb16"}, + {MNG_FN_RETRIEVE_IDX8, "retrieve_idx8"}, + {MNG_FN_RETRIEVE_GA8, "retrieve_ga8"}, + {MNG_FN_RETRIEVE_GA16, "retrieve_ga16"}, + {MNG_FN_RETRIEVE_RGBA8, "retrieve_rgba8"}, + {MNG_FN_RETRIEVE_RGBA16, "retrieve_rgba16"}, + + {MNG_FN_DELTA_G1, "delta_g1"}, + {MNG_FN_DELTA_G2, "delta_g2"}, + {MNG_FN_DELTA_G4, "delta_g4"}, + {MNG_FN_DELTA_G8, "delta_g8"}, + {MNG_FN_DELTA_G16, "delta_g16"}, + {MNG_FN_DELTA_RGB8, "delta_rgb8"}, + {MNG_FN_DELTA_RGB16, "delta_rgb16"}, + {MNG_FN_DELTA_IDX1, "delta_idx1"}, + {MNG_FN_DELTA_IDX2, "delta_idx2"}, + {MNG_FN_DELTA_IDX4, "delta_idx4"}, + {MNG_FN_DELTA_IDX8, "delta_idx8"}, + {MNG_FN_DELTA_GA8, "delta_ga8"}, + {MNG_FN_DELTA_GA16, "delta_ga16"}, + {MNG_FN_DELTA_RGBA8, "delta_rgba8"}, + {MNG_FN_DELTA_RGBA16, "delta_rgba16"}, + + {MNG_FN_CREATE_ANI_LOOP, "create_ani_loop"}, + {MNG_FN_CREATE_ANI_ENDL, "create_ani_endl"}, + {MNG_FN_CREATE_ANI_DEFI, "create_ani_defi"}, + {MNG_FN_CREATE_ANI_BASI, "create_ani_basi"}, + {MNG_FN_CREATE_ANI_CLON, "create_ani_clon"}, + {MNG_FN_CREATE_ANI_PAST, "create_ani_past"}, + {MNG_FN_CREATE_ANI_DISC, "create_ani_disc"}, + {MNG_FN_CREATE_ANI_BACK, "create_ani_back"}, + {MNG_FN_CREATE_ANI_FRAM, "create_ani_fram"}, + {MNG_FN_CREATE_ANI_MOVE, "create_ani_move"}, + {MNG_FN_CREATE_ANI_CLIP, "create_ani_clip"}, + {MNG_FN_CREATE_ANI_SHOW, "create_ani_show"}, + {MNG_FN_CREATE_ANI_TERM, "create_ani_term"}, + {MNG_FN_CREATE_ANI_SAVE, "create_ani_save"}, + {MNG_FN_CREATE_ANI_SEEK, "create_ani_seek"}, + {MNG_FN_CREATE_ANI_GAMA, "create_ani_gama"}, + {MNG_FN_CREATE_ANI_CHRM, "create_ani_chrm"}, + {MNG_FN_CREATE_ANI_SRGB, "create_ani_srgb"}, + {MNG_FN_CREATE_ANI_ICCP, "create_ani_iccp"}, + {MNG_FN_CREATE_ANI_PLTE, "create_ani_plte"}, + {MNG_FN_CREATE_ANI_TRNS, "create_ani_trns"}, + {MNG_FN_CREATE_ANI_BKGD, "create_ani_bkgd"}, + {MNG_FN_CREATE_ANI_DHDR, "create_ani_dhdr"}, + {MNG_FN_CREATE_ANI_PROM, "create_ani_prom"}, + {MNG_FN_CREATE_ANI_IPNG, "create_ani_ipng"}, + {MNG_FN_CREATE_ANI_IJNG, "create_ani_ijng"}, + {MNG_FN_CREATE_ANI_PPLT, "create_ani_pplt"}, + {MNG_FN_CREATE_ANI_MAGN, "create_ani_magn"}, + + {MNG_FN_CREATE_ANI_IMAGE, "create_ani_image"}, + + {MNG_FN_FREE_ANI_LOOP, "free_ani_loop"}, + {MNG_FN_FREE_ANI_ENDL, "free_ani_endl"}, + {MNG_FN_FREE_ANI_DEFI, "free_ani_defi"}, + {MNG_FN_FREE_ANI_BASI, "free_ani_basi"}, + {MNG_FN_FREE_ANI_CLON, "free_ani_clon"}, + {MNG_FN_FREE_ANI_PAST, "free_ani_past"}, + {MNG_FN_FREE_ANI_DISC, "free_ani_disc"}, + {MNG_FN_FREE_ANI_BACK, "free_ani_back"}, + {MNG_FN_FREE_ANI_FRAM, "free_ani_fram"}, + {MNG_FN_FREE_ANI_MOVE, "free_ani_move"}, + {MNG_FN_FREE_ANI_CLIP, "free_ani_clip"}, + {MNG_FN_FREE_ANI_SHOW, "free_ani_show"}, + {MNG_FN_FREE_ANI_TERM, "free_ani_term"}, + {MNG_FN_FREE_ANI_SAVE, "free_ani_save"}, + {MNG_FN_FREE_ANI_SEEK, "free_ani_seek"}, + {MNG_FN_FREE_ANI_GAMA, "free_ani_gama"}, + {MNG_FN_FREE_ANI_CHRM, "free_ani_chrm"}, + {MNG_FN_FREE_ANI_SRGB, "free_ani_srgb"}, + {MNG_FN_FREE_ANI_ICCP, "free_ani_iccp"}, + {MNG_FN_FREE_ANI_PLTE, "free_ani_plte"}, + {MNG_FN_FREE_ANI_TRNS, "free_ani_trns"}, + {MNG_FN_FREE_ANI_BKGD, "free_ani_bkgd"}, + {MNG_FN_FREE_ANI_DHDR, "free_ani_dhdr"}, + {MNG_FN_FREE_ANI_PROM, "free_ani_prom"}, + {MNG_FN_FREE_ANI_IPNG, "free_ani_ipng"}, + {MNG_FN_FREE_ANI_IJNG, "free_ani_ijng"}, + {MNG_FN_FREE_ANI_PPLT, "free_ani_pplt"}, + {MNG_FN_FREE_ANI_MAGN, "free_ani_magn"}, + + {MNG_FN_FREE_ANI_IMAGE, "free_ani_image"}, + + {MNG_FN_PROCESS_ANI_LOOP, "process_ani_loop"}, + {MNG_FN_PROCESS_ANI_ENDL, "process_ani_endl"}, + {MNG_FN_PROCESS_ANI_DEFI, "process_ani_defi"}, + {MNG_FN_PROCESS_ANI_BASI, "process_ani_basi"}, + {MNG_FN_PROCESS_ANI_CLON, "process_ani_clon"}, + {MNG_FN_PROCESS_ANI_PAST, "process_ani_past"}, + {MNG_FN_PROCESS_ANI_DISC, "process_ani_disc"}, + {MNG_FN_PROCESS_ANI_BACK, "process_ani_back"}, + {MNG_FN_PROCESS_ANI_FRAM, "process_ani_fram"}, + {MNG_FN_PROCESS_ANI_MOVE, "process_ani_move"}, + {MNG_FN_PROCESS_ANI_CLIP, "process_ani_clip"}, + {MNG_FN_PROCESS_ANI_SHOW, "process_ani_show"}, + {MNG_FN_PROCESS_ANI_TERM, "process_ani_term"}, + {MNG_FN_PROCESS_ANI_SAVE, "process_ani_save"}, + {MNG_FN_PROCESS_ANI_SEEK, "process_ani_seek"}, + {MNG_FN_PROCESS_ANI_GAMA, "process_ani_gama"}, + {MNG_FN_PROCESS_ANI_CHRM, "process_ani_chrm"}, + {MNG_FN_PROCESS_ANI_SRGB, "process_ani_srgb"}, + {MNG_FN_PROCESS_ANI_ICCP, "process_ani_iccp"}, + {MNG_FN_PROCESS_ANI_PLTE, "process_ani_plte"}, + {MNG_FN_PROCESS_ANI_TRNS, "process_ani_trns"}, + {MNG_FN_PROCESS_ANI_BKGD, "process_ani_bkgd"}, + {MNG_FN_PROCESS_ANI_DHDR, "process_ani_dhdr"}, + {MNG_FN_PROCESS_ANI_PROM, "process_ani_prom"}, + {MNG_FN_PROCESS_ANI_IPNG, "process_ani_ipng"}, + {MNG_FN_PROCESS_ANI_IJNG, "process_ani_ijng"}, + {MNG_FN_PROCESS_ANI_PPLT, "process_ani_pplt"}, + {MNG_FN_PROCESS_ANI_MAGN, "process_ani_magn"}, + + {MNG_FN_PROCESS_ANI_IMAGE, "process_ani_image"}, + + {MNG_FN_RESTORE_BACKIMAGE, "restore_backimage"}, + {MNG_FN_RESTORE_BACKCOLOR, "restore_backcolor"}, + {MNG_FN_RESTORE_BGCOLOR, "restore_bgcolor"}, + {MNG_FN_RESTORE_RGB8, "restore_rgb8"}, + {MNG_FN_RESTORE_BGR8, "restore_bgr8"}, + {MNG_FN_RESTORE_BKGD, "restore_bkgd"}, + + {MNG_FN_INIT_IHDR, "init_ihdr"}, + {MNG_FN_INIT_PLTE, "init_plte"}, + {MNG_FN_INIT_IDAT, "init_idat"}, + {MNG_FN_INIT_IEND, "init_iend"}, + {MNG_FN_INIT_TRNS, "init_trns"}, + {MNG_FN_INIT_GAMA, "init_gama"}, + {MNG_FN_INIT_CHRM, "init_chrm"}, + {MNG_FN_INIT_SRGB, "init_srgb"}, + {MNG_FN_INIT_ICCP, "init_iccp"}, + {MNG_FN_INIT_TEXT, "init_text"}, + {MNG_FN_INIT_ZTXT, "init_ztxt"}, + {MNG_FN_INIT_ITXT, "init_itxt"}, + {MNG_FN_INIT_BKGD, "init_bkgd"}, + {MNG_FN_INIT_PHYS, "init_phys"}, + {MNG_FN_INIT_SBIT, "init_sbit"}, + {MNG_FN_INIT_SPLT, "init_splt"}, + {MNG_FN_INIT_HIST, "init_hist"}, + {MNG_FN_INIT_TIME, "init_time"}, + {MNG_FN_INIT_MHDR, "init_mhdr"}, + {MNG_FN_INIT_MEND, "init_mend"}, + {MNG_FN_INIT_LOOP, "init_loop"}, + {MNG_FN_INIT_ENDL, "init_endl"}, + {MNG_FN_INIT_DEFI, "init_defi"}, + {MNG_FN_INIT_BASI, "init_basi"}, + {MNG_FN_INIT_CLON, "init_clon"}, + {MNG_FN_INIT_PAST, "init_past"}, + {MNG_FN_INIT_DISC, "init_disc"}, + {MNG_FN_INIT_BACK, "init_back"}, + {MNG_FN_INIT_FRAM, "init_fram"}, + {MNG_FN_INIT_MOVE, "init_move"}, + {MNG_FN_INIT_CLIP, "init_clip"}, + {MNG_FN_INIT_SHOW, "init_show"}, + {MNG_FN_INIT_TERM, "init_term"}, + {MNG_FN_INIT_SAVE, "init_save"}, + {MNG_FN_INIT_SEEK, "init_seek"}, + {MNG_FN_INIT_EXPI, "init_expi"}, + {MNG_FN_INIT_FPRI, "init_fpri"}, + {MNG_FN_INIT_NEED, "init_need"}, + {MNG_FN_INIT_PHYG, "init_phyg"}, + {MNG_FN_INIT_JHDR, "init_jhdr"}, + {MNG_FN_INIT_JDAT, "init_jdat"}, + {MNG_FN_INIT_JSEP, "init_jsep"}, + {MNG_FN_INIT_DHDR, "init_dhdr"}, + {MNG_FN_INIT_PROM, "init_prom"}, + {MNG_FN_INIT_IPNG, "init_ipng"}, + {MNG_FN_INIT_PPLT, "init_pplt"}, + {MNG_FN_INIT_IJNG, "init_ijng"}, + {MNG_FN_INIT_DROP, "init_drop"}, + {MNG_FN_INIT_DBYK, "init_dbyk"}, + {MNG_FN_INIT_ORDR, "init_ordr"}, + {MNG_FN_INIT_UNKNOWN, "init_unknown"}, + {MNG_FN_INIT_MAGN, "init_magn"}, + {MNG_FN_INIT_JDAA, "init_jdaa"}, + + {MNG_FN_FREE_IHDR, "free_ihdr"}, + {MNG_FN_FREE_PLTE, "free_plte"}, + {MNG_FN_FREE_IDAT, "free_idat"}, + {MNG_FN_FREE_IEND, "free_iend"}, + {MNG_FN_FREE_TRNS, "free_trns"}, + {MNG_FN_FREE_GAMA, "free_gama"}, + {MNG_FN_FREE_CHRM, "free_chrm"}, + {MNG_FN_FREE_SRGB, "free_srgb"}, + {MNG_FN_FREE_ICCP, "free_iccp"}, + {MNG_FN_FREE_TEXT, "free_text"}, + {MNG_FN_FREE_ZTXT, "free_ztxt"}, + {MNG_FN_FREE_ITXT, "free_itxt"}, + {MNG_FN_FREE_BKGD, "free_bkgd"}, + {MNG_FN_FREE_PHYS, "free_phys"}, + {MNG_FN_FREE_SBIT, "free_sbit"}, + {MNG_FN_FREE_SPLT, "free_splt"}, + {MNG_FN_FREE_HIST, "free_hist"}, + {MNG_FN_FREE_TIME, "free_time"}, + {MNG_FN_FREE_MHDR, "free_mhdr"}, + {MNG_FN_FREE_MEND, "free_mend"}, + {MNG_FN_FREE_LOOP, "free_loop"}, + {MNG_FN_FREE_ENDL, "free_endl"}, + {MNG_FN_FREE_DEFI, "free_defi"}, + {MNG_FN_FREE_BASI, "free_basi"}, + {MNG_FN_FREE_CLON, "free_clon"}, + {MNG_FN_FREE_PAST, "free_past"}, + {MNG_FN_FREE_DISC, "free_disc"}, + {MNG_FN_FREE_BACK, "free_back"}, + {MNG_FN_FREE_FRAM, "free_fram"}, + {MNG_FN_FREE_MOVE, "free_move"}, + {MNG_FN_FREE_CLIP, "free_clip"}, + {MNG_FN_FREE_SHOW, "free_show"}, + {MNG_FN_FREE_TERM, "free_term"}, + {MNG_FN_FREE_SAVE, "free_save"}, + {MNG_FN_FREE_SEEK, "free_seek"}, + {MNG_FN_FREE_EXPI, "free_expi"}, + {MNG_FN_FREE_FPRI, "free_fpri"}, + {MNG_FN_FREE_NEED, "free_need"}, + {MNG_FN_FREE_PHYG, "free_phyg"}, + {MNG_FN_FREE_JHDR, "free_jhdr"}, + {MNG_FN_FREE_JDAT, "free_jdat"}, + {MNG_FN_FREE_JSEP, "free_jsep"}, + {MNG_FN_FREE_DHDR, "free_dhdr"}, + {MNG_FN_FREE_PROM, "free_prom"}, + {MNG_FN_FREE_IPNG, "free_ipng"}, + {MNG_FN_FREE_PPLT, "free_pplt"}, + {MNG_FN_FREE_IJNG, "free_ijng"}, + {MNG_FN_FREE_DROP, "free_drop"}, + {MNG_FN_FREE_DBYK, "free_dbyk"}, + {MNG_FN_FREE_ORDR, "free_ordr"}, + {MNG_FN_FREE_UNKNOWN, "free_unknown"}, + {MNG_FN_FREE_MAGN, "free_magn"}, + {MNG_FN_FREE_JDAA, "free_jdaa"}, + + {MNG_FN_READ_IHDR, "read_ihdr"}, + {MNG_FN_READ_PLTE, "read_plte"}, + {MNG_FN_READ_IDAT, "read_idat"}, + {MNG_FN_READ_IEND, "read_iend"}, + {MNG_FN_READ_TRNS, "read_trns"}, + {MNG_FN_READ_GAMA, "read_gama"}, + {MNG_FN_READ_CHRM, "read_chrm"}, + {MNG_FN_READ_SRGB, "read_srgb"}, + {MNG_FN_READ_ICCP, "read_iccp"}, + {MNG_FN_READ_TEXT, "read_text"}, + {MNG_FN_READ_ZTXT, "read_ztxt"}, + {MNG_FN_READ_ITXT, "read_itxt"}, + {MNG_FN_READ_BKGD, "read_bkgd"}, + {MNG_FN_READ_PHYS, "read_phys"}, + {MNG_FN_READ_SBIT, "read_sbit"}, + {MNG_FN_READ_SPLT, "read_splt"}, + {MNG_FN_READ_HIST, "read_hist"}, + {MNG_FN_READ_TIME, "read_time"}, + {MNG_FN_READ_MHDR, "read_mhdr"}, + {MNG_FN_READ_MEND, "read_mend"}, + {MNG_FN_READ_LOOP, "read_loop"}, + {MNG_FN_READ_ENDL, "read_endl"}, + {MNG_FN_READ_DEFI, "read_defi"}, + {MNG_FN_READ_BASI, "read_basi"}, + {MNG_FN_READ_CLON, "read_clon"}, + {MNG_FN_READ_PAST, "read_past"}, + {MNG_FN_READ_DISC, "read_disc"}, + {MNG_FN_READ_BACK, "read_back"}, + {MNG_FN_READ_FRAM, "read_fram"}, + {MNG_FN_READ_MOVE, "read_move"}, + {MNG_FN_READ_CLIP, "read_clip"}, + {MNG_FN_READ_SHOW, "read_show"}, + {MNG_FN_READ_TERM, "read_term"}, + {MNG_FN_READ_SAVE, "read_save"}, + {MNG_FN_READ_SEEK, "read_seek"}, + {MNG_FN_READ_EXPI, "read_expi"}, + {MNG_FN_READ_FPRI, "read_fpri"}, + {MNG_FN_READ_NEED, "read_need"}, + {MNG_FN_READ_PHYG, "read_phyg"}, + {MNG_FN_READ_JHDR, "read_jhdr"}, + {MNG_FN_READ_JDAT, "read_jdat"}, + {MNG_FN_READ_JSEP, "read_jsep"}, + {MNG_FN_READ_DHDR, "read_dhdr"}, + {MNG_FN_READ_PROM, "read_prom"}, + {MNG_FN_READ_IPNG, "read_ipng"}, + {MNG_FN_READ_PPLT, "read_pplt"}, + {MNG_FN_READ_IJNG, "read_ijng"}, + {MNG_FN_READ_DROP, "read_drop"}, + {MNG_FN_READ_DBYK, "read_dbyk"}, + {MNG_FN_READ_ORDR, "read_ordr"}, + {MNG_FN_READ_UNKNOWN, "read_unknown"}, + {MNG_FN_READ_MAGN, "read_magn"}, + {MNG_FN_READ_JDAA, "read_jdaa"}, + + {MNG_FN_WRITE_IHDR, "write_ihdr"}, + {MNG_FN_WRITE_PLTE, "write_plte"}, + {MNG_FN_WRITE_IDAT, "write_idat"}, + {MNG_FN_WRITE_IEND, "write_iend"}, + {MNG_FN_WRITE_TRNS, "write_trns"}, + {MNG_FN_WRITE_GAMA, "write_gama"}, + {MNG_FN_WRITE_CHRM, "write_chrm"}, + {MNG_FN_WRITE_SRGB, "write_srgb"}, + {MNG_FN_WRITE_ICCP, "write_iccp"}, + {MNG_FN_WRITE_TEXT, "write_text"}, + {MNG_FN_WRITE_ZTXT, "write_ztxt"}, + {MNG_FN_WRITE_ITXT, "write_itxt"}, + {MNG_FN_WRITE_BKGD, "write_bkgd"}, + {MNG_FN_WRITE_PHYS, "write_phys"}, + {MNG_FN_WRITE_SBIT, "write_sbit"}, + {MNG_FN_WRITE_SPLT, "write_splt"}, + {MNG_FN_WRITE_HIST, "write_hist"}, + {MNG_FN_WRITE_TIME, "write_time"}, + {MNG_FN_WRITE_MHDR, "write_mhdr"}, + {MNG_FN_WRITE_MEND, "write_mend"}, + {MNG_FN_WRITE_LOOP, "write_loop"}, + {MNG_FN_WRITE_ENDL, "write_endl"}, + {MNG_FN_WRITE_DEFI, "write_defi"}, + {MNG_FN_WRITE_BASI, "write_basi"}, + {MNG_FN_WRITE_CLON, "write_clon"}, + {MNG_FN_WRITE_PAST, "write_past"}, + {MNG_FN_WRITE_DISC, "write_disc"}, + {MNG_FN_WRITE_BACK, "write_back"}, + {MNG_FN_WRITE_FRAM, "write_fram"}, + {MNG_FN_WRITE_MOVE, "write_move"}, + {MNG_FN_WRITE_CLIP, "write_clip"}, + {MNG_FN_WRITE_SHOW, "write_show"}, + {MNG_FN_WRITE_TERM, "write_term"}, + {MNG_FN_WRITE_SAVE, "write_save"}, + {MNG_FN_WRITE_SEEK, "write_seek"}, + {MNG_FN_WRITE_EXPI, "write_expi"}, + {MNG_FN_WRITE_FPRI, "write_fpri"}, + {MNG_FN_WRITE_NEED, "write_need"}, + {MNG_FN_WRITE_PHYG, "write_phyg"}, + {MNG_FN_WRITE_JHDR, "write_jhdr"}, + {MNG_FN_WRITE_JDAT, "write_jdat"}, + {MNG_FN_WRITE_JSEP, "write_jsep"}, + {MNG_FN_WRITE_DHDR, "write_dhdr"}, + {MNG_FN_WRITE_PROM, "write_prom"}, + {MNG_FN_WRITE_IPNG, "write_ipng"}, + {MNG_FN_WRITE_PPLT, "write_pplt"}, + {MNG_FN_WRITE_IJNG, "write_ijng"}, + {MNG_FN_WRITE_DROP, "write_drop"}, + {MNG_FN_WRITE_DBYK, "write_dbyk"}, + {MNG_FN_WRITE_ORDR, "write_ordr"}, + {MNG_FN_WRITE_UNKNOWN, "write_unknown"}, + {MNG_FN_WRITE_MAGN, "write_magn"}, + {MNG_FN_WRITE_JDAA, "write_jdaa"}, + + {MNG_FN_ZLIB_INITIALIZE, "zlib_initialize"}, + {MNG_FN_ZLIB_CLEANUP, "zlib_cleanup"}, + {MNG_FN_ZLIB_INFLATEINIT, "zlib_inflateinit"}, + {MNG_FN_ZLIB_INFLATEROWS, "zlib_inflaterows"}, + {MNG_FN_ZLIB_INFLATEDATA, "zlib_inflatedata"}, + {MNG_FN_ZLIB_INFLATEFREE, "zlib_inflatefree"}, + {MNG_FN_ZLIB_DEFLATEINIT, "zlib_deflateinit"}, + {MNG_FN_ZLIB_DEFLATEROWS, "zlib_deflaterows"}, + {MNG_FN_ZLIB_DEFLATEDATA, "zlib_deflatedata"}, + {MNG_FN_ZLIB_DEFLATEFREE, "zlib_deflatefree"}, + + {MNG_FN_PROCESS_DISPLAY_IHDR, "process_display_ihdr"}, + {MNG_FN_PROCESS_DISPLAY_PLTE, "process_display_plte"}, + {MNG_FN_PROCESS_DISPLAY_IDAT, "process_display_idat"}, + {MNG_FN_PROCESS_DISPLAY_IEND, "process_display_iend"}, + {MNG_FN_PROCESS_DISPLAY_TRNS, "process_display_trns"}, + {MNG_FN_PROCESS_DISPLAY_GAMA, "process_display_gama"}, + {MNG_FN_PROCESS_DISPLAY_CHRM, "process_display_chrm"}, + {MNG_FN_PROCESS_DISPLAY_SRGB, "process_display_srgb"}, + {MNG_FN_PROCESS_DISPLAY_ICCP, "process_display_iccp"}, + {MNG_FN_PROCESS_DISPLAY_BKGD, "process_display_bkgd"}, + {MNG_FN_PROCESS_DISPLAY_PHYS, "process_display_phys"}, + {MNG_FN_PROCESS_DISPLAY_SBIT, "process_display_sbit"}, + {MNG_FN_PROCESS_DISPLAY_SPLT, "process_display_splt"}, + {MNG_FN_PROCESS_DISPLAY_HIST, "process_display_hist"}, + {MNG_FN_PROCESS_DISPLAY_MHDR, "process_display_mhdr"}, + {MNG_FN_PROCESS_DISPLAY_MEND, "process_display_mend"}, + {MNG_FN_PROCESS_DISPLAY_LOOP, "process_display_loop"}, + {MNG_FN_PROCESS_DISPLAY_ENDL, "process_display_endl"}, + {MNG_FN_PROCESS_DISPLAY_DEFI, "process_display_defi"}, + {MNG_FN_PROCESS_DISPLAY_BASI, "process_display_basi"}, + {MNG_FN_PROCESS_DISPLAY_CLON, "process_display_clon"}, + {MNG_FN_PROCESS_DISPLAY_PAST, "process_display_past"}, + {MNG_FN_PROCESS_DISPLAY_DISC, "process_display_disc"}, + {MNG_FN_PROCESS_DISPLAY_BACK, "process_display_back"}, + {MNG_FN_PROCESS_DISPLAY_FRAM, "process_display_fram"}, + {MNG_FN_PROCESS_DISPLAY_MOVE, "process_display_move"}, + {MNG_FN_PROCESS_DISPLAY_CLIP, "process_display_clip"}, + {MNG_FN_PROCESS_DISPLAY_SHOW, "process_display_show"}, + {MNG_FN_PROCESS_DISPLAY_TERM, "process_display_term"}, + {MNG_FN_PROCESS_DISPLAY_SAVE, "process_display_save"}, + {MNG_FN_PROCESS_DISPLAY_SEEK, "process_display_seek"}, + {MNG_FN_PROCESS_DISPLAY_EXPI, "process_display_expi"}, + {MNG_FN_PROCESS_DISPLAY_FPRI, "process_display_fpri"}, + {MNG_FN_PROCESS_DISPLAY_NEED, "process_display_need"}, + {MNG_FN_PROCESS_DISPLAY_PHYG, "process_display_phyg"}, + {MNG_FN_PROCESS_DISPLAY_JHDR, "process_display_jhdr"}, + {MNG_FN_PROCESS_DISPLAY_JDAT, "process_display_jdat"}, + {MNG_FN_PROCESS_DISPLAY_JSEP, "process_display_jsep"}, + {MNG_FN_PROCESS_DISPLAY_DHDR, "process_display_dhdr"}, + {MNG_FN_PROCESS_DISPLAY_PROM, "process_display_prom"}, + {MNG_FN_PROCESS_DISPLAY_IPNG, "process_display_ipng"}, + {MNG_FN_PROCESS_DISPLAY_PPLT, "process_display_pplt"}, + {MNG_FN_PROCESS_DISPLAY_IJNG, "process_display_ijng"}, + {MNG_FN_PROCESS_DISPLAY_DROP, "process_display_drop"}, + {MNG_FN_PROCESS_DISPLAY_DBYK, "process_display_dbyk"}, + {MNG_FN_PROCESS_DISPLAY_ORDR, "process_display_ordr"}, + {MNG_FN_PROCESS_DISPLAY_MAGN, "process_display_magn"}, + {MNG_FN_PROCESS_DISPLAY_JDAA, "process_display_jdaa"}, + + {MNG_FN_JPEG_INITIALIZE, "jpeg_initialize"}, + {MNG_FN_JPEG_CLEANUP, "jpeg_cleanup"}, + {MNG_FN_JPEG_DECOMPRESSINIT, "jpeg_decompressinit"}, + {MNG_FN_JPEG_DECOMPRESSDATA, "jpeg_decompressdata"}, + {MNG_FN_JPEG_DECOMPRESSFREE, "jpeg_decompressfree"}, + + {MNG_FN_STORE_JPEG_G8, "store_jpeg_g8"}, + {MNG_FN_STORE_JPEG_RGB8, "store_jpeg_rgb8"}, + {MNG_FN_STORE_JPEG_G12, "store_jpeg_g12"}, + {MNG_FN_STORE_JPEG_RGB12, "store_jpeg_rgb12"}, + {MNG_FN_STORE_JPEG_GA8, "store_jpeg_ga8"}, + {MNG_FN_STORE_JPEG_RGBA8, "store_jpeg_rgba8"}, + {MNG_FN_STORE_JPEG_GA12, "store_jpeg_ga12"}, + {MNG_FN_STORE_JPEG_RGBA12, "store_jpeg_rgba12"}, + {MNG_FN_STORE_JPEG_G8_ALPHA, "store_jpeg_g8_alpha"}, + {MNG_FN_STORE_JPEG_RGB8_ALPHA, "store_jpeg_rgb8_alpha"}, + + {MNG_FN_INIT_JPEG_A1_NI, "init_jpeg_a1_ni"}, + {MNG_FN_INIT_JPEG_A2_NI, "init_jpeg_a2_ni"}, + {MNG_FN_INIT_JPEG_A4_NI, "init_jpeg_a4_ni"}, + {MNG_FN_INIT_JPEG_A8_NI, "init_jpeg_a8_ni"}, + {MNG_FN_INIT_JPEG_A16_NI, "init_jpeg_a16_ni"}, + + {MNG_FN_STORE_JPEG_G8_A1, "store_jpeg_g8_a1"}, + {MNG_FN_STORE_JPEG_G8_A2, "store_jpeg_g8_a2"}, + {MNG_FN_STORE_JPEG_G8_A4, "store_jpeg_g8_a4"}, + {MNG_FN_STORE_JPEG_G8_A8, "store_jpeg_g8_a8"}, + {MNG_FN_STORE_JPEG_G8_A16, "store_jpeg_g8_a16"}, + + {MNG_FN_STORE_JPEG_RGB8_A1, "store_jpeg_rgb8_a1"}, + {MNG_FN_STORE_JPEG_RGB8_A2, "store_jpeg_rgb8_a2"}, + {MNG_FN_STORE_JPEG_RGB8_A4, "store_jpeg_rgb8_a4"}, + {MNG_FN_STORE_JPEG_RGB8_A8, "store_jpeg_rgb8_a8"}, + {MNG_FN_STORE_JPEG_RGB8_A16, "store_jpeg_rgb8_a16"}, + + {MNG_FN_STORE_JPEG_G12_A1, "store_jpeg_g12_a1"}, + {MNG_FN_STORE_JPEG_G12_A2, "store_jpeg_g12_a2"}, + {MNG_FN_STORE_JPEG_G12_A4, "store_jpeg_g12_a4"}, + {MNG_FN_STORE_JPEG_G12_A8, "store_jpeg_g12_a8"}, + {MNG_FN_STORE_JPEG_G12_A16, "store_jpeg_g12_a16"}, + + {MNG_FN_STORE_JPEG_RGB12_A1, "store_jpeg_rgb12_a1"}, + {MNG_FN_STORE_JPEG_RGB12_A2, "store_jpeg_rgb12_a2"}, + {MNG_FN_STORE_JPEG_RGB12_A4, "store_jpeg_rgb12_a4"}, + {MNG_FN_STORE_JPEG_RGB12_A8, "store_jpeg_rgb12_a8"}, + {MNG_FN_STORE_JPEG_RGB12_A16, "store_jpeg_rgb12_a16"}, + + {MNG_FN_NEXT_JPEG_ALPHAROW, "next_jpeg_alpharow"}, + {MNG_FN_NEXT_JPEG_ROW, "next_jpeg_row"}, + {MNG_FN_DISPLAY_JPEG_ROWS, "display_jpeg_rows"}, + + {MNG_FN_MAGNIFY_G8_X1, "magnify_g8_x1"}, + {MNG_FN_MAGNIFY_G8_X2, "magnify_g8_x2"}, + {MNG_FN_MAGNIFY_RGB8_X1, "magnify_rgb8_x1"}, + {MNG_FN_MAGNIFY_RGB8_X2, "magnify_rgb8_x2"}, + {MNG_FN_MAGNIFY_GA8_X1, "magnify_ga8_x1"}, + {MNG_FN_MAGNIFY_GA8_X2, "magnify_ga8_x2"}, + {MNG_FN_MAGNIFY_GA8_X3, "magnify_ga8_x3"}, + {MNG_FN_MAGNIFY_GA8_X4, "magnify_ga8_x4"}, + {MNG_FN_MAGNIFY_RGBA8_X1, "magnify_rgba8_x1"}, + {MNG_FN_MAGNIFY_RGBA8_X2, "magnify_rgba8_x2"}, + {MNG_FN_MAGNIFY_RGBA8_X3, "magnify_rgba8_x3"}, + {MNG_FN_MAGNIFY_RGBA8_X4, "magnify_rgba8_x4"}, + {MNG_FN_MAGNIFY_G8_X3, "magnify_g8_x3"}, + {MNG_FN_MAGNIFY_RGB8_X3, "magnify_rgb8_x3"}, + {MNG_FN_MAGNIFY_GA8_X5, "magnify_ga8_x5"}, + {MNG_FN_MAGNIFY_RGBA8_X5, "magnify_rgba8_x5"}, + + {MNG_FN_MAGNIFY_G8_Y1, "magnify_g8_y1"}, + {MNG_FN_MAGNIFY_G8_Y2, "magnify_g8_y2"}, + {MNG_FN_MAGNIFY_RGB8_Y1, "magnify_rgb8_y1"}, + {MNG_FN_MAGNIFY_RGB8_Y2, "magnify_rgb8_y2"}, + {MNG_FN_MAGNIFY_GA8_Y1, "magnify_ga8_y1"}, + {MNG_FN_MAGNIFY_GA8_Y2, "magnify_ga8_y2"}, + {MNG_FN_MAGNIFY_GA8_Y3, "magnify_ga8_y3"}, + {MNG_FN_MAGNIFY_GA8_Y4, "magnify_ga8_y4"}, + {MNG_FN_MAGNIFY_RGBA8_Y1, "magnify_rgba8_y1"}, + {MNG_FN_MAGNIFY_RGBA8_Y2, "magnify_rgba8_y2"}, + {MNG_FN_MAGNIFY_RGBA8_Y3, "magnify_rgba8_y3"}, + {MNG_FN_MAGNIFY_RGBA8_Y4, "magnify_rgba8_y4"}, + {MNG_FN_MAGNIFY_G8_Y3, "magnify_g8_y3"}, + {MNG_FN_MAGNIFY_RGB8_Y3, "magnify_rgb8_y3"}, + {MNG_FN_MAGNIFY_GA8_Y5, "magnify_ga8_y5"}, + {MNG_FN_MAGNIFY_RGBA8_Y5, "magnify_rgba8_y5"}, + + {MNG_FN_DELTA_G1_G1, "delta_g1_g1"}, + {MNG_FN_DELTA_G2_G2, "delta_g2_g2"}, + {MNG_FN_DELTA_G4_G4, "delta_g4_g4"}, + {MNG_FN_DELTA_G8_G8, "delta_g8_g8"}, + {MNG_FN_DELTA_G16_G16, "delta_g16_g16"}, + {MNG_FN_DELTA_RGB8_RGB8, "delta_rgb8_rgb8"}, + {MNG_FN_DELTA_RGB16_RGB16, "delta_rgb16_rgb16"}, + {MNG_FN_DELTA_GA8_GA8, "delta_ga8_ga8"}, + {MNG_FN_DELTA_GA8_G8, "delta_ga8_g8"}, + {MNG_FN_DELTA_GA8_A8, "delta_ga8_a8"}, + {MNG_FN_DELTA_GA16_GA16, "delta_ga16_ga16"}, + {MNG_FN_DELTA_GA16_G16, "delta_ga16_g16"}, + {MNG_FN_DELTA_GA16_A16, "delta_ga16_a16"}, + {MNG_FN_DELTA_RGBA8_RGBA8, "delta_rgba8_rgba8"}, + {MNG_FN_DELTA_RGBA8_RGB8, "delta_rgba8_rgb8"}, + {MNG_FN_DELTA_RGBA8_A8, "delta_rgba8_a8"}, + {MNG_FN_DELTA_RGBA16_RGBA16, "delta_rgba16_rgba16"}, + {MNG_FN_DELTA_RGBA16_RGB16, "delta_rgba16_rgb16"}, + {MNG_FN_DELTA_RGBA16_A16, "delta_rgba16_a16"}, + }; +#endif /* MNG_INCLUDE_TRACE_STINGS */ + +/* ************************************************************************** */ + +mng_retcode mng_trace (mng_datap pData, + mng_uint32 iFunction, + mng_uint32 iLocation) +{ + mng_pchar zName = 0; /* bufferptr for tracestring */ + + if ((pData == 0) || (pData->iMagic != MNG_MAGIC)) + return MNG_INVALIDHANDLE; /* no good if the handle is corrupt */ + + if (pData->fTraceproc) /* report back to user ? */ + { +#ifdef MNG_INCLUDE_TRACE_STRINGS + { /* binary search variables */ + mng_int32 iTop, iLower, iUpper, iMiddle; + mng_trace_entryp pEntry; /* pointer to found entry */ + /* determine max index of table */ + iTop = (sizeof (trace_table) / sizeof (trace_table [0])) - 1; + + iLower = 0; /* initialize binary search */ + iMiddle = iTop >> 1; /* start in the middle */ + iUpper = iTop; + pEntry = 0; /* no goods yet! */ + + do /* the binary search itself */ + { + if (trace_table [iMiddle].iFunction < iFunction) + iLower = iMiddle + 1; + else if (trace_table [iMiddle].iFunction > iFunction) + iUpper = iMiddle - 1; + else + { + pEntry = &trace_table [iMiddle]; + break; + }; + + iMiddle = (iLower + iUpper) >> 1; + } + while (iLower <= iUpper); + + if (pEntry) /* found it ? */ + zName = pEntry->zTracetext; + + } +#endif + /* oke, now tell */ + if (!pData->fTraceproc (((mng_handle)pData), iFunction, iLocation, zName)) + return MNG_APPTRACEABORT; + + } + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_TRACE_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_trace.h b/freeimage241/Source/LibMNG/libmng_trace.h new file mode 100644 index 0000000..e1f4b39 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_trace.h @@ -0,0 +1,1211 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_trace.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : Trace functions (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the trace functions * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - added chunk-access function trace-codes * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * 0.5.1 - 05/13/2000 - G.Juyn * */ +/* * - added save_state & restore_state trace-codes * */ +/* * 0.5.1 - 05/15/2000 - G.Juyn * */ +/* * - added getimgdata & putimgdata trace-codes * */ +/* * * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - added JNG tracecodes * */ +/* * 0.5.2 - 05/23/2000 - G.Juyn * */ +/* * - added trace-table entry definition * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added tracecodes for global animation color-chunks * */ +/* * - added tracecodes for get/set of default ZLIB/IJG parms * */ +/* * - added tracecodes for global PLTE,tRNS,bKGD * */ +/* * 0.5.2 - 05/30/2000 - G.Juyn * */ +/* * - added tracecodes for image-object promotion * */ +/* * - added tracecodes for delta-image processing * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - added tracecodes for getalphaline callback * */ +/* * 0.5.2 - 06/05/2000 - G.Juyn * */ +/* * - added tracecode for RGB8_A8 canvasstyle * */ +/* * 0.5.2 - 06/06/2000 - G.Juyn * */ +/* * - added tracecode for mng_read_resume HLAPI function * */ +/* * * */ +/* * 0.5.3 - 06/06/2000 - G.Juyn * */ +/* * - added tracecodes for tracing JPEG progression * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added tracecodes for get/set speedtype * */ +/* * - added tracecodes for get imagelevel * */ +/* * 0.5.3 - 06/22/2000 - G.Juyn * */ +/* * - added tracecode for delta-image processing * */ +/* * - added tracecodes for PPLT chunk processing * */ +/* * * */ +/* * 0.9.1 - 07/07/2000 - G.Juyn * */ +/* * - added tracecodes for special display processing * */ +/* * 0.9.1 - 07/08/2000 - G.Juyn * */ +/* * - added tracecode for get/set suspensionmode * */ +/* * - added tracecodes for get/set display variables * */ +/* * - added tracecode for read_databuffer (I/O-suspension) * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added tracecodes for SAVE/SEEK callbacks * */ +/* * - added tracecodes for get/set sectionbreaks * */ +/* * - added tracecode for special error routine * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - added tracecode for updatemngheader * */ +/* * * */ +/* * 0.9.2 - 07/31/2000 - G.Juyn * */ +/* * - added tracecodes for status_xxxxx functions * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * - added tracecode for updatemngsimplicity * */ +/* * * */ +/* * 0.9.3 - 08/26/2000 - G.Juyn * */ +/* * - added MAGN chunk * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * 0.9.3 - 10/10/2000 - G.Juyn * */ +/* * - added support for alpha-depth prediction * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - added JDAA chunk * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/16/2000 - G.Juyn * */ +/* * - added functions to retrieve PNG/JNG specific header-info * */ +/* * - added optional support for bKGD for PNG images * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * - added routine to discard "invalid" objects * */ +/* * 0.9.3 - 10/19/2000 - G.Juyn * */ +/* * - implemented delayed delta-processing * */ +/* * 0.9.3 - 10/20/2000 - G.Juyn * */ +/* * - added get/set for bKGD preference setting * */ +/* * 0.9.3 - 10/21/2000 - G.Juyn * */ +/* * - added get function for interlace/progressive display * */ +/* * * */ +/* * 0.9.4 - 1/18/2001 - G.Juyn * */ +/* * - added "new" MAGN methods 3, 4 & 5 * */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * 1.0.1 - 04/21/2001 - G.Juyn (code by G.Kelly) * */ +/* * - added BGRA8 canvas with premultiplied alpha * */ +/* * 1.0.1 - 05/02/2001 - G.Juyn * */ +/* * - added "default" sRGB generation (Thanks Marti!) * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added optimization option for MNG-video playback * */ +/* * - added processterm callback * */ +/* * 1.0.2 - 06/25/2001 - G.Juyn * */ +/* * - added option to turn off progressive refresh * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_trace_h_ +#define _libmng_trace_h_ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_TRACE_PROCS + +/* ************************************************************************** */ + +/* TODO: add a trace-mask so certain functions can be excluded */ + +mng_retcode mng_trace (mng_datap pData, + mng_uint32 iFunction, + mng_uint32 iLocation); + +/* ************************************************************************** */ + +#define MNG_TRACE(D,F,L) { mng_retcode iR = mng_trace (D,F,L); \ + if (iR) return iR; } + +#define MNG_TRACEB(D,F,L) { if (mng_trace (D,F,L)) return MNG_FALSE; } + +#define MNG_TRACEX(D,F,L) { if (mng_trace (D,F,L)) return 0; } + +/* ************************************************************************** */ + +#define MNG_LC_START 1 +#define MNG_LC_END 2 +#define MNG_LC_INITIALIZE 3 +#define MNG_LC_CLEANUP 4 + +/* ************************************************************************** */ + +#define MNG_LC_JPEG_CREATE_DECOMPRESS 101 +#define MNG_LC_JPEG_READ_HEADER 102 +#define MNG_LC_JPEG_START_DECOMPRESS 103 +#define MNG_LC_JPEG_START_OUTPUT 104 +#define MNG_LC_JPEG_READ_SCANLINES 105 +#define MNG_LC_JPEG_FINISH_OUTPUT 106 +#define MNG_LC_JPEG_FINISH_DECOMPRESS 107 +#define MNG_LC_JPEG_DESTROY_DECOMPRESS 108 + +/* ************************************************************************** */ + +#define MNG_FN_INITIALIZE 1 +#define MNG_FN_RESET 2 +#define MNG_FN_CLEANUP 3 +#define MNG_FN_READ 4 +#define MNG_FN_WRITE 5 +#define MNG_FN_CREATE 6 +#define MNG_FN_READDISPLAY 7 +#define MNG_FN_DISPLAY 8 +#define MNG_FN_DISPLAY_RESUME 9 +#define MNG_FN_DISPLAY_FREEZE 10 +#define MNG_FN_DISPLAY_RESET 11 +#define MNG_FN_DISPLAY_GOFRAME 12 +#define MNG_FN_DISPLAY_GOLAYER 13 +#define MNG_FN_DISPLAY_GOTIME 14 +#define MNG_FN_GETLASTERROR 15 +#define MNG_FN_READ_RESUME 16 + +#define MNG_FN_SETCB_MEMALLOC 101 +#define MNG_FN_SETCB_MEMFREE 102 +#define MNG_FN_SETCB_READDATA 103 +#define MNG_FN_SETCB_WRITEDATA 104 +#define MNG_FN_SETCB_ERRORPROC 105 +#define MNG_FN_SETCB_TRACEPROC 106 +#define MNG_FN_SETCB_PROCESSHEADER 107 +#define MNG_FN_SETCB_PROCESSTEXT 108 +#define MNG_FN_SETCB_GETCANVASLINE 109 +#define MNG_FN_SETCB_GETBKGDLINE 110 +#define MNG_FN_SETCB_REFRESH 111 +#define MNG_FN_SETCB_GETTICKCOUNT 112 +#define MNG_FN_SETCB_SETTIMER 113 +#define MNG_FN_SETCB_PROCESSGAMMA 114 +#define MNG_FN_SETCB_PROCESSCHROMA 115 +#define MNG_FN_SETCB_PROCESSSRGB 116 +#define MNG_FN_SETCB_PROCESSICCP 117 +#define MNG_FN_SETCB_PROCESSAROW 118 +#define MNG_FN_SETCB_OPENSTREAM 119 +#define MNG_FN_SETCB_CLOSESTREAM 120 +#define MNG_FN_SETCB_GETALPHALINE 121 +#define MNG_FN_SETCB_PROCESSSAVE 122 +#define MNG_FN_SETCB_PROCESSSEEK 123 +#define MNG_FN_SETCB_PROCESSNEED 124 +#define MNG_FN_SETCB_PROCESSUNKNOWN 125 +#define MNG_FN_SETCB_PROCESSMEND 126 +#define MNG_FN_SETCB_PROCESSTERM 127 + +#define MNG_FN_GETCB_MEMALLOC 201 +#define MNG_FN_GETCB_MEMFREE 202 +#define MNG_FN_GETCB_READDATA 203 +#define MNG_FN_GETCB_WRITEDATA 204 +#define MNG_FN_GETCB_ERRORPROC 205 +#define MNG_FN_GETCB_TRACEPROC 206 +#define MNG_FN_GETCB_PROCESSHEADER 207 +#define MNG_FN_GETCB_PROCESSTEXT 208 +#define MNG_FN_GETCB_GETCANVASLINE 209 +#define MNG_FN_GETCB_GETBKGDLINE 210 +#define MNG_FN_GETCB_REFRESH 211 +#define MNG_FN_GETCB_GETTICKCOUNT 212 +#define MNG_FN_GETCB_SETTIMER 213 +#define MNG_FN_GETCB_PROCESSGAMMA 214 +#define MNG_FN_GETCB_PROCESSCHROMA 215 +#define MNG_FN_GETCB_PROCESSSRGB 216 +#define MNG_FN_GETCB_PROCESSICCP 217 +#define MNG_FN_GETCB_PROCESSAROW 218 +#define MNG_FN_GETCB_OPENSTREAM 219 +#define MNG_FN_GETCB_CLOSESTREAM 220 +#define MNG_FN_GETCB_GETALPHALINE 221 +#define MNG_FN_GETCB_PROCESSSAVE 222 +#define MNG_FN_GETCB_PROCESSSEEK 223 +#define MNG_FN_GETCB_PROCESSNEED 224 +#define MNG_FN_GETCB_PROCESSUNKNOWN 225 +#define MNG_FN_GETCB_PROCESSMEND 226 +#define MNG_FN_GETCB_PROCESSTERM 227 + +#define MNG_FN_SET_USERDATA 301 +#define MNG_FN_SET_CANVASSTYLE 302 +#define MNG_FN_SET_BKGDSTYLE 303 +#define MNG_FN_SET_BGCOLOR 304 +#define MNG_FN_SET_STORECHUNKS 305 +#define MNG_FN_SET_VIEWGAMMA 306 +#define MNG_FN_SET_DISPLAYGAMMA 307 +#define MNG_FN_SET_DFLTIMGGAMMA 308 +#define MNG_FN_SET_SRGB 309 +#define MNG_FN_SET_OUTPUTPROFILE 310 +#define MNG_FN_SET_SRGBPROFILE 311 +#define MNG_FN_SET_MAXCANVASWIDTH 312 +#define MNG_FN_SET_MAXCANVASHEIGHT 313 +#define MNG_FN_SET_MAXCANVASSIZE 314 +#define MNG_FN_SET_ZLIB_LEVEL 315 +#define MNG_FN_SET_ZLIB_METHOD 316 +#define MNG_FN_SET_ZLIB_WINDOWBITS 317 +#define MNG_FN_SET_ZLIB_MEMLEVEL 318 +#define MNG_FN_SET_ZLIB_STRATEGY 319 +#define MNG_FN_SET_ZLIB_MAXIDAT 320 +#define MNG_FN_SET_JPEG_DCTMETHOD 321 +#define MNG_FN_SET_JPEG_QUALITY 322 +#define MNG_FN_SET_JPEG_SMOOTHING 323 +#define MNG_FN_SET_JPEG_PROGRESSIVE 324 +#define MNG_FN_SET_JPEG_OPTIMIZED 325 +#define MNG_FN_SET_JPEG_MAXJDAT 326 +#define MNG_FN_SET_SPEED 327 +#define MNG_FN_SET_SUSPENSIONMODE 328 +#define MNG_FN_SET_SECTIONBREAKS 329 +#define MNG_FN_SET_USEBKGD 330 +#define MNG_FN_SET_OUTPUTPROFILE2 331 +#define MNG_FN_SET_SRGBPROFILE2 332 +#define MNG_FN_SET_OUTPUTSRGB 333 +#define MNG_FN_SET_SRGBIMPLICIT 334 +#define MNG_FN_SET_CACHEPLAYBACK 335 +#define MNG_FN_SET_DOPROGRESSIVE 336 + +#define MNG_FN_GET_USERDATA 401 +#define MNG_FN_GET_SIGTYPE 402 +#define MNG_FN_GET_IMAGETYPE 403 +#define MNG_FN_GET_IMAGEWIDTH 404 +#define MNG_FN_GET_IMAGEHEIGHT 405 +#define MNG_FN_GET_TICKS 406 +#define MNG_FN_GET_FRAMECOUNT 407 +#define MNG_FN_GET_LAYERCOUNT 408 +#define MNG_FN_GET_PLAYTIME 409 +#define MNG_FN_GET_SIMPLICITY 410 +#define MNG_FN_GET_CANVASSTYLE 411 +#define MNG_FN_GET_BKGDSTYLE 412 +#define MNG_FN_GET_BGCOLOR 413 +#define MNG_FN_GET_STORECHUNKS 414 +#define MNG_FN_GET_VIEWGAMMA 415 +#define MNG_FN_GET_DISPLAYGAMMA 416 +#define MNG_FN_GET_DFLTIMGGAMMA 417 +#define MNG_FN_GET_SRGB 418 +#define MNG_FN_GET_MAXCANVASWIDTH 419 +#define MNG_FN_GET_MAXCANVASHEIGHT 420 +#define MNG_FN_GET_ZLIB_LEVEL 421 +#define MNG_FN_GET_ZLIB_METHOD 422 +#define MNG_FN_GET_ZLIB_WINDOWBITS 423 +#define MNG_FN_GET_ZLIB_MEMLEVEL 424 +#define MNG_FN_GET_ZLIB_STRATEGY 425 +#define MNG_FN_GET_ZLIB_MAXIDAT 426 +#define MNG_FN_GET_JPEG_DCTMETHOD 427 +#define MNG_FN_GET_JPEG_QUALITY 428 +#define MNG_FN_GET_JPEG_SMOOTHING 429 +#define MNG_FN_GET_JPEG_PROGRESSIVE 430 +#define MNG_FN_GET_JPEG_OPTIMIZED 431 +#define MNG_FN_GET_JPEG_MAXJDAT 432 +#define MNG_FN_GET_SPEED 433 +#define MNG_FN_GET_IMAGELEVEL 434 +#define MNG_FN_GET_SUSPENSIONMODE 435 +#define MNG_FN_GET_STARTTIME 436 +#define MNG_FN_GET_RUNTIME 437 +#define MNG_FN_GET_CURRENTFRAME 438 +#define MNG_FN_GET_CURRENTLAYER 439 +#define MNG_FN_GET_CURRENTPLAYTIME 440 +#define MNG_FN_GET_SECTIONBREAKS 441 +#define MNG_FN_GET_ALPHADEPTH 442 +#define MNG_FN_GET_BITDEPTH 443 +#define MNG_FN_GET_COLORTYPE 444 +#define MNG_FN_GET_COMPRESSION 445 +#define MNG_FN_GET_FILTER 446 +#define MNG_FN_GET_INTERLACE 447 +#define MNG_FN_GET_ALPHABITDEPTH 448 +#define MNG_FN_GET_ALPHACOMPRESSION 449 +#define MNG_FN_GET_ALPHAFILTER 450 +#define MNG_FN_GET_ALPHAINTERLACE 451 +#define MNG_FN_GET_USEBKGD 452 +#define MNG_FN_GET_REFRESHPASS 453 +#define MNG_FN_GET_CACHEPLAYBACK 454 +#define MNG_FN_GET_DOPROGRESSIVE 455 + +#define MNG_FN_STATUS_ERROR 481 +#define MNG_FN_STATUS_READING 482 +#define MNG_FN_STATUS_SUSPENDBREAK 483 +#define MNG_FN_STATUS_CREATING 484 +#define MNG_FN_STATUS_WRITING 485 +#define MNG_FN_STATUS_DISPLAYING 486 +#define MNG_FN_STATUS_RUNNING 487 +#define MNG_FN_STATUS_TIMERBREAK 488 + +/* ************************************************************************** */ + +#define MNG_FN_ITERATE_CHUNKS 601 + +#define MNG_FN_GETCHUNK_IHDR 701 +#define MNG_FN_GETCHUNK_PLTE 702 +#define MNG_FN_GETCHUNK_IDAT 703 +#define MNG_FN_GETCHUNK_IEND 704 +#define MNG_FN_GETCHUNK_TRNS 705 +#define MNG_FN_GETCHUNK_GAMA 706 +#define MNG_FN_GETCHUNK_CHRM 707 +#define MNG_FN_GETCHUNK_SRGB 708 +#define MNG_FN_GETCHUNK_ICCP 709 +#define MNG_FN_GETCHUNK_TEXT 710 +#define MNG_FN_GETCHUNK_ZTXT 711 +#define MNG_FN_GETCHUNK_ITXT 712 +#define MNG_FN_GETCHUNK_BKGD 713 +#define MNG_FN_GETCHUNK_PHYS 714 +#define MNG_FN_GETCHUNK_SBIT 715 +#define MNG_FN_GETCHUNK_SPLT 716 +#define MNG_FN_GETCHUNK_HIST 717 +#define MNG_FN_GETCHUNK_TIME 718 +#define MNG_FN_GETCHUNK_MHDR 719 +#define MNG_FN_GETCHUNK_MEND 720 +#define MNG_FN_GETCHUNK_LOOP 721 +#define MNG_FN_GETCHUNK_ENDL 722 +#define MNG_FN_GETCHUNK_DEFI 723 +#define MNG_FN_GETCHUNK_BASI 724 +#define MNG_FN_GETCHUNK_CLON 725 +#define MNG_FN_GETCHUNK_PAST 726 +#define MNG_FN_GETCHUNK_DISC 727 +#define MNG_FN_GETCHUNK_BACK 728 +#define MNG_FN_GETCHUNK_FRAM 729 +#define MNG_FN_GETCHUNK_MOVE 730 +#define MNG_FN_GETCHUNK_CLIP 731 +#define MNG_FN_GETCHUNK_SHOW 732 +#define MNG_FN_GETCHUNK_TERM 733 +#define MNG_FN_GETCHUNK_SAVE 734 +#define MNG_FN_GETCHUNK_SEEK 735 +#define MNG_FN_GETCHUNK_EXPI 736 +#define MNG_FN_GETCHUNK_FPRI 737 +#define MNG_FN_GETCHUNK_NEED 738 +#define MNG_FN_GETCHUNK_PHYG 739 +#define MNG_FN_GETCHUNK_JHDR 740 +#define MNG_FN_GETCHUNK_JDAT 741 +#define MNG_FN_GETCHUNK_JSEP 742 +#define MNG_FN_GETCHUNK_DHDR 743 +#define MNG_FN_GETCHUNK_PROM 744 +#define MNG_FN_GETCHUNK_IPNG 745 +#define MNG_FN_GETCHUNK_PPLT 746 +#define MNG_FN_GETCHUNK_IJNG 747 +#define MNG_FN_GETCHUNK_DROP 748 +#define MNG_FN_GETCHUNK_DBYK 749 +#define MNG_FN_GETCHUNK_ORDR 750 +#define MNG_FN_GETCHUNK_UNKNOWN 751 +#define MNG_FN_GETCHUNK_MAGN 752 +#define MNG_FN_GETCHUNK_JDAA 753 + +#define MNG_FN_GETCHUNK_PAST_SRC 781 +#define MNG_FN_GETCHUNK_SAVE_ENTRY 782 +#define MNG_FN_GETCHUNK_PPLT_ENTRY 783 +#define MNG_FN_GETCHUNK_ORDR_ENTRY 784 + +#define MNG_FN_PUTCHUNK_IHDR 801 +#define MNG_FN_PUTCHUNK_PLTE 802 +#define MNG_FN_PUTCHUNK_IDAT 803 +#define MNG_FN_PUTCHUNK_IEND 804 +#define MNG_FN_PUTCHUNK_TRNS 805 +#define MNG_FN_PUTCHUNK_GAMA 806 +#define MNG_FN_PUTCHUNK_CHRM 807 +#define MNG_FN_PUTCHUNK_SRGB 808 +#define MNG_FN_PUTCHUNK_ICCP 809 +#define MNG_FN_PUTCHUNK_TEXT 810 +#define MNG_FN_PUTCHUNK_ZTXT 811 +#define MNG_FN_PUTCHUNK_ITXT 812 +#define MNG_FN_PUTCHUNK_BKGD 813 +#define MNG_FN_PUTCHUNK_PHYS 814 +#define MNG_FN_PUTCHUNK_SBIT 815 +#define MNG_FN_PUTCHUNK_SPLT 816 +#define MNG_FN_PUTCHUNK_HIST 817 +#define MNG_FN_PUTCHUNK_TIME 818 +#define MNG_FN_PUTCHUNK_MHDR 819 +#define MNG_FN_PUTCHUNK_MEND 820 +#define MNG_FN_PUTCHUNK_LOOP 821 +#define MNG_FN_PUTCHUNK_ENDL 822 +#define MNG_FN_PUTCHUNK_DEFI 823 +#define MNG_FN_PUTCHUNK_BASI 824 +#define MNG_FN_PUTCHUNK_CLON 825 +#define MNG_FN_PUTCHUNK_PAST 826 +#define MNG_FN_PUTCHUNK_DISC 827 +#define MNG_FN_PUTCHUNK_BACK 828 +#define MNG_FN_PUTCHUNK_FRAM 829 +#define MNG_FN_PUTCHUNK_MOVE 830 +#define MNG_FN_PUTCHUNK_CLIP 831 +#define MNG_FN_PUTCHUNK_SHOW 832 +#define MNG_FN_PUTCHUNK_TERM 833 +#define MNG_FN_PUTCHUNK_SAVE 834 +#define MNG_FN_PUTCHUNK_SEEK 835 +#define MNG_FN_PUTCHUNK_EXPI 836 +#define MNG_FN_PUTCHUNK_FPRI 837 +#define MNG_FN_PUTCHUNK_NEED 838 +#define MNG_FN_PUTCHUNK_PHYG 839 +#define MNG_FN_PUTCHUNK_JHDR 840 +#define MNG_FN_PUTCHUNK_JDAT 841 +#define MNG_FN_PUTCHUNK_JSEP 842 +#define MNG_FN_PUTCHUNK_DHDR 843 +#define MNG_FN_PUTCHUNK_PROM 844 +#define MNG_FN_PUTCHUNK_IPNG 845 +#define MNG_FN_PUTCHUNK_PPLT 846 +#define MNG_FN_PUTCHUNK_IJNG 847 +#define MNG_FN_PUTCHUNK_DROP 848 +#define MNG_FN_PUTCHUNK_DBYK 849 +#define MNG_FN_PUTCHUNK_ORDR 850 +#define MNG_FN_PUTCHUNK_UNKNOWN 851 +#define MNG_FN_PUTCHUNK_MAGN 852 +#define MNG_FN_PUTCHUNK_JDAA 853 + +#define MNG_FN_PUTCHUNK_PAST_SRC 881 +#define MNG_FN_PUTCHUNK_SAVE_ENTRY 882 +#define MNG_FN_PUTCHUNK_PPLT_ENTRY 883 +#define MNG_FN_PUTCHUNK_ORDR_ENTRY 884 + +/* ************************************************************************** */ + +#define MNG_FN_GETIMGDATA_SEQ 901 +#define MNG_FN_GETIMGDATA_CHUNKSEQ 902 +#define MNG_FN_GETIMGDATA_CHUNK 903 + +#define MNG_FN_PUTIMGDATA_IHDR 951 +#define MNG_FN_PUTIMGDATA_JHDR 952 +#define MNG_FN_PUTIMGDATA_BASI 953 +#define MNG_FN_PUTIMGDATA_DHDR 954 + +#define MNG_FN_UPDATEMNGHEADER 981 +#define MNG_FN_UPDATEMNGSIMPLICITY 982 + +/* ************************************************************************** */ + +#define MNG_FN_PROCESS_RAW_CHUNK 1001 +#define MNG_FN_READ_GRAPHIC 1002 +#define MNG_FN_DROP_CHUNKS 1003 +#define MNG_FN_PROCESS_ERROR 1004 +#define MNG_FN_CLEAR_CMS 1005 +#define MNG_FN_DROP_OBJECTS 1006 +#define MNG_FN_READ_CHUNK 1007 +#define MNG_FN_LOAD_BKGDLAYER 1008 +#define MNG_FN_NEXT_FRAME 1009 +#define MNG_FN_NEXT_LAYER 1010 +#define MNG_FN_INTERFRAME_DELAY 1011 +#define MNG_FN_DISPLAY_IMAGE 1012 +#define MNG_FN_DROP_IMGOBJECTS 1013 +#define MNG_FN_DROP_ANIOBJECTS 1014 +#define MNG_FN_INFLATE_BUFFER 1015 +#define MNG_FN_DEFLATE_BUFFER 1016 +#define MNG_FN_WRITE_RAW_CHUNK 1017 +#define MNG_FN_WRITE_GRAPHIC 1018 +#define MNG_FN_SAVE_STATE 1019 +#define MNG_FN_RESTORE_STATE 1020 +#define MNG_FN_DROP_SAVEDATA 1021 +#define MNG_FN_EXECUTE_DELTA_IMAGE 1022 +#define MNG_FN_PROCESS_DISPLAY 1023 +#define MNG_FN_CLEAR_CANVAS 1024 +#define MNG_FN_READ_DATABUFFER 1025 +#define MNG_FN_STORE_ERROR 1026 +#define MNG_FN_DROP_INVALID_OBJECTS 1027 + +/* ************************************************************************** */ + +#define MNG_FN_DISPLAY_RGB8 1101 +#define MNG_FN_DISPLAY_RGBA8 1102 +#define MNG_FN_DISPLAY_ARGB8 1103 +#define MNG_FN_DISPLAY_BGR8 1104 +#define MNG_FN_DISPLAY_BGRA8 1105 +#define MNG_FN_DISPLAY_ABGR8 1106 +#define MNG_FN_DISPLAY_RGB16 1107 +#define MNG_FN_DISPLAY_RGBA16 1108 +#define MNG_FN_DISPLAY_ARGB16 1109 +#define MNG_FN_DISPLAY_BGR16 1110 +#define MNG_FN_DISPLAY_BGRA16 1111 +#define MNG_FN_DISPLAY_ABGR16 1112 +#define MNG_FN_DISPLAY_INDEX8 1113 +#define MNG_FN_DISPLAY_INDEXA8 1114 +#define MNG_FN_DISPLAY_AINDEX8 1115 +#define MNG_FN_DISPLAY_GRAY8 1116 +#define MNG_FN_DISPLAY_GRAY16 1117 +#define MNG_FN_DISPLAY_GRAYA8 1118 +#define MNG_FN_DISPLAY_GRAYA16 1119 +#define MNG_FN_DISPLAY_AGRAY8 1120 +#define MNG_FN_DISPLAY_AGRAY16 1121 +#define MNG_FN_DISPLAY_DX15 1122 +#define MNG_FN_DISPLAY_DX16 1123 +#define MNG_FN_DISPLAY_RGB8_A8 1124 +#define MNG_FN_DISPLAY_BGRA8PM 1125 + +/* ************************************************************************** */ + +#define MNG_FN_INIT_FULL_CMS 1201 +#define MNG_FN_CORRECT_FULL_CMS 1202 +#define MNG_FN_INIT_GAMMA_ONLY 1204 +#define MNG_FN_CORRECT_GAMMA_ONLY 1205 +#define MNG_FN_CORRECT_APP_CMS 1206 +#define MNG_FN_INIT_FULL_CMS_OBJ 1207 +#define MNG_FN_INIT_GAMMA_ONLY_OBJ 1208 +#define MNG_FN_INIT_APP_CMS 1209 +#define MNG_FN_INIT_APP_CMS_OBJ 1210 + +/* ************************************************************************** */ + +#define MNG_FN_PROCESS_G1 1301 +#define MNG_FN_PROCESS_G2 1302 +#define MNG_FN_PROCESS_G4 1303 +#define MNG_FN_PROCESS_G8 1304 +#define MNG_FN_PROCESS_G16 1305 +#define MNG_FN_PROCESS_RGB8 1306 +#define MNG_FN_PROCESS_RGB16 1307 +#define MNG_FN_PROCESS_IDX1 1308 +#define MNG_FN_PROCESS_IDX2 1309 +#define MNG_FN_PROCESS_IDX4 1310 +#define MNG_FN_PROCESS_IDX8 1311 +#define MNG_FN_PROCESS_GA8 1312 +#define MNG_FN_PROCESS_GA16 1313 +#define MNG_FN_PROCESS_RGBA8 1314 +#define MNG_FN_PROCESS_RGBA16 1315 + +/* ************************************************************************** */ + +#define MNG_FN_INIT_G1_NI 1401 +#define MNG_FN_INIT_G1_I 1402 +#define MNG_FN_INIT_G2_NI 1403 +#define MNG_FN_INIT_G2_I 1404 +#define MNG_FN_INIT_G4_NI 1405 +#define MNG_FN_INIT_G4_I 1406 +#define MNG_FN_INIT_G8_NI 1407 +#define MNG_FN_INIT_G8_I 1408 +#define MNG_FN_INIT_G16_NI 1409 +#define MNG_FN_INIT_G16_I 1410 +#define MNG_FN_INIT_RGB8_NI 1411 +#define MNG_FN_INIT_RGB8_I 1412 +#define MNG_FN_INIT_RGB16_NI 1413 +#define MNG_FN_INIT_RGB16_I 1414 +#define MNG_FN_INIT_IDX1_NI 1415 +#define MNG_FN_INIT_IDX1_I 1416 +#define MNG_FN_INIT_IDX2_NI 1417 +#define MNG_FN_INIT_IDX2_I 1418 +#define MNG_FN_INIT_IDX4_NI 1419 +#define MNG_FN_INIT_IDX4_I 1420 +#define MNG_FN_INIT_IDX8_NI 1421 +#define MNG_FN_INIT_IDX8_I 1422 +#define MNG_FN_INIT_GA8_NI 1423 +#define MNG_FN_INIT_GA8_I 1424 +#define MNG_FN_INIT_GA16_NI 1425 +#define MNG_FN_INIT_GA16_I 1426 +#define MNG_FN_INIT_RGBA8_NI 1427 +#define MNG_FN_INIT_RGBA8_I 1428 +#define MNG_FN_INIT_RGBA16_NI 1429 +#define MNG_FN_INIT_RGBA16_I 1430 + +#define MNG_FN_INIT_ROWPROC 1497 +#define MNG_FN_NEXT_ROW 1498 +#define MNG_FN_CLEANUP_ROWPROC 1499 + +/* ************************************************************************** */ + +#define MNG_FN_FILTER_A_ROW 1501 +#define MNG_FN_FILTER_SUB 1502 +#define MNG_FN_FILTER_UP 1503 +#define MNG_FN_FILTER_AVERAGE 1504 +#define MNG_FN_FILTER_PAETH 1505 + +#define MNG_FN_INIT_ROWDIFFERING 1551 +#define MNG_FN_DIFFER_G1 1552 +#define MNG_FN_DIFFER_G2 1553 +#define MNG_FN_DIFFER_G4 1554 +#define MNG_FN_DIFFER_G8 1555 +#define MNG_FN_DIFFER_G16 1556 +#define MNG_FN_DIFFER_RGB8 1557 +#define MNG_FN_DIFFER_RGB16 1558 +#define MNG_FN_DIFFER_IDX1 1559 +#define MNG_FN_DIFFER_IDX2 1560 +#define MNG_FN_DIFFER_IDX4 1561 +#define MNG_FN_DIFFER_IDX8 1562 +#define MNG_FN_DIFFER_GA8 1563 +#define MNG_FN_DIFFER_GA16 1564 +#define MNG_FN_DIFFER_RGBA8 1565 +#define MNG_FN_DIFFER_RGBA16 1566 + +/* ************************************************************************** */ + +#define MNG_FN_CREATE_IMGDATAOBJECT 1601 +#define MNG_FN_FREE_IMGDATAOBJECT 1602 +#define MNG_FN_CLONE_IMGDATAOBJECT 1603 +#define MNG_FN_CREATE_IMGOBJECT 1604 +#define MNG_FN_FREE_IMGOBJECT 1605 +#define MNG_FN_FIND_IMGOBJECT 1606 +#define MNG_FN_CLONE_IMGOBJECT 1607 +#define MNG_FN_RESET_OBJECTDETAILS 1608 +#define MNG_FN_RENUM_IMGOBJECT 1609 +#define MNG_FN_PROMOTE_IMGOBJECT 1610 +#define MNG_FN_MAGNIFY_IMGOBJECT 1611 + +/* ************************************************************************** */ + +#define MNG_FN_STORE_G1 1701 +#define MNG_FN_STORE_G2 1702 +#define MNG_FN_STORE_G4 1703 +#define MNG_FN_STORE_G8 1704 +#define MNG_FN_STORE_G16 1705 +#define MNG_FN_STORE_RGB8 1706 +#define MNG_FN_STORE_RGB16 1707 +#define MNG_FN_STORE_IDX1 1708 +#define MNG_FN_STORE_IDX2 1709 +#define MNG_FN_STORE_IDX4 1710 +#define MNG_FN_STORE_IDX8 1711 +#define MNG_FN_STORE_GA8 1712 +#define MNG_FN_STORE_GA16 1713 +#define MNG_FN_STORE_RGBA8 1714 +#define MNG_FN_STORE_RGBA16 1715 + +#define MNG_FN_RETRIEVE_G8 1751 +#define MNG_FN_RETRIEVE_G16 1752 +#define MNG_FN_RETRIEVE_RGB8 1753 +#define MNG_FN_RETRIEVE_RGB16 1754 +#define MNG_FN_RETRIEVE_IDX8 1755 +#define MNG_FN_RETRIEVE_GA8 1756 +#define MNG_FN_RETRIEVE_GA16 1757 +#define MNG_FN_RETRIEVE_RGBA8 1758 +#define MNG_FN_RETRIEVE_RGBA16 1759 + +#define MNG_FN_DELTA_G1 1771 +#define MNG_FN_DELTA_G2 1772 +#define MNG_FN_DELTA_G4 1773 +#define MNG_FN_DELTA_G8 1774 +#define MNG_FN_DELTA_G16 1775 +#define MNG_FN_DELTA_RGB8 1776 +#define MNG_FN_DELTA_RGB16 1777 +#define MNG_FN_DELTA_IDX1 1778 +#define MNG_FN_DELTA_IDX2 1779 +#define MNG_FN_DELTA_IDX4 1780 +#define MNG_FN_DELTA_IDX8 1781 +#define MNG_FN_DELTA_GA8 1782 +#define MNG_FN_DELTA_GA16 1783 +#define MNG_FN_DELTA_RGBA8 1784 +#define MNG_FN_DELTA_RGBA16 1785 + +/* ************************************************************************** */ + +#define MNG_FN_CREATE_ANI_LOOP 1801 +#define MNG_FN_CREATE_ANI_ENDL 1802 +#define MNG_FN_CREATE_ANI_DEFI 1803 +#define MNG_FN_CREATE_ANI_BASI 1804 +#define MNG_FN_CREATE_ANI_CLON 1805 +#define MNG_FN_CREATE_ANI_PAST 1806 +#define MNG_FN_CREATE_ANI_DISC 1807 +#define MNG_FN_CREATE_ANI_BACK 1808 +#define MNG_FN_CREATE_ANI_FRAM 1809 +#define MNG_FN_CREATE_ANI_MOVE 1810 +#define MNG_FN_CREATE_ANI_CLIP 1811 +#define MNG_FN_CREATE_ANI_SHOW 1812 +#define MNG_FN_CREATE_ANI_TERM 1813 +#define MNG_FN_CREATE_ANI_SAVE 1814 +#define MNG_FN_CREATE_ANI_SEEK 1815 +#define MNG_FN_CREATE_ANI_GAMA 1816 +#define MNG_FN_CREATE_ANI_CHRM 1817 +#define MNG_FN_CREATE_ANI_SRGB 1818 +#define MNG_FN_CREATE_ANI_ICCP 1819 +#define MNG_FN_CREATE_ANI_PLTE 1820 +#define MNG_FN_CREATE_ANI_TRNS 1821 +#define MNG_FN_CREATE_ANI_BKGD 1822 +#define MNG_FN_CREATE_ANI_DHDR 1823 +#define MNG_FN_CREATE_ANI_PROM 1824 +#define MNG_FN_CREATE_ANI_IPNG 1825 +#define MNG_FN_CREATE_ANI_IJNG 1826 +#define MNG_FN_CREATE_ANI_PPLT 1827 +#define MNG_FN_CREATE_ANI_MAGN 1828 + +#define MNG_FN_CREATE_ANI_IMAGE 1891 + +/* ************************************************************************** */ + +#define MNG_FN_FREE_ANI_LOOP 1901 +#define MNG_FN_FREE_ANI_ENDL 1902 +#define MNG_FN_FREE_ANI_DEFI 1903 +#define MNG_FN_FREE_ANI_BASI 1904 +#define MNG_FN_FREE_ANI_CLON 1905 +#define MNG_FN_FREE_ANI_PAST 1906 +#define MNG_FN_FREE_ANI_DISC 1907 +#define MNG_FN_FREE_ANI_BACK 1908 +#define MNG_FN_FREE_ANI_FRAM 1909 +#define MNG_FN_FREE_ANI_MOVE 1910 +#define MNG_FN_FREE_ANI_CLIP 1911 +#define MNG_FN_FREE_ANI_SHOW 1912 +#define MNG_FN_FREE_ANI_TERM 1913 +#define MNG_FN_FREE_ANI_SAVE 1914 +#define MNG_FN_FREE_ANI_SEEK 1915 +#define MNG_FN_FREE_ANI_GAMA 1916 +#define MNG_FN_FREE_ANI_CHRM 1917 +#define MNG_FN_FREE_ANI_SRGB 1918 +#define MNG_FN_FREE_ANI_ICCP 1919 +#define MNG_FN_FREE_ANI_PLTE 1920 +#define MNG_FN_FREE_ANI_TRNS 1921 +#define MNG_FN_FREE_ANI_BKGD 1922 +#define MNG_FN_FREE_ANI_DHDR 1923 +#define MNG_FN_FREE_ANI_PROM 1924 +#define MNG_FN_FREE_ANI_IPNG 1925 +#define MNG_FN_FREE_ANI_IJNG 1926 +#define MNG_FN_FREE_ANI_PPLT 1927 +#define MNG_FN_FREE_ANI_MAGN 1928 + +#define MNG_FN_FREE_ANI_IMAGE 1991 + +/* ************************************************************************** */ + +#define MNG_FN_PROCESS_ANI_LOOP 2001 +#define MNG_FN_PROCESS_ANI_ENDL 2002 +#define MNG_FN_PROCESS_ANI_DEFI 2003 +#define MNG_FN_PROCESS_ANI_BASI 2004 +#define MNG_FN_PROCESS_ANI_CLON 2005 +#define MNG_FN_PROCESS_ANI_PAST 2006 +#define MNG_FN_PROCESS_ANI_DISC 2007 +#define MNG_FN_PROCESS_ANI_BACK 2008 +#define MNG_FN_PROCESS_ANI_FRAM 2009 +#define MNG_FN_PROCESS_ANI_MOVE 2010 +#define MNG_FN_PROCESS_ANI_CLIP 2011 +#define MNG_FN_PROCESS_ANI_SHOW 2012 +#define MNG_FN_PROCESS_ANI_TERM 2013 +#define MNG_FN_PROCESS_ANI_SAVE 2014 +#define MNG_FN_PROCESS_ANI_SEEK 2015 +#define MNG_FN_PROCESS_ANI_GAMA 2016 +#define MNG_FN_PROCESS_ANI_CHRM 2017 +#define MNG_FN_PROCESS_ANI_SRGB 2018 +#define MNG_FN_PROCESS_ANI_ICCP 2019 +#define MNG_FN_PROCESS_ANI_PLTE 2020 +#define MNG_FN_PROCESS_ANI_TRNS 2021 +#define MNG_FN_PROCESS_ANI_BKGD 2022 +#define MNG_FN_PROCESS_ANI_DHDR 2023 +#define MNG_FN_PROCESS_ANI_PROM 2024 +#define MNG_FN_PROCESS_ANI_IPNG 2025 +#define MNG_FN_PROCESS_ANI_IJNG 2026 +#define MNG_FN_PROCESS_ANI_PPLT 2027 +#define MNG_FN_PROCESS_ANI_MAGN 2028 + +#define MNG_FN_PROCESS_ANI_IMAGE 2091 + +/* ************************************************************************** */ + +#define MNG_FN_RESTORE_BACKIMAGE 2101 +#define MNG_FN_RESTORE_BACKCOLOR 2102 +#define MNG_FN_RESTORE_BGCOLOR 2103 +#define MNG_FN_RESTORE_RGB8 2104 +#define MNG_FN_RESTORE_BGR8 2105 +#define MNG_FN_RESTORE_BKGD 2106 + +/* ************************************************************************** */ + +#define MNG_FN_INIT_IHDR 2201 +#define MNG_FN_INIT_PLTE 2202 +#define MNG_FN_INIT_IDAT 2203 +#define MNG_FN_INIT_IEND 2204 +#define MNG_FN_INIT_TRNS 2205 +#define MNG_FN_INIT_GAMA 2206 +#define MNG_FN_INIT_CHRM 2207 +#define MNG_FN_INIT_SRGB 2208 +#define MNG_FN_INIT_ICCP 2209 +#define MNG_FN_INIT_TEXT 2210 +#define MNG_FN_INIT_ZTXT 2211 +#define MNG_FN_INIT_ITXT 2212 +#define MNG_FN_INIT_BKGD 2213 +#define MNG_FN_INIT_PHYS 2214 +#define MNG_FN_INIT_SBIT 2215 +#define MNG_FN_INIT_SPLT 2216 +#define MNG_FN_INIT_HIST 2217 +#define MNG_FN_INIT_TIME 2218 +#define MNG_FN_INIT_MHDR 2219 +#define MNG_FN_INIT_MEND 2220 +#define MNG_FN_INIT_LOOP 2221 +#define MNG_FN_INIT_ENDL 2222 +#define MNG_FN_INIT_DEFI 2223 +#define MNG_FN_INIT_BASI 2224 +#define MNG_FN_INIT_CLON 2225 +#define MNG_FN_INIT_PAST 2226 +#define MNG_FN_INIT_DISC 2227 +#define MNG_FN_INIT_BACK 2228 +#define MNG_FN_INIT_FRAM 2229 +#define MNG_FN_INIT_MOVE 2230 +#define MNG_FN_INIT_CLIP 2231 +#define MNG_FN_INIT_SHOW 2232 +#define MNG_FN_INIT_TERM 2233 +#define MNG_FN_INIT_SAVE 2234 +#define MNG_FN_INIT_SEEK 2235 +#define MNG_FN_INIT_EXPI 2236 +#define MNG_FN_INIT_FPRI 2237 +#define MNG_FN_INIT_NEED 2238 +#define MNG_FN_INIT_PHYG 2239 +#define MNG_FN_INIT_JHDR 2240 +#define MNG_FN_INIT_JDAT 2241 +#define MNG_FN_INIT_JSEP 2242 +#define MNG_FN_INIT_DHDR 2243 +#define MNG_FN_INIT_PROM 2244 +#define MNG_FN_INIT_IPNG 2245 +#define MNG_FN_INIT_PPLT 2246 +#define MNG_FN_INIT_IJNG 2247 +#define MNG_FN_INIT_DROP 2248 +#define MNG_FN_INIT_DBYK 2249 +#define MNG_FN_INIT_ORDR 2250 +#define MNG_FN_INIT_UNKNOWN 2251 +#define MNG_FN_INIT_MAGN 2252 +#define MNG_FN_INIT_JDAA 2253 + +/* ************************************************************************** */ + +#define MNG_FN_FREE_IHDR 2401 +#define MNG_FN_FREE_PLTE 2402 +#define MNG_FN_FREE_IDAT 2403 +#define MNG_FN_FREE_IEND 2404 +#define MNG_FN_FREE_TRNS 2405 +#define MNG_FN_FREE_GAMA 2406 +#define MNG_FN_FREE_CHRM 2407 +#define MNG_FN_FREE_SRGB 2408 +#define MNG_FN_FREE_ICCP 2409 +#define MNG_FN_FREE_TEXT 2410 +#define MNG_FN_FREE_ZTXT 2411 +#define MNG_FN_FREE_ITXT 2412 +#define MNG_FN_FREE_BKGD 2413 +#define MNG_FN_FREE_PHYS 2414 +#define MNG_FN_FREE_SBIT 2415 +#define MNG_FN_FREE_SPLT 2416 +#define MNG_FN_FREE_HIST 2417 +#define MNG_FN_FREE_TIME 2418 +#define MNG_FN_FREE_MHDR 2419 +#define MNG_FN_FREE_MEND 2420 +#define MNG_FN_FREE_LOOP 2421 +#define MNG_FN_FREE_ENDL 2422 +#define MNG_FN_FREE_DEFI 2423 +#define MNG_FN_FREE_BASI 2424 +#define MNG_FN_FREE_CLON 2425 +#define MNG_FN_FREE_PAST 2426 +#define MNG_FN_FREE_DISC 2427 +#define MNG_FN_FREE_BACK 2428 +#define MNG_FN_FREE_FRAM 2429 +#define MNG_FN_FREE_MOVE 2430 +#define MNG_FN_FREE_CLIP 2431 +#define MNG_FN_FREE_SHOW 2432 +#define MNG_FN_FREE_TERM 2433 +#define MNG_FN_FREE_SAVE 2434 +#define MNG_FN_FREE_SEEK 2435 +#define MNG_FN_FREE_EXPI 2436 +#define MNG_FN_FREE_FPRI 2437 +#define MNG_FN_FREE_NEED 2438 +#define MNG_FN_FREE_PHYG 2439 +#define MNG_FN_FREE_JHDR 2440 +#define MNG_FN_FREE_JDAT 2441 +#define MNG_FN_FREE_JSEP 2442 +#define MNG_FN_FREE_DHDR 2443 +#define MNG_FN_FREE_PROM 2444 +#define MNG_FN_FREE_IPNG 2445 +#define MNG_FN_FREE_PPLT 2446 +#define MNG_FN_FREE_IJNG 2447 +#define MNG_FN_FREE_DROP 2448 +#define MNG_FN_FREE_DBYK 2449 +#define MNG_FN_FREE_ORDR 2450 +#define MNG_FN_FREE_UNKNOWN 2451 +#define MNG_FN_FREE_MAGN 2452 +#define MNG_FN_FREE_JDAA 2453 + +/* ************************************************************************** */ + +#define MNG_FN_READ_IHDR 2601 +#define MNG_FN_READ_PLTE 2602 +#define MNG_FN_READ_IDAT 2603 +#define MNG_FN_READ_IEND 2604 +#define MNG_FN_READ_TRNS 2605 +#define MNG_FN_READ_GAMA 2606 +#define MNG_FN_READ_CHRM 2607 +#define MNG_FN_READ_SRGB 2608 +#define MNG_FN_READ_ICCP 2609 +#define MNG_FN_READ_TEXT 2610 +#define MNG_FN_READ_ZTXT 2611 +#define MNG_FN_READ_ITXT 2612 +#define MNG_FN_READ_BKGD 2613 +#define MNG_FN_READ_PHYS 2614 +#define MNG_FN_READ_SBIT 2615 +#define MNG_FN_READ_SPLT 2616 +#define MNG_FN_READ_HIST 2617 +#define MNG_FN_READ_TIME 2618 +#define MNG_FN_READ_MHDR 2619 +#define MNG_FN_READ_MEND 2620 +#define MNG_FN_READ_LOOP 2621 +#define MNG_FN_READ_ENDL 2622 +#define MNG_FN_READ_DEFI 2623 +#define MNG_FN_READ_BASI 2624 +#define MNG_FN_READ_CLON 2625 +#define MNG_FN_READ_PAST 2626 +#define MNG_FN_READ_DISC 2627 +#define MNG_FN_READ_BACK 2628 +#define MNG_FN_READ_FRAM 2629 +#define MNG_FN_READ_MOVE 2630 +#define MNG_FN_READ_CLIP 2631 +#define MNG_FN_READ_SHOW 2632 +#define MNG_FN_READ_TERM 2633 +#define MNG_FN_READ_SAVE 2634 +#define MNG_FN_READ_SEEK 2635 +#define MNG_FN_READ_EXPI 2636 +#define MNG_FN_READ_FPRI 2637 +#define MNG_FN_READ_NEED 2638 +#define MNG_FN_READ_PHYG 2639 +#define MNG_FN_READ_JHDR 2640 +#define MNG_FN_READ_JDAT 2641 +#define MNG_FN_READ_JSEP 2642 +#define MNG_FN_READ_DHDR 2643 +#define MNG_FN_READ_PROM 2644 +#define MNG_FN_READ_IPNG 2645 +#define MNG_FN_READ_PPLT 2646 +#define MNG_FN_READ_IJNG 2647 +#define MNG_FN_READ_DROP 2648 +#define MNG_FN_READ_DBYK 2649 +#define MNG_FN_READ_ORDR 2650 +#define MNG_FN_READ_UNKNOWN 2651 +#define MNG_FN_READ_MAGN 2652 +#define MNG_FN_READ_JDAA 2653 + +/* ************************************************************************** */ + +#define MNG_FN_WRITE_IHDR 2801 +#define MNG_FN_WRITE_PLTE 2802 +#define MNG_FN_WRITE_IDAT 2803 +#define MNG_FN_WRITE_IEND 2804 +#define MNG_FN_WRITE_TRNS 2805 +#define MNG_FN_WRITE_GAMA 2806 +#define MNG_FN_WRITE_CHRM 2807 +#define MNG_FN_WRITE_SRGB 2808 +#define MNG_FN_WRITE_ICCP 2809 +#define MNG_FN_WRITE_TEXT 2810 +#define MNG_FN_WRITE_ZTXT 2811 +#define MNG_FN_WRITE_ITXT 2812 +#define MNG_FN_WRITE_BKGD 2813 +#define MNG_FN_WRITE_PHYS 2814 +#define MNG_FN_WRITE_SBIT 2815 +#define MNG_FN_WRITE_SPLT 2816 +#define MNG_FN_WRITE_HIST 2817 +#define MNG_FN_WRITE_TIME 2818 +#define MNG_FN_WRITE_MHDR 2819 +#define MNG_FN_WRITE_MEND 2820 +#define MNG_FN_WRITE_LOOP 2821 +#define MNG_FN_WRITE_ENDL 2822 +#define MNG_FN_WRITE_DEFI 2823 +#define MNG_FN_WRITE_BASI 2824 +#define MNG_FN_WRITE_CLON 2825 +#define MNG_FN_WRITE_PAST 2826 +#define MNG_FN_WRITE_DISC 2827 +#define MNG_FN_WRITE_BACK 2828 +#define MNG_FN_WRITE_FRAM 2829 +#define MNG_FN_WRITE_MOVE 2830 +#define MNG_FN_WRITE_CLIP 2831 +#define MNG_FN_WRITE_SHOW 2832 +#define MNG_FN_WRITE_TERM 2833 +#define MNG_FN_WRITE_SAVE 2834 +#define MNG_FN_WRITE_SEEK 2835 +#define MNG_FN_WRITE_EXPI 2836 +#define MNG_FN_WRITE_FPRI 2837 +#define MNG_FN_WRITE_NEED 2838 +#define MNG_FN_WRITE_PHYG 2839 +#define MNG_FN_WRITE_JHDR 2840 +#define MNG_FN_WRITE_JDAT 2841 +#define MNG_FN_WRITE_JSEP 2842 +#define MNG_FN_WRITE_DHDR 2843 +#define MNG_FN_WRITE_PROM 2844 +#define MNG_FN_WRITE_IPNG 2845 +#define MNG_FN_WRITE_PPLT 2846 +#define MNG_FN_WRITE_IJNG 2847 +#define MNG_FN_WRITE_DROP 2848 +#define MNG_FN_WRITE_DBYK 2849 +#define MNG_FN_WRITE_ORDR 2850 +#define MNG_FN_WRITE_UNKNOWN 2851 +#define MNG_FN_WRITE_MAGN 2852 +#define MNG_FN_WRITE_JDAA 2853 + +/* ************************************************************************** */ + +#define MNG_FN_ZLIB_INITIALIZE 3001 +#define MNG_FN_ZLIB_CLEANUP 3002 +#define MNG_FN_ZLIB_INFLATEINIT 3003 +#define MNG_FN_ZLIB_INFLATEROWS 3004 +#define MNG_FN_ZLIB_INFLATEDATA 3005 +#define MNG_FN_ZLIB_INFLATEFREE 3006 +#define MNG_FN_ZLIB_DEFLATEINIT 3007 +#define MNG_FN_ZLIB_DEFLATEROWS 3008 +#define MNG_FN_ZLIB_DEFLATEDATA 3009 +#define MNG_FN_ZLIB_DEFLATEFREE 3010 + +/* ************************************************************************** */ + +#define MNG_FN_PROCESS_DISPLAY_IHDR 3201 +#define MNG_FN_PROCESS_DISPLAY_PLTE 3202 +#define MNG_FN_PROCESS_DISPLAY_IDAT 3203 +#define MNG_FN_PROCESS_DISPLAY_IEND 3204 +#define MNG_FN_PROCESS_DISPLAY_TRNS 3205 +#define MNG_FN_PROCESS_DISPLAY_GAMA 3206 +#define MNG_FN_PROCESS_DISPLAY_CHRM 3207 +#define MNG_FN_PROCESS_DISPLAY_SRGB 3208 +#define MNG_FN_PROCESS_DISPLAY_ICCP 3209 +#define MNG_FN_PROCESS_DISPLAY_BKGD 3210 +#define MNG_FN_PROCESS_DISPLAY_PHYS 3211 +#define MNG_FN_PROCESS_DISPLAY_SBIT 3212 +#define MNG_FN_PROCESS_DISPLAY_SPLT 3213 +#define MNG_FN_PROCESS_DISPLAY_HIST 3214 +#define MNG_FN_PROCESS_DISPLAY_MHDR 3215 +#define MNG_FN_PROCESS_DISPLAY_MEND 3216 +#define MNG_FN_PROCESS_DISPLAY_LOOP 3217 +#define MNG_FN_PROCESS_DISPLAY_ENDL 3218 +#define MNG_FN_PROCESS_DISPLAY_DEFI 3219 +#define MNG_FN_PROCESS_DISPLAY_BASI 3220 +#define MNG_FN_PROCESS_DISPLAY_CLON 3221 +#define MNG_FN_PROCESS_DISPLAY_PAST 3222 +#define MNG_FN_PROCESS_DISPLAY_DISC 3223 +#define MNG_FN_PROCESS_DISPLAY_BACK 3224 +#define MNG_FN_PROCESS_DISPLAY_FRAM 3225 +#define MNG_FN_PROCESS_DISPLAY_MOVE 3226 +#define MNG_FN_PROCESS_DISPLAY_CLIP 3227 +#define MNG_FN_PROCESS_DISPLAY_SHOW 3228 +#define MNG_FN_PROCESS_DISPLAY_TERM 3229 +#define MNG_FN_PROCESS_DISPLAY_SAVE 3230 +#define MNG_FN_PROCESS_DISPLAY_SEEK 3231 +#define MNG_FN_PROCESS_DISPLAY_EXPI 3232 +#define MNG_FN_PROCESS_DISPLAY_FPRI 3233 +#define MNG_FN_PROCESS_DISPLAY_NEED 3234 +#define MNG_FN_PROCESS_DISPLAY_PHYG 3235 +#define MNG_FN_PROCESS_DISPLAY_JHDR 3236 +#define MNG_FN_PROCESS_DISPLAY_JDAT 3237 +#define MNG_FN_PROCESS_DISPLAY_JSEP 3238 +#define MNG_FN_PROCESS_DISPLAY_DHDR 3239 +#define MNG_FN_PROCESS_DISPLAY_PROM 3240 +#define MNG_FN_PROCESS_DISPLAY_IPNG 3241 +#define MNG_FN_PROCESS_DISPLAY_PPLT 3242 +#define MNG_FN_PROCESS_DISPLAY_IJNG 3243 +#define MNG_FN_PROCESS_DISPLAY_DROP 3244 +#define MNG_FN_PROCESS_DISPLAY_DBYK 3245 +#define MNG_FN_PROCESS_DISPLAY_ORDR 3246 +#define MNG_FN_PROCESS_DISPLAY_MAGN 3247 +#define MNG_FN_PROCESS_DISPLAY_JDAA 3248 + +/* ************************************************************************** */ + +#define MNG_FN_JPEG_INITIALIZE 3401 +#define MNG_FN_JPEG_CLEANUP 3402 +#define MNG_FN_JPEG_DECOMPRESSINIT 3403 +#define MNG_FN_JPEG_DECOMPRESSDATA 3404 +#define MNG_FN_JPEG_DECOMPRESSFREE 3405 + +#define MNG_FN_STORE_JPEG_G8 3501 +#define MNG_FN_STORE_JPEG_RGB8 3502 +#define MNG_FN_STORE_JPEG_G12 3503 +#define MNG_FN_STORE_JPEG_RGB12 3504 +#define MNG_FN_STORE_JPEG_GA8 3505 +#define MNG_FN_STORE_JPEG_RGBA8 3506 +#define MNG_FN_STORE_JPEG_GA12 3507 +#define MNG_FN_STORE_JPEG_RGBA12 3508 +#define MNG_FN_STORE_JPEG_G8_ALPHA 3509 +#define MNG_FN_STORE_JPEG_RGB8_ALPHA 3510 + +#define MNG_FN_INIT_JPEG_A1_NI 3511 +#define MNG_FN_INIT_JPEG_A2_NI 3512 +#define MNG_FN_INIT_JPEG_A4_NI 3513 +#define MNG_FN_INIT_JPEG_A8_NI 3514 +#define MNG_FN_INIT_JPEG_A16_NI 3515 + +#define MNG_FN_STORE_JPEG_G8_A1 3521 +#define MNG_FN_STORE_JPEG_G8_A2 3522 +#define MNG_FN_STORE_JPEG_G8_A4 3523 +#define MNG_FN_STORE_JPEG_G8_A8 3524 +#define MNG_FN_STORE_JPEG_G8_A16 3525 + +#define MNG_FN_STORE_JPEG_RGB8_A1 3531 +#define MNG_FN_STORE_JPEG_RGB8_A2 3532 +#define MNG_FN_STORE_JPEG_RGB8_A4 3533 +#define MNG_FN_STORE_JPEG_RGB8_A8 3534 +#define MNG_FN_STORE_JPEG_RGB8_A16 3535 + +#define MNG_FN_STORE_JPEG_G12_A1 3541 +#define MNG_FN_STORE_JPEG_G12_A2 3542 +#define MNG_FN_STORE_JPEG_G12_A4 3543 +#define MNG_FN_STORE_JPEG_G12_A8 3544 +#define MNG_FN_STORE_JPEG_G12_A16 3545 + +#define MNG_FN_STORE_JPEG_RGB12_A1 3551 +#define MNG_FN_STORE_JPEG_RGB12_A2 3552 +#define MNG_FN_STORE_JPEG_RGB12_A4 3553 +#define MNG_FN_STORE_JPEG_RGB12_A8 3554 +#define MNG_FN_STORE_JPEG_RGB12_A16 3555 + +#define MNG_FN_NEXT_JPEG_ALPHAROW 3591 +#define MNG_FN_NEXT_JPEG_ROW 3592 +#define MNG_FN_DISPLAY_JPEG_ROWS 3593 + +/* ************************************************************************** */ + +#define MNG_FN_MAGNIFY_G8_X1 3701 +#define MNG_FN_MAGNIFY_G8_X2 3702 +#define MNG_FN_MAGNIFY_RGB8_X1 3703 +#define MNG_FN_MAGNIFY_RGB8_X2 3704 +#define MNG_FN_MAGNIFY_GA8_X1 3705 +#define MNG_FN_MAGNIFY_GA8_X2 3706 +#define MNG_FN_MAGNIFY_GA8_X3 3707 +#define MNG_FN_MAGNIFY_GA8_X4 3708 +#define MNG_FN_MAGNIFY_RGBA8_X1 3709 +#define MNG_FN_MAGNIFY_RGBA8_X2 3710 +#define MNG_FN_MAGNIFY_RGBA8_X3 3711 +#define MNG_FN_MAGNIFY_RGBA8_X4 3712 +#define MNG_FN_MAGNIFY_G8_X3 3713 +#define MNG_FN_MAGNIFY_RGB8_X3 3714 +#define MNG_FN_MAGNIFY_GA8_X5 3715 +#define MNG_FN_MAGNIFY_RGBA8_X5 3716 + +#define MNG_FN_MAGNIFY_G8_Y1 3751 +#define MNG_FN_MAGNIFY_G8_Y2 3752 +#define MNG_FN_MAGNIFY_RGB8_Y1 3753 +#define MNG_FN_MAGNIFY_RGB8_Y2 3754 +#define MNG_FN_MAGNIFY_GA8_Y1 3755 +#define MNG_FN_MAGNIFY_GA8_Y2 3756 +#define MNG_FN_MAGNIFY_GA8_Y3 3757 +#define MNG_FN_MAGNIFY_GA8_Y4 3758 +#define MNG_FN_MAGNIFY_RGBA8_Y1 3759 +#define MNG_FN_MAGNIFY_RGBA8_Y2 3760 +#define MNG_FN_MAGNIFY_RGBA8_Y3 3761 +#define MNG_FN_MAGNIFY_RGBA8_Y4 3762 +#define MNG_FN_MAGNIFY_G8_Y3 3763 +#define MNG_FN_MAGNIFY_RGB8_Y3 3764 +#define MNG_FN_MAGNIFY_GA8_Y5 3765 +#define MNG_FN_MAGNIFY_RGBA8_Y5 3766 + +/* ************************************************************************** */ + +#define MNG_FN_DELTA_G1_G1 3801 +#define MNG_FN_DELTA_G2_G2 3802 +#define MNG_FN_DELTA_G4_G4 3803 +#define MNG_FN_DELTA_G8_G8 3804 +#define MNG_FN_DELTA_G16_G16 3805 +#define MNG_FN_DELTA_RGB8_RGB8 3806 +#define MNG_FN_DELTA_RGB16_RGB16 3807 +#define MNG_FN_DELTA_GA8_GA8 3808 +#define MNG_FN_DELTA_GA8_G8 3809 +#define MNG_FN_DELTA_GA8_A8 3810 +#define MNG_FN_DELTA_GA16_GA16 3811 +#define MNG_FN_DELTA_GA16_G16 3812 +#define MNG_FN_DELTA_GA16_A16 3813 +#define MNG_FN_DELTA_RGBA8_RGBA8 3814 +#define MNG_FN_DELTA_RGBA8_RGB8 3815 +#define MNG_FN_DELTA_RGBA8_A8 3816 +#define MNG_FN_DELTA_RGBA16_RGBA16 3817 +#define MNG_FN_DELTA_RGBA16_RGB16 3818 +#define MNG_FN_DELTA_RGBA16_A16 3819 + +/* ************************************************************************** */ +/* * * */ +/* * Trace string-table entry * */ +/* * * */ +/* ************************************************************************** */ + +typedef struct { + mng_uint32 iFunction; + mng_pchar zTracetext; + } mng_trace_entry; +typedef mng_trace_entry * mng_trace_entryp; + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_TRACE_PROCS */ + +/* ************************************************************************** */ + +#endif /* _libmng_trace_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_types.h b/freeimage241/Source/LibMNG/libmng_types.h new file mode 100644 index 0000000..eeffb0e --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_types.h @@ -0,0 +1,494 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_types.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.2 * */ +/* * * */ +/* * purpose : type specifications * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Specification of the types used by the library * */ +/* * Creates platform-independant structure * */ +/* * * */ +/* * changes : 0.5.1 - 05/06/2000 - G.Juyn * */ +/* * - added iteratechunk callback definition * */ +/* * 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - improved definitions for DLL support * */ +/* * - added 8-bit palette definition * */ +/* * - added general array definitions * */ +/* * - added MNG_NULL definition * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - changed most callback prototypes to allow the app * */ +/* * to report errors during callback processing * */ +/* * 0.5.1 - 05/16/2000 - G.Juyn * */ +/* * - moved standard header includes into this file * */ +/* * (stdlib/mem for mem-mngmt & math for fp gamma-calc) * */ +/* * * */ +/* * 0.5.2 - 05/18/2000 - G.Juyn * */ +/* * - B003 - fixed problem with being proprietary * */ +/* * to Borland platform * */ +/* * - added helper definitions for JNG (IJG-based) * */ +/* * - fixed support for IJGSRC6B * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - added default IJG compression parameters and such * */ +/* * 0.5.2 - 05/31/2000 - G.Juyn * */ +/* * - fixed inclusion for memcpy (contributed by Tim Rowley) * */ +/* * - added mng_int32p (contributed by Tim Rowley) * */ +/* * 0.5.2 - 06/02/2000 - G.Juyn * */ +/* * - removed SWAP_ENDIAN reference (contributed by Tim Rowley)* */ +/* * - added getalphaline callback for RGB8_A8 canvasstyle * */ +/* * * */ +/* * 0.5.3 - 06/21/2000 - G.Juyn * */ +/* * - added speedtype to facilitate testing * */ +/* * 0.5.3 - 06/27/2000 - G.Juyn * */ +/* * - added typedef for mng_size_t * */ +/* * - changed size parameter for memory callbacks to * */ +/* * mng_size_t * */ +/* * 0.5.3 - 06/28/2000 - G.Juyn * */ +/* * - changed definition of 32-bit ints (64-bit platforms) * */ +/* * - changed definition of mng_handle (64-bit platforms) * */ +/* * 0.5.3 - 06/29/2000 - G.Juyn * */ +/* * - changed definition of mng_handle (again) * */ +/* * - swapped refresh parameters * */ +/* * - added inclusion of stdlib.h for abs() * */ +/* * * */ +/* * 0.9.0 - 06/30/2000 - G.Juyn * */ +/* * - changed refresh parameters to 'x,y,width,height' * */ +/* * 0.9.1 - 07/10/2000 - G.Juyn * */ +/* * - added suspendbuffer constants * */ +/* * 0.9.1 - 07/15/2000 - G.Juyn * */ +/* * - added callbacks for SAVE/SEEK processing * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/07/2000 - G.Juyn * */ +/* * - B111300 - fixup for improved portability * */ +/* * 0.9.3 - 08/12/2000 - G.Juyn * */ +/* * - added workaround for faulty PhotoShop iCCP chunk * */ +/* * 0.9.3 - 09/11/2000 - G.Juyn * */ +/* * - added export of zlib functions from windows dll * */ +/* * - fixed inclusion parameters once again to make those * */ +/* * external libs work together * */ +/* * - re-fixed fixed inclusion parameters * */ +/* * (these freeking libraries make me mad) * */ +/* * 0.9.3 - 10/11/2000 - G.Juyn * */ +/* * - added support for nEED * */ +/* * 0.9.3 - 10/17/2000 - G.Juyn * */ +/* * - added callback to process non-critical unknown chunks * */ +/* * * */ +/* * 0.9.4 - 11/20/2000 - R.Giles * */ +/* * - fixed inclusion of lcms header for non-windows platforms * */ +/* * 0.9.4 - 12/12/2000 - G.Juyn * */ +/* * - changed callback convention for MSVC (Thanks Chad) * */ +/* * 0.9.4 - 12/16/2000 - G.Juyn * */ +/* * - fixed mixup of data- & function-pointers (thanks Dimitri)* */ +/* * * */ +/* * 1.0.1 - 02/08/2001 - G.Juyn * */ +/* * - added MEND processing callback * */ +/* * * */ +/* * 1.0.2 - 06/23/2001 - G.Juyn * */ +/* * - added processterm callback * */ +/* * * */ +/* ************************************************************************** */ + +#ifndef _libmng_types_h_ +#define _libmng_types_h_ + +/* ************************************************************************** */ + +#ifdef __BORLANDC__ +#pragma option -AT /* turn off strict ANSI-C for the moment */ +#endif + +#ifndef WIN32 +#if defined(_WIN32) || defined(__WIN32__) || defined(_Windows) || defined(_WINDOWS) +#define WIN32 /* gather them into a single define */ +#endif +#endif + +/* ************************************************************************** */ +/* * * */ +/* * Here's where the external & standard libs are embedded * */ +/* * * */ +/* * (it can be a bit of a pain in the lower-back to get them to work * */ +/* * together) * */ +/* * * */ +/* ************************************************************************** */ + +#ifdef WIN32 /* only include needed stuff */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#endif + +#ifdef MNG_USE_DLL +#ifdef MNG_SKIP_ZLIB +#undef MNG_INCLUDE_ZLIB +#endif +#ifdef MNG_SKIP_LCMS +#undef MNG_INCLUDE_LCMS +#endif +#ifdef MNG_SKIP_IJG6B +#undef MNG_INCLUDE_IJG6B +#endif +#endif + +#ifdef MNG_INCLUDE_ZLIB /* zlib by Mark Adler & Jean-loup Gailly */ +#include "../zlib/zlib.h" +#endif + +#ifdef MNG_INCLUDE_LCMS /* little cms by Marti Maria Saguer */ +#ifndef ZLIB_DLL +#undef FAR +#endif +#ifdef WIN32 /* different header locations */ +#include "lcms.h" +#else +#include "lcms/lcms.h" +#endif +#endif /* MNG_INCLUDE_LCMS */ + +#ifdef MNG_INCLUDE_IJG6B /* IJG's jpgsrc6b */ +#include +#ifdef MNG_USE_SETJMP +#include /* needed for error-recovery (blergh) */ +#else +#ifdef WIN32 +#define USE_WINDOWS_MESSAGEBOX /* display a messagebox under Windoze */ +#endif +#endif /* MNG_USE_SETJMP */ +#ifdef FAR +#undef FAR /* possibly defined by zlib or lcms */ +#endif +#include "../libjpeg/jpeglib.h" /* all that for JPEG support :-) */ +#endif /* MNG_INCLUDE_IJG6B */ + +#if defined(MNG_INTERNAL_MEMMNGMT) || defined(MNG_INCLUDE_FILTERS) +#include /* "calloc" & "free" & "abs" */ +#endif + +#include /* get proper integer widths */ + +#ifdef WIN32 +/* B003 */ +#if defined __BORLANDC__ +#include /* defines "memcpy" for BCB */ +#else +#include /* defines "memcpy" for other win32 platforms */ +#endif +/* B003 */ +#ifdef MNG_CHECK_BAD_ICCP +#include /* strncmp() */ +#endif +#else +#ifdef BSD +#include /* defines "memcpy" for BSD (?) */ +#else +#include /* defines "memcpy" for all others (???) */ +#endif +#endif + +#if defined(MNG_FULL_CMS) || defined(MNG_GAMMA_ONLY) +#include /* fp gamma-calculation */ +#endif + +/* ************************************************************************** */ +/* * * */ +/* * Platform-dependant stuff * */ +/* * * */ +/* ************************************************************************** */ + +/* TODO: this may require some elaboration for other platforms; + only works with BCB for now */ + +#ifndef MNG_DLL +#if defined(MNG_BUILD_DLL) || defined(MNG_USE_DLL) +#define MNG_DLL +#endif +#endif + +#if defined(MNG_DLL) && defined(WIN32) /* setup DLL calling conventions */ +#define MNG_DECL __stdcall +#if defined(MNG_BUILD_DLL) +#define MNG_EXT __declspec(dllexport) +#elif defined(MNG_USE_DLL) +#define MNG_EXT __declspec(dllimport) +#else +#define MNG_EXT +#endif +#ifdef MNG_STRICT_ANSI +#undef MNG_STRICT_ANSI /* can't do strict-ANSI with this DLL-stuff */ +#endif +#else +#define MNG_DECL /* dummies for non-DLL */ +#define MNG_EXT +#endif /* MNG_DLL && WIN32 */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* now force ANSI-C from here on */ +#endif + +/* ************************************************************************** */ + +#if USHRT_MAX == 0xffffffffU /* get the proper 32-bit width !!! */ +typedef unsigned short mng_uint32; +typedef signed short mng_int32; +#elif UINT_MAX == 0xffffffffU +typedef unsigned int mng_uint32; +typedef signed int mng_int32; +#elif ULONG_MAX == 0xffffffffU +typedef unsigned long mng_uint32; +typedef signed long mng_int32; +#else +#error "Sorry, I can't find any 32-bit integers on this platform." +#endif + +typedef signed short mng_int16; /* other basic integers */ +typedef unsigned short mng_uint16; +typedef signed char mng_int8; +typedef unsigned char mng_uint8; + +typedef double mng_float; /* basic float */ + +typedef size_t mng_size_t; /* size field for memory allocation */ + +typedef char * mng_pchar; /* string */ +typedef void * mng_ptr; /* generic pointer */ +typedef void (*mng_fptr) (void); /* generic function pointer */ + +/* ************************************************************************** */ +/* * * */ +/* * Platform-independant from here * */ +/* * * */ +/* ************************************************************************** */ + +typedef mng_uint32 * mng_uint32p; /* pointer to unsigned longs */ +typedef mng_int32 * mng_int32p; /* pointer to longs */ +typedef mng_uint16 * mng_uint16p; /* pointer to unsigned words */ +typedef mng_uint8 * mng_uint8p; /* pointer to unsigned bytes */ + +typedef mng_int8 mng_bool; /* booleans */ + +struct mng_data_struct; +typedef struct mng_data_struct * mng_handle; /* generic handle */ + +typedef mng_int32 mng_retcode; /* generic return code */ +typedef mng_int32 mng_chunkid; /* 4-byte chunkname identifier */ +typedef mng_ptr mng_chunkp; /* pointer to a chunk-structure */ +typedef mng_ptr mng_objectp; /* pointer to an object-structure */ + +typedef mng_chunkid * mng_chunkidp; /* pointer to chunkid */ + +typedef struct { /* 8-bit palette element */ + mng_uint8 iRed; + mng_uint8 iGreen; + mng_uint8 iBlue; + } mng_palette8e; +typedef mng_palette8e mng_palette8[256]; /* 8-bit palette */ +typedef mng_palette8e * mng_palette8ep; + +typedef mng_uint8 mng_uint8arr[256]; /* generic arrays */ +typedef mng_uint8 mng_uint8arr4[4]; +typedef mng_uint16 mng_uint16arr[256]; +typedef mng_uint32 mng_uint32arr2[2]; + +/* ************************************************************************** */ + +#define MNG_FALSE 0 +#define MNG_TRUE 1 +#define MNG_NULL 0 + +#define MNG_SUSPENDBUFFERSIZE 32768 +#define MNG_SUSPENDREQUESTSIZE 1024 + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB + +/* size of temporary zlib buffer for deflate processing */ +#define MNG_ZLIB_MAXBUF 8192 + +/* default zlib compression parameters for deflateinit2 */ +#define MNG_ZLIB_LEVEL 9 /* level */ +#define MNG_ZLIB_METHOD Z_DEFLATED /* method */ +#define MNG_ZLIB_WINDOWBITS 15 /* window size */ +#define MNG_ZLIB_MEMLEVEL 9 /* memory level */ +#define MNG_ZLIB_STRATEGY Z_DEFAULT_STRATEGY /* strategy */ + +#define MNG_MAX_IDAT_SIZE 4096 /* maximum size of IDAT data */ + +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_JNG + +#ifdef MNG_INCLUDE_IJG6B /* IJG helper defs */ +typedef struct jpeg_compress_struct mngjpeg_comp; +typedef struct jpeg_decompress_struct mngjpeg_decomp; +typedef struct jpeg_error_mgr mngjpeg_error; +typedef struct jpeg_source_mgr mngjpeg_source; + +typedef mngjpeg_comp * mngjpeg_compp; +typedef mngjpeg_decomp * mngjpeg_decompp; +typedef mngjpeg_error * mngjpeg_errorp; +typedef mngjpeg_source * mngjpeg_sourcep; + +typedef J_DCT_METHOD mngjpeg_dctmethod; + +/* default IJG parameters for compression */ +#define MNG_JPEG_DCT JDCT_DEFAULT /* DCT algorithm (JDCT_ISLOW) */ +#define MNG_JPEG_QUALITY 100 /* quality 0..100; 100=best */ +#define MNG_JPEG_SMOOTHING 0 /* default no smoothing */ +#define MNG_JPEG_PROGRESSIVE MNG_FALSE /* default is just baseline */ +#define MNG_JPEG_OPTIMIZED MNG_FALSE /* default is not optimized */ +#endif /* MNG_INCLUDE_IJG6B */ + +#define MNG_JPEG_MAXBUF 65500 /* max size of temp JPEG buffer */ +#define MNG_MAX_JDAT_SIZE 4096 /* maximum size of JDAT data */ + +#endif /* MNG_INCLUDE_JNG */ + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_LCMS +typedef cmsHPROFILE mng_cmsprof; /* little CMS helper defs */ +typedef cmsHTRANSFORM mng_cmstrans; +typedef cmsCIExyY mng_CIExyY; +typedef cmsCIExyYTRIPLE mng_CIExyYTRIPLE; +typedef LPGAMMATABLE mng_gammatabp; +#endif /* MNG_INCLUDE_LCMS */ + +/* ************************************************************************** */ + + /* enumeration of known graphics types */ +enum mng_imgtypes {mng_it_unknown, mng_it_png, mng_it_mng, mng_it_jng}; +typedef enum mng_imgtypes mng_imgtype; + + /* enumeration of animation speed-types */ +enum mng_speedtypes {mng_st_normal, mng_st_fast, mng_st_slow, mng_st_slowest}; +typedef enum mng_speedtypes mng_speedtype; + +/* ************************************************************************** */ + + /* memory management callbacks */ +typedef mng_ptr (MNG_DECL *mng_memalloc) (mng_size_t iLen); +typedef void (MNG_DECL *mng_memfree) (mng_ptr iPtr, + mng_size_t iLen); + + /* I/O management callbacks */ +typedef mng_bool (MNG_DECL *mng_openstream) (mng_handle hHandle); +typedef mng_bool (MNG_DECL *mng_closestream) (mng_handle hHandle); +typedef mng_bool (MNG_DECL *mng_readdata) (mng_handle hHandle, + mng_ptr pBuf, + mng_uint32 iBuflen, + mng_uint32p pRead); +typedef mng_bool (MNG_DECL *mng_writedata) (mng_handle hHandle, + mng_ptr pBuf, + mng_uint32 iBuflen, + mng_uint32p pWritten); + + /* error & trace processing callbacks */ +typedef mng_bool (MNG_DECL *mng_errorproc) (mng_handle hHandle, + mng_int32 iErrorcode, + mng_int8 iSeverity, + mng_chunkid iChunkname, + mng_uint32 iChunkseq, + mng_int32 iExtra1, + mng_int32 iExtra2, + mng_pchar zErrortext); +typedef mng_bool (MNG_DECL *mng_traceproc) (mng_handle hHandle, + mng_int32 iFuncnr, + mng_int32 iFuncseq, + mng_pchar zFuncname); + + /* read processing callbacks */ +typedef mng_bool (MNG_DECL *mng_processheader) (mng_handle hHandle, + mng_uint32 iWidth, + mng_uint32 iHeight); +typedef mng_bool (MNG_DECL *mng_processtext) (mng_handle hHandle, + mng_uint8 iType, + mng_pchar zKeyword, + mng_pchar zText, + mng_pchar zLanguage, + mng_pchar zTranslation); +typedef mng_bool (MNG_DECL *mng_processsave) (mng_handle hHandle); +typedef mng_bool (MNG_DECL *mng_processseek) (mng_handle hHandle, + mng_pchar zName); +typedef mng_bool (MNG_DECL *mng_processneed) (mng_handle hHandle, + mng_pchar zKeyword); +typedef mng_bool (MNG_DECL *mng_processmend) (mng_handle hHandle, + mng_uint32 iIterationsdone, + mng_uint32 iIterationsleft); +typedef mng_bool (MNG_DECL *mng_processunknown) (mng_handle hHandle, + mng_chunkid iChunkid, + mng_uint32 iRawlen, + mng_ptr pRawdata); +typedef mng_bool (MNG_DECL *mng_processterm) (mng_handle hHandle, + mng_uint8 iTermaction, + mng_uint8 iIteraction, + mng_uint32 iDelay, + mng_uint32 iItermax); + + /* display processing callbacks */ +typedef mng_ptr (MNG_DECL *mng_getcanvasline) (mng_handle hHandle, + mng_uint32 iLinenr); +typedef mng_ptr (MNG_DECL *mng_getbkgdline) (mng_handle hHandle, + mng_uint32 iLinenr); +typedef mng_ptr (MNG_DECL *mng_getalphaline) (mng_handle hHandle, + mng_uint32 iLinenr); +typedef mng_bool (MNG_DECL *mng_refresh) (mng_handle hHandle, + mng_uint32 iX, + mng_uint32 iY, + mng_uint32 iWidth, + mng_uint32 iHeight); + + /* timer management callbacks */ +typedef mng_uint32 (MNG_DECL *mng_gettickcount) (mng_handle hHandle); +typedef mng_bool (MNG_DECL *mng_settimer) (mng_handle hHandle, + mng_uint32 iMsecs); + + /* color management callbacks */ +typedef mng_bool (MNG_DECL *mng_processgamma) (mng_handle hHandle, + mng_uint32 iGamma); +typedef mng_bool (MNG_DECL *mng_processchroma) (mng_handle hHandle, + mng_uint32 iWhitepointx, + mng_uint32 iWhitepointy, + mng_uint32 iRedx, + mng_uint32 iRedy, + mng_uint32 iGreenx, + mng_uint32 iGreeny, + mng_uint32 iBluex, + mng_uint32 iBluey); +typedef mng_bool (MNG_DECL *mng_processsrgb) (mng_handle hHandle, + mng_uint8 iRenderingintent); +typedef mng_bool (MNG_DECL *mng_processiccp) (mng_handle hHandle, + mng_uint32 iProfilesize, + mng_ptr pProfile); +typedef mng_bool (MNG_DECL *mng_processarow) (mng_handle hHandle, + mng_uint32 iRowsamples, + mng_bool bIsRGBA16, + mng_ptr pRow); + + /* chunk access callback(s) */ +typedef mng_bool (MNG_DECL *mng_iteratechunk) (mng_handle hHandle, + mng_handle hChunk, + mng_chunkid iChunkid, + mng_uint32 iChunkseq); + +/* ************************************************************************** */ + +#endif /* _libmng_types_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_write.c b/freeimage241/Source/LibMNG/libmng_write.c new file mode 100644 index 0000000..07a530f --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_write.c @@ -0,0 +1,139 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_write.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Write management (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the write management routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * 0.5.1 - 05/16/2000 - G.Juyn * */ +/* * - moved the actual write_graphic functionality from * */ +/* * mng_hlapi to it's appropriate function here * */ +/* * * */ +/* * 0.9.1 - 07/19/2000 - G.Juyn * */ +/* * - fixed writing of signature * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_memory.h" +#include "libmng_chunks.h" +#include "libmng_chunk_io.h" +#include "libmng_write.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_WRITE_PROCS + +/* ************************************************************************** */ + +mng_retcode write_graphic (mng_datap pData) +{ + mng_chunkp pChunk; + mng_retcode iRetcode; + mng_uint32 iWritten; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_GRAPHIC, MNG_LC_START) +#endif + + pChunk = pData->pFirstchunk; /* we'll start with the first, thank you */ + + if (pChunk) /* is there anything to write ? */ + { /* open the file */ + if (!pData->fOpenstream ((mng_handle)pData)) + MNG_ERROR (pData, MNG_APPIOERROR) + else + { + pData->bWriting = MNG_TRUE; /* indicate writing */ + pData->iWritebufsize = 32768; /* get a temporary write buffer */ + /* reserve 12 bytes for length, chunkname & crc */ + MNG_ALLOC (pData, pData->pWritebuf, pData->iWritebufsize+12) + /* write the signature */ + if (((mng_chunk_headerp)pChunk)->iChunkname == MNG_UINT_IHDR) + mng_put_uint32 (pData->pWritebuf, PNG_SIG); + else + if (((mng_chunk_headerp)pChunk)->iChunkname == MNG_UINT_JHDR) + mng_put_uint32 (pData->pWritebuf, JNG_SIG); + else + mng_put_uint32 (pData->pWritebuf, MNG_SIG); + + mng_put_uint32 (pData->pWritebuf+4, POST_SIG); + + if (!pData->fWritedata ((mng_handle)pData, pData->pWritebuf, 8, &iWritten)) + { + MNG_FREE (pData, pData->pWritebuf, pData->iWritebufsize+12) + MNG_ERROR (pData, MNG_APPIOERROR) + } + + if (iWritten != 8) /* disk full ? */ + { + MNG_FREE (pData, pData->pWritebuf, pData->iWritebufsize+12) + MNG_ERROR (pData, MNG_OUTPUTERROR) + } + + while (pChunk) /* so long as there's something to write */ + { /* let's call it's output routine */ + iRetcode = ((mng_chunk_headerp)pChunk)->fWrite (pData, pChunk); + + if (iRetcode) /* on error bail out */ + { + MNG_FREE (pData, pData->pWritebuf, pData->iWritebufsize+12) + return iRetcode; + } + /* neeeext */ + pChunk = ((mng_chunk_headerp)pChunk)->pNext; + } + /* free the temporary buffer */ + MNG_FREE (pData, pData->pWritebuf, pData->iWritebufsize+12) + + pData->bWriting = MNG_FALSE; /* done writing */ + /* close the stream now */ + if (!pData->fClosestream ((mng_handle)pData)) + MNG_ERROR (pData, MNG_APPIOERROR) + + } + } + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_WRITE_GRAPHIC, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_WRITE_PROCS */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + + diff --git a/freeimage241/Source/LibMNG/libmng_write.h b/freeimage241/Source/LibMNG/libmng_write.h new file mode 100644 index 0000000..df72396 --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_write.h @@ -0,0 +1,43 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_write.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : Write management (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the write management routines * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_write_h_ +#define _libmng_write_h_ + +/* ************************************************************************** */ + +mng_retcode write_graphic (mng_datap pData); + +/* ************************************************************************** */ + +#endif /* _libmng_write_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibMNG/libmng_zlib.c b/freeimage241/Source/LibMNG/libmng_zlib.c new file mode 100644 index 0000000..0730b2f --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_zlib.c @@ -0,0 +1,451 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_zlib.c copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : ZLIB library interface (implementation) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : implementation of the ZLIB library interface * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * 0.5.1 - 05/11/2000 - G.Juyn * */ +/* * - filled the deflatedata routine * */ +/* * 0.5.1 - 05/12/2000 - G.Juyn * */ +/* * - changed trace to macro for callback error-reporting * */ +/* * * */ +/* * 0.5.2 - 05/20/2000 - G.Juyn * */ +/* * - fixed for JNG alpha handling * */ +/* * 0.5.2 - 05/24/2000 - G.Juyn * */ +/* * - moved init of default zlib parms from here to * */ +/* * "mng_hlapi.c" * */ +/* * * */ +/* * 0.5.3 - 06/16/2000 - G.Juyn * */ +/* * - changed progressive-display processing * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* * 0.9.3 - 08/08/2000 - G.Juyn * */ +/* * - fixed compiler-warnings from Mozilla * */ +/* * 0.9.3 - 09/07/2000 - G.Juyn * */ +/* * - added support for new filter_types * */ +/* * * */ +/* ************************************************************************** */ + +#include "libmng.h" +#include "libmng_data.h" +#include "libmng_error.h" +#include "libmng_trace.h" +#ifdef __BORLANDC__ +#pragma hdrstop +#endif +#include "libmng_memory.h" +#include "libmng_pixels.h" +#include "libmng_filter.h" +#include "libmng_zlib.h" + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +/* ************************************************************************** */ + +#ifdef MNG_INCLUDE_ZLIB + +/* ************************************************************************** */ + +voidpf mngzlib_alloc (voidpf pData, + uInt iCount, + uInt iSize) +{ + voidpf pPtr; /* temporary space */ + +#ifdef MNG_INTERNAL_MEMMNGMT + pPtr = calloc (iCount, iSize); /* local allocation */ +#else + if (((mng_datap)pData)->fMemalloc) /* callback function set ? */ + pPtr = ((mng_datap)pData)->fMemalloc (iCount * iSize); + else + pPtr = Z_NULL; /* can't allocate! */ +#endif + + return pPtr; /* return the result */ +} + +/* ************************************************************************** */ + +void mngzlib_free (voidpf pData, + voidpf pAddress) +{ +#ifdef MNG_INTERNAL_MEMMNGMT + free (pAddress); /* free locally */ +#else + if (((mng_datap)pData)->fMemfree) /* callback set? */ + ((mng_datap)pData)->fMemfree (pAddress, 1); +#endif +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_initialize (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INITIALIZE, MNG_LC_START) +#endif + +#ifdef MNG_INTERNAL_MEMMNGMT + pData->sZlib.zalloc = Z_NULL; /* let zlib figure out memory management */ + pData->sZlib.zfree = Z_NULL; + pData->sZlib.opaque = Z_NULL; +#else /* use user-provided callbacks */ + pData->sZlib.zalloc = mngzlib_alloc; + pData->sZlib.zfree = mngzlib_free; + pData->sZlib.opaque = (voidpf)pData; +#endif + + pData->bInflating = MNG_FALSE; /* not performing any action yet */ + pData->bDeflating = MNG_FALSE; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INITIALIZE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_cleanup (mng_datap pData) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_CLEANUP, MNG_LC_START) +#endif + + if (pData->bInflating) /* force zlib cleanup */ + mngzlib_inflatefree (pData); + if (pData->bDeflating) + mngzlib_deflatefree (pData); + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_CLEANUP, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_inflateinit (mng_datap pData) +{ + int iZrslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEINIT, MNG_LC_START) +#endif + /* initialize zlib structures and such */ + iZrslt = inflateInit (&pData->sZlib); + + if (iZrslt != Z_OK) /* on error bail out */ + MNG_ERRORZ (pData, (mng_uint32)iZrslt) + + pData->bInflating = MNG_TRUE; /* really inflating something now */ + pData->sZlib.next_out = 0; /* force JIT initialization */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEINIT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +#ifdef MNG_SUPPORT_DISPLAY +mng_retcode mngzlib_inflaterows (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata) +{ + int iZrslt; + mng_retcode iRslt; + mng_ptr pSwap; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEROWS, MNG_LC_START) +#endif + + pData->sZlib.next_in = pIndata; /* let zlib know where to get stuff */ + pData->sZlib.avail_in = (uInt)iInlen; + + if (pData->sZlib.next_out == 0) /* initialize output variables ? */ + { /* let zlib know where to store stuff */ + pData->sZlib.next_out = pData->pWorkrow; + pData->sZlib.avail_out = (uInt)(pData->iRowsize + pData->iPixelofs); + } + + do + { /* now inflate a row */ + iZrslt = inflate (&pData->sZlib, Z_SYNC_FLUSH); + /* produced a full row ? */ + if (((iZrslt == Z_OK) || (iZrslt == Z_STREAM_END)) && + (pData->sZlib.avail_out == 0)) + { /* shouldn't we be at the end ? */ + if (pData->iRow >= (mng_int32)pData->iDataheight) +/* MNG_ERROR (pData, MNG_TOOMUCHIDAT) */ ; /* TODO: check this!!! */ + else + { /* has leveling info ? */ +/* if (pData->iFilterofs) + iRslt = init_rowdiffering (pData); + else + iRslt = MNG_NOERROR; */ + /* filter the row if necessary */ +/* if ((!iRslt) && (pData->iFilterofs < pData->iPixelofs ) && + (*(pData->pWorkrow + pData->iFilterofs)) ) */ + if (*(pData->pWorkrow + pData->iFilterofs)) + iRslt = filter_a_row (pData); + else + iRslt = MNG_NOERROR; + /* additonal leveling/differing ? */ + if ((!iRslt) && (pData->fDifferrow)) + { + iRslt = ((mng_differrow)pData->fDifferrow) (pData); + + pSwap = pData->pWorkrow; + pData->pWorkrow = pData->pPrevrow; + pData->pPrevrow = pSwap; /* make sure we're processing the right data */ + } + + if (!iRslt) + { +#ifdef MNG_INCLUDE_JNG + if (pData->bHasJHDR) /* is JNG alpha-channel ? */ + { /* just store in object ? */ + if ((!iRslt) && (pData->fStorerow)) + iRslt = ((mng_storerow)pData->fStorerow) (pData); + } + else +#endif /* MNG_INCLUDE_JNG */ + { /* process this row */ + if ((!iRslt) && (pData->fProcessrow)) + iRslt = ((mng_processrow)pData->fProcessrow) (pData); + /* store in object ? */ + if ((!iRslt) && (pData->fStorerow)) + iRslt = ((mng_storerow)pData->fStorerow) (pData); + /* color correction ? */ + if ((!iRslt) && (pData->fCorrectrow)) + iRslt = ((mng_correctrow)pData->fCorrectrow) (pData); + /* slap onto canvas ? */ + if ((!iRslt) && (pData->fDisplayrow)) + { + iRslt = ((mng_displayrow)pData->fDisplayrow) (pData); + + if (!iRslt) /* check progressive display refresh */ + iRslt = display_progressive_check (pData); + + } + } + } + + if (iRslt) /* on error bail out */ + MNG_ERROR (pData, iRslt); + + if (!pData->fDifferrow) /* swap row-pointers */ + { + pSwap = pData->pWorkrow; + pData->pWorkrow = pData->pPrevrow; + pData->pPrevrow = pSwap; /* so prev points to the processed row! */ + } + + iRslt = next_row (pData); /* adjust variables for next row */ + + if (iRslt) /* on error bail out */ + MNG_ERROR (pData, iRslt); + } + /* let zlib know where to store next output */ + pData->sZlib.next_out = pData->pWorkrow; + pData->sZlib.avail_out = (uInt)(pData->iRowsize + pData->iPixelofs); + } + } /* until some error or EOI */ + while ((iZrslt == Z_OK) && (pData->sZlib.avail_in > 0)); + /* on error bail out */ + if ((iZrslt != Z_OK) && (iZrslt != Z_STREAM_END)) + MNG_ERRORZ (pData, (mng_uint32)iZrslt) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEROWS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} +#endif /* MNG_SUPPORT_DISPLAY */ + +/* ************************************************************************** */ + +mng_retcode mngzlib_inflatedata (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata) +{ + int iZrslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEDATA, MNG_LC_START) +#endif + /* let zlib know where to get stuff */ + pData->sZlib.next_in = pIndata; + pData->sZlib.avail_in = (uInt)iInlen; + /* now inflate the data in one go! */ + iZrslt = inflate (&pData->sZlib, Z_FINISH); + /* not enough room in output-buffer ? */ + if ((iZrslt == Z_BUF_ERROR) || (pData->sZlib.avail_in > 0)) + return MNG_BUFOVERFLOW; + /* on error bail out */ + if ((iZrslt != Z_OK) && (iZrslt != Z_STREAM_END)) + MNG_ERRORZ (pData, (mng_uint32)iZrslt) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_inflatefree (mng_datap pData) +{ + int iZrslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEFREE, MNG_LC_START) +#endif + + pData->bInflating = MNG_FALSE; /* stopped it */ + + iZrslt = inflateEnd (&pData->sZlib); /* let zlib cleanup it's own stuff */ + + if (iZrslt != Z_OK) /* on error bail out */ + MNG_ERRORZ (pData, (mng_uint32)iZrslt) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_INFLATEFREE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_deflateinit (mng_datap pData) +{ + int iZrslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEINIT, MNG_LC_START) +#endif + /* initialize zlib structures and such */ + iZrslt = deflateInit2 (&pData->sZlib, pData->iZlevel, pData->iZmethod, + pData->iZwindowbits, pData->iZmemlevel, + pData->iZstrategy); + + if (iZrslt != Z_OK) /* on error bail out */ + MNG_ERRORZ (pData, (mng_uint32)iZrslt) + + pData->bDeflating = MNG_TRUE; /* really deflating something now */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEINIT, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_deflaterows (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata) +{ +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEROWS, MNG_LC_START) +#endif + + + + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEROWS, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_deflatedata (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata) +{ + int iZrslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEDATA, MNG_LC_START) +#endif + + pData->sZlib.next_in = pIndata; /* let zlib know where to get stuff */ + pData->sZlib.avail_in = (uInt)iInlen; + /* now deflate the data in one go! */ + iZrslt = deflate (&pData->sZlib, Z_FINISH); + /* not enough room in output-buffer ? */ + if ((iZrslt == Z_BUF_ERROR) || (pData->sZlib.avail_in > 0)) + return MNG_BUFOVERFLOW; + /* on error bail out */ + if ((iZrslt != Z_OK) && (iZrslt != Z_STREAM_END)) + MNG_ERRORZ (pData, (mng_uint32)iZrslt) + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEDATA, MNG_LC_END) +#endif + + return MNG_NOERROR; +} + +/* ************************************************************************** */ + +mng_retcode mngzlib_deflatefree (mng_datap pData) +{ + int iZrslt; + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEFREE, MNG_LC_START) +#endif + + iZrslt = deflateEnd (&pData->sZlib); /* let zlib cleanup it's own stuff */ + + if (iZrslt != Z_OK) /* on error bail out */ + MNG_ERRORZ (pData, (mng_uint32)iZrslt) + + pData->bDeflating = MNG_FALSE; /* stopped it */ + +#ifdef MNG_SUPPORT_TRACE + MNG_TRACE (pData, MNG_FN_ZLIB_DEFLATEFREE, MNG_LC_END) +#endif + + return MNG_NOERROR; /* done */ +} + +/* ************************************************************************** */ + +#endif /* MNG_INCLUDE_ZLIB */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ + diff --git a/freeimage241/Source/LibMNG/libmng_zlib.h b/freeimage241/Source/LibMNG/libmng_zlib.h new file mode 100644 index 0000000..e5bfbdb --- /dev/null +++ b/freeimage241/Source/LibMNG/libmng_zlib.h @@ -0,0 +1,62 @@ +/* ************************************************************************** */ +/* * For conditions of distribution and use, * */ +/* * see copyright notice in libmng.h * */ +/* ************************************************************************** */ +/* * * */ +/* * project : libmng * */ +/* * file : libmng_zlib.h copyright (c) 2000 G.Juyn * */ +/* * version : 1.0.0 * */ +/* * * */ +/* * purpose : ZLIB package interface (definition) * */ +/* * * */ +/* * author : G.Juyn * */ +/* * web : http://www.3-t.com * */ +/* * email : mailto:info@3-t.com * */ +/* * * */ +/* * comment : Definition of the ZLIB package interface * */ +/* * * */ +/* * changes : 0.5.1 - 05/08/2000 - G.Juyn * */ +/* * - changed strict-ANSI stuff * */ +/* * * */ +/* * 0.9.2 - 08/05/2000 - G.Juyn * */ +/* * - changed file-prefixes * */ +/* * * */ +/* ************************************************************************** */ + +#if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) +#pragma option -A /* force ANSI-C */ +#endif + +#ifndef _libmng_zlib_h_ +#define _libmng_zlib_h_ + +/* ************************************************************************** */ + +mng_retcode mngzlib_initialize (mng_datap pData); +mng_retcode mngzlib_cleanup (mng_datap pData); + +mng_retcode mngzlib_inflateinit (mng_datap pData); +mng_retcode mngzlib_inflaterows (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata); +mng_retcode mngzlib_inflatedata (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata); +mng_retcode mngzlib_inflatefree (mng_datap pData); + +mng_retcode mngzlib_deflateinit (mng_datap pData); +mng_retcode mngzlib_deflaterows (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata); +mng_retcode mngzlib_deflatedata (mng_datap pData, + mng_uint32 iInlen, + mng_uint8p pIndata); +mng_retcode mngzlib_deflatefree (mng_datap pData); + +/* ************************************************************************** */ + +#endif /* _libmng_zlib_h_ */ + +/* ************************************************************************** */ +/* * end of file * */ +/* ************************************************************************** */ diff --git a/freeimage241/Source/LibPNG/ANNOUNCE b/freeimage241/Source/LibPNG/ANNOUNCE new file mode 100644 index 0000000..7827622 --- /dev/null +++ b/freeimage241/Source/LibPNG/ANNOUNCE @@ -0,0 +1,28 @@ + +Libpng 1.0.10 - March 30, 2001 + +This is a public release of libpng, intended for use in production codes. + +Changes since the last public release (1.0.9): + + Revised makefile.dec + Reformatted libpng.3 to eliminate bad line breaks. + Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c + Added prototype for png_mmx_support() near the top of pnggccrd.c + Moved some error checking from png_handle_IHDR to png_set_IHDR. + Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. + Revised png_mmx_support() function in pnggccrd.c + Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c + Fixed memory leak in contrib/visupng/PngFile.c + Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) + Added warnings when retrieving or setting gamma=0. + Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, + and png_strlen. + Fixed bug in progressive reading (pngpread.c) with small images (height < 8). + Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin + Added beos project files (Chris Herborth) + +Send comments/corrections/commendations to +png-implement@ccrc.wustl.edu or to randeg@alum.rpi.edu + +Glenn R-P diff --git a/freeimage241/Source/LibPNG/CHANGES b/freeimage241/Source/LibPNG/CHANGES new file mode 100644 index 0000000..0915330 --- /dev/null +++ b/freeimage241/Source/LibPNG/CHANGES @@ -0,0 +1,960 @@ +CHANGES - changes for libpng + +version 0.2 + added reader into png.h + fixed small problems in stub file +version 0.3 + added pull reader + split up pngwrite.c to several files + added pnglib.txt + added example.c + cleaned up writer, adding a few new tranformations + fixed some bugs in writer + interfaced with zlib 0.5 + added K&R support + added check for 64 KB blocks for 16 bit machines +version 0.4 + cleaned up code and commented code + simplified time handling into png_time + created png_color_16 and png_color_8 to handle color needs + cleaned up color type defines + fixed various bugs + made various names more consistant + interfaced with zlib 0.71 + cleaned up zTXt reader and writer (using zlib's Reset functions) + split transformations into pngrtran.c and pngwtran.c +version 0.5 + interfaced with zlib 0.8 + fixed many reading and writing bugs + saved using 3 spaces instead of tabs +version 0.6 + added png_large_malloc() and png_large_free() + added png_size_t + cleaned up some compiler warnings + added png_start_read_image() +version 0.7 + cleaned up lots of bugs + finished dithering and other stuff + added test program + changed name from pnglib to libpng +version 0.71 [June, 1995] + changed pngtest.png for zlib 0.93 + fixed error in libpng.txt and example.c +version 0.8 + cleaned up some bugs + added png_set_filler() + split up pngstub.c into pngmem.c, pngio.c, and pngerror.c + added #define's to remove unwanted code + moved png_info_init() to png.c + added old_size into png_realloc() + added functions to manually set filtering and compression info + changed compression parameters based on image type + optimized filter selection code + added version info + changed external functions passing floats to doubles (k&r problems?) + put all the configurable stuff in pngconf.h + enabled png_set_shift to work with paletted images on read + added png_read_update_info() - updates info structure with + transformations +version 0.81 [August, 1995] + incorporated Tim Wegner's medium model code (thanks, Tim) +version 0.82 [September, 1995] + [unspecified changes] +version 0.85 [December, 1995] + added more medium model code (almost everything's a far) + added i/o, error, and memory callback functions + fixed some bugs (16 bit, 4 bit interlaced, etc.) + added first run progressive reader (barely tested) +version 0.86 [January, 1996] + fixed bugs + improved documentation +version 0.87 [January, 1996] + fixed medium model bugs + fixed other bugs introduced in 0.85 and 0.86 + added some minor documentation +version 0.88 [January, 1996] + fixed progressive bugs + replaced tabs with spaces + cleaned up documentation + added callbacks for read/write and warning/error functions +version 0.89 [July, 1996] + added new initialization API to make libpng work better with shared libs + we now have png_create_read_struct(), png_create_write_struct(), + png_create_info_struct(), png_destroy_read_struct(), and + png_destroy_write_struct() instead of the separate calls to + malloc and png_read_init(), png_info_init(), and png_write_init() + changed warning/error callback functions to fix bug - this means you + should use the new initialization API if you were using the old + png_set_message_fn() calls, and that the old API no longer exists + so that people are aware that they need to change their code + changed filter selection API to allow selection of multiple filters + since it didn't work in previous versions of libpng anyways + optimized filter selection code + fixed png_set_background() to allow using an arbitrary RGB color for + paletted images + fixed gamma and background correction for paletted images, so + png_correct_palette is not needed unless you are correcting an + external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED + in pngconf.h) - if nobody uses this, it may disappear in the future. + fixed bug with Borland 64K memory allocation (Alexander Lehmann) + fixed bug in interlace handling (Smarasderagd, I think) + added more error checking for writing and image to reduce invalid files + separated read and write functions so that they won't both be linked + into a binary when only reading or writing functionality is used + new pngtest image also has interlacing and zTXt + updated documentation to reflect new API +version 0.90 [January, 1997] + made CRC errors/warnings on critical and ancillary chunks configurable + libpng will use the zlib CRC routines by (compile-time) default + changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner) + added external C++ wrapper statements to png.h (Gilles Dauphin) + allow PNG file to be read when some or all of file signature has already + been read from the beginning of the stream. ****This affects the size + of info_struct and invalidates all programs that use a shared libpng**** + fixed png_filler() declarations + fixed? background color conversions + fixed order of error function pointers to match documentation + current chunk name is now available in png_struct to reduce the number + of nearly identical error messages (will simplify multi-lingual + support when available) + try to get ready for unknown-chunk callback functions: + - previously read critical chunks are flagged, so the chunk handling + routines can determine if the chunk is in the right place + - all chunk handling routines have the same prototypes, so we will + be able to handle all chunks via a callback mechanism + try to fix Linux "setjmp" buffer size problems + removed png_large_malloc, png_large_free, and png_realloc functions. +version 0.95 [March, 1997] + fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never + fixed bug in PNG file signature compares when start != 0 + changed parameter type of png_set_filler(...filler...) from png_byte + to png_uint_32 + added test for MACOS to ensure that both math.h and fp.h are not #included + added macros for libpng to be compiled as a Windows DLL (Andreas Kupries) + added "packswap" transformation, which changes the endianness of + packed-pixel bytes (Kevin Bracey) + added "strip_alpha" transformation, which removes the alpha channel of + input images without using it (not neccesarily a good idea) + added "swap_alpha" transformation, which puts the alpha channel in front + of the color bytes instead of after + removed all implicit variable tests which assume NULL == 0 (I think) + changed several variables to "png_size_t" to show 16/32-bit limitations + added new pCAL chunk read/write support + added experimental filter selection weighting (Greg Roelofs) + removed old png_set_rgbx() and png_set_xrgb() functions that have been + obsolete for about 2 years now (use png_set_filler() instead) + added macros to read 16- and 32-bit ints directly from buffer, to be + used only on those systems that support it (namely PowerPC and 680x0) + With some testing, this may become the default for MACOS/PPC systems. + only calculate CRC on data if we are going to use it + added macros for zTXt compression type PNG_zTXt_COMPRESSION_??? + added macros for simple libpng debugging output selectable at compile time + removed PNG_READ_END_MODE in progressive reader (Smarasderagd) + more description of info_struct in libpng.txt and png.h + more instructions in example.c + more chunk types tested in pngtest.c + renamed pngrcb.c to pngset.c, and all png_read_ functions to be + png_set_. We now have corresponding png_get_ + functions in pngget.c to get infomation in info_ptr. This isolates + the application from the internal organization of png_info_struct + (good for shared library implementations). +version 0.96 [May, 1997] + fixed serious bug with < 8bpp images introduced in 0.95 + fixed 256-color transparency bug (Greg Roelofs) + fixed up documentation (Greg Roelofs, Laszlo Nyul) + fixed "error" in pngconf.h for Linux setjmp() behaviour + fixed DOS medium model support (Tim Wegner) + fixed png_check_keyword() for case with error in static string text + added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul) + added typecasts to quiet compiler errors + added more debugging info +version 0.97 [January, 1998] + removed PNG_USE_OWN_CRC capability + relocated png_set_crc_action from pngrutil.c to pngrtran.c + fixed typecasts of "new_key", etc. (Andreas Dilger) + added RFC 1152 [sic] date support + fixed bug in gamma handling of 4-bit grayscale + added 2-bit grayscale gamma handling (Glenn R-P) + added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P) + minor corrections in libpng.txt + added simple sRGB support (Glenn R-P) + easier conditional compiling, e.g. define PNG_READ/WRITE_NOT_FULLY_SUPPORTED; + all configurable options can be selected from command-line instead + of having to edit pngconf.h (Glenn R-P) + fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P) + added more conditions for png_do_background, to avoid changing + black pixels to background when a background is supplied and + no pixels are transparent + repaired PNG_NO_STDIO behaviour + tested NODIV support and made it default behaviour (Greg Roelofs) + added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler) + regularized version numbering scheme and bumped shared-library major + version number to 2 to avoid problems with libpng 0.89 apps (Greg Roelofs) +version 0.98 [January, 1998] + cleaned up some typos in libpng.txt and in code documentation + fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler) + cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c + changed recommendation about file_gamma for PC images to .51 from .45, + in example.c and libpng.txt, added comments to distinguish between + screen_gamma, viewing_gamma, and display_gamma. + changed all references to RFC1152 to read RFC1123 and changed the + PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED + added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent) + changed srgb_intent from png_byte to int to avoid compiler bugs +version 0.99 [January 30, 1998] + free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler) + fixed a longstanding "packswap" bug in pngtrans.c + fixed some inconsistencies in pngconf.h that prevented compiling with + PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined + fixed some typos and made other minor rearrangement of libpng.txt (Andreas) + changed recommendation about file_gamma for PC images to .50 from .51 in + example.c and libpng.txt, and changed file_gamma for sRGB images to .45 + added a number of functions to access information from the png structure + png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit) + added TARGET_MACOS similar to zlib-1.0.8 + define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined + added type casting to all png_malloc() function calls +version 0.99a [January 31, 1998] + Added type casts and parentheses to all returns that return a value.(Tim W.) +version 0.99b [February 4, 1998] + Added type cast png_uint_32 on malloc function calls where needed. + Changed type of num_hist from png_uint_32 to int (same as num_palette). + Added checks for rowbytes overflow, in case png_size_t is less than 32 bits. + Renamed makefile.elf to makefile.lnx. +version 0.99c [February 7, 1998] + More type casting. Removed erroneous overflow test in pngmem.c. + Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes. + Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5. +version 0.99d [February 11, 1998] + Renamed "far_to_near()" "png_far_to_near()" + Revised libpng.3 + Version 99c "buffered" operations didn't work as intended. Replaced them + with png_memcpy_check() and png_memset_check(). + Added many "if (png_ptr == NULL) return" to quell compiler warnings about + unused png_ptr, mostly in pngget.c and pngset.c. + Check for overlength tRNS chunk present when indexed-color PLTE is read. + Cleaned up spelling errors in libpng.3/libpng.txt + Corrected a problem with png_get_tRNS() which returned undefined trans array +version 0.99e [February 28, 1998] + Corrected png_get_tRNS() again. + Add parentheses for easier reading of pngget.c, fixed "||" should be "&&". + Touched up example.c to make more of it compileable, although the entire + file still can't be compiled (Willem van Schaik) + Fixed a bug in png_do_shift() (Bryan Tsai) + Added a space in png.h prototype for png_write_chunk_start() + Replaced pngtest.png with one created with zlib 1.1.1 + Changed pngtest to report PASS even when file size is different (Jean-loup G.) + Corrected some logic errors in png_do_invert_alpha() (Chris Patterson) +version 0.99f [March 5, 1998] + Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey) + Moved makefiles into a "scripts" directory, and added INSTALL instruction file + Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok) + Added pointers to "note on libpng versions" in makefile.lnx and README + Added row callback feature when reading and writing nonprogressive rows + and added a test of this feature in pngtest.c + Added user transform callbacks, with test of the feature in pngtest.c +version 0.99g [March 6, 1998, morning] + Minor changes to pngtest.c to suppress compiler warnings. + Removed "beta" language from documentation. +version 0.99h [March 6, 1998, evening] + Minor changes to previous minor changes to pngtest.c + Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED + and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro + Added user transform capability +version 1.00 [March 7, 1998] + Changed several typedefs in pngrutil.c + Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik) + replaced "while(1)" with "for(;;)" + added PNGARG() to prototypes in pngtest.c and removed some prototypes + updated some of the makefiles (Tom Lane) + changed some typedefs (s_start, etc.) in pngrutil.c + fixed dimensions of "short_months" array in pngwrite.c + Replaced ansi2knr.c with the one from jpeg-v6 +version 1.0.0 [March 8, 1998] + Changed name from 1.00 to 1.0.0 (Adam Costello) + Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert) +version 1.0.0a [March 9, 1998] + Fixed three bugs in pngrtran.c to make gamma+background handling consistent + (Greg Roelofs) + Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz + for major, minor, and bugfix releases. This is 10001. (Adam Costello, + Tom Lane) + Make months range from 1-12 in png_convert_to_rfc1123 +version 1.0.0b [March 13, 1998] + Quieted compiler complaints about two empty "for" loops in pngrutil.c + Minor changes to makefile.s2x + Removed #ifdef/#endif around a png_free() in pngread.c +version 1.0.1 [March 14, 1998] + Changed makefile.s2x to reduce security risk of using a relative pathname + Fixed some typos in the documentation (Greg). + Fixed a problem with value of "channels" returned by png_read_update_info() +version 1.0.1a [April 21, 1998] + Optimized Paeth calculations by replacing abs() function calls with intrinsics + plus other loop optimizations. Improves avg decoding speed by about 20%. + Commented out i386istic "align" compiler flags in makefile.lnx. + Reduced the default warning level in some makefiles, to make them consistent. + Removed references to IJG and JPEG in the ansi2knr.c copyright statement. + Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation. + Added grayscale and 16-bit capability to png_do_read_filler(). + Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes + too large when writing an image with bit_depth < 8 (Bob Dellaca). + Corrected some bugs in the experimental weighted filtering heuristics. + Moved a misplaced pngrutil code block that truncates tRNS if it has more + than num_palette entries -- test was done before num_palette was defined. + Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins). + Changed compiler flags in makefile.wat for better optimization (Pawel Mrochen). +version 1.0.1b [May 2, 1998] + Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg). + Relocated the png_composite macros from pngrtran.c to png.h (Greg). + Added makefile.sco (contributed by Mike Hopkirk). + Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a. + Fixed a bug in pngrtran.c that would set channels=5 under some circumstances. + More work on the Paeth-filtering, achieving imperceptible speedup (A Kleinert). + More work on loop optimization which may help when compiled with C++ compilers. + Added warnings when people try to use transforms they've defined out. + Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran. + Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg) +version 1.0.1c [May 11, 1998] + Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for + filler bytes should have been 0xff instead of 0xf. + Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images. + Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED + out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h + Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED, + for consistency, in pngconf.h + Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier + to remove unwanted capabilities via the compile line + Made some corrections to grammar (which, it's) in documentation (Greg). + Corrected example.c, use of row_pointers in png_write_image(). +version 1.0.1d [May 24, 1998] + Corrected several statements that used side effects illegally in pngrutil.c + and pngtrans.c, that were introduced in version 1.0.1b + Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert) + More corrections to example.c, use of row_pointers in png_write_image() + and png_read_rows(). + Added pngdll.mak and pngdef.pas to scripts directory, contributed by + Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5 + Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.) + Changed several loops from count-down to count-up, for consistency. +version 1.0.1e [June 6, 1998] + Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and + added warnings when people try to set png_read_fn and png_write_fn in + the same structure. + Added a test such that png_do_gamma will be done when num_trans==0 + for truecolor images that have defined a background. This corrects an + error that was introduced in libpng-0.90 that can cause gamma processing + to be skipped. + Added tests in png.h to include "trans" and "trans_values" in structures + when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined. + Add png_free(png_ptr->time_buffer) in png_destroy_read_struct() + Moved png_convert_to_rfc_1123() from pngwrite.c to png.c + Added capability for user-provided malloc_fn() and free_fn() functions, + and revised pngtest.c to demonstrate their use, replacing the + PNGTEST_DEBUG_MEM feature. + Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner). +version 1.0.2 [June 14, 1998] + Fixed two bugs in makefile.bor . +version 1.0.2a [December 30, 1998] + Replaced and extended code that was removed from png_set_filler() in 1.0.1a. + Fixed a bug in png_do_filler() that made it fail to write filler bytes in + the left-most pixel of each row (Kevin Bracey). + Changed "static pngcharp tIME_string" to "static char tIME_string[30]" + in pngtest.c (Duncan Simpson). + Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk + even when no tIME chunk was present in the source file. + Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit. + Fixed a problem in png_read_push_finish_row(), which would not skip some + passes that it should skip, for images that are less than 3 pixels high. + Interchanged the order of calls to png_do_swap() and png_do_shift() + in pngwtran.c (John Cromer). + Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h . + Changed "bad adaptive filter type" from error to warning in pngrutil.c . + Fixed a documentation error about default filtering with 8-bit indexed-color. + Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO + (L. Peter Deutsch). + Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions. + Added png_get_copyright() and png_get_header_version() functions. + Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c + Added information about debugging in libpng.txt and libpng.3 . + Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco. + Removed lines after Dynamic Dependencies" in makefile.aco . + Revised makefile.dec to make a shared library (Jeremie Petit). + Removed trailing blanks from all files. +version 1.0.2a [January 6, 1999] + Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h + Added "if" tests to silence complaints about unused png_ptr in png.h and png.c + Changed "check_if_png" function in example.c to return true (nonzero) if PNG. + Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig() + which is obsolete. +version 1.0.3 [January 14, 1999] + Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice) + Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO. +version 1.0.3a [August 12, 1999] + Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning + if an attempt is made to read an interlaced image when it's not supported. + Added check if png_ptr->trans is defined before freeing it in pngread.c + Modified the Y2K statement to include versions back to version 0.71 + Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c + Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments) + Replaced leading blanks with tab characters in makefile.hux + Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents. + Changed (float)red and (float)green to (double)red, (double)green + in png_set_rgb_to_gray() to avoid "promotion" problems in AIX. + Fixed a bug in pngconf.h that omitted when PNG_DEBUG==0 (K Bracey). + Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt). + Updated documentation to refer to the PNG-1.2 specification. + Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c + in makefile.knr, INSTALL, and README (L. Peter Deutsch) + Fixed bugs in calculation of the length of rowbytes when adding alpha + channels to 16-bit images, in pngrtran.c (Chris Nokleberg) + Added function png_set_user_transform_info() to store user_transform_ptr, + user_depth, and user_channels into the png_struct, and a function + png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg) + Added function png_set_empty_plte_permitted() to make libpng useable + in MNG applications. + Corrected the typedef for png_free_ptr in png.h (Jesse Jones). + Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be + consistent with PNG-1.2, and allow variance of 500 before complaining. + Added assembler code contributed by Intel in file pngvcrd.c and modified + makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, Gilles Vollant) + Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy. + Added some aliases for png_set_expand() in pngrtran.c, namely + png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS() + (Greg Roelofs, in "PNG: The Definitive Guide"). + Added makefile.beo for BEOS on X86, contributed by Sander Stok. +version 1.0.3b [August 26, 1999] + Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h + Changed leading blanks to tabs in all makefiles. + Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code. + Made alternate versions of png_set_expand() in pngrtran.c, namely + png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha + (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases. + Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h + Revised calculation of num_blocks in pngmem.c to avoid a potentially + negative shift distance, whose results are undefined in the C language. + Added a check in pngset.c to prevent writing multiple tIME chunks. + Added a check in pngwrite.c to detect invalid small window_bits sizes. +version 1.0.3d [September 4, 1999] + Fixed type casting of igamma in pngrutil.c + Added new png_expand functions to scripts/pngdef.pas and pngos2.def + Added a demo read_user_transform_fn that examines the row filters in pngtest.c +version 1.0.4 [September 24, 1999] + Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined + Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h + Made several minor corrections to pngtest.c + Renamed the makefiles with longer but more user friendly extensions. + Copied the PNG copyright and license to a separate LICENSE file. + Revised documentation, png.h, and example.c to remove reference to + "viewing_gamma" which no longer appears in the PNG specification. + Revised pngvcrd.c to use MMX code for interlacing only on the final pass. + Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a + Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX + assembler code) and makefile.vcwin32 (doesn't). + Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING) + Added a copy of pngnow.png to the distribution. +version 1.0.4a [September 25, 1999] + Increase max_pixel_depth in pngrutil.c if a user transform needs it. + Changed several division operations to right-shifts in pngvcrd.c +version 1.0.4b [September 30, 1999] + Added parentheses in line 3732 of pngvcrd.c + Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1 +version 1.0.4c [October 1, 1999] + Added a "png_check_version" function in png.c and pngtest.c that will generate + a helpful compiler error if an old png.h is found in the search path. + Changed type of png_user_transform_depth|channels from int to png_byte. +version 1.0.4d [October 6, 1999] + Changed 0.45 to 0.45455 in png_set_sRGB() + Removed unused PLTE entries from pngnow.png + Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly. +version 1.0.4e [October 10, 1999] + Fixed sign error in pngvcrd.c (Greg Roelofs) + Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P) +version 1.0.4f [October 15, 1999] + Surrounded example.c code with #if 0 .. #endif to prevent people from + inadvertently trying to compile it. + Changed png_get_header_version() from a function to a macro in png.h + Added type casting mostly in pngrtran.c and pngwtran.c + Removed some pointless "ptr = NULL" in pngmem.c + Added a "contrib" directory containing the source code from Greg's book. +version 1.0.5 [October 15, 1999] + Minor editing of the INSTALL and README files. +version 1.0.5a [October 23, 1999] + Added contrib/pngsuite and contrib/pngminus (Willem van Schaik) + Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans) + Further optimization and bugfix of pngvcrd.c + Revised pngset.c so that it does not allocate or free memory in the user's + text_ptr structure. Instead, it makes its own copy. + Created separate write_end_info_struct in pngtest.c for a more severe test. + Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak. +version 1.0.5b [November 23, 1999] + Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and + PNG_FLAG_WROTE_tIME from flags to mode. + Added png_write_info_before_PLTE() function. + Fixed some typecasting in contrib/gregbook/*.c + Updated scripts/makevms.com and added makevms.com to contrib/gregbook + and contrib/pngminus (Martin Zinser) +version 1.0.5c [November 26, 1999] + Moved png_get_header_version from png.h to png.c, to accomodate ansi2knr. + Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to + accomodate making DLL's: Moved usr_png_ver from global variable to function + png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and + eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays + into pngtypes.h. Eliminated use of global png_pass arrays. Declared the + png_CHNK and png_pass arrays to be "const". Made the global arrays + available to applications (although none are used in libpng itself) when + PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined. + Removed some extraneous "-I" from contrib/pngminus/makefile.std + Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2. + Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3 +version 1.0.5d [November 29, 1999] + Add type cast (png_const_charp) two places in png.c + Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays. + Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available + to applications a macro "PNG_USE_LOCAL_ARRAYS". + #ifdef out all the new declarations when PNG_USE_GLOBAL_ARRAYS is defined. + Added PNG_EXPORT_VAR macro to accommodate making DLL's. +version 1.0.5e [November 30, 1999] + Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text + structure; refactored the inflate/deflate support to make adding new chunks + with trailing compressed parts easier in the future, and added new functions + png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP, + png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond). + NOTE: Applications that write text chunks MUST define png_text->lang + before calling png_set_text(). It must be set to NULL if you want to + write tEXt or zTXt chunks. If you want your application to be able to + run with older versions of libpng, use + + #ifdef PNG_iTXt_SUPPORTED + png_text[i].lang = NULL; + #endif + + Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned + offsets (Eric S. Raymond). + Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into + PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED + macros, leaving the separate macros also available. + Removed comments on #endifs at the end of many short, non-nested #if-blocks. +version 1.0.5f [December 6, 1999] + Changed makefile.solaris to issue a warning about potential problems when + the ucb "ld" is in the path ahead of the ccs "ld". + Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3. + Added sCAL chunk support (Eric S. Raymond). +version 1.0.5g [December 7, 1999] + Fixed "png_free_spallettes" typo in png.h + Added code to handle new chunks in pngpread.c + Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block + Added "translated_key" to png_text structure and png_write_iTXt(). + Added code in pngwrite.c to work around a newly discovered zlib bug. +version 1.0.5h [December 10, 1999] + NOTE: regarding the note for version 1.0.5e, the following must also + be included in your code: + png_text[i].translated_key = NULL; + Unknown chunk handling is now supported. + Option to eliminate all floating point support was added. Some new + fixed-point functions such as png_set_gAMA_fixed() were added. + Expanded tabs and removed trailing blanks in source files. +version 1.0.5i [December 13, 1999] + Added some type casts to silence compiler warnings. + Renamed "png_free_spalette" to "png_free_spalettes" for consistency. + Removed leading blanks from a #define in pngvcrd.c + Added some parameters to the new png_set_keep_unknown_chunks() function. + Added a test for up->location != 0 in the first instance of writing + unknown chunks in pngwrite.c + Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to + prevent recursion. + Added png_free_hIST() function. + Various patches to fix bugs in the sCAL and integer cHRM processing, + and to add some convenience macros for use with sCAL. +version 1.0.5j [December 21, 1999] + Changed "unit" parameter of png_write_sCAL from png_byte to int, to work + around buggy compilers. + Added new type "png_fixed_point" for integers that hold float*100000 values + Restored backward compatibility of tEXt/zTXt chunk processing: + Restored the first four members of png_text to the same order as v.1.0.5d. + Added members "lang_key" and "itxt_length" to png_text struct. Set + text_length=0 when "text" contains iTXt data. Use the "compression" + member to distinguish among tEXt/zTXt/iTXt types. Added + PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros. + The "Note" above, about backward incompatibility of libpng-1.0.5e, no + longer applies. + Fixed png_read|write_iTXt() to read|write parameters in the right order, + and to write the iTXt chunk after IDAT if it appears in the end_ptr. + Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs) + Reversed the order of trying to write floating-point and fixed-point gAMA. +version 1.0.5k [December 27, 1999] + Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))" + Added png_handle_as_unknown() function (Glenn) + Added png_free_chunk_list() function and chunk_list and num_chunk_list members + of png_ptr. + Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE. + Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings + about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored) + Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR). + Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is. + Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP(). +version 1.0.5l [January 1, 2000] + Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr() + for setting a callback function to handle unknown chunks and for + retrieving the associated user pointer (Glenn). +version 1.0.5m [January 7, 2000] + Added high-level functions png_read_png(), png_write_png(), png_free_pixels(). +version 1.0.5n [January 9, 2000] + Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its + own memory for info_ptr->palette. This makes it safe for the calling + application to free its copy of the palette any time after it calls + png_set_PLTE(). +version 1.0.5o [January 20, 2000] + Cosmetic changes only (removed some trailing blanks and TABs) +version 1.0.5p [January 31, 2000] + Renamed pngdll.mak to makefile.bd32 + Cosmetic changes in pngtest.c +version 1.0.5q [February 5, 2000] + Relocated the makefile.solaris warning about PATH problems. + Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg) + Revised makefile.gcmmx + Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros +version 1.0.5r [February 7, 2000] + Removed superfluous prototype for png_get_itxt from png.h + Fixed a bug in pngrtran.c that improperly expanded the background color. + Return *num_text=0 from png_get_text() when appropriate, and fix documentation + of png_get_text() in libpng.txt/libpng.3. +version 1.0.5s [February 18, 2000] + Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the + new error handler that's planned for the next libpng release, and changed + example.c, pngtest.c, and contrib programs to use this macro. + Revised some of the DLL-export macros in pngconf.h (Greg Roelofs) + Fixed a bug in png_read_png() that caused it to fail to expand some images + that it should have expanded. + Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions + in pngget.c + Changed the allocation of palette, history, and trans arrays back to + the version 1.0.5 method (linking instead of copying) which restores + backward compatibility with version 1.0.5. Added some remarks about + that in example.c. Added "free_me" member to info_ptr and png_ptr + and added png_free_data() function. + Updated makefile.linux and makefile.gccmmx to make directories conditionally. + Made cosmetic changes to pngasmrd.h + Added png_set_rows() and png_get_rows(), for use with png_read|write_png(). + Modified png_read_png() to allocate info_ptr->row_pointers only if it + hasn't already been allocated. +version 1.0.5t [March 4, 2000] + Changed png_jmp_env() migration aiding macro to png_jmpbuf(). + Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c + Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when + PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b + Files in contrib/gregbook were revised to use png_jmpbuf() and to select + a 24-bit visual if one is available, and to allow abbreviated options. + Files in contrib/pngminus were revised to use the png_jmpbuf() macro. + Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s +version 1.0.5u [March 5, 2000] + Simplified the code that detects old png.h in png.c and pngtest.c + Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp) + Increased precision of rgb_to_gray calculations from 8 to 15 bits and + added png_set_rgb_to_gray_fixed() function. + Added makefile.bc32 (32-bit Borland C++, C mode) +version 1.0.5v [March 11, 2000] + Added some parentheses to the png_jmpbuf macro definition. + Updated references to the zlib home page, which has moved to freesoftware.com. + Corrected bugs in documentation regarding png_read_row() and png_write_row(). + Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt. + Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3, + revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin) +version 1.0.6 [March 20, 2000] + Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c + Added makefile.sggcc (SGI IRIX with gcc) +version 1.0.6d [April 7, 2000] + Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO + Added data_length parameter to png_decompress_chunk() function + Revised documentation to remove reference to abandoned png_free_chnk functions + Fixed an error in png_rgb_to_gray_fixed() + Revised example.c, usage of png_destroy_write_struct(). + Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file + Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c + Simplify png_sig_bytes() function to remove use of non-ISO-C strdup(). +version 1.0.6e [April 9, 2000] + Added png_data_freer() function. + In the code that checks for over-length tRNS chunks, added check of + info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann) + Minor revisions of libpng.txt/libpng.3. + Check for existing data and free it if the free_me flag is set, in png_set_*() + and png_handle_*(). + Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED + is defined. + Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c + and mentioned the purposes of the two macros in libpng.txt/libpng.3. +version 1.0.6f [April 14, 2000] + Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data. + Add checks in png_set_text() for NULL members of the input text structure. + Revised libpng.txt/libpng.3. + Removed superfluous prototype for png_set_itxt from png.h + Removed "else" from pngread.c, after png_error(), and changed "0" to "length". + Changed several png_errors about malformed ancillary chunks to png_warnings. +version 1.0.6g [April 24, 2000] + Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined. + Relocated paragraph about png_set_background() in libpng.3/libpng.txt + and other revisions (Matthias Benckmann) + Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and + png_ptr members to restore binary compatibility with libpng-1.0.5 + (breaks compatibility with libpng-1.0.6). +version 1.0.6h [April 24, 2000] + Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds + libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h) + This is a temporary change for test purposes. +version 1.0.6i [May 2, 2000] + Rearranged some members at the end of png_info and png_struct, to put + unknown_chunks_num and free_me within the original size of the png_structs + and free_me, png_read_user_fn, and png_free_fn within the original png_info, + because some old applications allocate the structs directly instead of + using png_create_*(). + Added documentation of user memory functions in libpng.txt/libpng.3 + Modified png_read_png so that it will use user_allocated row_pointers + if present, unless free_me directs that it be freed, and added description + of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3. + Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version + 1.00) members of png_struct and png_info, to regain binary compatibility + when you define this macro. Capabilities lost in this event + are user transforms (new in version 1.0.0),the user transform pointer + (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT, + the high-level interface, and unknown chunks support (all new in 1.0.6). + This was necessary because of old applications that allocate the structs + directly as authors were instructed to do in libpng-0.88 and earlier, + instead of using png_create_*(). + Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which + can be used to detect codes that directly allocate the structs, and + code to check these modes in png_read_init() and png_write_init() and + generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED + was not defined. + Added makefile.intel and updated makefile.watcom (Pawel Mrochen) +version 1.0.6j [May 3, 2000] + Overloaded png_read_init() and png_write_init() with macros that convert + calls to png_read_init_2() or png_write_init_2() that check the version + and structure sizes. +version 1.0.7beta11 [May 7, 2000] + Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes + which are no longer used. + Eliminated the three new members of png_text when PNG_NO_iTXt_SUPPORTED + or PNG_LEGACY_SUPPORTED is defined. + Made PNG_NO_ITXT_SUPPORTED the default setting, to avoid memory overrun + when old applications fill the info_ptr->text structure directly. + Added PNGAPI macro, and added it to the definitions of all exported functions. + Relocated version macro definitions ahead of the includes of zlib.h and + pngconf.h in png.h. +version 1.0.7beta12 [May 12, 2000] + Revised pngset.c to avoid a problem with expanding the png_debug macro. + Deleted some extraneous defines from pngconf.h + Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined. + Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined. + Added png_access_version_number() function. + Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data(). + Expanded libpng.3/libpng.txt information about png_data_freer(). +version 1.0.7beta14 [May 17, 2000] (beta13 was not published) + Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as + warnings instead of errors, as pngrutil.c does. + Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png() + will actually write IDATs. + Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32. + Make png_free_data() ignore its final parameter except when freeing data + that can have multiple instances (text, sPLT, unknowns). + Fixed a new bug in png_set_rows(). + Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5. + Added png_set_invalid() function. + Fixed incorrect illustrations of png_destroy_write_struct() in example.c. +version 1.0.7beta15 [May 30, 2000] + Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce + fewer error messages. + Rearranged checks for Z_OK to check the most likely path first in pngpread.c + and pngwutil.c. + Added checks in pngtest.c for png_create_*() returning NULL, and mentioned + in libpng.txt/libpng.3 the need for applications to check this. + Changed names of png_default_*() functions in pngtest to pngtest_*(). + Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32. + Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c + Set each pointer to NULL after freeing it in png_free_data(). + Worked around a problem in pngconf.h; AIX's strings.h defines an "index" + macro that conflicts with libpng's png_color_16.index. (Dimitri Papadapoulos) + Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux). +version 1.0.7beta16 [June 4, 2000] + Revised the workaround of AIX string.h "index" bug. + Added a check for overlength PLTE chunk in pngrutil.c. + Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer + indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler. + Added a warning in png_decompress_chunk() when it runs out of data, e.g. + when it tries to read an erroneous PhotoShop iCCP chunk. + Added PNG_USE_DLL macro. + Revised the copyright/disclaimer/license notice. + Added contrib/msvctest directory +version 1.0.7rc1 [June 9, 2000] + Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200) + Added contrib/visupng directory (Willem van Schaik) +version 1.0.7beta18 [June 23, 2000] + Revised PNGAPI definition, and pngvcrd.c to work with __GCC__ + and do not redefine PNGAPI if it is passed in via a compiler directive. + Revised visupng/PngFile.c to remove returns from within the Try block. + Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros. + Updated contrib/visupng/cexcept.h to version 1.0.0. + Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks. +version 1.0.7rc2 [June 28, 2000] + Updated license to include disclaimers required by UCITA. + Fixed "DJBPP" typo in pnggccrd.c introduced in beta18. +version 1.0.7 [July 1, 2000] + Revised the definition of "trans_values" in libpng.3/libpng.txt +version 1.0.8beta1 [July 8, 2000] + Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks. + Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and + pngwutil.c. + Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h. + Removed unused "#include " from png.c + Added WindowsCE support. + Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment. +version 1.0.8beta2 [July 10, 2000] + Added project files to the wince directory and made further revisions + of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE. +version 1.0.8beta3 [July 11, 2000] + Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS() + for indexed-color input files to avoid potential double-freeing trans array + under some unusual conditions; problem was introduced in version 1.0.6f. + Further revisions to pngtest.c and files in the wince subdirectory. +version 1.0.8beta4 [July 14, 2000] + Added the files pngbar.png and pngbar.jpg to the distribution. + Added makefile.cygwin, and cygwin support in pngconf.h + Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory) +version 1.0.8rc1 [July 16, 2000] + Revised png_debug() macros and statements to eliminate compiler warnings. +version 1.0.8 [July 24, 2000] + Added png_flush() in pngwrite.c, after png_write_IEND(). + Updated makefile.hpux to build a shared library. +version 1.0.9beta1 [November 10, 2000] + Fixed typo in scripts/makefile.hpux + Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser) + Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser) + Changed "cdrom.com" in documentation to "libpng.org" + Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg). + Changed type of "params" from voidp to png_voidp in png_read|write_png(). + Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h. + Revised the 3 instances of WRITEFILE in pngtest.c. + Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory. + Updated png.rc in dll/msvc project + Revised makefile.dec to define and use LIBPATH and INCPATH + Increased size of global png_libpng_ver[] array from 12 to 18 chars. + Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const. + Removed duplicate png_crc_finish() from png_handle_bKGD() function. + Added a warning when application calls png_read_update_info() multiple times. + Revised makefile.cygwin + Fixed bugs in iCCP support in pngrutil.c and pngwutil.c. + Replaced png_set_empty_plte_permitted() with png_permit_mng_features(). +version 1.0.9beta2 [November 19, 2000] + Renamed the "dll" subdirectory "projects". + Added borland project files to "projects" subdirectory. + Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate. + Add error message in png_set_compression_buffer_size() when malloc fails. +version 1.0.9beta3 [November 23, 2000] + Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project. + Removed the png_flush() in pngwrite.c that crashes some applications + that don't set png_output_flush_fn. + Added makefile.macosx and makefile.aix to scripts directory. +version 1.0.9beta4 [December 1, 2000] + Change png_chunk_warning to png_warning in png_check_keyword(). + Increased the first part of msg buffer from 16 to 18 in png_chunk_error(). +version 1.0.9beta5 [December 15, 2000] + Added support for filter method 64 (for PNG datastreams embedded in MNG). +version 1.0.9beta6 [December 18, 2000] + Revised png_set_filter() to accept filter method 64 when appropriate. + Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to + help prevent applications from using MNG features in PNG datastreams. + Added png_permit_mng_features() function. + Revised libpng.3/libpng.txt. Changed "filter type" to "filter method". +version 1.0.9rc1 [December 23, 2000] + Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c + Fixed error handling of unknown compression type in png_decompress_chunk(). + In pngconf.h, define __cdecl when _MSC_VER is defined. +version 1.0.9beta7 [December 28, 2000] + Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places. + Revised memory management in png_set_hIST and png_handle_hIST in a backward + compatible manner. PLTE and tRNS were revised similarly. + Revised the iCCP chunk reader to ignore trailing garbage. +version 1.0.9beta8 [January 12, 2001] + Moved pngasmrd.h into pngconf.h. + Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop. +version 1.0.9beta9 [January 15, 2001] + Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to + wince and msvc project module definition files. + Minor revision of makefile.cygwin. + Fixed bug with progressive reading of narrow interlaced images in pngpread.c +version 1.0.9beta10 [January 16, 2001] + Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined. + Fixed "png_mmx_supported" typo in project definition files. +version 1.0.9beta11 [January 19, 2001] + Updated makefile.sgi to make shared library. + Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED + by default, for the benefit of DLL forward compatibility. These will + be re-enabled in version 1.2.0. +version 1.0.9rc2 [January 22, 2001] + Revised cygwin support. +version 1.0.9 [January 31, 2001] + Added check of cygwin's ALL_STATIC in pngconf.h + Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos. +version 1.0.10beta1 [March 14, 2001] + Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc. + Reformatted libpng.3 to eliminate bad line breaks. + Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c + Added prototype for png_mmx_support() near the top of pnggccrd.c + Moved some error checking from png_handle_IHDR to png_set_IHDR. + Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros. + Revised png_mmx_support() function in pnggccrd.c + Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c + Fixed memory leak in contrib/visupng/PngFile.c + Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version) + Added warnings when retrieving or setting gamma=0. + Increased the first part of msg buffer from 16 to 18 in png_chunk_warning(). +version 1.0.10rc1 [March 23, 2001] + Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy, + and png_strlen. + Revised png_mmx_supported() function in pnggccrd.c to return proper value. + Fixed bug in progressive reading (pngpread.c) with small images (height < 8). +version 1.0.10 [March 30, 2001] + Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin + Added beos project files (Chris Herborth) +version 1.0.11beta1 [April 3, 2001] + Added type casts on several png_malloc() calls (Dimitri Papadapoulos). + Removed a no-longer needed AIX work-around from pngconf.h + Changed several "//" single-line comments to C-style in pnggccrd.c +version 1.0.11beta2 [April 11, 2001] + Removed PNGAPI from several functions whose prototypes did not have PNGAPI. + Updated scripts/pngos2.def +version 1.0.11beta3 [April 14, 2001] + Added checking the results of many instances of png_malloc() for NULL +version 1.0.11beta4 [April 20, 2001] + Undid the changes from version 1.0.11beta3. Added a check for NULL return + from user's malloc_fn(). + Removed some useless type casts of the NULL pointer. + Added makefile.netbsd +version 1.0.11 [April 27, 2001] + Revised makefile.netbsd +version 1.0.12beta1 [May 17, 2001] + Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot) + Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h + Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings. + Bumped DLLNUM to 2. + Added a check for attempts to read or write PLTE in grayscale PNG datastreams. + Eliminated the png_error about apps using png_read|write_init(). Instead, + libpng will reallocate the png_struct and info_struct if they are too small. + This achieves future binary compatibility for old applications written for + libpng-0.88 and earlier. + Modified png_create_struct so it passes user mem_ptr to user memory allocator. +version 1.0.12rc1 [May 30, 2001] + Check for missing profile length field in iCCP chunk and free chunk_data + in case of truncated iCCP chunk. + Updated makefile.sgi and makefile.sggcc + Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly + if user attempts to run it on an 8-bit display. + Expanded the warnings about incompatible library and application. + Added netware project, distributed in a separate zip file. + Began distributing wince project in a separate zip file. +version 1.0.12 [June 8, 2001] + Fixed new "PLTE_PERMITTED" typo (should be PLTE_SUPPORTED) in pngwutil.c. + Updated contrib/gregbook + +Send comments/corrections/commendations to +png-implement@ccrc.wustl.edu or to randeg@alum.rpi.edu + +Glenn R-P diff --git a/freeimage241/Source/LibPNG/INSTALL b/freeimage241/Source/LibPNG/INSTALL new file mode 100644 index 0000000..1dc078e --- /dev/null +++ b/freeimage241/Source/LibPNG/INSTALL @@ -0,0 +1,136 @@ + +Installing libpng version 1.0.10 - March 30, 2001 + +Before installing libpng, you must first install zlib. zlib +can usually be found wherever you got libpng. zlib can be +placed in another directory, at the same level as libpng. +Note that your system might already have a preinstalled +zlib, but you will still need to have access to the +zlib.h and zconf.h include files that correspond to the +version of zlib that's installed. + +You can rename the directories that you downloaded (they +might be called "libpng-1.0.10" or "lpng109" and "zlib-1.1.3" +or "zlib113") so that you have directories called "zlib" and "libpng". + +Your directory structure should look like this: + + .. (the parent directory) + libpng (this directory) + INSTALL (this file) + README + *.h + *.c + contrib + gregbook + msvctest + pngminus + pngsuite + visupng + projects + beos + borland + msvc + wince + scripts + makefile.* + pngtest.png + etc. + zlib + README + *.h + *.c + contrib + etc. + +If the line endings in the files look funny, you may wish to get the other +distribution of libpng. It is available in both tar.gz (UNIX style line +endings) and zip (DOS style line endings) formats. + +If you are building libpng with MSVC, you can enter the libpng\msvc directory +and follow the instructions in msvc\README.txt. You can build libpng for +WindowsCE by entering the libpng\wince directory and following the +instructions in the README* files. + +Else enter the zlib directory and follow the instructions in zlib/README, +then come back here and choose the appropriate makefile.sys in the scripts +directory. + +The files that are presently available in the scripts directory +include + + makefile.std => Generic UNIX makefile (cc, creates static libpng.a) + makefile.linux => Linux/ELF makefile (gcc, creates libpng.so.2.1.0.10) + makefile.gcmmx => Linux/ELF makefile (gcc, creates libpng.so.2.1.0.10, + uses assembler code tuned for Intel MMX platform) + makefile.gcc => Generic makefile (gcc, creates static libpng.a) + makefile.knr => Archaic UNIX Makefile that converts files with + ansi2knr (Requires ansi2knr.c from + ftp://ftp.cs.wisc.edu/ghost) + makefile.aix => AIX makefile + makefile.cygwin => Cygwin/gcc makefile + makefile.dec => DEC Alpha UNIX makefile + makefile.hpgcc => HPUX makefile using gcc + makefile.hpux => HPUX (10.20 and 11.00) makefile + makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 (static) + makefile.intel => Intel C/C++ version 4.0 and later + libpng.icc => Project file for IBM VisualAge/C++ version 4.0 or later + makefile.macosx => MACOS X Makefile + makefile.sgi => Silicon Graphics IRIX makefile (cc, creates static lib) + makefile.sggcc => Silicon Graphics (gcc, creates libpng.so.2.1.0.10) + makefile.sunos => Sun makefile + makefile.solaris => Solaris 2.X makefile (gcc, creates libpng.so.2.1.0.10) + makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc + makefile.mips => MIPS makefile + makefile.acorn => Acorn makefile + makefile.amiga => Amiga makefile + smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC compiler + (Requires SCOPTIONS, copied from scripts/SCOPTIONS.ppc) + makefile.atari => Atari makefile + makefile.beos => BEOS makefile for X86 + makefile.bor => Borland makefile (uses bcc) + makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode) + makefile.bd32 => To make a png32bd.dll with Borland C++ 4.5 + makefile.tc3 => Turbo C 3.0 makefile + makefile.dj2 => DJGPP 2 makefile + makefile.msc => Microsoft C makefile + makefile.vcawin32 => makefile for Microsoft Visual C++ 5.0 and later (uses + assembler code tuned for Intel MMX platform) + makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and later (does + not use assembler code) + makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def) + pngos2.def => OS/2 module definition file used by makefile.os2 + makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model + makevms.com => VMS build script + descrip.mms => VMS makefile for MMS or MMK + pngdef.pas => Defines for a png32bd.dll with Borland C++ 4.5 + SCOPTIONS.ppc => Used with smakefile.ppc + +Copy the file (or files) that you need from the +scripts directory into this directory, for example + + MSDOS example: copy scripts\makefile.msc makefile + UNIX example: cp scripts/makefile.std makefile + +Read the makefile to see if you need to change any source or +target directories to match your preferences. + +Then read pngconf.h to see if you want to make any configuration +changes. + +Then just run "make test" which will create the libpng library in +this directory and run a quick test that reads the "pngtest.png" +file and writes a "pngout.png" file that should be identical to it. +Look for "9782 zero samples" in the output of the test. For more +confidence, you can run another test by typing "pngtest pngnow.png" +and looking for "289 zero samples" in the output. Also, you can +run "pngtest -m *.png" in the "contrib/pngsuite" directory and compare +your output with the result shown in contrib/pngsuite/README. + +Most of the makefiles will allow you to run "make install" to +put the library in its final resting place (if you want to +do that, run "make install" in the zlib directory first if necessary). + +Further information can be found in the README and libpng.txt +files, in the individual makefiles, in png.h, in the README files in +subdirectories of the LIB directory, and the manual pages libpng.3 and png.5. diff --git a/freeimage241/Source/LibPNG/KNOWNBUG b/freeimage241/Source/LibPNG/KNOWNBUG new file mode 100644 index 0000000..fb09e2f --- /dev/null +++ b/freeimage241/Source/LibPNG/KNOWNBUG @@ -0,0 +1,7 @@ + +Known bugs in libpng-1.0.12 + +1. April 22, 2001: pnggccrd.c has been reported to crash on NetBSD when + reading interlaced PNG files, when assembler code is enabled. + + STATUS: Under investigation. diff --git a/freeimage241/Source/LibPNG/LICENSE b/freeimage241/Source/LibPNG/LICENSE new file mode 100644 index 0000000..68f7381 --- /dev/null +++ b/freeimage241/Source/LibPNG/LICENSE @@ -0,0 +1,102 @@ + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +libpng versions 1.0.7, July 1, 2000, through 1.0.11, April 27, 2001, are +Copyright (c) 2000, 2001 Glenn Randers-Pehrson +and are distributed according to the same disclaimer and license as libpng-1.0.6 +with the following individuals added to the list of Contributing Authors + + Simon-Pierre Cadieux + Eric S. Raymond + Gilles Vollant + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are +distributed according to the same disclaimer and license as libpng-0.96, +with the following individuals added to the list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996, 1997 Andreas Dilger +Distributed according to the same disclaimer and license as libpng-0.88, +with the following individuals added to the list of Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + +1. The origin of this source code must not be misrepresented. + +2. Altered versions must be plainly marked as such and + must not be misrepresented as being the original source. + +3. This Copyright notice may not be removed or altered from + any source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + + +A "png_get_copyright" function is available, for convenient use in "about" +boxes and the like: + + printf("%s",png_get_copyright(NULL)); + +Also, the PNG logo (in PNG format, of course) is supplied in the +files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a +certification mark of the Open Source Initiative. + +Glenn Randers-Pehrson +randeg@alum.rpi.edu +April 27, 2001 diff --git a/freeimage241/Source/LibPNG/LibPNG.dsp b/freeimage241/Source/LibPNG/LibPNG.dsp new file mode 100644 index 0000000..b700b89 --- /dev/null +++ b/freeimage241/Source/LibPNG/LibPNG.dsp @@ -0,0 +1,172 @@ +# Microsoft Developer Studio Project File - Name="LibPNG" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=LibPNG - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LibPNG.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LibPNG.mak" CFG="LibPNG - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LibPNG - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "LibPNG - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/FreeImage/LibPNG", PJAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LibPNG - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "..\zlib" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "LibPNG - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\zlib" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "LibPNG - Win32 Release" +# Name "LibPNG - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\png.c +# End Source File +# Begin Source File + +SOURCE=.\pngerror.c +# End Source File +# Begin Source File + +SOURCE=.\pnggccrd.c +# End Source File +# Begin Source File + +SOURCE=.\pngget.c +# End Source File +# Begin Source File + +SOURCE=.\pngmem.c +# End Source File +# Begin Source File + +SOURCE=.\pngpread.c +# End Source File +# Begin Source File + +SOURCE=.\pngread.c +# End Source File +# Begin Source File + +SOURCE=.\pngrio.c +# End Source File +# Begin Source File + +SOURCE=.\pngrtran.c +# End Source File +# Begin Source File + +SOURCE=.\pngrutil.c +# End Source File +# Begin Source File + +SOURCE=.\pngset.c +# End Source File +# Begin Source File + +SOURCE=.\pngtest.c +# End Source File +# Begin Source File + +SOURCE=.\pngtrans.c +# End Source File +# Begin Source File + +SOURCE=.\pngvcrd.c +# End Source File +# Begin Source File + +SOURCE=.\pngwio.c +# End Source File +# Begin Source File + +SOURCE=.\pngwrite.c +# End Source File +# Begin Source File + +SOURCE=.\pngwtran.c +# End Source File +# Begin Source File + +SOURCE=.\pngwutil.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\png.h +# End Source File +# Begin Source File + +SOURCE=.\pngconf.h +# End Source File +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/LibPNG/README b/freeimage241/Source/LibPNG/README new file mode 100644 index 0000000..08b88aa --- /dev/null +++ b/freeimage241/Source/LibPNG/README @@ -0,0 +1,251 @@ +README for libpng 1.0.12 - June 8, 2001 (shared library 2.1) +See the note about version numbers near the top of png.h + +See INSTALL for instructions on how to install libpng. + +Libpng comes in two distribution formats. Get libpng-*.tar.gz if you +want UNIX-style line endings in the text files, or lpng*.zip if you want +DOS-style line endings. + +Version 0.89 was the first official release of libpng. Don't let the +fact that it's the first release fool you. The libpng library has been in +extensive use and testing since mid-1995. By late 1997 it had +finally gotten to the stage where there hadn't been significant +changes to the API in some time, and people have a bad feeling about +libraries with versions < 1.0. Version 1.0.0 was released in +March 1998. + +**** +Note that some of the changes to the png_info structure render this +version of the library binary incompatible with libpng-0.89 or +earlier versions if you are using a shared library. The type of the +"filler" parameter for png_set_filler() has changed from png_byte to +png_uint_32, which will affect shared-library applications that use +this function. + +To avoid problems with changes to the internals of png_info_struct, +new APIs have been made available in 0.95 to avoid direct application +access to info_ptr. These functions are the png_set_ and +png_get_ functions. These functions should be used when +accessing/storing the info_struct data, rather than manipulating it +directly, to avoid such problems in the future. + +It is important to note that the APIs do not make current programs +that access the info struct directly incompatible with the new +library. However, it is strongly suggested that new programs use +the new APIs (as shown in example.c and pngtest.c), and older programs +be converted to the new format, to facilitate upgrades in the future. +**** + +Additions since 0.90 include the ability to compile libpng as a +Windows DLL, and new APIs for accessing data in the info struct. +Experimental functions include the ability to set weighting and cost +factors for row filter selection, direct reads of integers from buffers +on big-endian processors that support misaligned data access, faster +methods of doing alpha composition, and more accurate 16->8 bit color +conversion. + +The additions since 0.89 include the ability to read from a PNG stream +which has had some (or all) of the signature bytes read by the calling +application. This also allows the reading of embedded PNG streams that +do not have the PNG file signature. As well, it is now possible to set +the library action on the detection of chunk CRC errors. It is possible +to set different actions based on whether the CRC error occurred in a +critical or an ancillary chunk. + +The changes made to the library, and bugs fixed are based on discussions +on the PNG implementation mailing list +and not on material submitted privately to Guy, Andreas, or Glenn. They will +forward any good suggestions to the list. + +For a detailed description on using libpng, read libpng.txt. For +examples of libpng in a program, see example.c and pngtest.c. For usage +information and restrictions (what little they are) on libpng, see +png.h. For a description on using zlib (the compression library used by +libpng) and zlib's restrictions, see zlib.h + +I have included a general makefile, as well as several machine and +compiler specific ones, but you may have to modify one for your own needs. + +You should use zlib 1.0.4 or later to run this, but it MAY work with +versions as old as zlib 0.95. Even so, there are bugs in older zlib +versions which can cause the output of invalid compression streams for +some images. You will definitely need zlib 1.0.4 or later if you are +taking advantage of the MS-DOS "far" structure allocation for the small +and medium memory models. You should also note that zlib is a +compression library that is useful for more things than just PNG files. +You can use zlib as a drop-in replacement for fread() and fwrite() if +you are so inclined. + +zlib should be available at the same place that libpng is. +If not, it should be at ftp.uu.net in /graphics/png +Eventually, it will be at ftp.uu.net in /pub/archiving/zip/zlib + +You may also want a copy of the PNG specification. It is available +as an RFC and a W3C Recommendation. Failing +these resources you can try ftp.uu.net in the /graphics/png directory. + +This code is currently being archived at ftp.uu.net in the +/graphics/png directory, and on CompuServe, Lib 20 (PNG SUPPORT) +at GO GRAPHSUP. If you can't find it in any of those places, +e-mail me, and I'll help you find it. + +If you have any code changes, requests, problems, etc., please e-mail +them to me. Also, I'd appreciate any make files or project files, +and any modifications you needed to make to get libpng to compile, +along with a #define variable to tell what compiler/system you are on. +If you needed to add transformations to libpng, or wish libpng would +provide the image in a different way, drop me a note (and code, if +possible), so I can consider supporting the transformation. +Finally, if you get any warning messages when compiling libpng +(note: not zlib), and they are easy to fix, I'd appreciate the +fix. Please mention "libpng" somewhere in the subject line. Thanks. + +This release was created and will be supported by myself (of course +based in a large way on Guy's and Andreas' earlier work), and the PNG group. + +randeg@alum.rpi.edu +png-implement@ccrc.wustl.edu + +You can't reach Guy, the original libpng author, at the addresses +given in previous versions of this document. He and Andreas will read mail +addressed to the png-implement list, however. + +Please do not send general questions about PNG. Send them to +the address in the specification (png-group@w3.org). At the same +time, please do not send libpng questions to that address, send them to me +or to png-implement@ccrc.wustl.edu. I'll +get them in the end anyway. If you have a question about something +in the PNG specification that is related to using libpng, send it +to me. Send me any questions that start with "I was using libpng, +and ...". If in doubt, send questions to me. I'll bounce them +to others, if necessary. + +Please do not send suggestions on how to change PNG. We have +been discussing PNG for three years now, and it is official and +finished. If you have suggestions for libpng, however, I'll +gladly listen. Even if your suggestion is not used for version +1.0, it may be used later. + +Files in this distribution: + + ANNOUNCE => Announcement of this version, with recent changes + CHANGES => Description of changes between libpng versions + KNOWNBUG => List of known bugs and deficiencies + LICENSE => License to use and redistribute libpng + README => This file + TODO => Things not implemented in the current library + Y2KINFO => Statement of Y2K compliance + example.c => Example code for using libpng functions + libpng.3 => manual page for libpng (includes libpng.txt) + libpng.txt => Description of libpng and its functions + libpngpf.3 => manual page for libpng's private functions + png.5 => manual page for the PNG format + png.c => Basic interface functions common to library + png.h => Library function and interface declarations + pngconf.h => System specific library configuration + pngasmrd.h => Header file for assembler-coded functions + pngerror.c => Error/warning message I/O functions + pngget.c => Functions for retrieving info from struct + pngmem.c => Memory handling functions + pngbar.png => PNG logo, 88x31 + pngnow.png => PNG logo, 98x31 + pngpread.c => Progressive reading functions + pngread.c => Read data/helper high-level functions + pngrio.c => Lowest-level data read I/O functions + pngrtran.c => Read data transformation functions + pngrutil.c => Read data utility functions + pngset.c => Functions for storing data into the info_struct + pngtest.c => Library test program + pngtest.png => Library test sample image + pngtrans.c => Common data transformation functions + pngwio.c => Lowest-level write I/O functions + pngwrite.c => High-level write functions + pngwtran.c => Write data transformations + pngwutil.c => Write utility functions + contrib => Contributions + gregbook => source code for PNG reading and writing, from + Greg Roelofs' "PNG: The Definitive Guide", + O'Reilly, 1999 + msvctest => Builds and runs pngtest using a MSVC workspace + pngminus => Simple pnm2png and png2pnm programs + pngsuite => Test images + visupng => Contains a MSVC workspace for VisualPng + projects => Contains project files and workspaces for building DLL + beos => Contains a Beos workspace for building libpng + borland => Contains a Borland workspace for building libpng + and zlib + msvc => Contains a Microsoft Visual C++ (MSVC) workspace + for building libpng and zlib + netware.txt => Contains instructions for downloading a set of + project files for building libpng and zlib on + Netware. + wince.txt => Contains instructions for downloading a Microsoft + Visual C++ (Windows CD Toolkit) workspace for + building libpng and zlib on WindowsCE + scripts => Directory containing scripts for building libpng: + descrip.mms => VMS makefile for MMS or MMK + makefile.std => Generic UNIX makefile (cc, creates static libpng.a) + makefile.linux => Linux/ELF makefile + (gcc, creates libpng.so.2.1.0.12) + makefile.gcmmx => Linux/ELF makefile (gcc, creates + libpng.so.2.1.0.12, uses assembler code + tuned for Intel MMX platform) + makefile.gcc => Generic makefile (gcc, creates static libpng.a) + makefile.knr => Archaic UNIX Makefile that converts files with + ansi2knr (Requires ansi2knr.c from + ftp://ftp.cs.wisc.edu/ghost) + makefile.aix => AIX makefile + makefile.cygwin => Cygwin/gcc makefile + makefile.dec => DEC Alpha UNIX makefile + makefile.hpgcc => HPUX makefile using gcc + makefile.hpux => HPUX (10.20 and 11.00) makefile + makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 (static) + makefile.intel => Intel C/C++ version 4.0 and later + libpng.icc => Project file, IBM VisualAge/C++ 4.0 or later + makefile.macosx => MACOS X Makefile + makefile.netbsd => NetBSD/cc makefile, uses PNGGCCRD + makefile.sgi => Silicon Graphics IRIX (cc, creates static lib) + makefile.sggcc => Silicon Graphics (gcc, creates libpng.so.2.1.0.12) + makefile.sunos => Sun makefile + makefile.solaris => Solaris 2.X makefile + (gcc, creates libpng.so.2.1.0.12) + makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc + makefile.mips => MIPS makefile + makefile.acorn => Acorn makefile + makefile.amiga => Amiga makefile + smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC + compiler (Requires SCOPTIONS, copied from + scripts/SCOPTIONS.ppc) + makefile.atari => Atari makefile + makefile.beos => BEOS makefile for X86 + makefile.bor => Borland makefile (uses bcc) + makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode) + makefile.bd32 => To make a png32bd.dll with Borland C++ 4.5 + makefile.tc3 => Turbo C 3.0 makefile + makefile.dj2 => DJGPP 2 makefile + makefile.msc => Microsoft C makefile + makefile.vcawin32 => makefile for Microsoft Visual C++ 5.0 and + later (uses assembler code tuned for Intel MMX + platform) + makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and + later (does not use assembler code) + makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def) + pngos2.def => OS/2 module definition file used by makefile.os2 + makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model + makevms.com => VMS build script + pngdef.pas => Defines for a png32bd.dll with Borland C++ 4.5 + SCOPTIONS.ppc => Used with smakefile.ppc + +Good luck, and happy coding. + +-Glenn Randers-Pehrson + Internet: randeg@alum.rpi.edu + +-Andreas Eric Dilger + Internet: adilger@enel.ucalgary.ca + Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/ + +-Guy Eric Schalnat + (formerly of Group 42, Inc) + Internet: gschal@infinet.com diff --git a/freeimage241/Source/LibPNG/TODO b/freeimage241/Source/LibPNG/TODO new file mode 100644 index 0000000..a5f6395 --- /dev/null +++ b/freeimage241/Source/LibPNG/TODO @@ -0,0 +1,24 @@ +TODO - list of things to do for libpng: + +Final bug fixes. +Improve API by hiding the png_struct and png_info structs. +Finish work on the no-floating-point version (including gamma compensation) +Better C++ wrapper/full C++ implementation? +Fix problem with C++ and EXTERN "C". +cHRM transformation. +Improve setjmp/longjmp usage or remove it in favor of returning error codes. +Add "grayscale->palette" transformation and "palette->grayscale" detection. +Improved dithering. +Multi-lingual error and warning message support. +Complete sRGB transformation (presently it simply uses gamma=0.45455). +Man pages for function calls. +Better documentation. +Better filter selection + (counting huffman bits/precompression? filter inertia? filter costs?). +Histogram creation. +Text conversion between different code pages (Latin-1 -> Mac and DOS). +Should we always malloc 2^bit_depth PLTE/tRNS/hIST entries for safety? +Build gamma tables using fixed point (and do away with floating point entirely). +Use greater precision when changing to linear gamma for compositing against + background and doing rgb-to-gray transformation. +Investigate pre-incremented loop counters and other loop constructions. diff --git a/freeimage241/Source/LibPNG/Y2KINFO b/freeimage241/Source/LibPNG/Y2KINFO new file mode 100644 index 0000000..84feed2 --- /dev/null +++ b/freeimage241/Source/LibPNG/Y2KINFO @@ -0,0 +1,55 @@ + Y2K compliance in libpng: + ========================= + + April 27, 2001 + + Since the PNG Development group is an ad-hoc body, we can't make + an official declaration. + + This is your unofficial assurance that libpng from version 0.71 and + upward through 1.0.11 are Y2K compliant. It is my belief that earlier + versions were also Y2K compliant. + + Libpng only has three year fields. One is a 2-byte unsigned integer + that will hold years up to 65535. The other two hold the date in text + format, and will hold years up to 9999. + + The integer is + "png_uint_16 year" in png_time_struct. + + The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + + There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + + All appear to handle dates properly in a Y2K environment. The + png_convert_from_time_t() function calls gmtime() to convert from system + clock time, which returns (year - 1900), which we properly convert to + the full 4-digit year. There is a possibility that applications using + libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + function, or that they are incorrectly passing only a 2-digit year + instead of "year - 1900" into the png_convert_from_struct_tm() function, + but this is not under our control. The libpng documentation has always + stated that it works with 4-digit years, and the APIs have been + documented as such. + + The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned + integer to hold the year, and can hold years as large as 65535. + + zlib, upon which libpng depends, is also Y2K compliant. It contains + no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group diff --git a/freeimage241/Source/LibPNG/configure b/freeimage241/Source/LibPNG/configure new file mode 100644 index 0000000..18b0cdc --- /dev/null +++ b/freeimage241/Source/LibPNG/configure @@ -0,0 +1,6 @@ +echo " + There is no \"configure\" script for Libpng-1.0.10. Instead, please + copy the appropriate makefile for your system from the \"scripts\" + directory. Read the INSTALL file for more details. +" + diff --git a/freeimage241/Source/LibPNG/example.c b/freeimage241/Source/LibPNG/example.c new file mode 100644 index 0000000..f0fe688 --- /dev/null +++ b/freeimage241/Source/LibPNG/example.c @@ -0,0 +1,778 @@ + +#if 0 /* in case someone actually tries to compile this */ + +/* example.c - an example of using libpng */ + +/* This is an example of how to use libpng to read and write PNG files. + * The file libpng.txt is much more verbose then this. If you have not + * read it, do so first. This was designed to be a starting point of an + * implementation. This is not officially part of libpng, is hereby placed + * in the public domain, and therefore does not require a copyright notice. + * + * This file does not currently compile, because it is missing certain + * parts, like allocating memory to hold an image. You will have to + * supply these parts to get it to compile. For an example of a minimal + * working PNG reader/writer, see pngtest.c, included in this distribution; + * see also the programs in the contrib directory. + */ + +#include "png.h" + + /* The png_jmpbuf() macro, used in error handling, became available in + * libpng version 1.0.6. If you want to be able to run your code with older + * versions of libpng, you must define the macro yourself (but only if it + * is not already defined by libpng!). + */ + +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() + * returns zero if the image is a PNG and nonzero if it isn't a PNG. + * + * The function check_if_png() shown here, but not used, returns nonzero (true) + * if the file can be opened and is a PNG, 0 (false) otherwise. + * + * If this call is successful, and you are going to keep the file open, + * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once + * you have created the png_ptr, so that libpng knows your application + * has read that many bytes from the start of the file. Make sure you + * don't call png_set_sig_bytes() with more than 8 bytes read or give it + * an incorrect number of bytes read, or you will either have read too + * many bytes (your fault), or you are telling libpng to read the wrong + * number of magic bytes (also your fault). + * + * Many applications already read the first 2 or 4 bytes from the start + * of the image to determine the file type, so it would be easiest just + * to pass the bytes to png_sig_cmp() or even skip that if you know + * you have a PNG file, and call png_set_sig_bytes(). + */ +#define PNG_BYTES_TO_CHECK 4 +int check_if_png(char *file_name, FILE **fp) +{ + char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if ((*fp = fopen(file_name, "rb")) == NULL) + return 0; + + /* Read in some of the signature bytes */ + if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) + return 0; + + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + Return nonzero (true) if they match */ + + return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); +} + +/* Read a PNG file. You may want to return an error code if the read + * fails (depending upon the failure). There are two "prototypes" given + * here - one where we are given the filename, and we need to open the + * file, and the other where we are given an open file (possibly with + * some or all of the magic bytes read - see comments above). + */ +#ifdef open_file /* prototype 1 */ +void read_png(char *file_name) /* We need to open the file */ +{ + png_structp png_ptr; + png_infop info_ptr; + unsigned int sig_read = 0; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + FILE *fp; + + if ((fp = fopen(file_name, "rb")) == NULL) + return (ERROR); +#else no_open_file /* prototype 2 */ +void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; +#endif no_open_file /* only use one prototype! */ + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also supply the + * the compiler header file version, so that we know if the application + * was compiled with a compatible version of the library. REQUIRED + */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the memory for image information. REQUIRED. */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + /* Set error handling if you are using the setjmp/longjmp method (this is + * the normal method of doing things with libpng). REQUIRED unless you + * set up your own error handlers in the png_create_read_struct() earlier. + */ + + if (setjmp(png_jmpbuf(png_ptr))) + { + /* Free all of the memory associated with the png_ptr and info_ptr */ + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fp); + /* If we get here, we had a problem reading the file */ + return (ERROR); + } + + /* One of the following I/O initialization methods is REQUIRED */ +#ifdef streams /* PNG file I/O method 1 */ + /* Set up the input control if you are using standard C streams */ + png_init_io(png_ptr, fp); + +#else no_streams /* PNG file I/O method 2 */ + /* If you are using replacement read functions, instead of calling + * png_init_io() here you would call: + */ + png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* Use only one I/O method! */ + + /* If we have already read some of the signature */ + png_set_sig_bytes(png_ptr, sig_read); + +#ifdef hilevel + /* + * If you have enough memory to read in the entire image at once, + * and you need to specify only transforms that can be controlled + * with one of the PNG_TRANSFORM_* bits (this presently excludes + * dithering, filling, setting background, and doing gamma + * adjustment), then you can read the entire image (including + * pixels) into the info structure with this call: + */ + png_read_png(png_ptr, info_ptr, png_transforms, NULL); +#else + /* OK, you're doing it the hard way, with the lower-level functions */ + + /* The call to png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). REQUIRED + */ + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, NULL, NULL); + +/**** Set up the data transformations you want. Note that these are all + **** optional. Only call them if you want/need them. Many of the + **** transformations only work on specific types of images, and many + **** are mutually exclusive. + ****/ + + /* tell libpng to strip 16 bit/color files down to 8 bits/color */ + png_set_strip_16(png_ptr); + + /* Strip alpha bytes from the input data without combining with the + * background (not recommended). + */ + png_set_strip_alpha(png_ptr); + + /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + png_set_packing(png_ptr); + + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). */ + png_set_packswap(png_ptr); + + /* Expand paletted colors into true RGB triplets */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + + /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png_ptr); + + /* Expand paletted or RGB images with transparency to full alpha channels + * so the data will be available as RGBA quartets. + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + + /* Set the background color to draw transparent and alpha images over. + * It is possible to set the red, green, and blue components directly + * for paletted images instead of supplying a palette index. Note that + * even if the PNG file supplies a background, you are not required to + * use it - you should use the (solid) application background if it has one. + */ + + png_color_16 my_background, *image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + /* Some suggestions as to how to get a screen gamma value */ + + /* Note that screen gamma is the display_exponent, which includes + * the CRT_exponent and any correction for viewing conditions */ + if (/* We have a user-defined screen gamma value */) + { + screen_gamma = user-defined screen_gamma; + } + /* This is one way that applications share the same screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) + { + screen_gamma = atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly + lit room */ + screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ + } + + /* Tell libpng to handle the gamma conversion for you. The final call + * is a good guess for PC generated images, but it should be configurable + * by the user at run time by the user. It is strongly suggested that + * your application support gamma correction. + */ + + int intent; + + if (png_get_sRGB(png_ptr, info_ptr, &intent)) + png_set_gamma(png_ptr, screen_gamma, 0.45455); + else + { + double image_gamma; + if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) + png_set_gamma(png_ptr, screen_gamma, image_gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + } + + /* Dither RGB files down to 8 bit palette or reduce palettes + * to the number of colors available on your screen. + */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + int num_palette; + png_colorp palette; + + /* This reduces the image to the application supplied palette */ + if (/* we have our own palette */) + { + /* An array of colors to which the image should be dithered */ + png_color std_color_cube[MAX_SCREEN_COLORS]; + + png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, + MAX_SCREEN_COLORS, NULL, 0); + } + /* This reduces the image to the palette supplied in the file */ + else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) + { + png_uint_16p histogram; + + png_get_hIST(png_ptr, info_ptr, &histogram); + + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 0); + } + } + + /* invert monochrome files to have 0 as white and 1 as black */ + png_set_invert_mono(png_ptr); + + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, sig_bit); + } + + /* flip the RGB pixels to BGR (or RGBA to BGRA) */ + if (color_type & PNG_COLOR_MASK_COLOR) + png_set_bgr(png_ptr); + + /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + png_set_swap_alpha(png_ptr); + + /* swap bytes of 16 bit files to least significant byte first */ + png_set_swap(png_ptr); + + /* Add filler (or alpha) byte (before/after each RGB triplet) */ + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + + /* Turn on interlace handling. REQUIRED if you are not using + * png_read_image(). To see how to handle interlacing passes, + * see the png_read_row() method below: + */ + number_passes = png_set_interlace_handling(png_ptr); + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (ie you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* Allocate the memory to hold the image using the fields of info_ptr. */ + + /* The easiest way to read the image: */ + png_bytep row_pointers[height]; + + for (row = 0; row < height; row++) + { + row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, + info_ptr)); + } + + /* Now it's time to read the image. One of these methods is REQUIRED */ +#ifdef entire /* Read the entire image in one go */ + png_read_image(png_ptr, row_pointers); + +#else no_entire /* Read the image one or more scanlines at a time */ + /* The other way to read images - deal with interlacing: */ + + for (pass = 0; pass < number_passes; pass++) + { +#ifdef single /* Read the image a single row at a time */ + for (y = 0; y < height; y++) + { + png_read_rows(png_ptr, &row_pointers[y], NULL, 1); + } + +#else no_single /* Read the image several rows at a time */ + for (y = 0; y < height; y += number_of_rows) + { +#ifdef sparkle /* Read the image using the "sparkle" effect. */ + png_read_rows(png_ptr, &row_pointers[y], NULL, number_of_rows); + + png_read_rows(png_ptr, NULL, row_pointers[y], number_of_rows); +#else no_sparkle /* Read the image using the "rectangle" effect */ + png_read_rows(png_ptr, NULL, &row_pointers[y], number_of_rows); +#endif no_sparkle /* use only one of these two methods */ + } + + /* if you want to display the image after every pass, do + so here */ +#endif no_single /* use only one of these two methods */ + } +#endif no_entire /* use only one of these two methods */ + + /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); +#endif hilevel + + /* At this point you have read the entire image */ + + /* clean up after the read, and free any memory allocated - REQUIRED */ + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + /* close the file */ + fclose(fp); + + /* that's it */ + return (OK); +} + +/* progressively read a file */ + +int +initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) +{ + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible in case we are using dynamically + * linked libraries. + */ + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (*png_ptr == NULL) + { + *info_ptr = NULL; + return (ERROR); + } + + *info_ptr = png_create_info_struct(png_ptr); + + if (*info_ptr == NULL) + { + png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf((*png_ptr)))) + { + png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You will need to provide all three + * function callbacks, even if you aren't using them all. + * If you aren't using all functions, you can specify NULL + * parameters. Even when all three functions are NULL, + * you need to call png_set_progressive_read_fn(). + * These functions shouldn't be dependent on global or + * static variables if you are decoding several images + * simultaneously. You should store stream specific data + * in a separate struct, given as the second parameter, + * and retrieve the pointer from inside the callbacks using + * the function png_get_progressive_ptr(png_ptr). + */ + png_set_progressive_read_fn(*png_ptr, (void *)stream_data, + info_callback, row_callback, end_callback); + + return (OK); +} + +int +process_data(png_structp *png_ptr, png_infop *info_ptr, + png_bytep buffer, png_uint_32 length) +{ + if (setjmp(png_jmpbuf((*png_ptr)))) + { + /* Free the png_ptr and info_ptr memory on error */ + png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it chunks of data as + * they arrive from the data stream (in order, of course). + * On Segmented machines, don't give it any more than 64K. + * The library seems to run fine with sizes of 4K, although + * you can give it much less if necessary (I assume you can + * give it chunks of 1 byte, but I haven't tried with less + * than 256 bytes yet). When this function returns, you may + * want to display any rows that were generated in the row + * callback, if you aren't already displaying them there. + */ + png_process_data(*png_ptr, *info_ptr, buffer, length); + return (OK); +} + +info_callback(png_structp png_ptr, png_infop info) +{ +/* do any setup here, including setting any of the transformations + * mentioned in the Reading PNG files section. For now, you _must_ + * call either png_start_read_image() or png_read_update_info() + * after all the transformations are set (even if you don't set + * any). You may start getting rows before png_process_data() + * returns, so this is your last chance to prepare for that. + */ +} + +row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) +{ +/* this function is called for every row in the image. If the + * image is interlacing, and you turned on the interlace handler, + * this function will be called for every row in every pass. + * Some of these rows will not be changed from the previous pass. + * When the row is not changed, the new_row variable will be NULL. + * The rows and passes are called in order, so you don't really + * need the row_num and pass, but I'm supplying them because it + * may make your life easier. + * + * For the non-NULL rows of interlaced images, you must call + * png_progressive_combine_row() passing in the row and the + * old row. You can call this function for NULL rows (it will + * just return) and for non-interlaced images (it just does the + * png_memcpy for you) if it will make the code easier. Thus, you + * can just do this for all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, new_row); + +/* where old_row is what was displayed for previous rows. Note + * that the first pass (pass == 0 really) will completely cover + * the old row, so the rows do not have to be initialized. After + * the first pass (and only for interlaced images), you will have + * to pass the current row, and the function will combine the + * old row and the new row. + */ +} + +end_callback(png_structp png_ptr, png_infop info) +{ +/* this function is called when the whole image has been read, + * including any chunks after the image (up to and including + * the IEND). You will usually have the same info chunk as you + * had in the header, although some data may have been added + * to the comments and time fields. + * + * Most people won't do much here, perhaps setting a flag that + * marks the image as finished. + */ +} + +/* write a png file */ +void write_png(char *file_name /* , ... other image information ... */) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette; + + /* open the file */ + fp = fopen(file_name, "wb"); + if (fp == NULL) + return (ERROR); + + /* Create and initialize the png_struct with the desired error handler + * functions. If you want to use the default stderr and longjump method, + * you can supply NULL for the last three parameters. We also check that + * the library version is compatible with the one used at compile time, + * in case we are using dynamically linked libraries. REQUIRED. + */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + png_voidp user_error_ptr, user_error_fn, user_warning_fn); + + if (png_ptr == NULL) + { + fclose(fp); + return (ERROR); + } + + /* Allocate/initialize the image information data. REQUIRED */ + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + fclose(fp); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return (ERROR); + } + + /* Set error handling. REQUIRED if you aren't supplying your own + * error handling functions in the png_create_write_struct() call. + */ + if (setjmp(png_jmpbuf(png_ptr))) + { + /* If we get here, we had a problem reading the file */ + fclose(fp); + png_destroy_write_struct(&png_ptr, &info_ptr); + return (ERROR); + } + + /* One of the following I/O initialization functions is REQUIRED */ +#ifdef streams /* I/O initialization method 1 */ + /* set up the output control if you are using standard C streams */ + png_init_io(png_ptr, fp); +#else no_streams /* I/O initialization method 2 */ + /* If you are using replacement read functions, instead of calling + * png_init_io() here you would call */ + png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, + user_IO_flush_function); + /* where user_io_ptr is a structure you want available to the callbacks */ +#endif no_streams /* only use one initialization method */ + +#ifdef hilevel + /* This is the easy way. Use it if you already have all the + * image info living info in the structure. You could "|" many + * PNG_TRANSFORM flags into the png_transforms integer here. + */ + png_write_png(png_ptr, info_ptr, png_transforms, NULL); +#else + /* This is the hard way */ + + /* Set the image information here. Width and height are up to 2^31, + * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on + * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, + * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, + * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or + * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST + * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED + */ + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, + PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* set the palette if there is one. REQUIRED for indexed-color images */ + palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH + * sizeof (png_color)); + /* ... set palette colors ... */ + png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); + /* You must not free palette here, because png_set_PLTE only makes a link to + the palette that you malloced. Wait until you are about to destroy + the png structure. */ + + /* optional significant bit chunk */ + /* if we are dealing with a grayscale image then */ + sig_bit.gray = true_bit_depth; + /* otherwise, if we are dealing with a color image then */ + sig_bit.red = true_red_bit_depth; + sig_bit.green = true_green_bit_depth; + sig_bit.blue = true_blue_bit_depth; + /* if the image has an alpha channel then */ + sig_bit.alpha = true_alpha_bit_depth; + png_set_sBIT(png_ptr, info_ptr, sig_bit); + + + /* Optional gamma chunk is strongly suggested if you have any guess + * as to the correct gamma of the image. + */ + png_set_gAMA(png_ptr, info_ptr, gamma); + + /* Optionally write comments into the image */ + text_ptr[0].key = "Title"; + text_ptr[0].text = "Mona Lisa"; + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[1].key = "Author"; + text_ptr[1].text = "Leonardo DaVinci"; + text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr[2].key = "Description"; + text_ptr[2].text = ""; + text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; +#ifdef PNG_iTXt_SUPPORTED + text_ptr[0].lang = NULL; + text_ptr[1].lang = NULL; + text_ptr[2].lang = NULL; +#endif + png_set_text(png_ptr, info_ptr, text_ptr, 3); + + /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ + /* note that if sRGB is present the gAMA and cHRM chunks must be ignored + * on read and must be written in accordance with the sRGB profile */ + + /* Write the file header information. REQUIRED */ + png_write_info(png_ptr, info_ptr); + + /* If you want, you can write the info in two steps, in case you need to + * write your private chunk ahead of PLTE: + * + * png_write_info_before_PLTE(write_ptr, write_info_ptr); + * write_my_chunk(); + * png_write_info(png_ptr, info_ptr); + * + * However, given the level of known- and unknown-chunk support in 1.1.0 + * and up, this should no longer be necessary. + */ + + /* Once we write out the header, the compression type on the text + * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or + * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again + * at the end. + */ + + /* set up the transformations you want. Note that these are + * all optional. Only call them if you want them. + */ + + /* invert monochrome pixels */ + png_set_invert_mono(png_ptr); + + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + png_set_shift(png_ptr, &sig_bit); + + /* pack pixels into bytes */ + png_set_packing(png_ptr); + + /* swap location of alpha bytes from ARGB to RGBA */ + png_set_swap_alpha(png_ptr); + + /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into + * RGB (4 channels -> 3 channels). The second parameter is not used. + */ + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + + /* flip BGR pixels to RGB */ + png_set_bgr(png_ptr); + + /* swap bytes of 16-bit files to most significant byte first */ + png_set_swap(png_ptr); + + /* swap bits of 1, 2, 4 bit packed pixel formats */ + png_set_packswap(png_ptr); + + /* turn on interlace handling if you are not using png_write_image() */ + if (interlacing) + number_passes = png_set_interlace_handling(png_ptr); + else + number_passes = 1; + + /* The easiest way to write the image (you may have a different memory + * layout, however, so choose what fits your needs best). You need to + * use the first method if you aren't handling interlacing yourself. + */ + png_uint_32 k, height, width; + png_byte image[height][width*bytes_per_pixel]; + png_bytep row_pointers[height]; + for (k = 0; k < height; k++) + row_pointers[k] = image + k*width*bytes_per_pixel; + + /* One of the following output methods is REQUIRED */ +#ifdef entire /* write out the entire image data in one call */ + png_write_image(png_ptr, row_pointers); + + /* the other way to write the image - deal with interlacing */ + +#else no_entire /* write out the image data by one or more scanlines */ + /* The number of passes is either 1 for non-interlaced images, + * or 7 for interlaced images. + */ + for (pass = 0; pass < number_passes; pass++) + { + /* Write a few rows at a time. */ + png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); + + /* If you are only writing one row at a time, this works */ + for (y = 0; y < height; y++) + { + png_write_rows(png_ptr, &row_pointers[y], 1); + } + } +#endif no_entire /* use only one output method */ + + /* You can write optional chunks like tEXt, zTXt, and tIME at the end + * as well. Shouldn't be necessary in 1.1.0 and up as all the public + * chunks are supported and you can use png_set_unknown_chunks() to + * register unknown chunks into the info structure to be written out. + */ + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); +#endif hilevel + + /* If you png_malloced a palette, free it here (don't free info_ptr->palette, + as recommended in versions 1.0.5m and earlier of this example; if + libpng mallocs info_ptr->palette, libpng will free it). If you + allocated it with malloc() instead of png_malloc(), use free() instead + of png_free(). */ + png_free(png_ptr, palette); + palette=NULL; + + /* Similarly, if you png_malloced any data that you passed in with + png_set_something(), such as a hist or trans array, free it here, + when you can be sure that libpng is through with it. */ + png_free(png_ptr, trans); + trans=NULL; + + /* clean up after the write, and free any memory allocated */ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /* close the file */ + fclose(fp); + + /* that's it */ + return (OK); +} + +#endif /* if 0 */ diff --git a/freeimage241/Source/LibPNG/libpng.txt b/freeimage241/Source/LibPNG/libpng.txt new file mode 100644 index 0000000..6164057 --- /dev/null +++ b/freeimage241/Source/LibPNG/libpng.txt @@ -0,0 +1,2776 @@ +libpng.txt - A description on how to use and modify libpng + + libpng version 1.0.12 - June 8, 2001 + Updated and distributed by Glenn Randers-Pehrson + + Copyright (c) 1998-2001 Glenn Randers-Pehrson + For conditions of distribution and use, see copyright + notice in png.h. + + based on: + + libpng 1.0 beta 6 version 0.96 May 28, 1997 + Updated and distributed by Andreas Dilger + Copyright (c) 1996, 1997 Andreas Dilger + + libpng 1.0 beta 2 - version 0.88 January 26, 1996 + For conditions of distribution and use, see copyright + notice in png.h. Copyright (c) 1995, 1996 Guy Eric + Schalnat, Group 42, Inc. + + Updated/rewritten per request in the libpng FAQ + Copyright (c) 1995, 1996 Frank J. T. Wojcik + December 18, 1995 & January 20, 1996 + +I. Introduction + +This file describes how to use and modify the PNG reference library +(known as libpng) for your own use. There are five sections to this +file: introduction, structures, reading, writing, and modification and +configuration notes for various special platforms. In addition to this +file, example.c is a good starting point for using the library, as +it is heavily commented and should include everything most people +will need. We assume that libpng is already installed; see the +INSTALL file for instructions on how to install libpng. + +Libpng was written as a companion to the PNG specification, as a way +of reducing the amount of time and effort it takes to support the PNG +file format in application programs. + +The PNG-1.2 specification is available at +and at . + +The PNG-1.0 specification is available +as RFC 2083 and as a +W3C Recommendation . Some +additional chunks are described in the special-purpose public chunks +documents at . + +Other information +about PNG, and the latest version of libpng, can be found at the PNG home +page, +and at . + +Most users will not have to modify the library significantly; advanced +users may want to modify it more. All attempts were made to make it as +complete as possible, while keeping the code easy to understand. +Currently, this library only supports C. Support for other languages +is being considered. + +Libpng has been designed to handle multiple sessions at one time, +to be easily modifiable, to be portable to the vast majority of +machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy +to use. The ultimate goal of libpng is to promote the acceptance of +the PNG file format in whatever way possible. While there is still +work to be done (see the TODO file), libpng should cover the +majority of the needs of its users. + +Libpng uses zlib for its compression and decompression of PNG files. +Further information about zlib, and the latest version of zlib, can +be found at the zlib home page, . +The zlib compression utility is a general purpose utility that is +useful for more than PNG files, and can be used without libpng. +See the documentation delivered with zlib for more details. +You can usually find the source files for the zlib utility wherever you +find the libpng source files. + +Libpng is thread safe, provided the threads are using different +instances of the structures. Each thread should have its own +png_struct and png_info instances, and thus its own image. +Libpng does not protect itself against two threads using the +same instance of a structure. + + +II. Structures + +There are two main structures that are important to libpng, png_struct +and png_info. The first, png_struct, is an internal structure that +will not, for the most part, be used by a user except as the first +variable passed to every libpng function call. + +The png_info structure is designed to provide information about the +PNG file. At one time, the fields of png_info were intended to be +directly accessible to the user. However, this tended to cause problems +with applications using dynamically loaded libraries, and as a result +a set of interface functions for png_info (the png_get_*() and png_set_*() +functions) was developed. The fields of png_info are still available for +older applications, but it is suggested that applications use the new +interfaces if at all possible. + +Applications that do make direct access to the members of png_struct (except +for png_ptr->jmpbuf) must be recompiled whenever the library is updated, +and applications that make direct access to the members of png_info must +be recompiled if they were compiled or loaded with libpng version 1.0.6, +in which the members were in a different order. In version 1.0.7, the +members of the png_info structure reverted to the old order, as they were +in versions 0.97c through 1.0.5. Starting with version 2.0.0, both +structures are going to be hidden, and the contents of the structures will +only be accessible through the png_get/png_set functions. + +The png.h header file is an invaluable reference for programming with libpng. +And while I'm on the topic, make sure you include the libpng header file: + +#include + +III. Reading + +We'll now walk you through the possible functions to call when reading +in a PNG file sequentially, briefly explaining the syntax and purpose +of each one. See example.c and png.h for more detail. While +progressive reading is covered in the next section, you will still +need some of the functions discussed in this section to read a PNG +file. + +Setup + +You will want to do the I/O initialization(*) before you get into libpng, +so if it doesn't work, you don't have much to undo. Of course, you +will also want to insure that you are, in fact, dealing with a PNG +file. Libpng provides a simple check to see if a file is a PNG file. +To use it, pass in the first 1 to 8 bytes of the file to the function +png_sig_cmp(), and it will return 0 if the bytes match the corresponding +bytes of the PNG signature, or nonzero otherwise. Of course, the more bytes +you pass in, the greater the accuracy of the prediction. + +If you are intending to keep the file pointer open for use in libpng, +you must ensure you don't read more than 8 bytes from the beginning +of the file, and you also have to make a call to png_set_sig_bytes_read() +with the number of bytes you read from the beginning. Libpng will +then only check the bytes (if any) that your program didn't read. + +(*): If you are not using the standard I/O functions, you will need +to replace them with custom functions. See the discussion under +Customizing libpng. + + + FILE *fp = fopen(file_name, "rb"); + if (!fp) + { + return (ERROR); + } + fread(header, 1, number, fp); + is_png = !png_sig_cmp(header, 0, number); + if (!is_png) + { + return (NOT_PNG); + } + + +Next, png_struct and png_info need to be allocated and initialized. In +order to ensure that the size of these structures is correct even with a +dynamically linked libpng, there are functions to initialize and +allocate the structures. We also pass the library version, optional +pointers to error handling functions, and a pointer to a data struct for +use by the error functions, if necessary (the pointer and functions can +be NULL if the default error handlers are to be used). See the section +on Changes to Libpng below regarding the old initialization functions. +The structure allocation functions quietly return NULL if they fail to +create the structure, so your application should check for that. + + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, + (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_read_struct_2() instead of png_create_read_struct(): + + png_structp png_ptr = png_create_read_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +The error handling routines passed to png_create_read_struct() +and the memory alloc/free routines passed to png_create_struct_2() +are only necessary if you are not using the libpng supplied error +handling and memory alloc/free functions. + +When libpng encounters an error, it expects to longjmp back +to your routine. Therefore, you will need to call setjmp and pass +your png_jmpbuf(png_ptr). If you read the file from different +routines, you will need to update the jmpbuf field every time you enter +a new routine that will call a png_*() function. + +See your documentation of setjmp/longjmp for your compiler for more +information on setjmp/longjmp. See the discussion on libpng error +handling in the Customizing Libpng section below for more information +on the libpng error handling. If an error occurs, and libpng longjmp's +back to your setjmp, you will want to call png_destroy_read_struct() to +free any memory. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + fclose(fp); + return (ERROR); + } + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the input code. The default for libpng is to +use the C function fread(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. If you wish to handle reading data in another +way, you need not call the png_init_io() function, but you must then +implement the libpng I/O methods discussed in the Customizing Libpng +section below. + + png_init_io(png_ptr, fp); + +If you had previously opened the file and read any of the signature from +the beginning in order to see if this was a PNG file, you need to let +libpng know that there are some bytes missing from the start of the file. + + png_set_sig_bytes(png_ptr, number); + +Setting up callback code + +You can set up a callback function to handle any unknown chunks in the +input stream. You must supply the function + + read_chunk_callback(png_ptr ptr, + png_unknown_chunkp chunk); + { + /* The unknown chunk structure contains your + chunk data: */ + png_byte name[5]; + png_byte *data; + png_size_t size; + /* Note that libpng has already taken care of + the CRC handling */ + + /* put your code here. Return one of the + following: */ + + return (-n); /* chunk had an error */ + return (0); /* did not recognize */ + return (n); /* success */ + } + +(You can give your function another name that you like instead of +"read_chunk_callback") + +To inform libpng about your function, use + + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, + read_chunk_callback); + +This names not only the callback function, but also a user pointer that +you can retrieve with + + png_get_user_chunk_ptr(png_ptr); + +At this point, you can set up a callback function that will be +called after each row has been read, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void read_row_callback(png_ptr ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "read_row_callback") + +To inform libpng about your function, use + + png_set_read_status_fn(png_ptr, read_row_callback); + +Unknown-chunk handling + +Now you get to set the way the library processes unknown chunks in the +input PNG stream. Both known and unknown chunks will be read. Normal +behavior is that known chunks will be parsed into information in +various info_ptr members; unknown chunks will be discarded. To change +this, you can call: + + png_set_keep_unknown_chunks(png_ptr, info_ptr, keep, + chunk_list, num_chunks); + keep - 0: do not keep + 1: keep only if safe-to-copy + 2: keep even if unsafe-to-copy + chunk_list - list of chunks affected (a byte string, + five bytes per chunk, NULL or '\0' if + num_chunks is 0) + num_chunks - number of chunks affected; if 0, all + unknown chunks are affected + +Unknown chunks declared in this way will be saved as raw data onto a +list of png_unknown_chunk structures. If a chunk that is normally +known to libpng is named in the list, it will be handled as unknown, +according to the "keep" directive. If a chunk is named in successive +instances of png_set_keep_unknown_chunks(), the final instance will +take precedence. + +The high-level read interface + +At this point there are two ways to proceed; through the high-level +read interface, or through a sequence of low-level read operations. +You can use the high-level interface if (a) you are willing to read +the entire image into memory, and (b) the input transformations +you want to do are limited to the following set: + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to + 8 bits + PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel + PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit + samples to bytes + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_EXPAND Perform set_expand() + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + +(This excludes setting a background color, doing gamma transformation, +dithering, and setting filler.) If this is the case, simply do this: + + png_read_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the logical OR of +some set of transformation flags. This call is equivalent to png_read_info(), +followed the set of transformations indicated by the transform mask, +then png_read_image(), and finally png_read_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future input transform.) + +After you have called png_read_png(), you can retrieve the image data +with + + row_pointers = png_get_rows(png_ptr, info_ptr); + +where row_pointers is an array of pointers to the pixel data for each row: + + png_bytep row_pointers[height]; + +If you know your image size and pixel size ahead of time, you can allocate +row_pointers prior to calling png_read_png() with + + row_pointers = png_malloc(png_ptr, + height*sizeof(png_bytep)); + for (int i=0; i) and +png_get_(png_ptr, info_ptr, ...) functions return non-zero if the +data has been read, or zero if it is missing. The parameters to the +png_get_ are set directly if they are simple data types, or a pointer +into the info_ptr is returned for any complex types. + + png_get_PLTE(png_ptr, info_ptr, &palette, + &num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_get_gAMA(png_ptr, info_ptr, &gamma); + gamma - the gamma the file is written + at (PNG_INFO_gAMA) + + png_get_sRGB(png_ptr, info_ptr, &srgb_intent); + srgb_intent - the rendering intent (PNG_INFO_sRGB) + The presence of the sRGB chunk + means that the pixel data is in the + sRGB color space. This chunk also + implies specific values of gAMA and + cHRM. + + png_get_iCCP(png_ptr, info_ptr, &name, + &compression_type, &profile, &proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, + red, green, and blue channels, + whichever are appropriate for the + given color type (png_color_16) + + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, + &trans_values); + trans - array of transparent entries for + palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_get_hIST(png_ptr, info_ptr, &hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_get_tIME(png_ptr, info_ptr, &mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_get_bKGD(png_ptr, info_ptr, &background); + background - background color (PNG_VALID_bKGD) + valid 16-bit red, green and blue + values, regardless of color_type + + num_comments = png_get_text(png_ptr, info_ptr, + &text_ptr, &num_text); + num_comments - number of comments + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (empty + string for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 + (empty string for unknown). + num_text - number of comments (same as + num_comments; you can put NULL here + to avoid the duplication) + Note while png_set_text() will accept text, language, + and translated keywords that can be NULL pointers, the + structure returned by png_get_text will always contain + regular zero-terminated C strings. They might be + empty strings but they will never be NULL pointers. + + num_spalettes = png_get_sPLT(png_ptr, info_ptr, + &palette_ptr); + palette_ptr - array of palette structures holding + contents of one or more sPLT chunks + read. + num_spalettes - number of sPLT chunks read. + + png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, + &unit_type); + offset_x - positive offset from the left edge + of the screen + offset_y - positive offset from the top edge + of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, + &unit_type); + res_x - pixels/unit physical resolution in + x direction + res_y - pixels/unit physical resolution in + x direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_get_sCAL(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_get_sCAL_s(png_ptr, info_ptr, &unit, &width, + &height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + num_unknown_chunks = png_get_unknown_chunks(png_ptr, + info_ptr, &unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position of chunk in file + + The value of "i" corresponds to the order in which the + chunks were read from the PNG file or inserted with the + png_set_unknown_chunks() function. + +The data from the pHYs chunk can be retrieved in several convenient +forms: + + res_x = png_get_x_pixels_per_meter(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_meter(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_meter(png_ptr, + info_ptr) + res_x = png_get_x_pixels_per_inch(png_ptr, + info_ptr) + res_y = png_get_y_pixels_per_inch(png_ptr, + info_ptr) + res_x_and_y = png_get_pixels_per_inch(png_ptr, + info_ptr) + aspect_ratio = png_get_pixel_aspect_ratio(png_ptr, + info_ptr) + + (Each of these returns 0 [signifying "unknown"] if + the data is not present or if res_x is 0; + res_x_and_y is 0 if res_x != res_y) + +The data from the oFFs chunk can be retrieved in several convenient +forms: + + x_offset = png_get_x_offset_microns(png_ptr, info_ptr); + y_offset = png_get_y_offset_microns(png_ptr, info_ptr); + x_offset = png_get_x_offset_inches(png_ptr, info_ptr); + y_offset = png_get_y_offset_inches(png_ptr, info_ptr); + + (Each of these returns 0 [signifying "unknown" if both + x and y are 0] if the data is not present or if the + chunk is present but the unit is the pixel) + +For more information, see the png_info definition in png.h and the +PNG specification for chunk contents. Be careful with trusting +rowbytes, as some of the transformations could increase the space +needed to hold a row (expand, filler, gray_to_rgb, etc.). +See png_read_update_info(), below. + +A quick word about text_ptr and num_text. PNG stores comments in +keyword/text pairs, one pair per chunk, with no limit on the number +of text chunks, and a 2^31 byte limit on their size. While there are +suggested keywords, there is no requirement to restrict the use to these +strings. It is strongly suggested that keywords and text be sensible +to humans (that's the point), so don't use abbreviations. Non-printing +symbols are not allowed. See the PNG specification for more details. +There is also no requirement to have text after the keyword. + +Keywords should be limited to 79 Latin-1 characters without leading or +trailing spaces, but non-consecutive spaces are allowed within the +keyword. It is possible to have the same keyword any number of times. +The text_ptr is an array of png_text structures, each holding a +pointer to a language string, a pointer to a keyword and a pointer to +a text string. The text string, language code, and translated +keyword may be empty or NULL pointers. The keyword/text +pairs are put into the array in the order that they are received. +However, some or all of the text chunks may be after the image, so, to +make sure you have read all the text chunks, don't mess with these +until after you read the stuff after the image. This will be +mentioned again below in the discussion that goes with png_read_end(). + +Input transformations + +After you've read the header information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +The colors used for the background and transparency values should be +supplied in the same format/depth as the current image data. They +are stored in the same format/depth as the image data in a bKGD or tRNS +chunk, so this is what libpng expects for this data. The colors are +transformed to keep in sync with the image data when an application +calls the png_read_update_info() routine (see below). + +Data will be decoded into the supplied row buffers packed into bytes +unless the library has been told to transform it into another format. +For example, 4 bit/pixel paletted or grayscale data will be returned +2 pixels/byte with the leftmost pixel in the high-order bits of the +byte, unless png_set_packing() is called. 8-bit RGB data will be stored +in RGB RGB RGB format unless png_set_filler() is called to insert filler +bytes, either before or after each RGB triplet. 16-bit RGB data will +be returned RRGGBB RRGGBB, with the most significant byte of the color +value first, unless png_set_strip_16() is called to transform it to +regular RGB RGB triplets, or png_set_filler() is called to insert +filler bytes, either before or after each RRGGBB triplet. Similarly, +8-bit or 16-bit grayscale data can be modified with png_set_filler() +or png_set_strip_16(). + +The following code transforms grayscale images of less than 8 to 8 bits, +changes paletted images to RGB, and adds a full alpha channel if there is +transparency information in a tRNS chunk. This is most useful on +grayscale images with bit depths of 2 or 4 or if there is a multiple-image +viewing application that wishes to treat all images in the same way. + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && + bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + +These three functions are actually aliases for png_set_expand(), added +in libpng version 1.0.4, with the function names expanded to improve code +readability. In some future version they may actually do different +things. + +PNG can have files with 16 bits per channel. If you only can handle +8 bits per channel, this will strip the pixels down to 8 bit. + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + +If, for some reason, you don't need the alpha channel on an image, +and you want to remove it rather than combining it with the background +(but the image author certainly had in mind that you *would* combine +it with the background, so that's what you should probably do): + + if (color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + +In PNG files, the alpha channel in an image +is the level of opacity. If you need the alpha channel in an image to +be the level of transparency instead of opacity, you can invert the +alpha channel (or the tRNS chunk data) after it's read, so that 0 is +fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit +images) is fully transparent, with + + png_set_invert_alpha(png_ptr); + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit +files. This code expands to 1 pixel per byte without changing the +values of the pixels: + + if (bit_depth < 8) + png_set_packing(png_ptr); + +PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels +stored in a PNG image have been "scaled" or "shifted" up to the next +higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to +8 bits/sample in the range [0, 255]). However, it is also possible to +convert the PNG pixel data back to the original bit depth of the image. +This call reduces the pixels back down to the original bit depth: + + png_color_16p sig_bit; + + if (png_get_sBIT(png_ptr, info_ptr, &sig_bit)) + png_set_shift(png_ptr, sig_bit); + +PNG files store 3-color pixels in red, green, blue order. This code +changes the storage of the pixels to blue, green, red: + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + +PNG files store RGB pixels packed into 3 bytes. This code expands them +into 4 bytes for windowing systems that need them in this format: + + if (bit_depth == 8 && color_type == + PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, + filler, PNG_FILLER_BEFORE); + +where "filler" is the 8 or 16-bit number to fill with, and the location is +either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether +you want the filler before the RGB or after. This transformation +does not affect images that already have full alpha channels. + +If you are reading an image with an alpha channel, and you need the +data as ARGB instead of the normal PNG format RGBA: + + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_swap_alpha(png_ptr); + +For some uses, you may want a grayscale image to be represented as +RGB. This code will do that conversion: + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + +Conversely, you can convert an RGB or RGBA image to grayscale or grayscale +with alpha. + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_rgb_to_gray_fixed(png_ptr, error_action, + int red_weight, int green_weight); + + error_action = 1: silently do the conversion + error_action = 2: issue a warning if the original + image has any pixel where + red != green or red != blue + error_action = 3: issue an error and abort the + conversion if the original + image has any pixel where + red != green or red != blue + + red_weight: weight of red component times 100000 + green_weight: weight of green component times 100000 + If either weight is negative, default + weights (21268, 71514) are used. + +If you have set error_action = 1 or 2, you can +later check whether the image really was gray, after processing +the image rows, with the png_get_rgb_to_gray_status(png_ptr) function. +It will return a png_byte that is zero if the image was gray or +1 if there were any non-gray pixels. bKGD and sBIT data +will be silently converted to grayscale, using the green channel +data, regardless of the error_action setting. + +With red_weight+green_weight<=100000, +the normalized graylevel is computed: + + int rw = red_weight * 65536; + int gw = green_weight * 65536; + int bw = 65536 - (rw + gw); + gray = (rw*red + gw*green + bw*blue)/65536; + +The default values approximate those recommended in the Charles +Poynton's Color FAQ, +Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net + + Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + +Libpng approximates this with + + Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + +which can be expressed with integers as + + Y = (6969 * R + 23434 * G + 2365 * B)/32768 + +The calculation is done in a linear colorspace, if the image gamma +is known. + +If you have a grayscale and you are using png_set_expand_depth() or +png_set_expand() to change to +a higher bit-depth, you must either supply the background color as a gray +value at the original file bit-depth (need_expand = 1) or else supply the +background color as an RGB triplet at the final, expanded bit depth +(need_expand = 0). Similarly, if you are reading a paletted image, you +must either supply the background color as a palette index (need_expand = 1) +or as an RGB triplet that may or may not be in the palette (need_expand = 0). + + png_color_16 my_background; + png_color_16p image_background; + + if (png_get_bKGD(png_ptr, info_ptr, &image_background)) + png_set_background(png_ptr, image_background, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + +The png_set_background() function tells libpng to composite images +with alpha or simple transparency against the supplied background +color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid), +you may use this color, or supply another color more suitable for +the current display (e.g., the background color from a web page). You +need to tell libpng whether the color is in the gamma space of the +display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file +(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one +that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't +know why anyone would use this, but it's here). + +To properly display PNG images on any kind of system, the application needs +to know what the display gamma is. Ideally, the user will know this, and +the application will allow them to set it. One method of allowing the user +to set the display gamma separately for each system is to check for a +SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be +correctly set. + +Note that display_gamma is the overall gamma correction required to produce +pleasing results, which depends on the lighting conditions in the surrounding +environment. In a dim or brightly lit room, no compensation other than +the physical gamma exponent of the monitor is needed, while in a dark room +a slightly smaller exponent is better. + + double gamma, screen_gamma; + + if (/* We have a user-defined screen + gamma value */) + { + screen_gamma = user_defined_screen_gamma; + } + /* One way that applications can share the same + screen gamma value */ + else if ((gamma_str = getenv("SCREEN_GAMMA")) + != NULL) + { + screen_gamma = (double)atof(gamma_str); + } + /* If we don't have another value */ + else + { + screen_gamma = 2.2; /* A good guess for a + PC monitor in a bright office or a dim room */ + screen_gamma = 2.0; /* A good guess for a + PC monitor in a dark room */ + screen_gamma = 1.7 or 1.0; /* A good + guess for Mac systems */ + } + +The png_set_gamma() function handles gamma transformations of the data. +Pass both the file gamma and the current screen_gamma. If the file does +not have a gamma value, you can pass one anyway if you have an idea what +it is (usually 0.45455 is a good guess for GIF images on PCs). Note +that file gammas are inverted from screen gammas. See the discussions +on gamma in the PNG specification for an excellent description of what +gamma is, and why all applications should support it. It is strongly +recommended that PNG viewers support gamma correction. + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, screen_gamma, gamma); + else + png_set_gamma(png_ptr, screen_gamma, 0.45455); + +If you need to reduce an RGB file to a paletted file, or if a paletted +file has more entries then will fit on your screen, png_set_dither() +will do that. Note that this is a simple match dither that merely +finds the closest color available. This should work fairly well with +optimized palettes, and fairly badly with linear color cubes. If you +pass a palette that is larger then maximum_colors, the file will +reduce the number of colors in the palette so it will fit into +maximum_colors. If there is a histogram, it will use it to make +more intelligent choices when reducing the palette. If there is no +histogram, it may not do as good a job. + + if (color_type & PNG_COLOR_MASK_COLOR) + { + if (png_get_valid(png_ptr, info_ptr, + PNG_INFO_PLTE)) + { + png_uint_16p histogram; + + png_get_hIST(png_ptr, info_ptr, + &histogram); + png_set_dither(png_ptr, palette, num_palette, + max_screen_colors, histogram, 1); + } + else + { + png_color std_color_cube[MAX_SCREEN_COLORS] = + { ... colors ... }; + + png_set_dither(png_ptr, std_color_cube, + MAX_SCREEN_COLORS, MAX_SCREEN_COLORS, + NULL,0); + } + } + +PNG files describe monochrome as black being zero and white being one. +The following code will reverse this (make black be one and white be +zero): + + if (bit_depth == 1 && color_type == PNG_COLOR_GRAY) + png_set_invert_mono(png_ptr); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code changes the storage to the +other way (little-endian, i.e. least significant bits first, the +way PCs store them): + + if (bit_depth == 16) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_read_user_transform_fn(png_ptr, + read_transform_fn); + +You must supply the function + + void read_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +after all of the other transformations have been processed. + +You can also set up a pointer to a user structure for use by your +callback function, and you can inform libpng that your transform +function will change the number of channels or bit depth with the +function + + png_set_user_transform_info(png_ptr, user_ptr, + user_depth, user_channels); + +The user's application, not libpng, is responsible for allocating and +freeing any memory required for the user structure. + +You can retrieve the pointer via the function +png_get_user_transform_ptr(). For example: + + voidp read_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +The last thing to handle is interlacing; this is covered in detail below, +but you must call the function here if you want libpng to handle expansion +of the interlaced image. + + number_of_passes = png_set_interlace_handling(png_ptr); + +After setting the transformations, libpng can update your png_info +structure to reflect any transformations you've requested with this +call. This is most useful to update the info structure's rowbytes +field so you can use it to allocate your image memory. This function +will also update your palette with the correct screen_gamma and +background if these have been given with the calls above. + + png_read_update_info(png_ptr, info_ptr); + +After you call png_read_update_info(), you can allocate any +memory you need to hold the image. The row data is simply +raw byte data for all forms of images. As the actual allocation +varies among applications, no example will be given. If you +are allocating one large chunk, you will need to build an +array of pointers to each row, as it will be needed for some +of the functions below. + +Reading image data + +After you've allocated memory, you can read the image data. +The simplest way to do this is in one function call. If you are +allocating enough memory to hold the whole image, you can just +call png_read_image() and libpng will read in all the image data +and put it in the memory area supplied. You will need to pass in +an array of pointers to each row. + +This function automatically handles interlacing, so you don't need +to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_read_rows(). + + png_read_image(png_ptr, row_pointers); + +where row_pointers is: + + png_bytep row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to read in the whole image at once, you can +use png_read_rows() instead. If there is no interlacing (check +interlace_type == PNG_INTERLACE_NONE), this is simple: + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +where row_pointers is the same as in the png_read_image() call. + +If you are doing this just one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + png_read_row(png_ptr, row_pointer, NULL); + +If the file is interlaced (interlace_type != 0 in the IHDR chunk), things +get somewhat harder. The only current (PNG Specification version 1.2) +interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7) +is a somewhat complicated 2D interlace scheme, known as Adam7, that +breaks down an image into seven smaller images of varying size, based +on an 8x8 grid. + +libpng can fill out those images or it can give them to you "as is". +If you want them filled out, there are two ways to do that. The one +mentioned in the PNG specification is to expand each pixel to cover +those pixels that have not been read yet (the "rectangle" method). +This results in a blocky image for the first pass, which gradually +smooths out as more pixels are read. The other method is the "sparkle" +method, where pixels are drawn only in their final locations, with the +rest of the image remaining whatever colors they were initialized to +before the start of the read. The first method usually looks better, +but tends to be slower, as there are more pixels to put in the rows. + +If you don't want libpng to handle the interlacing details, just call +png_read_rows() seven times to read in all seven images. Each of the +images is a valid image by itself, or they can all be combined on an +8x8 grid to form a single image (although if you intend to combine them +you would be far better off using the libpng interlace handling). + +The first pass will return an image 1/8 as wide as the entire image +(every 8th column starting in column 0) and 1/8 as high as the original +(every 8th row starting in row 0), the second will be 1/8 as wide +(starting in column 4) and 1/8 as high (also starting in row 0). The +third pass will be 1/4 as wide (every 4th pixel starting in column 0) and +1/8 as high (every 8th row starting in row 4), and the fourth pass will +be 1/4 as wide and 1/4 as high (every 4th column starting in column 2, +and every 4th row starting in row 0). The fifth pass will return an +image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2), +while the sixth pass will be 1/2 as wide and 1/2 as high as the original +(starting in column 1 and row 0). The seventh and final pass will be as +wide as the original, and 1/2 as high, containing all of the odd +numbered scanlines. Phew! + +If you want libpng to expand the images, call this before calling +png_start_read_image() or png_read_update_info(): + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes + = png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. +This function can be called even if the file is not interlaced, +where it will return one pass. + +If you are not going to display the image after each pass, but are +going to wait until the entire image is read in, use the sparkle +effect. This effect is faster and the end result of either method +is exactly the same. If you are planning on displaying the image +after each pass, the "rectangle" effect is generally considered the +better looking one. + +If you only want the "sparkle" effect, just call png_read_rows() as +normal, with the third parameter NULL. Make sure you make pass over +the image number_of_passes times, and you don't change the data in the +rows between calls. You can change the locations of the data, just +not the data. Each pass only writes the pixels appropriate for that +pass, and assumes the data from previous passes is still valid. + + png_read_rows(png_ptr, row_pointers, NULL, + number_of_rows); + +If you only want the first effect (the rectangles), do the same as +before except pass the row buffer in the third parameter, and leave +the second parameter NULL. + + png_read_rows(png_ptr, NULL, row_pointers, + number_of_rows); + +Finishing a sequential read + +After you are finished reading the image through either the high- or +low-level interfaces, you can finish reading the file. If you are +interested in comments or time, which may be stored either before or +after the image data, you should pass the separate png_info struct if +you want to keep the comments from before and after the image +separate. If you are not interested, you can pass NULL. + + png_read_end(png_ptr, end_info); + +When you are done, you can free all memory allocated by libpng like this: + + png_destroy_read_struct(&png_ptr, &info_ptr, + &end_info); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the logical OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those +cases do nothing. The "seq" parameter is ignored if only one item +of the selected data type, such as PLTE, is allowed. If "seq" is not +-1, and multiple items are allowed for the data type identified in +the mask, such as text or sPLT, only the n'th item in the structure +is freed, where n is "seq". + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +This function only affects data that has already been allocated. +You can call this function after reading the PNG data but before calling +any png_set_*() functions, to control whether the user or the png_set_*() +function is responsible for freeing any existing data that might be present, +and again after the png_set_*() functions to control whether the user +or png_destroy_*() is supposed to free the data. When the user assumes +responsibility for libpng-allocated data, the application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated your row_pointers in a single block, as suggested above in +the description of the high level read interface, you must not transfer +responsibility for freeing it to the png_set_rows or png_read_destroy function, +because they would also try to free the individual row_pointers[i]. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. + +The png_free_data() function will turn off the "valid" flag for anything +it frees. If you need to turn the flag off for a chunk that was freed by your +application instead of by libpng, you can use + + png_set_invalid(png_ptr, info_ptr, mask); + mask - identifies the chunks to be made invalid, + containing the logical OR of one or + more of + PNG_INFO_gAMA, PNG_INFO_sBIT, + PNG_INFO_cHRM, PNG_INFO_PLTE, + PNG_INFO_tRNS, PNG_INFO_bKGD, + PNG_INFO_hIST, PNG_INFO_pHYs, + PNG_INFO_oFFs, PNG_INFO_tIME, + PNG_INFO_pCAL, PNG_INFO_sRGB, + PNG_INFO_iCCP, PNG_INFO_sPLT, + PNG_INFO_sCAL, PNG_INFO_IDAT + +For a more compact example of reading a PNG image, see the file example.c. + +Reading PNG files progressively + +The progressive reader is slightly different then the non-progressive +reader. Instead of calling png_read_info(), png_read_rows(), and +png_read_end(), you make one call to png_process_data(), which calls +callbacks when it has the info, a row, or the end of the image. You +set up these callbacks with png_set_progressive_read_fn(). You don't +have to worry about the input/output functions of libpng, as you are +giving the library the data directly in png_process_data(). I will +assume that you have read the section on reading PNG files above, +so I will only highlight the differences (although I will show +all of the code). + +png_structp png_ptr; +png_infop info_ptr; + + /* An example code fragment of how you would + initialize the progressive reader in your + application. */ + int + initialize_png_reader() + { + png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, + (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new. You can provide functions + to be called when the header info is valid, + when each row is completed, and when the image + is finished. If you aren't using all functions, + you can specify NULL parameters. Even when all + three functions are NULL, you need to call + png_set_progressive_read_fn(). You can use + any struct as the user_ptr (cast to a void pointer + for the function call), and retrieve the pointer + from inside the callbacks using the function + + png_get_progressive_ptr(png_ptr); + + which will return a void pointer, which you have + to cast appropriately. + */ + png_set_progressive_read_fn(png_ptr, (void *)user_ptr, + info_callback, row_callback, end_callback); + + return 0; + } + + /* A code fragment that you call as you receive blocks + of data */ + int + process_data(png_bytep buffer, png_uint_32 length) + { + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, + (png_infopp)NULL); + return (ERROR); + } + + /* This one's new also. Simply give it a chunk + of data from the file stream (in order, of + course). On machines with segmented memory + models machines, don't give it any more than + 64K. The library seems to run fine with sizes + of 4K. Although you can give it much less if + necessary (I assume you can give it chunks of + 1 byte, I haven't tried less then 256 bytes + yet). When this function returns, you may + want to display any rows that were generated + in the row callback if you don't already do + so there. + */ + png_process_data(png_ptr, info_ptr, buffer, length); + return 0; + } + + /* This function is called (as set by + png_set_progressive_read_fn() above) when enough data + has been supplied so all of the header has been + read. + */ + void + info_callback(png_structp png_ptr, png_infop info) + { + /* Do any setup here, including setting any of + the transformations mentioned in the Reading + PNG files section. For now, you _must_ call + either png_start_read_image() or + png_read_update_info() after all the + transformations are set (even if you don't set + any). You may start getting rows before + png_process_data() returns, so this is your + last chance to prepare for that. + */ + } + + /* This function is called when each row of image + data is complete */ + + void + row_callback(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) + { + /* If the image is interlaced, and you turned + on the interlace handler, this function will + be called for every row in every pass. Some + of these rows will not be changed from the + previous pass. When the row is not changed, + the new_row variable will be NULL. The rows + and passes are called in order, so you don't + really need the row_num and pass, but I'm + supplying them because it may make your life + easier. + + For the non-NULL rows of interlaced images, + you must call png_progressive_combine_row() + passing in the row and the old row. You can + call this function for NULL rows (it will just + return) and for non-interlaced images (it just + does the memcpy for you) if it will make the + code easier. Thus, you can just do this for + all cases: + */ + + png_progressive_combine_row(png_ptr, old_row, + new_row); + + /* where old_row is what was displayed for + previously for the row. Note that the first + pass (pass == 0, really) will completely cover + the old row, so the rows do not have to be + initialized. After the first pass (and only + for interlaced images), you will have to pass + the current row, and the function will combine + the old row and the new row. + */ + } + + void + end_callback(png_structp png_ptr, png_infop info) + { + /* This function is called after the whole image + has been read, including any chunks after the + image (up to and including the IEND). You + will usually have the same info chunk as you + had in the header, although some data may have + been added to the comments and time fields. + + Most people won't do much here, perhaps setting + a flag that marks the image as finished. + */ + } + + + +IV. Writing + +Much of this is very similar to reading. However, everything of +importance is repeated here, so you won't have to constantly look +back up in the reading section to understand writing. + +Setup + +You will want to do the I/O initialization before you get into libpng, +so if it doesn't work, you don't have anything to undo. If you are not +using the standard I/O functions, you will need to replace them with +custom writing functions. See the discussion under Customizing libpng. + + FILE *fp = fopen(file_name, "wb"); + if (!fp) + { + return (ERROR); + } + +Next, png_struct and png_info need to be allocated and initialized. +As these can be both relatively large, you may not want to store these +on the stack, unless you have stack space to spare. Of course, you +will want to check if they return NULL. If you are also reading, +you won't want to name your read structure and your write structure +both "png_ptr"; you can call them anything you like, such as +"read_ptr" and "write_ptr". Look at pngtest.c, for example. + + png_structp png_ptr = png_create_write_struct + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn); + if (!png_ptr) + return (ERROR); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_write_struct(&png_ptr, + (png_infopp)NULL); + return (ERROR); + } + +If you want to use your own memory allocation routines, +define PNG_USER_MEM_SUPPORTED and use +png_create_write_struct_2() instead of png_create_write_struct(): + + png_structp png_ptr = png_create_write_struct_2 + (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, + user_error_fn, user_warning_fn, (png_voidp) + user_mem_ptr, user_malloc_fn, user_free_fn); + +After you have these structures, you will need to set up the +error handling. When libpng encounters an error, it expects to +longjmp() back to your routine. Therefore, you will need to call +setjmp() and pass the png_jmpbuf(png_ptr). If you +write the file from different routines, you will need to update +the png_jmpbuf(png_ptr) every time you enter a new routine that will +call a png_*() function. See your documentation of setjmp/longjmp +for your compiler for more information on setjmp/longjmp. See +the discussion on libpng error handling in the Customizing Libpng +section below for more information on the libpng error handling. + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (ERROR); + } + ... + return; + +If you would rather avoid the complexity of setjmp/longjmp issues, +you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case +errors will result in a call to PNG_ABORT() which defaults to abort(). + +Now you need to set up the output code. The default for libpng is to +use the C function fwrite(). If you use this, you will need to pass a +valid FILE * in the function png_init_io(). Be sure that the file is +opened in binary mode. Again, if you wish to handle writing data in +another way, see the discussion on libpng I/O handling in the Customizing +Libpng section below. + + png_init_io(png_ptr, fp); + +Write callbacks + +At this point, you can set up a callback function that will be +called after each row has been written, which you can use to control +a progress meter or the like. It's demonstrated in pngtest.c. +You must supply a function + + void write_row_callback(png_ptr, png_uint_32 row, + int pass); + { + /* put your code here */ + } + +(You can give it another name that you like instead of "write_row_callback") + +To inform libpng about your function, use + + png_set_write_status_fn(png_ptr, write_row_callback); + +You now have the option of modifying how the compression library will +run. The following functions are mainly for testing, but may be useful +in some cases, like if you need to write PNG files extremely fast and +are willing to give up some compression, or if you want to get the +maximum possible compression at the expense of slower writing. If you +have no special needs in this area, let the library do what it wants by +not calling this function at all, as it has been tuned to deliver a good +speed/compression ratio. The second parameter to png_set_filter() is +the filter method, for which the only valid values are 0 (as of the +July 1999 PNG specification, version 1.2) or 64 (if you are writing +a PNG datastream that is to be embedded in a MNG datastream). The third +parameter is a flag that indicates which filter type(s) are to be tested +for each scanline. See the PNG specification for details on the specific filter +types. + + + /* turn on or off filtering, and/or choose + specific filters. You can use either a single + PNG_FILTER_VALUE_NAME or the logical OR of one + or more PNG_FILTER_NAME masks. */ + png_set_filter(png_ptr, 0, + PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | + PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | + PNG_FILTER_UP | PNG_FILTER_VALUE_UP | + PNG_FILTER_AVE | PNG_FILTER_VALUE_AVE | + PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| + PNG_ALL_FILTERS); + +If an application +wants to start and stop using particular filters during compression, +it should start out with all of the filters (to ensure that the previous +row of pixels will be stored in case it's needed later), and then add +and remove them after the start of compression. + +If you are writing a PNG datastream that is to be embedded in a MNG +datastream, the second parameter can be either 0 or 64. + +The png_set_compression_*() functions interface to the zlib compression +library, and should mostly be ignored unless you really know what you are +doing. The only generally useful call is png_set_compression_level() +which changes how much time zlib spends on trying to compress the image +data. See the Compression Library (zlib.h and algorithm.txt, distributed +with zlib) for details on the compression levels. + + /* set the zlib compression level */ + png_set_compression_level(png_ptr, + Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, + Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192) + +extern PNG_EXPORT(void,png_set_zbuf_size) + +Setting the contents of info for output + +You now need to fill in the png_info structure with all the data you +wish to write before the actual image. Note that the only thing you +are allowed to write after the image is the text chunks and the time +chunk (as of PNG Specification 1.2, anyway). See png_write_end() and +the latest PNG specification for more information on that. If you +wish to write them before the image, fill them in now, and flag that +data as being valid. If you want to wait until after the data, don't +fill them until png_write_end(). For all the fields in png_info and +their data types, see png.h. For explanations of what the fields +contain, see the PNG specification. + +Some of the more important parts of the png_info are: + + png_set_IHDR(png_ptr, info_ptr, width, height, + bit_depth, color_type, interlace_type, + compression_type, filter_method) + width - holds the width of the image + in pixels (up to 2^31). + height - holds the height of the image + in pixels (up to 2^31). + bit_depth - holds the bit depth of one of the + image channels. + (valid values are 1, 2, 4, 8, 16 + and depend also on the + color_type. See also significant + bits (sBIT) below). + color_type - describes which color/alpha + channels are present. + PNG_COLOR_TYPE_GRAY + (bit depths 1, 2, 4, 8, 16) + PNG_COLOR_TYPE_GRAY_ALPHA + (bit depths 8, 16) + PNG_COLOR_TYPE_PALETTE + (bit depths 1, 2, 4, 8) + PNG_COLOR_TYPE_RGB + (bit_depths 8, 16) + PNG_COLOR_TYPE_RGB_ALPHA + (bit_depths 8, 16) + + PNG_COLOR_MASK_PALETTE + PNG_COLOR_MASK_COLOR + PNG_COLOR_MASK_ALPHA + + interlace_type - PNG_INTERLACE_NONE or + PNG_INTERLACE_ADAM7 + compression_type - (must be + PNG_COMPRESSION_TYPE_DEFAULT) + filter_method - (must be PNG_FILTER_TYPE_DEFAULT + or, if you are writing a PNG to + be embedded in a MNG datastream, + can also be + PNG_INTRAPIXEL_DIFFERENCING) + + png_set_PLTE(png_ptr, info_ptr, palette, + num_palette); + palette - the palette for the file + (array of png_color) + num_palette - number of entries in the palette + + png_set_gAMA(png_ptr, info_ptr, gamma); + gamma - the gamma the image was created + at (PNG_INFO_gAMA) + + png_set_sRGB(png_ptr, info_ptr, srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of + the sRGB chunk means that the pixel + data is in the sRGB color space. + This chunk also implies specific + values of gAMA and cHRM. Rendering + intent is the CSS-1 property that + has been defined by the International + Color Consortium + (http://www.color.org). + It can be one of + PNG_sRGB_INTENT_SATURATION, + PNG_sRGB_INTENT_PERCEPTUAL, + PNG_sRGB_INTENT_ABSOLUTE, or + PNG_sRGB_INTENT_RELATIVE. + + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, + srgb_intent); + srgb_intent - the rendering intent + (PNG_INFO_sRGB) The presence of the + sRGB chunk means that the pixel + data is in the sRGB color space. + This function also causes gAMA and + cHRM chunks with the specific values + that are consistent with sRGB to be + written. + + png_set_iCCP(png_ptr, info_ptr, name, compression_type, + profile, proflen); + name - The profile name. + compression - The compression type; always + PNG_COMPRESSION_TYPE_BASE for PNG 1.0. + You may give NULL to this argument to + ignore it. + profile - International Color Consortium color + profile data. May contain NULs. + proflen - length of profile data in bytes. + + png_set_sBIT(png_ptr, info_ptr, sig_bit); + sig_bit - the number of significant bits for + (PNG_INFO_sBIT) each of the gray, red, + green, and blue channels, whichever are + appropriate for the given color type + (png_color_16) + + png_set_tRNS(png_ptr, info_ptr, trans, num_trans, + trans_values); + trans - array of transparent entries for + palette (PNG_INFO_tRNS) + trans_values - graylevel or color sample values of + the single transparent color for + non-paletted images (PNG_INFO_tRNS) + num_trans - number of transparent entries + (PNG_INFO_tRNS) + + png_set_hIST(png_ptr, info_ptr, hist); + (PNG_INFO_hIST) + hist - histogram of palette (array of + png_uint_16) + + png_set_tIME(png_ptr, info_ptr, mod_time); + mod_time - time image was last modified + (PNG_VALID_tIME) + + png_set_bKGD(png_ptr, info_ptr, background); + background - background color (PNG_VALID_bKGD) + + png_set_text(png_ptr, info_ptr, text_ptr, num_text); + text_ptr - array of png_text holding image + comments + text_ptr[i].compression - type of compression used + on "text" PNG_TEXT_COMPRESSION_NONE + PNG_TEXT_COMPRESSION_zTXt + PNG_ITXT_COMPRESSION_NONE + PNG_ITXT_COMPRESSION_zTXt + text_ptr[i].key - keyword for comment. Must contain + 1-79 characters. + text_ptr[i].text - text comments for current + keyword. Can be NULL or empty. + text_ptr[i].text_length - length of text string, + after decompression, 0 for iTXt + text_ptr[i].itxt_length - length of itxt string, + after decompression, 0 for tEXt/zTXt + text_ptr[i].lang - language of comment (NULL or + empty for unknown). + text_ptr[i].translated_keyword - keyword in UTF-8 (NULL + or empty for unknown). + num_text - number of comments + + png_set_sPLT(png_ptr, info_ptr, &palette_ptr, + num_spalettes); + palette_ptr - array of png_sPLT_struct structures + to be added to the list of palettes + in the info structure. + num_spalettes - number of palette structures to be + added. + + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, + unit_type); + offset_x - positive offset from the left + edge of the screen + offset_y - positive offset from the top + edge of the screen + unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER + + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, + unit_type); + res_x - pixels/unit physical resolution + in x direction + res_y - pixels/unit physical resolution + in y direction + unit_type - PNG_RESOLUTION_UNKNOWN, + PNG_RESOLUTION_METER + + png_set_sCAL(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are doubles) + + png_set_sCAL_s(png_ptr, info_ptr, unit, width, height) + unit - physical scale units (an integer) + width - width of a pixel in physical scale units + height - height of a pixel in physical scale units + (width and height are strings like "2.54") + + png_set_unknown_chunks(png_ptr, info_ptr, &unknowns, + num_unknowns) + unknowns - array of png_unknown_chunk + structures holding unknown chunks + unknowns[i].name - name of unknown chunk + unknowns[i].data - data of unknown chunk + unknowns[i].size - size of unknown chunk's data + unknowns[i].location - position to write chunk in file + 0: do not write chunk + PNG_HAVE_IHDR: before PLTE + PNG_HAVE_PLTE: before IDAT + PNG_AFTER_IDAT: after IDAT + +The "location" member is set automatically according to +what part of the output file has already been written. +You can change its value after calling png_set_unknown_chunks() +as demonstrated in pngtest.c. Within each of the "locations", +the chunks are sequenced according to their position in the +structure (that is, the value of "i", which is the order in which +the chunk was either read from the input file or defined with +png_set_unknown_chunks). + +A quick word about text and num_text. text is an array of png_text +structures. num_text is the number of valid structures in the array. +Each png_text structure holds a language code, a keyword, a text value, +and a compression type. + +The compression types have the same valid numbers as the compression +types of the image data. Currently, the only valid number is zero. +However, you can store text either compressed or uncompressed, unlike +images, which always have to be compressed. So if you don't want the +text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE. +Because tEXt and zTXt chunks don't have a language field, if you +specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt +any language code or translated keyword will not be written out. + +Until text gets around 1000 bytes, it is not worth compressing it. +After the text has been written out to the file, the compression type +is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR, +so that it isn't written out again at the end (in case you are calling +png_write_end() with the same struct. + +The keywords that are given in the PNG Specification are: + + Title Short (one line) title or + caption for image + Author Name of image's creator + Description Description of image (possibly long) + Copyright Copyright notice + Creation Time Time of original image creation + (usually RFC 1123 format, see below) + Software Software used to create the image + Disclaimer Legal disclaimer + Warning Warning of nature of content + Source Device used to create the image + Comment Miscellaneous comment; conversion + from other image format + +The keyword-text pairs work like this. Keywords should be short +simple descriptions of what the comment is about. Some typical +keywords are found in the PNG specification, as is some recommendations +on keywords. You can repeat keywords in a file. You can even write +some text before the image and some after. For example, you may want +to put a description of the image before the image, but leave the +disclaimer until after, so viewers working over modem connections +don't have to wait for the disclaimer to go over the modem before +they start seeing the image. Finally, keywords should be full +words, not abbreviations. Keywords and text are in the ISO 8859-1 +(Latin-1) character set (a superset of regular ASCII) and can not +contain NUL characters, and should not contain control or other +unprintable characters. To make the comments widely readable, stick +with basic ASCII, and avoid machine specific character set extensions +like the IBM-PC character set. The keyword must be present, but +you can leave off the text string on non-compressed pairs. +Compressed pairs must have a text string, as only the text string +is compressed anyway, so the compression would be meaningless. + +PNG supports modification time via the png_time structure. Two +conversion routines are provided, png_convert_from_time_t() for +time_t and png_convert_from_struct_tm() for struct tm. The +time_t routine uses gmtime(). You don't have to use either of +these, but if you wish to fill in the png_time structure directly, +you should provide the time in universal time (GMT) if possible +instead of your local time. Note that the year number is the full +year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and +that months start with 1. + +If you want to store the time of the original image creation, you should +use a plain tEXt chunk with the "Creation Time" keyword. This is +necessary because the "creation time" of a PNG image is somewhat vague, +depending on whether you mean the PNG file, the time the image was +created in a non-PNG format, a still photo from which the image was +scanned, or possibly the subject matter itself. In order to facilitate +machine-readable dates, it is recommended that the "Creation Time" +tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), +although this isn't a requirement. Unlike the tIME chunk, the +"Creation Time" tEXt chunk is not expected to be automatically changed +by the software. To facilitate the use of RFC 1123 dates, a function +png_convert_to_rfc1123(png_timep) is provided to convert from PNG +time to an RFC 1123 format string. + +Writing unknown chunks + +You can use the png_set_unknown_chunks function to queue up chunks +for writing. You give it a chunk name, raw data, and a size; that's +all there is to it. The chunks will be written by the next following +png_write_info_before_PLTE, png_write_info, or png_write_end function. +Any chunks previously read into the info structure's unknown-chunk +list will also be written out in a sequence that satisfies the PNG +specification's ordering rules. + +The high-level write interface + +At this point there are two ways to proceed; through the high-level +write interface, or through a sequence of low-level write operations. +You can use the high-level interface if your image data is present +in the info structure. All defined output +transformations are permitted, enabled by the following masks. + + PNG_TRANSFORM_IDENTITY No transformation + PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples + PNG_TRANSFORM_PACKSWAP Change order of packed + pixels to LSB first + PNG_TRANSFORM_INVERT_MONO Invert monochrome images + PNG_TRANSFORM_SHIFT Normalize pixels to the + sBIT depth + PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA + to BGRA + PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA + to AG + PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity + to transparency + PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples + PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes. + +If you have valid image data in the info structure (you can use +png_set_rows() to put image data in the info structure), simply do this: + + png_write_png(png_ptr, info_ptr, png_transforms, NULL) + +where png_transforms is an integer containing the logical OR of some set of +transformation flags. This call is equivalent to png_write_info(), +followed the set of transformations indicated by the transform mask, +then png_write_image(), and finally png_write_end(). + +(The final parameter of this call is not yet used. Someday it might point +to transformation parameters required by some future output transform.) + +The low-level write interface + +If you are going the low-level route instead, you are now ready to +write all the file information up to the actual image data. You do +this with a call to png_write_info(). + + png_write_info(png_ptr, info_ptr); + +Note that there is one transformation you may need to do before +png_write_info(). In PNG files, the alpha channel in an image is the +level of opacity. If your data is supplied as a level of +transparency, you can invert the alpha channel before you write it, so +that 0 is fully transparent and 255 (in 8-bit or paletted images) or +65535 (in 16-bit images) is fully opaque, with + + png_set_invert_alpha(png_ptr); + +This must appear before png_write_info() instead of later with the +other transformations because in the case of paletted images the tRNS +chunk data has to be inverted before the tRNS chunk is written. If +your image is not a paletted image, the tRNS data (which in such cases +represents a single color to be rendered as transparent) won't need to +be changed, and you can safely do this transformation after your +png_write_info() call. + +If you need to write a private chunk that you want to appear before +the PLTE chunk when PLTE is present, you can write the PNG info in +two steps, and insert code to write your own chunk between them: + + png_write_info_before_PLTE(png_ptr, info_ptr); + png_set_unknown_chunks(png_ptr, info_ptr, ...); + png_write_info(png_ptr, info_ptr); + +After you've written the file information, you can set up the library +to handle any special transformations of the image data. The various +ways to transform the data will be described in the order that they +should occur. This is important, as some of these change the color +type and/or bit depth of the data, and some others only work on +certain color types and bit depths. Even though each transformation +checks to see if it has data that it can do something with, you should +make sure to only enable a transformation if it will be valid for the +data. For example, don't swap red and blue on grayscale data. + +PNG files store RGB pixels packed into 3 or 6 bytes. This code tells +the library to strip input data that has 4 or 8 bytes per pixel down +to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2 +bytes per pixel). + + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + +where the 0 is unused, and the location is either PNG_FILLER_BEFORE or +PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel +is stored XRGB or RGBX. + +PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as +they can, resulting in, for example, 8 pixels per byte for 1 bit files. +If the data is supplied at 1 pixel per byte, use this code, which will +correctly pack the pixels into a single byte: + + png_set_packing(png_ptr); + +PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your +data is of another bit depth, you can write an sBIT chunk into the +file so that decoders can recover the original data if desired. + + /* Set the true bit depth of the image data */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit.red = true_bit_depth; + sig_bit.green = true_bit_depth; + sig_bit.blue = true_bit_depth; + } + else + { + sig_bit.gray = true_bit_depth; + } + if (color_type & PNG_COLOR_MASK_ALPHA) + { + sig_bit.alpha = true_bit_depth; + } + + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +If the data is stored in the row buffer in a bit depth other than +one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG), +this will scale the values to appear to be the correct bit depth as +is required by PNG. + + png_set_shift(png_ptr, &sig_bit); + +PNG files store 16 bit pixels in network byte order (big-endian, +ie. most significant bits first). This code would be used if they are +supplied the other way (little-endian, i.e. least significant bits +first, the way PCs store them): + + if (bit_depth > 8) + png_set_swap(png_ptr); + +If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you +need to change the order the pixels are packed into bytes, you can use: + + if (bit_depth < 8) + png_set_packswap(png_ptr); + +PNG files store 3 color pixels in red, green, blue order. This code +would be used if they are supplied as blue, green, red: + + png_set_bgr(png_ptr); + +PNG files describe monochrome as black being zero and white being +one. This code would be used if the pixels are supplied with this reversed +(black being one and white being zero): + + png_set_invert_mono(png_ptr); + +Finally, you can write your own transformation function if none of +the existing ones meets your needs. This is done by setting a callback +with + + png_set_write_user_transform_fn(png_ptr, + write_transform_fn); + +You must supply the function + + void write_transform_fn(png_ptr ptr, row_info_ptr + row_info, png_bytep data) + +See pngtest.c for a working example. Your function will be called +before any of the other transformations are processed. + +You can also set up a pointer to a user structure for use by your +callback function. + + png_set_user_transform_info(png_ptr, user_ptr, 0, 0); + +The user_channels and user_depth parameters of this function are ignored +when writing; you can set them to zero as shown. + +You can retrieve the pointer via the function png_get_user_transform_ptr(). +For example: + + voidp write_user_transform_ptr = + png_get_user_transform_ptr(png_ptr); + +It is possible to have libpng flush any pending output, either manually, +or automatically after a certain number of lines have been written. To +flush the output stream a single time call: + + png_write_flush(png_ptr); + +and to have libpng flush the output stream periodically after a certain +number of scanlines have been written, call: + + png_set_flush(png_ptr, nrows); + +Note that the distance between rows is from the last time png_write_flush() +was called, or the first row of the image if it has never been called. +So if you write 50 lines, and then png_set_flush 25, it will flush the +output on the next scanline, and every 25 lines thereafter, unless +png_write_flush() is called before 25 more lines have been written. +If nrows is too small (less than about 10 lines for a 640 pixel wide +RGB image) the image compression may decrease noticeably (although this +may be acceptable for real-time applications). Infrequent flushing will +only degrade the compression performance by a few percent over images +that do not use flushing. + +Writing the image data + +That's it for the transformations. Now you can write the image data. +The simplest way to do this is in one function call. If you have the +whole image in memory, you can just call png_write_image() and libpng +will write the image. You will need to pass in an array of pointers to +each row. This function automatically handles interlacing, so you don't +need to call png_set_interlace_handling() or call this function multiple +times, or any of that other stuff necessary with png_write_rows(). + + png_write_image(png_ptr, row_pointers); + +where row_pointers is: + + png_byte *row_pointers[height]; + +You can point to void or char or whatever you use for pixels. + +If you don't want to write the whole image at once, you can +use png_write_rows() instead. If the file is not interlaced, +this is simple: + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +row_pointers is the same as in the png_write_image() call. + +If you are just writing one row at a time, you can do this with +a single row_pointer instead of an array of row_pointers: + + png_bytep row_pointer = row; + + png_write_row(png_ptr, row_pointer); + +When the file is interlaced, things can get a good deal more +complicated. The only currently (as of the PNG Specification +version 1.2, dated July 1999) defined interlacing scheme for PNG files +is the "Adam7" interlace scheme, that breaks down an +image into seven smaller images of varying size. libpng will build +these images for you, or you can do them yourself. If you want to +build them yourself, see the PNG specification for details of which +pixels to write when. + +If you don't want libpng to handle the interlacing details, just +use png_set_interlace_handling() and call png_write_rows() the +correct number of times to write all seven sub-images. + +If you want libpng to build the sub-images, call this before you start +writing any rows: + + number_of_passes = + png_set_interlace_handling(png_ptr); + +This will return the number of passes needed. Currently, this +is seven, but may change if another interlace type is added. + +Then write the complete image number_of_passes times. + + png_write_rows(png_ptr, row_pointers, + number_of_rows); + +As some of these rows are not used, and thus return immediately, +you may want to read about interlacing in the PNG specification, +and only update the rows that are actually used. + +Finishing a sequential write + +After you are finished writing the image, you should finish writing +the file. If you are interested in writing comments or time, you should +pass an appropriately filled png_info pointer. If you are not interested, +you can pass NULL. + + png_write_end(png_ptr, info_ptr); + +When you are done, you can free all memory used by libpng like this: + + png_destroy_write_struct(&png_ptr, &info_ptr); + +It is also possible to individually free the info_ptr members that +point to libpng-allocated storage with the following function: + + png_free_data(png_ptr, info_ptr, mask, seq) + mask - identifies data to be freed, a mask + containing the logical OR of one or + more of + PNG_FREE_PLTE, PNG_FREE_TRNS, + PNG_FREE_HIST, PNG_FREE_ICCP, + PNG_FREE_PCAL, PNG_FREE_ROWS, + PNG_FREE_SCAL, PNG_FREE_SPLT, + PNG_FREE_TEXT, PNG_FREE_UNKN, + or simply PNG_FREE_ALL + seq - sequence number of item to be freed + (-1 for all items) + +This function may be safely called when the relevant storage has +already been freed, or has not yet been allocated, or was allocated +by the user and not by libpng, and will in those +cases do nothing. The "seq" parameter is ignored if only one item +of the selected data type, such as PLTE, is allowed. If "seq" is not +-1, and multiple items are allowed for the data type identified in +the mask, such as text or sPLT, only the n'th item in the structure +is freed, where n is "seq". + +If you allocated data such as a palette that you passed +in to libpng with png_set_*, you must not free it until just before the call to +png_destroy_write_struct(). + +The default behavior is only to free data that was allocated internally +by libpng. This can be changed, so that libpng will not free the data, +or so that it will free data that was allocated by the user with png_malloc() +or png_zalloc() and passed in via a png_set_*() function, with + + png_data_freer(png_ptr, info_ptr, freer, mask) + mask - which data elements are affected + same choices as in png_free_data() + freer - one of + PNG_DESTROY_WILL_FREE_DATA + PNG_SET_WILL_FREE_DATA + PNG_USER_WILL_FREE_DATA + +For example, to transfer responsibility for some data from a read structure +to a write structure, you could use + + png_data_freer(read_ptr, read_info_ptr, + PNG_USER_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + png_data_freer(write_ptr, write_info_ptr, + PNG_DESTROY_WILL_FREE_DATA, + PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST) + +thereby briefly reassigning responsibility for freeing to the user but +immediately afterwards reassigning it once more to the write_destroy +function. Having done this, it would then be safe to destroy the read +structure and continue to use the PLTE, tRNS, and hIST data in the write +structure. + +This function only affects data that has already been allocated. +You can call this function before calling after the png_set_*() functions +to control whether the user or png_destroy_*() is supposed to free the data. +When the user assumes responsibility for libpng-allocated data, the +application must use +png_free() to free it, and when the user transfers responsibility to libpng +for data that the user has allocated, the user must have used png_malloc() +or png_zalloc() to allocate it. + +If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword +separately, do not transfer responsibility for freeing text_ptr to libpng, +because when libpng fills a png_text structure it combines these members with +the key member, and png_free_data() will free only text_ptr.key. Similarly, +if you transfer responsibility for free'ing text_ptr from libpng to your +application, your application must not separately free those members. +For a more compact example of writing a PNG image, see the file example.c. + +V. Modifying/Customizing libpng: + +There are three issues here. The first is changing how libpng does +standard things like memory allocation, input/output, and error handling. +The second deals with more complicated things like adding new chunks, +adding new transformations, and generally changing how libpng works. +Both of those are compile-time issues; that is, they are generally +determined at the time the code is written, and there is rarely a need +to provide the user with a means of changing them. The third is a +run-time issue: choosing between and/or tuning one or more alternate +versions of computationally intensive routines; specifically, optimized +assembly-language (and therefore compiler- and platform-dependent) +versions. + +Memory allocation, input/output, and error handling + +All of the memory allocation, input/output, and error handling in libpng +goes through callbacks that are user-settable. The default routines are +in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change +these functions, call the appropriate png_set_*_fn() function. + +Memory allocation is done through the functions png_malloc(), png_zalloc(), +and png_free(). These currently just call the standard C functions. If +your pointers can't access more then 64K at a time, you will want to set +MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling +memory allocation on a platform will change between applications, these +functions must be modified in the library at compile time. If you prefer +to use a different method of allocating and freeing data, you can use + + png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) + +This function also provides a void pointer that can be retrieved via + + mem_ptr=png_get_mem_ptr(png_ptr); + +Your replacement memory functions must have prototypes as follows: + + png_voidp malloc_fn(png_structp png_ptr, + png_uint_32 size); + void free_fn(png_structp png_ptr, png_voidp ptr); + +Your malloc_fn() can return NULL in case of failure. The png_malloc() +function will call png_error() if it receives a NULL from the system +memory allocator or from your replacement malloc_fn(). + +Input/Output in libpng is done through png_read() and png_write(), +which currently just call fread() and fwrite(). The FILE * is stored in +png_struct and is initialized via png_init_io(). If you wish to change +the method of I/O, the library supplies callbacks that you can set +through the function png_set_read_fn() and png_set_write_fn() at run +time, instead of calling the png_init_io() function. These functions +also provide a void pointer that can be retrieved via the function +png_get_io_ptr(). For example: + + png_set_read_fn(png_structp read_ptr, + voidp read_io_ptr, png_rw_ptr read_data_fn) + + png_set_write_fn(png_structp write_ptr, + voidp write_io_ptr, png_rw_ptr write_data_fn, + png_flush_ptr output_flush_fn); + + voidp read_io_ptr = png_get_io_ptr(read_ptr); + voidp write_io_ptr = png_get_io_ptr(write_ptr); + +The replacement I/O functions must have prototypes as follows: + + void user_read_data(png_structp png_ptr, + png_bytep data, png_uint_32 length); + void user_write_data(png_structp png_ptr, + png_bytep data, png_uint_32 length); + void user_flush_data(png_structp png_ptr); + +Supplying NULL for the read, write, or flush functions sets them back +to using the default C stream functions. It is an error to read from +a write stream, and vice versa. + +Error handling in libpng is done through png_error() and png_warning(). +Errors handled through png_error() are fatal, meaning that png_error() +should never return to its caller. Currently, this is handled via +setjmp() and longjmp() (unless you have compiled libpng with +PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()), +but you could change this to do things like exit() if you should wish. + +On non-fatal errors, png_warning() is called +to print a warning message, and then control returns to the calling code. +By default png_error() and png_warning() print a message on stderr via +fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined +(because you don't want the messages) or PNG_NO_STDIO defined (because +fprintf() isn't available). If you wish to change the behavior of the error +functions, you will need to set up your own message callbacks. These +functions are normally supplied at the time that the png_struct is created. +It is also possible to redirect errors and warnings to your own replacement +functions after png_create_*_struct() has been called by calling: + + png_set_error_fn(png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warning_fn); + + png_voidp error_ptr = png_get_error_ptr(png_ptr); + +If NULL is supplied for either error_fn or warning_fn, then the libpng +default function will be used, calling fprintf() and/or longjmp() if a +problem is encountered. The replacement error functions should have +parameters as follows: + + void user_error_fn(png_structp png_ptr, + png_const_charp error_msg); + void user_warning_fn(png_structp png_ptr, + png_const_charp warning_msg); + +The motivation behind using setjmp() and longjmp() is the C++ throw and +catch exception handling methods. This makes the code much easier to write, +as there is no need to check every return code of every function call. +However, there are some uncertainties about the status of local variables +after a longjmp, so the user may want to be careful about doing anything after +setjmp returns non-zero besides returning itself. Consult your compiler +documentation for more details. For an alternative approach, you may wish +to use the "cexcept" facility (see http://cexcept.sourceforge.net). + +Custom chunks + +If you need to read or write custom chunks, you may need to get deeper +into the libpng code. The library now has mechanisms for storing +and writing chunks of unknown type; you can even declare callbacks +for custom chunks. Hoewver, this may not be good enough if the +library code itself needs to know about interactions between your +chunk and existing `intrinsic' chunks. + +If you need to write a new intrinsic chunk, first read the PNG +specification. Acquire a first level of +understanding of how it works. Pay particular attention to the +sections that describe chunk names, and look at how other chunks were +designed, so you can do things similarly. Second, check out the +sections of libpng that read and write chunks. Try to find a chunk +that is similar to yours and use it as a template. More details can +be found in the comments inside the code. It is best to handle unknown +chunks in a generic method, via callback functions, instead of by +modifying libpng functions. + +If you wish to write your own transformation for the data, look through +the part of the code that does the transformations, and check out some of +the simpler ones to get an idea of how they work. Try to find a similar +transformation to the one you want to add and copy off of it. More details +can be found in the comments inside the code itself. + +Configuring for 16 bit platforms + +You will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more then 64K at a time. Even if you can, the memory +won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. + +Configuring for DOS + +For DOS users who only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +Configuring for Medium Model + +Libpng's support for medium model has been tested on most of the popular +compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the rows of data are defined as png_bytepp, which is an +unsigned char far * far *. + +Configuring for gui/windowing platforms: + +You will need to write new error and warning functions that use the GUI +interface, as described previously, and set them to be the error and +warning functions at the time that png_create_*_struct() is called, +in order to have them available during the structure initialization. +They can be changed later via png_set_error_fn(). On some compilers, +you may also have to change the memory allocators (png_malloc, etc.). + +Configuring for compiler xxx: + +All includes for libpng are in pngconf.h. If you need to add/change/delete +an include, this is the place to do it. The includes that are not +needed outside libpng are protected by the PNG_INTERNAL definition, +which is only defined for those routines inside libpng itself. The +files in libpng proper only include png.h, which includes pngconf.h. + +Configuring zlib: + +There are special functions to configure the compression. Perhaps the +most useful one changes the compression level, which currently uses +input compression values in the range 0 - 9. The library normally +uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests +have shown that for a large majority of images, compression values in +the range 3-6 compress nearly as well as higher levels, and do so much +faster. For online applications it may be desirable to have maximum speed +(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also +specify no compression (Z_NO_COMPRESSION = 0), but this would create +files larger than just storing the raw bitmap. You can specify the +compression level by calling: + + png_set_compression_level(png_ptr, level); + +Another useful one is to reduce the memory level used by the library. +The memory level defaults to 8, but it can be lowered if you are +short on memory (running DOS, for example, where you only have 640K). + + png_set_compression_mem_level(png_ptr, level); + +The other functions are for configuring zlib. They are not recommended +for normal use and may result in writing an invalid PNG file. See +zlib.h for more information on what these mean. + + png_set_compression_strategy(png_ptr, + strategy); + png_set_compression_window_bits(png_ptr, + window_bits); + png_set_compression_method(png_ptr, method); + png_set_compression_buffer_size(png_ptr, size); + +Controlling row filtering + +If you want to control whether libpng uses filtering or not, which +filters are used, and how it goes about picking row filters, you +can call one of these functions. The selection and configuration +of row filters can have a significant impact on the size and +encoding speed and a somewhat lesser impact on the decoding speed +of an image. Filtering is enabled by default for RGB and grayscale +images (with and without alpha), but not for paletted images nor +for any images with bit depths less than 8 bits/pixel. + +The 'method' parameter sets the main filtering method, which is +currently only '0' in the PNG 1.2 specification. The 'filters' +parameter sets which filter(s), if any, should be used for each +scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS +to turn filtering on and off, respectively. + +Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB, +PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise +ORed together with '|' to specify one or more filters to use. +These filters are described in more detail in the PNG specification. If +you intend to change the filter type during the course of writing +the image, you should start with flags set for all of the filters +you intend to use so that libpng can initialize its internal +structures appropriately for all of the filter types. + + filters = PNG_FILTER_NONE | PNG_FILTER_SUB + PNG_FILTER_UP | PNG_FILTER_AVE | + PNG_FILTER_PAETH | PNG_ALL_FILTERS; + or + filters = one of PNG_FILTER_VALUE_NONE, + PNG_FILTER_VALUE_SUB, PNG_FILTER_VALUE_UP, + PNG_FILTER_VALUE_AVE, PNG_FILTER_VALUE_PAETH + + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, + filters); + The second parameter can also be + PNG_INTRAPIXEL_DIFFERENCING if you are + writing a PNG to be embedded in a MNG + datastream. This parameter must be the + same as the value of filter_method used + in png_set_IHDR(). + +It is also possible to influence how libpng chooses from among the +available filters. This is done in two ways - by telling it how +important it is to keep the same filter for successive rows, and +by telling it the relative computational costs of the filters. + + double weights[3] = {1.5, 1.3, 1.1}, + costs[PNG_FILTER_VALUE_LAST] = + {1.0, 1.3, 1.3, 1.5, 1.7}; + + png_set_filter_selection(png_ptr, + PNG_FILTER_SELECTION_WEIGHTED, 3, + weights, costs); + +The weights are multiplying factors that indicate to libpng that the +row filter should be the same for successive rows unless another row filter +is that many times better than the previous filter. In the above example, +if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a +"sum of absolute differences" 1.5 x 1.3 times higher than other filters +and still be chosen, while the NONE filter could have a sum 1.1 times +higher than other filters and still be chosen. Unspecified weights are +taken to be 1.0, and the specified weights should probably be declining +like those above in order to emphasize recent filters over older filters. + +The filter costs specify for each filter type a relative decoding cost +to be considered when selecting row filters. This means that filters +with higher costs are less likely to be chosen over filters with lower +costs, unless their "sum of absolute differences" is that much smaller. +The costs do not necessarily reflect the exact computational speeds of +the various filters, since this would unduly influence the final image +size. + +Note that the numbers above were invented purely for this example and +are given only to help explain the function usage. Little testing has +been done to find optimum values for either the costs or the weights. + +Removing unwanted object code + +There are a bunch of #define's in pngconf.h that control what parts of +libpng are compiled. All the defines end in _SUPPORTED. If you are +never going to use a capability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space, or +you can turn off individual capabilities with defines that begin with +PNG_NO_. + +You can also turn all of the transforms and ancillary chunk capabilities +off en masse with compiler directives that define +PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, +or all four, +along with directives to turn on any of the capabilities that you do +want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable +the extra transformations but still leave the library fully capable of reading +and writing PNG files with all known public chunks +Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive +produces a library that is incapable of reading or writing ancillary chunks. +If you are not using the progressive reading capability, you can +turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse +this with the INTERLACING capability, which you'll still have). + +All the reading and writing specific code are in separate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with pngr and all the writing files start with +pngw. The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the library, +as this will cause applications linked with different versions of the +library to fail if they call functions not available in your library. +The size of the library itself should not be an issue, because only +those sections that are actually used will be loaded into memory. + +Requesting debug printout + +The macro definition PNG_DEBUG can be used to request debugging +printout. Set it to an integer value in the range 0 to 3. Higher +numbers result in increasing amounts of debugging information. The +information is printed to the "stderr" file, unless another file +name is specified in the PNG_DEBUG_FILE macro definition. + +When PNG_DEBUG > 0, the following functions (macros) become available: + + png_debug(level, message) + png_debug1(level, message, p1) + png_debug2(level, message, p1, p2) + +in which "level" is compared to PNG_DEBUG to decide whether to print +the message, "message" is the formatted string to be printed, +and p1 and p2 are parameters that are to be embedded in the string +according to printf-style formatting directives. For example, + + png_debug1(2, "foo=%d\n", foo); + +is expanded to + + if(PNG_DEBUG > 2) + fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo); + +When PNG_DEBUG is defined but is zero, the macros aren't defined, but you +can still use PNG_DEBUG to control your own debugging: + + #ifdef PNG_DEBUG + fprintf(stderr, ... + #endif + +When PNG_DEBUG = 1, the macros are defined, but only png_debug statements +having level = 0 will be printed. There aren't any such statements in +this version of libpng, but if you insert some they will be printed. + + +VI. MNG support + +The MNG specification (available at http://www.libpng.org/pub/mng) allows +certain extensions to PNG for PNG images that are embedded in MNG datastreams. +Libpng can support some of these extensions. To enable them, use the +png_permit_mng_features() function: + + feature_set = png_permit_mng_features(png_ptr, mask) + mask is a png_uint_32 containing the logical OR of the + features you want to enable. These include + PNG_FLAG_MNG_EMPTY_PLTE + PNG_FLAG_MNG_FILTER_64 + PNG_ALL_MNG_FEATURES + feature_set is a png_32_uint that is the logical AND of + your mask with the set of MNG features that is + supported by the version of libpng that you are using. + +It is an error to use this function when reading or writing a standalone +PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped +in a MNG datastream. As a minimum, it must have the MNG 8-byte signature +and the MHDR and MEND chunks. Libpng does not provide support for these +or any other MNG chunks; your application must provide its own support for +them. You may wish to consider using libmng (available at +http://www.libmng.com) instead. + +VII. Changes to Libpng from version 0.88 + +It should be noted that versions of libpng later than 0.96 are not +distributed by the original libpng author, Guy Schalnat, nor by +Andreas Dilger, who had taken over from Guy during 1996 and 1997, and +distributed versions 0.89 through 0.96, but rather by another member +of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are +still alive and well, but they have moved on to other things. + +The old libpng functions png_read_init(), png_write_init(), +png_info_init(), png_read_destroy(), and png_write_destroy() have been +moved to PNG_INTERNAL in version 0.95 to discourage their use. These +functions will be removed from libpng version 2.0.0. + +The preferred method of creating and initializing the libpng structures is +via the png_create_read_struct(), png_create_write_struct(), and +png_create_info_struct() because they isolate the size of the structures +from the application, allow version error checking, and also allow the +use of custom error handling routines during the initialization, which +the old functions do not. The functions png_read_destroy() and +png_write_destroy() do not actually free the memory that libpng +allocated for these structs, but just reset the data structures, so they +can be used instead of png_destroy_read_struct() and +png_destroy_write_struct() if you feel there is too much system overhead +allocating and freeing the png_struct for each image read. + +Setting the error callbacks via png_set_message_fn() before +png_read_init() as was suggested in libpng-0.88 is no longer supported +because this caused applications that do not use custom error functions +to fail if the png_ptr was not initialized to zero. It is still possible +to set the error callbacks AFTER png_read_init(), or to change them with +png_set_error_fn(), which is essentially the same function, but with a new +name to force compilation errors with applications that try to use the old +method. + +Starting with version 1.0.7, you can find out which version of the library +you are using at run-time: + + png_uint_32 libpng_vn = png_access_version_number(); + +The number libpng_vn is constructed from the major version, minor +version with leading zero, and release number with leading zero, +(e.g., libpng_vn for version 1.0.7 is 10007). + +You can also check which version of png.h you used when compiling your +application: + + png_uint_32 application_vn = PNG_LIBPNG_VER; + +VIII. Y2K Compliance in libpng + +June 8, 2001 + +Since the PNG Development group is an ad-hoc body, we can't make +an official declaration. + +This is your unofficial assurance that libpng from version 0.71 and +upward through 1.0.12 are Y2K compliant. It is my belief that earlier +versions were also Y2K compliant. + +Libpng only has three year fields. One is a 2-byte unsigned integer that +will hold years up to 65535. The other two hold the date in text +format, and will hold years up to 9999. + +The integer is + "png_uint_16 year" in png_time_struct. + +The strings are + "png_charp time_buffer" in png_struct and + "near_time_buffer", which is a local character string in png.c. + +There are seven time-related functions: + + png_convert_to_rfc_1123() in png.c + (formerly png_convert_to_rfc_1152() in error) + png_convert_from_struct_tm() in pngwrite.c, called + in pngwrite.c + png_convert_from_time_t() in pngwrite.c + png_get_tIME() in pngget.c + png_handle_tIME() in pngrutil.c, called in pngread.c + png_set_tIME() in pngset.c + png_write_tIME() in pngwutil.c, called in pngwrite.c + +All appear to handle dates properly in a Y2K environment. The +png_convert_from_time_t() function calls gmtime() to convert from system +clock time, which returns (year - 1900), which we properly convert to +the full 4-digit year. There is a possibility that applications using +libpng are not passing 4-digit years into the png_convert_to_rfc_1123() +function, or that they are incorrectly passing only a 2-digit year +instead of "year - 1900" into the png_convert_from_struct_tm() function, +but this is not under our control. The libpng documentation has always +stated that it works with 4-digit years, and the APIs have been +documented as such. + +The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned +integer to hold the year, and can hold years as large as 65535. + +zlib, upon which libpng depends, is also Y2K compliant. It contains +no date-related code. + + + Glenn Randers-Pehrson + libpng maintainer + PNG Development Group diff --git a/freeimage241/Source/LibPNG/png.c b/freeimage241/Source/LibPNG/png.c new file mode 100644 index 0000000..0cc4e8e --- /dev/null +++ b/freeimage241/Source/LibPNG/png.c @@ -0,0 +1,729 @@ + +/* png.c - location for general purpose libpng functions + * + * libpng version 1.0.12 - June 8, 2001 + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + */ + +#define PNG_INTERNAL +#define PNG_NO_EXTERN +#include "png.h" + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_0_12 Your_png_h_is_not_version_1_0_12; + +/* Version information for C files. This had better match the version + * string defined in png.h. */ + +#ifdef PNG_USE_GLOBAL_ARRAYS +/* png_libpng_ver was changed to a function in version 1.0.5c */ +const char png_libpng_ver[18] = "1.0.12"; + +/* png_sig was changed to a function in version 1.0.5c */ +/* Place to hold the signature string for a PNG file. */ +const png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + +/* Invoke global declarations for constant strings for known chunk types */ +PNG_IHDR; +PNG_IDAT; +PNG_IEND; +PNG_PLTE; +PNG_bKGD; +PNG_cHRM; +PNG_gAMA; +PNG_hIST; +PNG_iCCP; +PNG_iTXt; +PNG_oFFs; +PNG_pCAL; +PNG_sCAL; +PNG_pHYs; +PNG_sBIT; +PNG_sPLT; +PNG_sRGB; +PNG_tEXt; +PNG_tIME; +PNG_tRNS; +PNG_zTXt; + +/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + +/* start of interlace block */ +const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + +/* offset to next interlace block */ +const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + +/* start of interlace block in the y direction */ +const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + +/* offset to next interlace block in the y direction */ +const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + +/* width of interlace block (used in assembler routines only) */ +#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW +const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; +#endif + +/* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h +const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; +*/ + +/* Mask to determine which pixels are valid in a pass */ +const int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; + +/* Mask to determine which pixels to overwrite while displaying */ +const int FARDATA png_pass_dsp_mask[] + = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; + +#endif + +/* Tells libpng that we have already handled the first "num_bytes" bytes + * of the PNG file signature. If the PNG data is embedded into another + * stream we can set num_bytes = 8 so that libpng will not attempt to read + * or write any of the magic bytes before it starts on the IHDR. + */ + +void PNGAPI +png_set_sig_bytes(png_structp png_ptr, int num_bytes) +{ + png_debug(1, "in png_set_sig_bytes\n"); + if (num_bytes > 8) + png_error(png_ptr, "Too many bytes for PNG signature."); + + png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); +} + +/* Checks whether the supplied bytes match the PNG signature. We allow + * checking less than the full 8-byte signature so that those apps that + * already read the first few bytes of a file to determine the file type + * can simply check the remaining bytes for extra assurance. Returns + * an integer less than, equal to, or greater than zero if sig is found, + * respectively, to be less than, to match, or be greater than the correct + * PNG signature (this is the same behaviour as strcmp, memcmp, etc). + */ +int PNGAPI +png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + if (num_to_check > 8) + num_to_check = 8; + else if (num_to_check < 1) + return (0); + + if (start > 7) + return (0); + + if (start + num_to_check > 8) + num_to_check = 8 - start; + + return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); +} + +/* (Obsolete) function to check signature bytes. It does not allow one + * to check a partial signature. This function might be removed in the + * future - use png_sig_cmp(). Returns true (nonzero) if the file is a PNG. + */ +int PNGAPI +png_check_sig(png_bytep sig, int num) +{ + return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num)); +} + +/* Function to allocate memory for zlib and clear it to 0. */ +voidpf /* PRIVATE */ +png_zalloc(voidpf png_ptr, uInt items, uInt size) +{ + png_uint_32 num_bytes = (png_uint_32)items * size; + png_voidp ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); + +#ifndef PNG_NO_ZALLOC_ZERO + if (num_bytes > (png_uint_32)0x8000L) + { + png_memset(ptr, 0, (png_size_t)0x8000L); + png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0, + (png_size_t)(num_bytes - (png_uint_32)0x8000L)); + } + else + { + png_memset(ptr, 0, (png_size_t)num_bytes); + } +#endif + return ((voidpf)ptr); +} + +/* function to free memory for zlib */ +void /* PRIVATE */ +png_zfree(voidpf png_ptr, voidpf ptr) +{ + png_free((png_structp)png_ptr, (png_voidp)ptr); +} + +/* Reset the CRC variable to 32 bits of 1's. Care must be taken + * in case CRC is > 32 bits to leave the top bits 0. + */ +void /* PRIVATE */ +png_reset_crc(png_structp png_ptr) +{ + png_ptr->crc = crc32(0, Z_NULL, 0); +} + +/* Calculate the CRC over a section of data. We can only pass as + * much data to this routine as the largest single buffer size. We + * also check that this data will actually be used before going to the + * trouble of calculating it. + */ +void /* PRIVATE */ +png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length) +{ + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + if (need_crc) + png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); +} + +/* Allocate the memory for an info_struct for the application. We don't + * really need the png_ptr, but it could potentially be useful in the + * future. This should be used in favour of malloc(sizeof(png_info)) + * and png_info_init() so that applications that want to use a shared + * libpng don't have to be recompiled if png_info changes size. + */ +png_infop PNGAPI +png_create_info_struct(png_structp png_ptr) +{ + png_infop info_ptr; + + png_debug(1, "in png_create_info_struct\n"); + if(png_ptr == NULL) return (NULL); +#ifdef PNG_USER_MEM_SUPPORTED + if ((info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, + png_ptr->malloc_fn, png_ptr->mem_ptr)) != NULL) +#else + if ((info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO)) != NULL) +#endif + { + png_info_init_3(&info_ptr, sizeof(png_info)); + } + + return (info_ptr); +} + +/* This function frees the memory associated with a single info struct. + * Normally, one would use either png_destroy_read_struct() or + * png_destroy_write_struct() to free an info struct, but this may be + * useful for some applications. + */ +void PNGAPI +png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) +{ + png_infop info_ptr = NULL; + + png_debug(1, "in png_destroy_info_struct\n"); + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + png_info_destroy(png_ptr, info_ptr); + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn, + png_ptr->mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = (png_infop)NULL; + } +} + +/* Initialize the info structure. This is now an internal function (0.89) + * and applications using it are urged to use png_create_info_struct() + * instead. + */ +#undef png_info_init +void PNGAPI +png_info_init(png_infop info_ptr) +{ + /* We only come here via pre-1.0.12-compiled applications */ + png_info_init_3(&info_ptr, 0); +} + +void PNGAPI +png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) +{ + png_infop info_ptr = *ptr_ptr; + + png_debug(1, "in png_info_init_3\n"); + + if(sizeof(png_info) > png_info_struct_size) + { + png_destroy_struct(info_ptr); + info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); + *ptr_ptr = info_ptr; + } + + /* set everything to 0 */ + png_memset(info_ptr, 0, sizeof (png_info)); +} + +#ifdef PNG_FREE_ME_SUPPORTED +void PNGAPI +png_data_freer(png_structp png_ptr, png_infop info_ptr, + int freer, png_uint_32 mask) +{ + png_debug(1, "in png_data_freer\n"); + if (png_ptr == NULL || info_ptr == NULL) + return; + if(freer == PNG_DESTROY_WILL_FREE_DATA) + info_ptr->free_me |= mask; + else if(freer == PNG_USER_WILL_FREE_DATA) + info_ptr->free_me &= ~mask; + else + png_warning(png_ptr, + "Unknown freer parameter in png_data_freer."); +} +#endif + +void PNGAPI +png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, + int num) +{ + png_debug(1, "in png_free_data\n"); + if (png_ptr == NULL || info_ptr == NULL) + return; + +#if defined(PNG_TEXT_SUPPORTED) +/* free text item num or (if num == -1) all text items */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) +#else +if (mask & PNG_FREE_TEXT) +#endif +{ + if (num != -1) + { + if (info_ptr->text && info_ptr->text[num].key) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + } + else + { + int i; + for (i = 0; i < info_ptr->num_text; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + info_ptr->num_text=0; + } +} +#endif + +#if defined(PNG_tRNS_SUPPORTED) +/* free any tRNS entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) +#else +if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS)) +#endif +{ + png_free(png_ptr, info_ptr->trans); + info_ptr->valid &= ~PNG_INFO_tRNS; + info_ptr->trans = NULL; +} +#endif + +#if defined(PNG_sCAL_SUPPORTED) +/* free any sCAL entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) +#else +if (mask & PNG_FREE_SCAL) +#endif +{ +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); + info_ptr->scal_s_width = NULL; + info_ptr->scal_s_height = NULL; +#endif + info_ptr->valid &= ~PNG_INFO_sCAL; +} +#endif + +#if defined(PNG_pCAL_SUPPORTED) +/* free any pCAL entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) +#else +if (mask & PNG_FREE_PCAL) +#endif +{ + png_free(png_ptr, info_ptr->pcal_purpose); + png_free(png_ptr, info_ptr->pcal_units); + info_ptr->pcal_purpose = NULL; + info_ptr->pcal_units = NULL; + if (info_ptr->pcal_params != NULL) + { + int i; + for (i = 0; i < (int)info_ptr->pcal_nparams; i++) + { + png_free(png_ptr, info_ptr->pcal_params[i]); + info_ptr->pcal_params[i]=NULL; + } + png_free(png_ptr, info_ptr->pcal_params); + info_ptr->pcal_params = NULL; + } + info_ptr->valid &= ~PNG_INFO_pCAL; +} +#endif + +#if defined(PNG_iCCP_SUPPORTED) +/* free any iCCP entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) +#else +if (mask & PNG_FREE_ICCP) +#endif +{ + png_free(png_ptr, info_ptr->iccp_name); + png_free(png_ptr, info_ptr->iccp_profile); + info_ptr->iccp_name = NULL; + info_ptr->iccp_profile = NULL; + info_ptr->valid &= ~PNG_INFO_iCCP; +} +#endif + +#if defined(PNG_sPLT_SUPPORTED) +/* free a given sPLT entry, or (if num == -1) all sPLT entries */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) +#else +if (mask & PNG_FREE_SPLT) +#endif +{ + if (num != -1) + { + if(info_ptr->splt_palettes) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } + } + else + { + if(info_ptr->splt_palettes_num) + { + int i; + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + } + info_ptr->valid &= ~PNG_INFO_sPLT; + } +} +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) +#else +if (mask & PNG_FREE_UNKN) +#endif +{ + if (num != -1) + { + if(info_ptr->unknown_chunks) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + } + else + { + int i; + + if(info_ptr->unknown_chunks_num) + { + for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } + } +} +#endif + +#if defined(PNG_hIST_SUPPORTED) +/* free any hIST entry */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_HIST) & info_ptr->free_me) +#else +if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST)) +#endif +{ + png_free(png_ptr, info_ptr->hist); + info_ptr->hist = NULL; + info_ptr->valid &= ~PNG_INFO_hIST; +} +#endif + +/* free any PLTE entry that was internally allocated */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) +#else +if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE)) +#endif +{ + png_zfree(png_ptr, info_ptr->palette); + info_ptr->palette = NULL; + info_ptr->valid &= ~PNG_INFO_PLTE; + info_ptr->num_palette = 0; +} + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* free any image bits attached to the info structure */ +#ifdef PNG_FREE_ME_SUPPORTED +if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) +#else +if (mask & PNG_FREE_ROWS) +#endif +{ + if(info_ptr->row_pointers) + { + int row; + for (row = 0; row < (int)info_ptr->height; row++) + { + png_free(png_ptr, info_ptr->row_pointers[row]); + info_ptr->row_pointers[row]=NULL; + } + png_free(png_ptr, info_ptr->row_pointers); + info_ptr->row_pointers=NULL; + } + info_ptr->valid &= ~PNG_INFO_IDAT; +} +#endif + +#ifdef PNG_FREE_ME_SUPPORTED + if(num == -1) + info_ptr->free_me &= ~mask; + else + info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL); +#endif +} + +/* This is an internal routine to free any memory that the info struct is + * pointing to before re-using it or freeing the struct itself. Recall + * that png_free() checks for NULL pointers for us. + */ +void /* PRIVATE */ +png_info_destroy(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_info_destroy\n"); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + png_ptr->num_chunk_list=0; + } +#endif + + png_info_init_3(&info_ptr, sizeof(png_info)); +} + +/* This function returns a pointer to the io_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy() or png_read_destroy() are called. + */ +png_voidp PNGAPI +png_get_io_ptr(png_structp png_ptr) +{ + return (png_ptr->io_ptr); +} + +#if !defined(PNG_NO_STDIO) +/* Initialize the default input/output functions for the PNG file. If you + * use your own read or write routines, you can call either png_set_read_fn() + * or png_set_write_fn() instead of png_init_io(). If you have defined + * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't + * necessarily available. + */ +void PNGAPI +png_init_io(png_structp png_ptr, png_FILE_p fp) +{ + png_debug(1, "in png_init_io\n"); + png_ptr->io_ptr = (png_voidp)fp; +} +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +/* Convert the supplied time into an RFC 1123 string suitable for use in + * a "Creation Time" or other text-based time string. + */ +png_charp PNGAPI +png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime) +{ + static PNG_CONST char short_months[12][4] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + if (png_ptr->time_buffer == NULL) + { + png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* + sizeof(char))); + } + +#if defined(_WIN32_WCE) + { + wchar_t time_buf[29]; + wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"), + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); + WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, 29, + NULL, NULL); + } +#else +#ifdef USE_FAR_KEYWORD + { + char near_time_buf[29]; + sprintf(near_time_buf, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); + png_memcpy(png_ptr->time_buffer, near_time_buf, + 29*sizeof(char)); + } +#else + sprintf(png_ptr->time_buffer, "%d %s %d %02d:%02d:%02d +0000", + ptime->day % 32, short_months[(ptime->month - 1) % 12], + ptime->year, ptime->hour % 24, ptime->minute % 60, + ptime->second % 61); +#endif +#endif /* _WIN32_WCE */ + return ((png_charp)png_ptr->time_buffer); +} +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + +#if 0 +/* Signature string for a PNG file. */ +png_bytep PNGAPI +png_sig_bytes(void) +{ + return ((png_bytep)"\211\120\116\107\015\012\032\012"); +} +#endif + +png_charp PNGAPI +png_get_copyright(png_structp png_ptr) +{ + if (png_ptr != NULL || png_ptr == NULL) /* silence compiler warning */ + return ((png_charp) "\n libpng version 1.0.12 - June 8, 2001\n\ + Copyright (c) 1998-2001 Glenn Randers-Pehrson\n\ + Copyright (c) 1996, 1997 Andreas Dilger\n\ + Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.\n"); + return ((png_charp) ""); +} + +/* The following return the library version as a short string in the + * format 1.0.0 through 99.99.99zz. To get the version of *.h files used + * with your application, print out PNG_LIBPNG_VER_STRING, which is defined + * in png.h. + */ + +png_charp PNGAPI +png_get_libpng_ver(png_structp png_ptr) +{ + /* Version of *.c files used when building libpng */ + if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return((png_charp) "1.0.12"); + return((png_charp) "1.0.12"); +} + +png_charp PNGAPI +png_get_header_ver(png_structp png_ptr) +{ + /* Version of *.h files used when building libpng */ + if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return((png_charp) PNG_LIBPNG_VER_STRING); + return((png_charp) PNG_LIBPNG_VER_STRING); +} + +png_charp PNGAPI +png_get_header_version(png_structp png_ptr) +{ + /* Returns longer string containing both version and date */ + if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */ + return((png_charp) PNG_HEADER_VERSION_STRING); + return((png_charp) PNG_HEADER_VERSION_STRING); +} + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +int /* PRIVATE */ +png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name) +{ + /* check chunk_name and return "keep" value if it's on the list, else 0 */ + int i; + png_bytep p; + if((png_ptr == NULL && chunk_name == NULL) || png_ptr->num_chunk_list<=0) + return 0; + p=png_ptr->chunk_list+png_ptr->num_chunk_list*5-5; + for (i = png_ptr->num_chunk_list; i; i--, p-=5) + if (!png_memcmp(chunk_name, p, 4)) + return ((int)*(p+4)); + return 0; +} +#endif + +/* This function, added to libpng-1.0.6g, is untested. */ +int PNGAPI +png_reset_zstream(png_structp png_ptr) +{ + return (inflateReset(&png_ptr->zstream)); +} + +/* This function was added to libpng-1.0.7 */ +png_uint_32 PNGAPI +png_access_version_number(void) +{ + /* Version of *.c files used when building libpng */ + return((png_uint_32) 10012L); +} + +/* this function was added to libpng 1.2.0 */ +#if !defined(PNG_USE_PNGGCCRD) && \ + !(defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD)) +int PNGAPI +png_mmx_support(void) +{ + return -1; +} +#endif diff --git a/freeimage241/Source/LibPNG/png.h b/freeimage241/Source/LibPNG/png.h new file mode 100644 index 0000000..7f99453 --- /dev/null +++ b/freeimage241/Source/LibPNG/png.h @@ -0,0 +1,3088 @@ + +/* png.h - header file for PNG reference library + * + * libpng version 1.0.12 - June 8, 2001 + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.0.12 - June 8, 2001: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.11beta1-2 + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng.txt or libpng.3 for more information. The PNG specification + * is available as RFC 2083 + * and as a W3C Recommendation + */ + +/* + * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + * + * If you modify libpng you may insert additional notices immediately following + * this sentence. + * + * libpng versions 1.0.7, July 1, 2000, through 1.0.12, June 8, 2001, are + * Copyright (c) 2000, 2001 Glenn Randers-Pehrson, and are + * distributed according to the same disclaimer and license as libpng-1.0.6 + * with the following individuals added to the list of Contributing Authors + * + * Simon-Pierre Cadieux + * Eric S. Raymond + * Gilles Vollant + * + * and with the following additions to the disclaimer: + * + * There is no warranty against interference with your enjoyment of the + * library or against infringement. There is no warranty that our + * efforts or the library will fulfill any of your particular purposes + * or needs. This library is provided with all faults, and the entire + * risk of satisfactory quality, performance, accuracy, and effort is with + * the user. + * + * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are + * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson + * Distributed according to the same disclaimer and license as libpng-0.96, + * with the following individuals added to the list of Contributing Authors: + * + * Tom Lane + * Glenn Randers-Pehrson + * Willem van Schaik + * + * libpng versions 0.89, June 1996, through 0.96, May 1997, are + * Copyright (c) 1996, 1997 Andreas Dilger + * Distributed according to the same disclaimer and license as libpng-0.88, + * with the following individuals added to the list of Contributing Authors: + * + * John Bowler + * Kevin Bracey + * Sam Bushell + * Magnus Holmgren + * Greg Roelofs + * Tom Tanner + * + * libpng versions 0.5, May 1995, through 0.88, January 1996, are + * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. + * + * For the purposes of this copyright and license, "Contributing Authors" + * is defined as the following set of individuals: + * + * Andreas Dilger + * Dave Martindale + * Guy Eric Schalnat + * Paul Schmidt + * Tim Wegner + * + * The PNG Reference Library is supplied "AS IS". The Contributing Authors + * and Group 42, Inc. disclaim all warranties, expressed or implied, + * including, without limitation, the warranties of merchantability and of + * fitness for any purpose. The Contributing Authors and Group 42, Inc. + * assume no liability for direct, indirect, incidental, special, exemplary, + * or consequential damages, which may result from the use of the PNG + * Reference Library, even if advised of the possibility of such damage. + * + * Permission is hereby granted to use, copy, modify, and distribute this + * source code, or portions hereof, for any purpose, without fee, subject + * to the following restrictions: + * + * 1. The origin of this source code must not be misrepresented. + * + * 2. Altered versions must be plainly marked as such and + * must not be misrepresented as being the original source. + * + * 3. This Copyright notice may not be removed or altered from + * any source or altered source distribution. + * + * The Contributing Authors and Group 42, Inc. specifically permit, without + * fee, and encourage the use of this source code as a component to + * supporting the PNG file format in commercial products. If you use this + * source code in a product, acknowledgment is not required but would be + * appreciated. + */ + +/* + * A "png_get_copyright" function is available, for convenient use in "about" + * boxes and the like: + * + * printf("%s",png_get_copyright(NULL)); + * + * Also, the PNG logo (in PNG format, of course) is supplied in the + * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). + */ + +/* + * Libpng is OSI Certified Open Source Software. OSI Certified is a + * certification mark of the Open Source Initiative. + */ + +/* + * The contributing authors would like to thank all those who helped + * with testing, bug fixes, and patience. This wouldn't have been + * possible without all of you. + * + * Thanks to Frank J. T. Wojcik for helping with the documentation. + */ + +/* + * Y2K compliance in libpng: + * ========================= + * + * June 8, 2001 + * + * Since the PNG Development group is an ad-hoc body, we can't make + * an official declaration. + * + * This is your unofficial assurance that libpng from version 0.71 and + * upward through 1.0.12 are Y2K compliant. It is my belief that earlier + * versions were also Y2K compliant. + * + * Libpng only has three year fields. One is a 2-byte unsigned integer + * that will hold years up to 65535. The other two hold the date in text + * format, and will hold years up to 9999. + * + * The integer is + * "png_uint_16 year" in png_time_struct. + * + * The strings are + * "png_charp time_buffer" in png_struct and + * "near_time_buffer", which is a local character string in png.c. + * + * There are seven time-related functions: + * png.c: png_convert_to_rfc_1123() in png.c + * (formerly png_convert_to_rfc_1152() in error) + * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c + * png_convert_from_time_t() in pngwrite.c + * png_get_tIME() in pngget.c + * png_handle_tIME() in pngrutil.c, called in pngread.c + * png_set_tIME() in pngset.c + * png_write_tIME() in pngwutil.c, called in pngwrite.c + * + * All handle dates properly in a Y2K environment. The + * png_convert_from_time_t() function calls gmtime() to convert from system + * clock time, which returns (year - 1900), which we properly convert to + * the full 4-digit year. There is a possibility that applications using + * libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + * function, or that they are incorrectly passing only a 2-digit year + * instead of "year - 1900" into the png_convert_from_struct_tm() function, + * but this is not under our control. The libpng documentation has always + * stated that it works with 4-digit years, and the APIs have been + * documented as such. + * + * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned + * integer to hold the year, and can hold years as large as 65535. + * + * zlib, upon which libpng depends, is also Y2K compliant. It contains + * no date-related code. + * + * Glenn Randers-Pehrson + * libpng maintainer + * PNG Development Group + */ + +#ifndef PNG_H +#define PNG_H + +/* This is not the place to learn how to use libpng. The file libpng.txt + * describes how to use libpng, and the file example.c summarizes it + * with some code on which to build. This file is useful for looking + * at the actual function definitions and structure components. + */ + +/* Version information for png.h - this should match the version in png.c */ +#define PNG_LIBPNG_VER_STRING "1.0.12" + +#define PNG_LIBPNG_VER_SONUM 2 +#define PNG_LIBPNG_VER_DLLNUM %DLLNUM% + +/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ +#define PNG_LIBPNG_VER_MAJOR 1 +#define PNG_LIBPNG_VER_MINOR 0 +#define PNG_LIBPNG_VER_RELEASE 12 +/* This should match the numeric part of the final component of + * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ + +#define PNG_LIBPNG_VER_BUILD 0 + +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_TYPEMASK 7 +#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with STABLE only */ +#define PNG_LIBPNG_BUILD_TYPE 4 + +/* Careful here. At one time, Guy wanted to use 082, but that would be octal. + * We must not include leading zeros. + * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only + * version 1.0.0 was mis-numbered 100 instead of 10000). From + * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ +#define PNG_LIBPNG_VER 10012 /* 1.0.12 */ + +#ifndef PNG_VERSION_INFO_ONLY + +/* include the compression library's header */ +#include "..\Zlib\zlib.h" + +/* include all user configurable info, including optional assembler routines */ +#include "pngconf.h" + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* This file is arranged in several sections. The first section contains + * structure and type definitions. The second section contains the external + * library functions, while the third has the internal library functions, + * which applications aren't expected to use directly. + */ + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* Version information for C files, stored in png.c. This had better match + * the version above. + */ +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const char) png_libpng_ver[18]; + /* need room for 99.99.99beta99z*/ +#else +#define png_libpng_ver png_get_header_ver(NULL) +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +/* This was removed in version 1.0.5c */ +/* Structures to facilitate easy interlacing. See png.c for more details */ +PNG_EXPORT_VAR (const int FARDATA) png_pass_start[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_inc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_ystart[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_yinc[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_mask[7]; +PNG_EXPORT_VAR (const int FARDATA) png_pass_dsp_mask[7]; +#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW +PNG_EXPORT_VAR (const int FARDATA) png_pass_width[7]; +#endif +/* This isn't currently used. If you need it, see png.c for more details. +PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7]; +*/ +#endif + +#endif /* PNG_NO_EXTERN */ + +/* Three color definitions. The order of the red, green, and blue, (and the + * exact size) is not important, although the size of the fields need to + * be png_byte or png_uint_16 (as defined below). + */ +typedef struct png_color_struct +{ + png_byte red; + png_byte green; + png_byte blue; +} png_color; +typedef png_color FAR * png_colorp; +typedef png_color FAR * FAR * png_colorpp; + +typedef struct png_color_16_struct +{ + png_byte index; /* used for palette files */ + png_uint_16 red; /* for use in red green blue files */ + png_uint_16 green; + png_uint_16 blue; + png_uint_16 gray; /* for use in grayscale files */ +} png_color_16; +typedef png_color_16 FAR * png_color_16p; +typedef png_color_16 FAR * FAR * png_color_16pp; + +typedef struct png_color_8_struct +{ + png_byte red; /* for use in red green blue files */ + png_byte green; + png_byte blue; + png_byte gray; /* for use in grayscale files */ + png_byte alpha; /* for alpha channel files */ +} png_color_8; +typedef png_color_8 FAR * png_color_8p; +typedef png_color_8 FAR * FAR * png_color_8pp; + +/* + * The following two structures are used for the in-core representation + * of sPLT chunks. + */ +typedef struct png_sPLT_entry_struct +{ + png_uint_16 red; + png_uint_16 green; + png_uint_16 blue; + png_uint_16 alpha; + png_uint_16 frequency; +} png_sPLT_entry; +typedef png_sPLT_entry FAR * png_sPLT_entryp; +typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp; + +/* When the depth of the sPLT palette is 8 bits, the color and alpha samples + * occupy the LSB of their respective members, and the MSB of each member + * is zero-filled. The frequency member always occupies the full 16 bits. + */ + +typedef struct png_sPLT_struct +{ + png_charp name; /* palette name */ + png_byte depth; /* depth of palette samples */ + png_sPLT_entryp entries; /* palette entries */ + png_int_32 nentries; /* number of palette entries */ +} png_sPLT_t; +typedef png_sPLT_t FAR * png_sPLT_tp; +typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; + +#ifdef PNG_TEXT_SUPPORTED +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular zero-terminated C string. The "text", "lang", and + * "lang_key" fields can be regular C strings, empty strings, or NULL pointers. + * However, the * structure returned by png_get_text() will always contain + * regular zero-terminated C strings (possibly empty), never NULL pointers, + * so they can be safely used in printf() and other string-handling functions. + */ +typedef struct png_text_struct +{ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ + png_charp key; /* keyword, 1-79 character description of "text" */ + png_charp text; /* comment, may be an empty string (ie "") + or a NULL pointer */ + png_size_t text_length; /* length of the text string */ +#ifdef PNG_iTXt_SUPPORTED + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 0-79 characters + or a NULL pointer */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars or a NULL pointer */ +#endif +} png_text; +typedef png_text FAR * png_textp; +typedef png_text FAR * FAR * png_textpp; +#endif + +/* Supported compression types for text in PNG files (tEXt, and zTXt). + * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ +#define PNG_TEXT_COMPRESSION_NONE_WR -3 +#define PNG_TEXT_COMPRESSION_zTXt_WR -2 +#define PNG_TEXT_COMPRESSION_NONE -1 +#define PNG_TEXT_COMPRESSION_zTXt 0 +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ + +/* png_time is a way to hold the time in an machine independent way. + * Two conversions are provided, both from time_t and struct tm. There + * is no portable way to convert to either of these structures, as far + * as I know. If you know of a portable way, send it to me. As a side + * note - PNG has always been Year 2000 compliant! + */ +typedef struct png_time_struct +{ + png_uint_16 year; /* full year, as in, 1995 */ + png_byte month; /* month of year, 1 - 12 */ + png_byte day; /* day of month, 1 - 31 */ + png_byte hour; /* hour of day, 0 - 23 */ + png_byte minute; /* minute of hour, 0 - 59 */ + png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ +} png_time; +typedef png_time FAR * png_timep; +typedef png_time FAR * FAR * png_timepp; + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* libpng-using applications should NOT directly modify this byte. */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; +typedef png_unknown_chunk FAR * png_unknown_chunkp; +typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; +#endif + +/* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, then call png_write_info(). + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. + * + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. + * + * In any case, the order of the parameters in png_info_struct should NOT + * be changed for as long as possible to keep compatibility with applications + * that use the old direct-access method with png_info_struct. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. + */ +typedef struct png_info_struct +{ + /* the following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following is informational only on read, and not used on writes. */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4)*/ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + /* The gAMA chunk describes the gamma characteristics of the system + * on which the image was created, normally in the range [1.0, 2.5]. + * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. + */ + float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_sRGB_SUPPORTED) + /* GR-P, 0.96a */ + /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ + png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */ +#endif + +#if defined(PNG_TEXT_SUPPORTED) + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read/to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read/to write */ +#endif /* PNG_TEXT_SUPPORTED */ + +#if defined(PNG_tIME_SUPPORTED) + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#if defined(PNG_sBIT_SUPPORTED) + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans; /* transparent values for paletted image */ + png_color_16 trans_values; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#if defined(PNG_oFFs_SUPPORTED) + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#if defined(PNG_pHYs_SUPPORTED) + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#if defined(PNG_hIST_SUPPORTED) + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_cHRM_SUPPORTED + /* The cHRM chunk describes the CIE color characteristics of the monitor + * on which the PNG was created. This data allows the viewer to do gamut + * mapping of the input image to ensure that the viewer sees the same + * colors in the image as the creator. Values are in the range + * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float x_white; + float y_white; + float x_red; + float y_red; + float x_green; + float y_green; + float x_blue; + float y_blue; +#endif +#endif + +#if defined(PNG_pCAL_SUPPORTED) + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + png_size_t unknown_chunks_num; +#endif + +#if defined(PNG_iCCP_SUPPORTED) + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_charp iccp_profile; /* International Color Consortium profile data */ + /* Note to maintainer: should be png_bytep */ + png_uint_32 iccp_proflen; /* ICC profile data length */ + png_byte iccp_compression; /* Always zero */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) + /* data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + png_uint_32 splt_palettes_num; +#endif + +#if defined(PNG_sCAL_SUPPORTED) + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. This external representation is converted to double + * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + double scal_pixel_width; /* width of one pixel */ + double scal_pixel_height; /* height of one pixel */ +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED) + png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */ +#endif + +#if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED) + png_fixed_point int_x_white; + png_fixed_point int_y_white; + png_fixed_point int_x_red; + png_fixed_point int_y_red; + png_fixed_point int_x_green; + png_fixed_point int_y_green; + png_fixed_point int_x_blue; + png_fixed_point int_y_blue; +#endif + +} png_info; + +typedef png_info FAR * png_infop; +typedef png_info FAR * FAR * png_infopp; + +/* Maximum positive integer used in PNG is (2^31)-1 */ +#define PNG_MAX_UINT ((png_uint_32)0x7fffffffL) + +/* These describe the color_type field in png_info. */ +/* color type masks */ +#define PNG_COLOR_MASK_PALETTE 1 +#define PNG_COLOR_MASK_COLOR 2 +#define PNG_COLOR_MASK_ALPHA 4 + +/* color types. Note that not all combinations are legal */ +#define PNG_COLOR_TYPE_GRAY 0 +#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) +#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) +#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) +#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) +/* aliases */ +#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA +#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA + +/* This is for compression type. PNG 1.0-1.2 only define the single type. */ +#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ +#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE + +/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ +#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ +#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE + +/* These are for the interlacing type. These values should NOT be changed. */ +#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ +#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ +#define PNG_INTERLACE_LAST 2 /* Not a valid value */ + +/* These are for the oFFs chunk. These values should NOT be changed. */ +#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ +#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ +#define PNG_OFFSET_LAST 2 /* Not a valid value */ + +/* These are for the pCAL chunk. These values should NOT be changed. */ +#define PNG_EQUATION_LINEAR 0 /* Linear transformation */ +#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ +#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ +#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ +#define PNG_EQUATION_LAST 4 /* Not a valid value */ + +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + +/* These are for the pHYs chunk. These values should NOT be changed. */ +#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ +#define PNG_RESOLUTION_METER 1 /* pixels/meter */ +#define PNG_RESOLUTION_LAST 2 /* Not a valid value */ + +/* These are for the sRGB chunk. These values should NOT be changed. */ +#define PNG_sRGB_INTENT_PERCEPTUAL 0 +#define PNG_sRGB_INTENT_RELATIVE 1 +#define PNG_sRGB_INTENT_SATURATION 2 +#define PNG_sRGB_INTENT_ABSOLUTE 3 +#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ + +/* This is for text chunks */ +#define PNG_KEYWORD_MAX_LENGTH 79 + +/* Maximum number of entries in PLTE/sPLT/tRNS arrays */ +#define PNG_MAX_PALETTE_LENGTH 256 + +/* These determine if an ancillary chunk's data has been successfully read + * from the PNG header, or if the application has filled in the corresponding + * data in the info_struct to be written into the output file. The values + * of the PNG_INFO_ defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_uint_32 rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info FAR * png_row_infop; +typedef png_row_info FAR * FAR * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. + */ +typedef struct png_struct_def png_struct; +typedef png_struct FAR * png_structp; + +typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); +typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t)); +typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp)); +typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32, + int)); +typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop)); +typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp, + png_row_infop, png_bytep)); +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) +typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp)); +#endif +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t)); +typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp)); + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application, except to store + * the jmp_buf. + */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmpbuf; /* used in png_error */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ + png_error_ptr warning_fn; /* function for printing warnings */ + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions*/ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + z_stream zstream; /* pointer to decompression structure (below) */ + png_bytep zbuf; /* buffer for zlib */ + png_size_t zbuf_size; /* size of zbuf */ + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_uint_32 rowbytes; /* size of row in bytes */ + png_uint_32 irowbytes; /* size of current interlaced row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row */ + png_bytep row_buf; /* buffer to save current (unfiltered) row */ + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ + png_row_info row_info; /* used for transformation routines */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + png_uint_16 num_trans; /* number of transparency values */ + png_byte chunk_name[5]; /* null-terminated name of current chunk */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ + png_byte usr_channels; /* channels at start of write */ + png_byte sig_bytes; /* magic bytes read/written from start of file */ + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +#ifdef PNG_LEGACY_SUPPORTED + png_byte filler; /* filler byte for pixel expansion */ +#else + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif +#endif + +#if defined(PNG_bKGD_SUPPORTED) + png_byte background_gamma_type; +# ifdef PNG_FLOATING_POINT_SUPPORTED + float background_gamma; +# endif + png_color_16 background; /* background color in screen gamma space */ +# if defined(PNG_READ_GAMMA_SUPPORTED) + png_color_16 background_1; /* background normalized to gamma 1.0 */ +# endif /* PNG_READ_GAMMA && PNG_bKGD_SUPPORTED */ +#endif /* PNG_bKGD_SUPPORTED */ + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_flush_ptr output_flush_fn;/* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ +#ifdef PNG_FLOATING_POINT_SUPPORTED + float gamma; /* file gamma value */ + float screen_gamma; /* screen gamma value (display_exponent) */ +#endif +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans; /* transparency values for paletted files */ + png_color_16 trans_values; /* transparency values for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ + +# if defined(PNG_TEXT_SUPPORTED) + png_size_t current_text_size; /* current size of text input data */ + png_size_t current_text_left; /* how much text left to read in input */ + png_charp current_text; /* current text chunk buffer */ + png_charp current_text_ptr; /* current location in current_text */ +# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* for the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + png_bytep palette_lookup; /* lookup table for dithering */ + png_bytep dither_index; /* index translation for palette files */ +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED) + png_uint_16p hist; /* histogram */ +#endif + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_charp time_buffer; /* String to hold RFC 1123 time text */ +#endif + +/* New members added in libpng-1.0.6 */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) + png_voidp user_chunk_ptr; + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + int num_chunk_list; + png_bytep chunk_list; +#endif + +/* New members added in libpng-1.0.3 */ +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_byte rgb_to_gray_status; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + png_uint_16 rgb_to_gray_blue_coeff; +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* changed from png_byte to png_uint_32 at version 1.2.0 */ + png_byte mng_features_permitted; +#endif + +/* New member added in libpng-1.0.7 */ +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_fixed_point int_gamma; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_byte filter_type; +#endif + +#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD) +/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */ + png_uint_32 row_buf_size; +#endif + +/* New members added in libpng-1.2.0 */ +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + png_byte mmx_bitdepth_threshold; + png_uint_32 mmx_rowbytes_threshold; + png_uint_32 asm_flags; +#endif + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +}; + + +/* This prevents a compiler error in png_get_copyright() in png.c if png.c + and png.h are both at version 1.0.12 + */ +typedef png_structp version_1_0_12; + +typedef png_struct FAR * FAR * png_structpp; + +/* Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + */ + +/* Returns the version number of the library */ +extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr, + int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num)); + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +extern PNG_EXPORT(png_structp,png_create_read_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +extern PNG_EXPORT(png_structp,png_create_write_struct) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn)); + +extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size) + PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_compression_buffer_size) + PNGARG((png_structp png_ptr, png_uint_32 size)); + +/* Reset the compression stream */ +extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr)); + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_structp,png_create_read_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +extern PNG_EXPORT(png_structp,png_create_write_struct_2) + PNGARG((png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +#endif + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr, + png_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr, + png_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr)); + +/* Allocate and initialize the info structure */ +extern PNG_EXPORT(png_infop,png_create_info_struct) + PNGARG((png_structp png_ptr)); + +/* Initialize the info structure (old interface - DEPRECATED) */ +extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr)); +#define png_info_init(info_ptr) png_info_init_3(&info_ptr, sizeof(png_info)); +extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr, + png_size_t png_info_struct_size)); + +/* Writes all the PNG information before the image. */ +extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read the information before the actual image data. */ +extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +extern PNG_EXPORT(png_charp,png_convert_to_rfc1123) + PNGARG((png_structp png_ptr, png_timep ptime)); +#endif + +#if !defined(_WIN32_WCE) +/* "time.h" functions are not supported on WindowsCE */ +#if defined(PNG_WRITE_tIME_SUPPORTED) +/* convert from a struct tm to png_time */ +extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime, + struct tm FAR * ttime)); + +/* convert from time_t to png_time. Uses gmtime() */ +extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime, + time_t ttime)); +#endif /* PNG_WRITE_tIME_SUPPORTED */ +#endif /* _WIN32_WCE */ + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +/* Expand the grayscale to 24-bit RGB if necessary. */ +extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +/* Reduce RGB to grayscale. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, + int error_action, double red, double green )); +#endif +extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green )); +extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp + png_ptr)); +#endif + +extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth, + png_colorp palette)); + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 24-bit RGB images. */ +extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, + png_uint_32 filler, int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +#define PNG_FILLER_BEFORE 0 +#define PNG_FILLER_AFTER 1 +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr, + png_color_8p true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. */ +extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +/* Handle alpha and tRNS by replacing with a background color. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)); +#endif +#define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +#define PNG_BACKGROUND_GAMMA_SCREEN 1 +#define PNG_BACKGROUND_GAMMA_FILE 2 +#define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* strip the second byte of information from a 16-bit depth file. */ +extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* Turn on dithering, and reduce the palette to the number of colors available. */ +extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_uint_16p histogram, int full_dither)); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +/* Handle gamma correction. Screen_gamma=(display_exponent) */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, + double screen_gamma, double default_file_gamma)); +#endif +#endif + +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */ +/* Deprecated and will be removed. Use png_permit_mng_features() instead. */ +extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr, + int empty_plte_permitted)); +#endif + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +/* Set how many lines between output flushes - 0 for no flushing */ +extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr)); +#endif + +/* optional update palette with requested transformations */ +extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr)); + +/* optional call to update the users info structure */ +extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read a one or more rows of image data.*/ +extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); + +/* read a row of data.*/ +extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr, + png_bytep row, + png_bytep display_row)); + +/* read the whole image into memory at once. */ +extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* write a row of image data */ +extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr, + png_bytep row)); + +/* write a few rows of image data */ +extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr, + png_bytepp row, png_uint_32 num_rows)); + +/* write the image data */ +extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr, + png_bytepp image)); + +/* writes the end of the PNG file. */ +extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* read the end of the PNG file. */ +extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* free any memory associated with the png_info_struct */ +extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr, + png_infopp info_ptr_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp + png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* free all memory used by the read (old method - NOT DLL EXPORTED) */ +extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr, + png_infop end_info_ptr)); + +/* free any memory associated with the png_struct and the png_info_structs */ +extern PNG_EXPORT(void,png_destroy_write_struct) + PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); + +/* free any memory used in info_ptr struct (old method - NOT DLL EXPORTED) */ +extern void png_write_destroy_info PNGARG((png_infop info_ptr)); + +/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ +extern void png_write_destroy PNGARG((png_structp png_ptr)); + +/* set the libpng method of handling chunk CRC errors */ +extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr, + int crit_action, int ancil_action)); + +/* Values for png_set_crc_action() to say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, + int heuristic_method, int num_weights, png_doublep filter_weights, + png_doublep filter_costs)); +#endif +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr, + int level)); + +extern PNG_EXPORT(void,png_set_compression_mem_level) + PNGARG((png_structp png_ptr, int mem_level)); + +extern PNG_EXPORT(void,png_set_compression_strategy) + PNGARG((png_structp png_ptr, int strategy)); + +extern PNG_EXPORT(void,png_set_compression_window_bits) + PNGARG((png_structp png_ptr, int window_bits)); + +extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr, + int method)); + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng.txt for + * more information. + */ + +#if !defined(PNG_NO_STDIO) +/* Initialize the input/output for the PNG file to the default functions. */ +extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + */ +extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr, + png_voidp io_ptr, png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr, + png_read_status_ptr read_row_fn)); + +extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr read_user_transform_fn)); +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp + png_ptr, png_user_transform_ptr write_user_transform_fn)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp + png_ptr, png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr) + PNGARG((png_structp png_ptr)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp + png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr, + png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn)); + +/* returns the user pointer associated with the push read functions */ +extern PNG_EXPORT(png_voidp,png_get_progressive_ptr) + PNGARG((png_structp png_ptr)); + +/* function to be called when data becomes available */ +extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* function that combines rows. Not very much different than the + * png_combine_row() call. Is this even used????? + */ +extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, + png_bytep old_row, png_bytep new_row)); +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, + png_uint_32 size)); + +/* frees a pointer allocated by png_malloc() */ +extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr)); + +/* Free data that was allocated internally */ +extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 free_me, int num)); +#ifdef PNG_FREE_ME_SUPPORTED +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application */ +extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr, + png_infop info_ptr, int freer, png_uint_32 mask)); +#endif +/* assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#define PNG_FREE_UNKN 0x0200 +#define PNG_FREE_LIST 0x0400 +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr, + png_uint_32 size)); +extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr, + png_voidp ptr)); +#endif + +extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr, + png_voidp s1, png_voidp s2, png_uint_32 size)); + +extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr, + png_voidp s1, int value, png_uint_32 size)); + +#if defined(USE_FAR_KEYWORD) /* memory model conversion function */ +extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr, + int check)); +#endif /* USE_FAR_KEYWORD */ + +/* Fatal error in PNG image of libpng - can't continue */ +extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr, + png_const_charp error)); + +/* The same, but the chunk name is prepended to the error string. */ +extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr, + png_const_charp error)); + +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr, + png_const_charp message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr, + png_const_charp message)); + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr, +png_infop info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* Returns row_pointers, which is an array of pointers to scanlines that was +returned from png_read_png(). */ +extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr, +png_infop info_ptr)); +/* Set row_pointers, which is an array of pointers to scanlines for use +by png_write_png(). */ +extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image height in pixels. */ +extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image bit_depth. */ +extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image color_type. */ +extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image filter_type. */ +extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image interlace_type. */ +extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image compression_type. */ +extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +#endif + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); +extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp +png_ptr, png_infop info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +/* Returns pointer to signature string read from PNG header */ +extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr, +png_infop info_ptr)); + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p *background)); +#endif + +#if defined(PNG_bKGD_SUPPORTED) +extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_16p background)); +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); +#endif +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, double white_x, double white_y, double red_x, + double red_y, double green_x, double green_y, double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double *file_gamma)); +#endif +extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, + png_infop info_ptr, double file_gamma)); +#endif +extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p *hist)); +#endif + +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_16p hist)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#if defined(PNG_oFFs_SUPPORTED) +extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, + int *type, int *nparams, png_charp *units, png_charpp *params)); +#endif + +#if defined(PNG_pCAL_SUPPORTED) +extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_charp units, png_charpp params)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +#endif + +#if defined(PNG_pHYs_SUPPORTED) +extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp *palette, int *num_palette)); + +extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_colorp palette, int num_palette)); + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p *sig_bit)); +#endif + +#if defined(PNG_sBIT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_color_8p sig_bit)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *intent)); +#endif + +#if defined(PNG_sRGB_SUPPORTED) +extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr, + png_infop info_ptr, int intent)); +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen)); + /* Note to maintainer: profile should be png_bytepp */ +#endif + +#if defined(PNG_iCCP_SUPPORTED) +extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tpp entries)); +#endif + +#if defined(PNG_sPLT_SUPPORTED) +extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) +/* png_get_text also returns the number of text chunks in *num_text */ +extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* + * Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#if defined(PNG_TEXT_SUPPORTED) +extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep *mod_time)); +#endif + +#if defined(PNG_tIME_SUPPORTED) +extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_timep mod_time)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep *trans, int *num_trans, + png_color_16p *trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_bytep trans, int num_trans, + png_color_16p trans_values)); +#endif + +#if defined(PNG_tRNS_SUPPORTED) +#endif + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, double *width, double *height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); +#endif +#endif +#endif /* PNG_sCAL_SUPPORTED */ + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, double width, double height)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); +#endif +#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* provide a list of chunks and how they are to be handled, if the built-in + handling or default unknown chunk handling is not desired. Any chunks not + listed will be handled in the default manner. The IHDR and IEND chunks + must not be listed. + keep = 0: follow default behavour + = 1: do not keep + = 2: keep only if safe-to-copy + = 3: keep even if unsafe-to-copy +*/ +extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +extern PNG_EXPORT(void, png_set_unknown_chunk_location) + PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location)); +extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp + png_ptr, png_infop info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + If you need to turn it off for a chunk that your application has freed, + you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ +extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr, + png_infop info_ptr, int mask)); + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +/* The "params" pointer is currently not used and is for future expansion. */ +extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr, + png_infop info_ptr, + int transforms, + png_voidp params)); +#endif + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + */ +#ifdef PNG_DEBUG +#if (PNG_DEBUG > 0) +#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +#include +#if (PNG_DEBUG > 1) +#define png_debug(l,m) _RPT0(_CRT_WARN,m) +#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1) +#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2) +#endif +#else /* PNG_DEBUG_FILE || !_MSC_VER */ +#ifndef PNG_DEBUG_FILE +#define PNG_DEBUG_FILE stderr +#endif /* PNG_DEBUG_FILE */ +#if (PNG_DEBUG > 1) +#define png_debug(l,m) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ +} +#define png_debug1(l,m,p1) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ +} +#define png_debug2(l,m,p1,p2) \ +{ \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ +} +#endif /* (PNG_DEBUG > 1) */ +#endif /* _MSC_VER */ +#endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +#define png_debug(l, m) +#endif +#ifndef png_debug1 +#define png_debug1(l, m, p1) +#endif +#ifndef png_debug2 +#define png_debug2(l, m, p1, p2) +#endif + +extern PNG_EXPORT(png_bytep,png_sig_bytes) PNGARG((void)); + +extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); +extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp + png_ptr, png_uint_32 mng_features_permitted)); +#endif + +/* png_mmx_support will be included unconditionally starting in version 1.2.0 */ +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) || defined(PNG_USE_PNGGCCRD) +/* png.c, pnggccrd.c, or pngvcrd.c */ +extern PNG_EXPORT(int,png_mmx_support) PNGARG((void)); +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp + png_ptr, png_uint_32 strip_mode)); +#endif + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */ + +#define PNG_HEADER_VERSION_STRING \ + " libpng version 1.0.12 - June 8, 2001 (header)\n" + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 - \ + (png_uint_16)(alpha)) + (png_uint_16)128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(png_uint_32)(65535L - \ + (png_uint_32)(alpha)) + (png_uint_32)32768L); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + (png_uint_16)127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \ + (png_uint_32)32767) / (png_uint_32)65535L) + +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +/* These next functions are used internally in the code. They generally + * shouldn't be used unless you are writing code to add or replace some + * functionality in libpng. More information about most functions can + * be found in the files where the functions are located. + */ + +#if defined(PNG_INTERNAL) + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. + */ +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_HAVE_IDAT 0x04 +#define PNG_AFTER_IDAT 0x08 +#define PNG_HAVE_IEND 0x10 +#define PNG_HAVE_gAMA 0x20 +#define PNG_HAVE_cHRM 0x40 +#define PNG_HAVE_sRGB 0x80 +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 + +/* flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_DITHER 0x0040 +#define PNG_BACKGROUND 0x0080 +#define PNG_BACKGROUND_EXPAND 0x0100 + /* 0x0200 unused */ +#define PNG_16_TO_8 0x0400 +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000L +#define PNG_PACKSWAP 0x10000L +#define PNG_SWAP_ALPHA 0x20000L +#define PNG_STRIP_ALPHA 0x40000L +#define PNG_INVERT_ALPHA 0x80000L +#define PNG_USER_TRANSFORM 0x100000L +#define PNG_RGB_TO_GRAY_ERR 0x200000L +#define PNG_RGB_TO_GRAY_WARN 0x400000L +#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ + +/* flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_SHIFT 8 +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_SHIFT 3 +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 +#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 +#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 +#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 +#define PNG_FLAG_ZLIB_FINISHED 0x0020 +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_FREE_PLTE 0x1000 +#define PNG_FLAG_FREE_TRNS 0x2000 +#define PNG_FLAG_FREE_HIST 0x4000 +#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L +#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L + +/* For use in png_set_keep_unknown, png_handle_as_unknown */ +#define HANDLE_CHUNK_AS_DEFAULT 0 +#define HANDLE_CHUNK_NEVER 1 +#define HANDLE_CHUNK_IF_SAFE 2 +#define HANDLE_CHUNK_ALWAYS 3 + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* save typing and make code easier to understand */ +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ +#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) +/* place to hold the signature string for a PNG file. */ +#ifdef PNG_USE_GLOBAL_ARRAYS + PNG_EXPORT_VAR (const png_byte FARDATA) png_sig[8]; +#else +#define png_sig png_sig_bytes(NULL) +#endif +#endif /* PNG_NO_EXTERN */ + +/* Constant strings for known chunk types. If you need to add a chunk, + * define the name here, and add an invocation of the macro in png.c and + * wherever it's needed. + */ +#define PNG_IHDR const png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} +#define PNG_IDAT const png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} +#define PNG_IEND const png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} +#define PNG_PLTE const png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} +#define PNG_bKGD const png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} +#define PNG_cHRM const png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} +#define PNG_gAMA const png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} +#define PNG_hIST const png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} +#define PNG_iCCP const png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} +#define PNG_iTXt const png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} +#define PNG_oFFs const png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} +#define PNG_pCAL const png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} +#define PNG_sCAL const png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} +#define PNG_pHYs const png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} +#define PNG_sBIT const png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} +#define PNG_sPLT const png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} +#define PNG_sRGB const png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} +#define PNG_tEXt const png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} +#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} +#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} +#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} + +#ifdef PNG_USE_GLOBAL_ARRAYS +PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IDAT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_IEND[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_PLTE[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_bKGD[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_cHRM[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_gAMA[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_hIST[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iCCP[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_iTXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_oFFs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sCAL[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_pHYs[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sBIT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sPLT[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_sRGB[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5]; +PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5]; +#endif /* PNG_USE_GLOBAL_ARRAYS */ + + +/* Inline macros to do direct reads of bytes from the input buffer. These + * require that you are using an architecture that uses PNG byte ordering + * (MSB first) and supports unaligned data storage. I think that PowerPC + * in big-endian mode and 680x0 are the only ones that will support this. + * The x86 line of processors definitely do not. The png_get_int_32() + * routine also assumes we are using two's complement format for negative + * values, which is almost certainly true. + */ +#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED) +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +# define png_get_int_32(buf) ( *((png_int_32p) (buf))) +# endif +# define png_get_uint_32(buf) ( *((png_uint_32p) (buf))) +# define png_get_uint_16(buf) ( *((png_uint_16p) (buf))) +#else +# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED) +PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf)); +# endif +PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf)); +PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf)); +#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */ + +/* Initialize png_ptr struct for reading, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_read_struct instead). + */ +extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr)); +#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, sizeof(png_struct)); +extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Initialize png_ptr struct for writing, and allocate any other memory. + * (old interface - DEPRECATED - use png_create_write_struct instead). + */ +extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr)); +#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \ + PNG_LIBPNG_VER_STRING, sizeof(png_struct)); +extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size)); +extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, + png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t + png_info_size)); + +/* Allocate memory for an internal libpng struct */ +PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); + +/* Free memory from internal libpng struct */ +PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); + +PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr + malloc_fn, png_voidp mem_ptr)); +PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, + png_free_ptr free_fn, png_voidp mem_ptr)); + +/* Free any memory that info_ptr points to and reset struct. */ +PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* Function to allocate memory for zlib. */ +PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); + +/* Function to free memory for zlib */ +PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); + +/* Reset the CRC variable */ +PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); + +/* Write the "data" buffer to whatever output you are using. */ +PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, + png_size_t length)); + +/* Decompress data in a chunk that uses compression */ +#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ + defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr, + int comp_type, png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_length, png_size_t *data_length)); +#endif + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, + png_size_t length)); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +#endif + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). + * The only currently known PNG chunks that use signed numbers are + * the ancillary extension chunks, oFFs and pCAL. + */ +PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i)); + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i)); + +/* simple function to write the signature */ +PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr)); + +/* write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, + png_uint_32 height, + int bit_depth, int color_type, int compression_method, int filter_method, + int interlace_method)); + +PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, + png_uint_32 num_pal)); + +PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, + png_size_t length)); + +PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); + +#if defined(PNG_WRITE_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point + file_gamma)); +#endif +#endif + +#if defined(PNG_WRITE_sBIT_SUPPORTED) +PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, + int color_type)); +#endif + +#if defined(PNG_WRITE_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, + double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif + +#if defined(PNG_WRITE_sRGB_SUPPORTED) +PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, + int intent)); +#endif + +#if defined(PNG_WRITE_iCCP_SUPPORTED) +PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, + png_charp name, int compression_type, + png_charp profile, int proflen)); + /* Note to maintainer: profile should be png_bytep */ +#endif + +#if defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_sPLT_tp palette)); +#endif + +#if defined(PNG_WRITE_tRNS_SUPPORTED) +PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, + png_color_16p values, int number, int color_type)); +#endif + +#if defined(PNG_WRITE_bKGD_SUPPORTED) +PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, + png_color_16p values, int color_type)); +#endif + +#if defined(PNG_WRITE_hIST_SUPPORTED) +PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, + int num_hist)); +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, + png_charp key, png_charpp new_key)); +#endif + +#if defined(PNG_WRITE_tEXt_SUPPORTED) +PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len)); +#endif + +#if defined(PNG_WRITE_zTXt_SUPPORTED) +PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, + png_charp text, png_size_t text_len, int compression)); +#endif + +#if defined(PNG_WRITE_iTXt_SUPPORTED) +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)); +#endif + +#if defined(PNG_WRITE_oFFs_SUPPORTED) +PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, + png_uint_32 x_offset, png_uint_32 y_offset, int unit_type)); +#endif + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, + png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params)); +#endif + +#if defined(PNG_WRITE_pHYs_SUPPORTED) +PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type)); +#endif + +#if defined(PNG_WRITE_tIME_SUPPORTED) +PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, + png_timep mod_time)); +#endif + +#if defined(PNG_WRITE_sCAL_SUPPORTED) +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) +PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, + int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)); +#endif +#endif +#endif + +/* Called when finished processing a row of data */ +PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); + +/* Internal use only. Called before first row of data */ +PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); +#endif + +/* combine a row of data, dealing with alpha, etc. if requested */ +PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, + int mask)); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) +/* expand an interlaced row */ +/* OLD pre-1.0.9 interface: +PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations)); + */ +PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* grab pixels out of a row for an interlaced pass */ +PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, + png_bytep row, int pass)); +#endif + +/* unfilter a row */ +PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, + png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); + +/* Choose the best filter to use and filter the row data */ +PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, + png_row_infop row_info)); + +/* Write out the filtered row. */ +PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, + png_bytep filtered_row)); +/* finish a row while reading, dealing with interlacing passes, etc. */ +PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); + +/* initialize the row buffers, etc. */ +PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +/* optional call to update the users info structure */ +PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); + +/* these are the functions that do the transformations */ +#if defined(PNG_READ_FILLER_SUPPORTED) +PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 flags)); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop + row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) +PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p sig_bits)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, + png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); + +# if defined(PNG_CORRECT_PALETTE_SUPPORTED) +PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, + png_colorp palette, int num_palette)); +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) +PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth)); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) +PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, + png_color_8p bit_depth)); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift)); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift)); +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, + png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); +PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, + png_bytep row, png_color_16p trans_value)); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* decode the IHDR chunk */ +PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); + +#if defined(PNG_READ_bKGD_SUPPORTED) +PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_cHRM_SUPPORTED) +PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_gAMA_SUPPORTED) +PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_hIST_SUPPORTED) +PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_iCCP_SUPPORTED) +extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_oFFs_SUPPORTED) +PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pCAL_SUPPORTED) +PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_pHYs_SUPPORTED) +PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sBIT_SUPPORTED) +PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) +PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_sPLT_SUPPORTED) +extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#if defined(PNG_READ_sRGB_SUPPORTED) +PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tIME_SUPPORTED) +PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_tRNS_SUPPORTED) +PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, + png_uint_32 length)); +#endif + +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +PNG_EXTERN int png_handle_as_unknown PNGARG((png_structp png_ptr, png_bytep + chunk_name)); +#endif + +PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); + +PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, + png_bytep chunk_name)); + +/* handle the transformations for reading and writing */ +PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); + +PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, + png_uint_32 length)); +PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t length)); +PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, + png_bytep buffer, png_size_t buffer_length)); +PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); +PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); +PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, + png_infop info_ptr)); +PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); +#if defined(PNG_READ_tEXt_SUPPORTED) +PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) +PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr, png_uint_32 length)); +PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, + png_bytep row)); +#endif + +/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + +#endif /* PNG_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* do not put anything past this line */ +#endif /* PNG_H */ diff --git a/freeimage241/Source/LibPNG/pngasmrd.h b/freeimage241/Source/LibPNG/pngasmrd.h new file mode 100644 index 0000000..2db1852 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngasmrd.h @@ -0,0 +1,11 @@ +/* pngasmrd.h - assembler version of utilities to read a PNG file + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 2001 Glenn Randers-Pehrson + * + */ + +/* This file is obsolete in libpng-1.0.9 and later; its contents now appear + * at the end of pngconf.h. + */ diff --git a/freeimage241/Source/LibPNG/pngconf.h b/freeimage241/Source/LibPNG/pngconf.h new file mode 100644 index 0000000..0ce1b44 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngconf.h @@ -0,0 +1,1336 @@ +/* pngconf.h - machine configurable file for libpng + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifndef PNGCONF_H +#define PNGCONF_H + +/* This is the size of the compression buffer, and thus the size of + * an IDAT chunk. Make this whatever size you feel is best for your + * machine. One of these will be allocated per png_struct. When this + * is full, it writes the data to the disk, and does some other + * calculations. Making this an extremely small size will slow + * the library down, but you may want to experiment to determine + * where it becomes significant, if you are concerned with memory + * usage. Note that zlib allocates at least 32Kb also. For readers, + * this describes the size of the buffer available to read the data in. + * Unless this gets smaller than the size of a row (compressed), + * it should not make much difference how big this is. + */ + +#ifndef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 8192 +#endif + +/* Enable if you want a write-only libpng */ + +#ifndef PNG_NO_READ_SUPPORTED +# define PNG_READ_SUPPORTED +#endif + +/* Enable if you want a read-only libpng */ + +#ifndef PNG_NO_WRITE_SUPPORTED +# define PNG_WRITE_SUPPORTED +#endif + +/* Enabled by default in 1.2.0. You can disable this if you don't need to + support PNGs that are embedded in MNG datastreams */ +/* +#ifndef PNG_NO_MNG_FEATURES +# ifndef PNG_MNG_FEATURES_SUPPORTED +# define PNG_MNG_FEATURES_SUPPORTED +# endif +#endif +*/ + +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FLOATING_POINT_SUPPORTED +# endif +#endif + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. +#define PNG_MAX_MALLOC_64K + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +/* Special munging to support doing things the 'cygwin' way: + * 'Normal' png-on-win32 defines/defaults: + * PNG_BUILD_DLL -- building dll + * PNG_USE_DLL -- building an application, linking to dll + * (no define) -- building static library, or building an + * application and linking to the static lib + * 'Cygwin' defines/defaults: + * PNG_BUILD_DLL -- building the dll + * (no define) -- building an application, linking to the dll + * PNG_STATIC -- building the static lib, or building an application + * that links to the static lib. + * ALL_STATIC -- building various static libs, or building an application + * that links to the static libs. + * Thus, + * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and + * this bit of #ifdefs will define the 'correct' config variables based on + * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but + * unnecessary. + * + * Also, the precedence order is: + * ALL_STATIC (since we can't #undef something outside our namespace) + * PNG_BUILD_DLL + * PNG_STATIC + * (nothing) == PNG_USE_DLL + */ +#if defined(__CYGWIN__) +# if defined(ALL_STATIC) +# if defined(PNG_BUILD_DLL) +# undef PNG_BUILD_DLL +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# if !defined(PNG_STATIC) +# define PNG_STATIC +# endif +# else +# if defined (PNG_BUILD_DLL) +# if defined(PNG_STATIC) +# undef PNG_STATIC +# endif +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# else +# if defined(PNG_STATIC) +# if defined(PNG_USE_DLL) +# undef PNG_USE_DLL +# endif +# if defined(PNG_DLL) +# undef PNG_DLL +# endif +# else +# if !defined(PNG_USE_DLL) +# define PNG_USE_DLL +# endif +# if !defined(PNG_DLL) +# define PNG_DLL +# endif +# endif +# endif +# endif +#endif + +/* This protects us against compilers that run on a windowing system + * and thus don't have or would rather us not use the stdio types: + * stdin, stdout, and stderr. The only one currently used is stderr + * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will + * prevent these from being compiled and used. #defining PNG_NO_STDIO + * will also prevent these, plus will prevent the entire set of stdio + * macros and functions (FILE *, printf, etc.) from being compiled and used, + * unless (PNG_DEBUG > 0) has been #defined. + * + * #define PNG_NO_CONSOLE_IO + * #define PNG_NO_STDIO + */ + +#if defined(_WIN32_WCE) +# include + /* Console I/O functions are not supported on WindowsCE */ +# define PNG_NO_CONSOLE_IO +# ifdef PNG_DEBUG +# undef PNG_DEBUG +# endif +#endif + +#ifdef PNG_BUILD_DLL +# ifndef PNG_CONSOLE_IO_SUPPORTED +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# endif +#endif + +# ifdef PNG_NO_STDIO +# ifndef PNG_NO_CONSOLE_IO +# define PNG_NO_CONSOLE_IO +# endif +# ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# include +# endif +# endif +# else +# if !defined(_WIN32_WCE) +/* "stdio.h" functions are not supported on WindowsCE */ +# include +# endif +# endif + +/* This macro protects us against machines that don't have function + * prototypes (ie K&R style headers). If your compiler does not handle + * function prototypes, define this macro and use the included ansi2knr. + * I've always been able to use _NO_PROTO as the indicator, but you may + * need to drag the empty declaration out in front of here, or change the + * ifdef to suit your own needs. + */ +#ifndef PNGARG + +#ifdef OF /* zlib prototype munger */ +# define PNGARG(arglist) OF(arglist) +#else + +#ifdef _NO_PROTO +# define PNGARG(arglist) () +#else +# define PNGARG(arglist) arglist +#endif /* _NO_PROTO */ + +#endif /* OF */ + +#endif /* PNGARG */ + +/* Try to determine if we are compiling on a Mac. Note that testing for + * just __MWERKS__ is not good enough, because the Codewarrior is now used + * on non-Mac platforms. + */ +#ifndef MACOS +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) +# define MACOS +# endif +#endif + +/* enough people need this for various reasons to include it here */ +#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE) +# include +#endif + +#ifndef PNG_SETJMP_NOT_SUPPORTED +# define PNG_SETJMP_SUPPORTED +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This is an attempt to force a single setjmp behaviour on Linux. If + * the X config stuff didn't define _BSD_SOURCE we wouldn't need this. + */ + +# ifdef __linux__ +# ifdef _BSD_SOURCE +# define PNG_SAVE_BSD_SOURCE +# undef _BSD_SOURCE +# endif +# ifdef _SETJMP_H + __png.h__ already includes setjmp.h; + __dont__ include it again.; +# endif +# endif /* __linux__ */ + + /* include setjmp.h for error handling */ +# include + +# ifdef __linux__ +# ifdef PNG_SAVE_BSD_SOURCE +# define _BSD_SOURCE +# undef PNG_SAVE_BSD_SOURCE +# endif +# endif /* __linux__ */ +#endif /* PNG_SETJMP_SUPPORTED */ + +#ifdef BSD +# include +#else +# include +#endif + +/* Other defines for things like memory and the like can go here. */ +#ifdef PNG_INTERNAL + +#include + +/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which + * aren't usually used outside the library (as far as I know), so it is + * debatable if they should be exported at all. In the future, when it is + * possible to have run-time registry of chunk-handling functions, some of + * these will be made available again. +#define PNG_EXTERN extern + */ +#define PNG_EXTERN + +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ + +#if defined(PNG_FLOATING_POINT_SUPPORTED) +# if defined(MACOS) + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* Codewarrior on NT has linking problems without this. */ +#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) +# define PNG_ALWAYS_EXTERN +#endif + +/* For some reason, Borland C++ defines memcmp, etc. in mem.h, not + * stdlib.h like it should (I think). Or perhaps this is a C++ + * "feature"? + */ +#ifdef __TURBOC__ +# include +# include "alloc.h" +#endif + +#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \ + defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__)) +# include +#endif + +/* This controls how fine the dithering gets. As this allocates + * a largish chunk of memory (32K), those who are not as concerned + * with dithering quality can decrease some or all of these. + */ +#ifndef PNG_DITHER_RED_BITS +# define PNG_DITHER_RED_BITS 5 +#endif +#ifndef PNG_DITHER_GREEN_BITS +# define PNG_DITHER_GREEN_BITS 5 +#endif +#ifndef PNG_DITHER_BLUE_BITS +# define PNG_DITHER_BLUE_BITS 5 +#endif + +/* This controls how fine the gamma correction becomes when you + * are only interested in 8 bits anyway. Increasing this value + * results in more memory being used, and more pow() functions + * being called to fill in the gamma tables. Don't set this value + * less then 8, and even that may not work (I haven't tested it). + */ + +#ifndef PNG_MAX_GAMMA_8 +# define PNG_MAX_GAMMA_8 11 +#endif + +/* This controls how much a difference in gamma we can tolerate before + * we actually start doing gamma conversion. + */ +#ifndef PNG_GAMMA_THRESHOLD +# define PNG_GAMMA_THRESHOLD 0.05 +#endif + +#endif /* PNG_INTERNAL */ + +/* The following uses const char * instead of char * for error + * and warning message functions, so some compilers won't complain. + * If you do not want to use const, define PNG_NO_CONST here. + */ + +#ifndef PNG_NO_CONST +# define PNG_CONST const +#else +# define PNG_CONST +#endif + +/* The following defines give you the ability to remove code from the + * library that you will not be using. I wish I could figure out how to + * automate this, but I can't do that without making it seriously hard + * on the users. So if you are not using an ability, change the #define + * to and #undef, and that part of the library will not be compiled. If + * your linker can't find a function, you may want to make sure the + * ability is defined here. Some of these depend upon some others being + * defined. I haven't figured out all the interactions here, so you may + * have to experiment awhile to get everything to compile. If you are + * creating or using a shared library, you probably shouldn't touch this, + * as it will affect the size of the structures, and this will cause bad + * things to happen if the library and/or application ever change. + */ + +/* Any features you will not be using can be undef'ed here */ + +/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user + * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS + * on the compile line, then pick and choose which ones to define without + * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED + * if you only want to have a png-compliant reader/writer but don't need + * any of the extra transformations. This saves about 80 kbytes in a + * typical installation of the library. (PNG_NO_* form added in version + * 1.0.1c, for consistency) + */ + +/* The size of the png_text structure changed in libpng-1.0.6 when + * iTXt is supported. It is turned off by default, to support old apps + * that malloc the png_text structure instead of calling png_set_text() + * and letting libpng malloc it. It will be turned on by default in + * libpng-1.3.0. + */ + +#ifndef PNG_iTXt_SUPPORTED +# ifndef PNG_READ_iTXt_SUPPORTED +# define PNG_NO_READ_iTXt +# endif +# ifndef PNG_WRITE_iTXt_SUPPORTED +# define PNG_NO_WRITE_iTXt +# endif +#endif + +/* The following support, added after version 1.0.0, can be turned off here en + * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility + * with old applications that require the length of png_struct and png_info + * to remain unchanged. + */ + +#ifdef PNG_LEGACY_SUPPORTED +# define PNG_NO_FREE_ME +# define PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_NO_READ_USER_CHUNKS +# define PNG_NO_READ_iCCP +# define PNG_NO_WRITE_iCCP +# define PNG_NO_READ_iTXt +# define PNG_NO_WRITE_iTXt +# define PNG_NO_READ_sCAL +# define PNG_NO_WRITE_sCAL +# define PNG_NO_READ_sPLT +# define PNG_NO_WRITE_sPLT +# define PNG_NO_INFO_IMAGE +# define PNG_NO_READ_RGB_TO_GRAY +# define PNG_NO_READ_USER_TRANSFORM +# define PNG_NO_WRITE_USER_TRANSFORM +# define PNG_NO_USER_MEM +# define PNG_NO_READ_EMPTY_PLTE +# define PNG_NO_MNG_FEATURES +# define PNG_NO_FIXED_POINT_SUPPORTED +#endif + +/* Ignore attempt to turn off both floating and fixed point support */ +#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \ + !defined(PNG_NO_FIXED_POINT_SUPPORTED) +# define PNG_FIXED_POINT_SUPPORTED +#endif + +#ifndef PNG_NO_FREE_ME +# define PNG_FREE_ME_SUPPORTED +#endif + +#if defined(PNG_READ_SUPPORTED) + +#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_TRANSFORMS) +# define PNG_READ_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_READ_EXPAND +# define PNG_READ_EXPAND_SUPPORTED +# endif +# ifndef PNG_NO_READ_SHIFT +# define PNG_READ_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACK +# define PNG_READ_PACK_SUPPORTED +# endif +# ifndef PNG_NO_READ_BGR +# define PNG_READ_BGR_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP +# define PNG_READ_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_PACKSWAP +# define PNG_READ_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT +# define PNG_READ_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_READ_DITHER +# define PNG_READ_DITHER_SUPPORTED +# endif +# ifndef PNG_NO_READ_BACKGROUND +# define PNG_READ_BACKGROUND_SUPPORTED +# endif +# ifndef PNG_NO_READ_16_TO_8 +# define PNG_READ_16_TO_8_SUPPORTED +# endif +# ifndef PNG_NO_READ_FILLER +# define PNG_READ_FILLER_SUPPORTED +# endif +# ifndef PNG_NO_READ_GAMMA +# define PNG_READ_GAMMA_SUPPORTED +# endif +# ifndef PNG_NO_READ_GRAY_TO_RGB +# define PNG_READ_GRAY_TO_RGB_SUPPORTED +# endif +# ifndef PNG_NO_READ_SWAP_ALPHA +# define PNG_READ_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_INVERT_ALPHA +# define PNG_READ_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_STRIP_ALPHA +# define PNG_READ_STRIP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_READ_USER_TRANSFORM +# define PNG_READ_USER_TRANSFORM_SUPPORTED +# endif +# ifndef PNG_NO_READ_RGB_TO_GRAY +# define PNG_READ_RGB_TO_GRAY_SUPPORTED +# endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ + +#if !defined(PNG_NO_PROGRESSIVE_READ) && \ + !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */ +# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */ +#endif /* about interlacing capability! You'll */ + /* still have interlacing unless you change the following line: */ + +#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */ + +#ifndef PNG_NO_READ_COMPOSITE_NODIV +# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */ +# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */ +# endif +#endif + +/* Deprecated, will be removed from version 2.0.0. + Use PNG_MNG_FEATURES_SUPPORTED instead. */ +#ifndef PNG_NO_READ_EMPTY_PLTE +# define PNG_READ_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_READ_SUPPORTED */ + +#if defined(PNG_WRITE_SUPPORTED) + +# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_TRANSFORMS) +# define PNG_WRITE_TRANSFORMS_SUPPORTED +#endif + +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +# ifndef PNG_NO_WRITE_SHIFT +# define PNG_WRITE_SHIFT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACK +# define PNG_WRITE_PACK_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_BGR +# define PNG_WRITE_BGR_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_SWAP +# define PNG_WRITE_SWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_PACKSWAP +# define PNG_WRITE_PACKSWAP_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT +# define PNG_WRITE_INVERT_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_FILLER +# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */ +# endif +# ifndef PNG_NO_WRITE_SWAP_ALPHA +# define PNG_WRITE_SWAP_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_INVERT_ALPHA +# define PNG_WRITE_INVERT_ALPHA_SUPPORTED +# endif +# ifndef PNG_NO_WRITE_USER_TRANSFORM +# define PNG_WRITE_USER_TRANSFORM_SUPPORTED +# endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +# ifndef PNG_NO_USER_TRANSFORM_PTR +# define PNG_USER_TRANSFORM_PTR_SUPPORTED +# endif +#endif + +#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant + encoders, but can cause trouble + if left undefined */ + +#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#endif + +/* Will be enabled in libpng-1.2.0 */ +/* +#ifndef PNG_NO_ERROR_NUMBERS +#define PNG_ERROR_NUMBERS_SUPPORTED +#endif +*/ + +#ifndef PNG_NO_WRITE_FLUSH +# define PNG_WRITE_FLUSH_SUPPORTED +#endif + +/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */ +#ifndef PNG_NO_WRITE_EMPTY_PLTE +# define PNG_WRITE_EMPTY_PLTE_SUPPORTED +#endif + +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef PNG_NO_STDIO +# define PNG_TIME_RFC1123_SUPPORTED +#endif + +/* This adds extra functions in pngget.c for accessing data from the + * info pointer (added in version 0.99) + * png_get_image_width() + * png_get_image_height() + * png_get_bit_depth() + * png_get_color_type() + * png_get_compression_type() + * png_get_filter_type() + * png_get_interlace_type() + * png_get_pixel_aspect_ratio() + * png_get_pixels_per_meter() + * png_get_x_offset_pixels() + * png_get_y_offset_pixels() + * png_get_x_offset_microns() + * png_get_y_offset_microns() + */ +#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED) +# define PNG_EASY_ACCESS_SUPPORTED +#endif + +/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0 + even when PNG_USE_PNGVCRD or PNG_USE_PNGGCCRD is not defined */ +/* +#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) +# ifndef PNG_ASSEMBLER_CODE_SUPPORTED +# define PNG_ASSEMBLER_CODE_SUPPORTED +# endif +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_MMX_CODE_SUPPORTED +# endif +#endif +*/ +#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE) +# if defined(PNG_USE_PNGVCRD) || defined(PNG_USE_PNGGCCRD) +# ifndef PNG_ASSEMBLER_CODE_SUPPORTED +# define PNG_ASSEMBLER_CODE_SUPPORTED +# endif +# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE) +# define PNG_MMX_CODE_SUPPORTED +# endif +# endif +#endif + +/* This will be enabled by default in libpng-1.2.0 */ +/* +#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED) +# define PNG_USER_MEM_SUPPORTED +#endif +*/ + +/* These are currently experimental features, define them if you want */ + +/* very little testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +# endif +#endif +*/ + +/* This is only for PowerPC big-endian and 680x0 systems */ +/* some testing */ +/* +#ifdef PNG_READ_SUPPORTED +# ifndef PNG_PNG_READ_BIG_ENDIAN_SUPPORTED +# define PNG_READ_BIG_ENDIAN_SUPPORTED +# endif +#endif +*/ + +/* Buggy compilers (e.g., gcc 2.7.2.2) need this */ +/* +#define PNG_NO_POINTER_INDEXING +*/ + +/* These functions are turned off by default, as they will be phased out. */ +/* +#define PNG_USELESS_TESTS_SUPPORTED +#define PNG_CORRECT_PALETTE_SUPPORTED +*/ + +/* Any chunks you are not interested in, you can undef here. The + * ones that allocate memory may be expecially important (hIST, + * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info + * a bit smaller. + */ + +#if defined(PNG_READ_SUPPORTED) && \ + !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_READ_ANCILLARY_CHUNKS) +# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#if defined(PNG_WRITE_SUPPORTED) && \ + !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \ + !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS) +# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#endif + +#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_READ_TEXT +# define PNG_NO_READ_iTXt +# define PNG_NO_READ_tEXt +# define PNG_NO_READ_zTXt +#endif +#ifndef PNG_NO_READ_bKGD +# define PNG_READ_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +#endif +#ifndef PNG_NO_READ_cHRM +# define PNG_READ_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +#endif +#ifndef PNG_NO_READ_gAMA +# define PNG_READ_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +#endif +#ifndef PNG_NO_READ_hIST +# define PNG_READ_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +#endif +#ifndef PNG_NO_READ_iCCP +# define PNG_READ_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +#endif +#ifndef PNG_NO_READ_iTXt +# define PNG_READ_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_oFFs +# define PNG_READ_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +#endif +#ifndef PNG_NO_READ_pCAL +# define PNG_READ_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_sCAL +# define PNG_READ_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +#endif +#ifndef PNG_NO_READ_pHYs +# define PNG_READ_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +#endif +#ifndef PNG_NO_READ_sBIT +# define PNG_READ_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sPLT +# define PNG_READ_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +#endif +#ifndef PNG_NO_READ_sRGB +# define PNG_READ_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +#endif +#ifndef PNG_NO_READ_tEXt +# define PNG_READ_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_tIME +# define PNG_READ_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +#endif +#ifndef PNG_NO_READ_tRNS +# define PNG_READ_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +#endif +#ifndef PNG_NO_READ_zTXt +# define PNG_READ_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +#endif +#if !defined(PNG_NO_READ_USER_CHUNKS) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +# define PNG_READ_USER_CHUNKS_SUPPORTED +# define PNG_USER_CHUNKS_SUPPORTED +# ifdef PNG_NO_READ_UNKNOWN_CHUNKS +# undef PNG_NO_READ_UNKNOWN_CHUNKS +# endif +# ifdef PNG_NO_HANDLE_AS_UNKNOWN +# undef PNG_NO_HANDLE_AS_UNKNOWN +# endif +#endif +#ifndef PNG_NO_READ_OPT_PLTE +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ +#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ + defined(PNG_READ_zTXt_SUPPORTED) +# define PNG_READ_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +#endif + +#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ + +#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_WRITE_TEXT +# define PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_tEXt +# define PNG_NO_WRITE_zTXt +#endif +#ifndef PNG_NO_WRITE_bKGD +# define PNG_WRITE_bKGD_SUPPORTED +# ifndef PNG_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_cHRM +# define PNG_WRITE_cHRM_SUPPORTED +# ifndef PNG_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_gAMA +# define PNG_WRITE_gAMA_SUPPORTED +# ifndef PNG_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_hIST +# define PNG_WRITE_hIST_SUPPORTED +# ifndef PNG_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iCCP +# define PNG_WRITE_iCCP_SUPPORTED +# ifndef PNG_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_iTXt +# define PNG_WRITE_iTXt_SUPPORTED +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_oFFs +# define PNG_WRITE_oFFs_SUPPORTED +# ifndef PNG_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pCAL +# define PNG_WRITE_pCAL_SUPPORTED +# ifndef PNG_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sCAL +# define PNG_WRITE_sCAL_SUPPORTED +# ifndef PNG_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_pHYs +# define PNG_WRITE_pHYs_SUPPORTED +# ifndef PNG_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sBIT +# define PNG_WRITE_sBIT_SUPPORTED +# ifndef PNG_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sPLT +# define PNG_WRITE_sPLT_SUPPORTED +# ifndef PNG_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_sRGB +# define PNG_WRITE_sRGB_SUPPORTED +# ifndef PNG_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tEXt +# define PNG_WRITE_tEXt_SUPPORTED +# ifndef PNG_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tIME +# define PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_tRNS +# define PNG_WRITE_tRNS_SUPPORTED +# ifndef PNG_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_zTXt +# define PNG_WRITE_zTXt_SUPPORTED +# ifndef PNG_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +# endif +#endif +#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif +# ifndef PNG_NO_HANDLE_AS_UNKNOWN +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# endif +# endif +#endif +#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ + defined(PNG_WRITE_zTXt_SUPPORTED) +# define PNG_WRITE_TEXT_SUPPORTED +# ifndef PNG_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +# endif +#endif + +#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ + +/* Turn this off to disable png_read_png() and + * png_write_png() and leave the row_pointers member + * out of the info structure. + */ +#ifndef PNG_NO_INFO_IMAGE +# define PNG_INFO_IMAGE_SUPPORTED +#endif + +/* need the time information for reading tIME chunks */ +#if defined(PNG_tIME_SUPPORTED) +# if !defined(_WIN32_WCE) + /* "time.h" functions are not supported on WindowsCE */ +# include +# endif +#endif + +/* Some typedefs to get us started. These should be safe on most of the + * common platforms. The typedefs should be at least as large as the + * numbers suggest (a png_uint_32 must be at least 32 bits long), but they + * don't have to be exactly that size. Some compilers dislike passing + * unsigned shorts as function parameters, so you may be better off using + * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may + * want to have unsigned int for png_uint_32 instead of unsigned long. + */ + +typedef unsigned long png_uint_32; +typedef long png_int_32; +typedef unsigned short png_uint_16; +typedef short png_int_16; +typedef unsigned char png_byte; + +/* This is usually size_t. It is typedef'ed just in case you need it to + change (I'm not sure if you will or not, so I thought I'd be safe) */ +typedef size_t png_size_t; + +/* The following is needed for medium model support. It cannot be in the + * PNG_INTERNAL section. Needs modification for other compilers besides + * MSC. Model independent support declares all arrays and pointers to be + * large using the far keyword. The zlib version used must also support + * model independent data. As of version zlib 1.0.4, the necessary changes + * have been made in zlib. The USE_FAR_KEYWORD define triggers other + * changes that are needed. (Tim Wegner) + */ + +/* Separate compiler dependencies (problem here is that zlib.h always + defines FAR. (SJT) */ +#ifdef __BORLANDC__ +# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) +# define LDATA 1 +# else +# define LDATA 0 +# endif + /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ +# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) +# define PNG_MAX_MALLOC_64K +# if (LDATA != 1) +# ifndef FAR +# define FAR __far +# endif +# define USE_FAR_KEYWORD +# endif /* LDATA != 1 */ + /* Possibly useful for moving data out of default segment. + * Uncomment it if you want. Could also define FARDATA as + * const if your compiler supports it. (SJT) +# define FARDATA FAR + */ +# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ +#endif /* __BORLANDC__ */ + + +/* Suggest testing for specific compiler first before testing for + * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, + * making reliance oncertain keywords suspect. (SJT) + */ + +/* MSC Medium model */ +#if defined(FAR) +# if defined(M_I86MM) +# define USE_FAR_KEYWORD +# define FARDATA FAR +# include +# endif +#endif + +/* SJT: default case */ +#ifndef FAR +# define FAR +#endif + +/* At this point FAR is always defined */ +#ifndef FARDATA +# define FARDATA +#endif + +/* Typedef for floating-point numbers that are converted + to fixed-point with a multiple of 100,000, e.g., int_gamma */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void FAR * png_voidp; +typedef png_byte FAR * png_bytep; +typedef png_uint_32 FAR * png_uint_32p; +typedef png_int_32 FAR * png_int_32p; +typedef png_uint_16 FAR * png_uint_16p; +typedef png_int_16 FAR * png_int_16p; +typedef PNG_CONST char FAR * png_const_charp; +typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; + +#ifndef PNG_NO_STDIO +#if defined(_WIN32_WCE) +typedef HANDLE png_FILE_p; +#else +typedef FILE * png_FILE_p; +#endif +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * png_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte FAR * FAR * png_bytepp; +typedef png_uint_32 FAR * FAR * png_uint_32pp; +typedef png_int_32 FAR * FAR * png_int_32pp; +typedef png_uint_16 FAR * FAR * png_uint_16pp; +typedef png_int_16 FAR * FAR * png_int_16pp; +typedef PNG_CONST char FAR * FAR * png_const_charpp; +typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double FAR * FAR * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char FAR * FAR * FAR * png_charppp; + +/* libpng typedefs for types in zlib. If zlib changes + * or another compression library is used, then change these. + * Eliminates need to change all the source files. + */ +typedef charf * png_zcharp; +typedef charf * FAR * png_zcharpp; +typedef z_stream FAR * png_zstreamp; + +/* + * Define PNG_BUILD_DLL if the module being built is a Windows + * LIBPNG DLL. + * + * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL. + * It is equivalent to Microsoft predefined macro _DLL that is + * automatically defined when you compile using the share + * version of the CRT (C Run-Time library) + * + * The cygwin mods make this behavior a little different: + * Define PNG_BUILD_DLL if you are building a dll for use with cygwin + * Define PNG_STATIC if you are building a static library for use with cygwin, + * -or- if you are building an application that you want to link to the + * static library. + * PNG_USE_DLL is defined by default (no user action needed) unless one of + * the other flags is defined. + */ + +#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL)) +# define PNG_DLL +#endif +/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib. + * When building a static lib, default to no GLOBAL ARRAYS, but allow + * command-line override + */ +#if defined(__CYGWIN__) +# if !defined(PNG_STATIC) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +# else +# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS) +# if defined(PNG_USE_GLOBAL_ARRAYS) +# undef PNG_USE_GLOBAL_ARRAYS +# endif +# endif +# endif +# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# define PNG_USE_LOCAL_ARRAYS +# endif +#endif + +/* Do not use global arrays (helps with building DLL's) + * They are no longer used in libpng itself, since version 1.0.5c, + * but might be required for some pre-1.0.5c applications. + */ +#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS) +# if defined(PNG_NO_GLOBAL_ARRAYS) || (defined(__GNUC__) && defined(PNG_DLL)) +# define PNG_USE_LOCAL_ARRAYS +# else +# define PNG_USE_GLOBAL_ARRAYS +# endif +#endif + + +#ifndef PNGAPI + +#if defined(__MINGW32__) || defined(__CYGWIN__) && !defined(PNG_MODULEDEF) +# ifndef PNG_NO_MODULEDEF +# define PNG_NO_MODULEDEF +# endif +#endif + +#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF) +# define PNG_IMPEXP +#endif + +#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \ + (( defined(_Windows) || defined(_WINDOWS) || \ + defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ + ) && !defined(__CYGWIN__)) + +# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# define PNGAPI __cdecl +# else +# define PNGAPI _cdecl +# endif + +# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \ + 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */) +# define PNG_IMPEXP +# endif + +# if !defined(PNG_IMPEXP) + +# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol +# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol + + /* Borland/Microsoft */ +# if defined(_MSC_VER) || defined(__BORLANDC__) +# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500) +# define PNG_EXPORT PNG_EXPORT_TYPE1 +# else +# define PNG_EXPORT PNG_EXPORT_TYPE2 +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __export +# else +# define PNG_IMPEXP /*__import*/ /* doesn't exist AFAIK in + VC++*/ +# endif /* Exists in Borland C++ for + C++ classes (== huge) */ +# endif +# endif + +# if !defined(PNG_IMPEXP) +# if defined(PNG_BUILD_DLL) +# define PNG_IMPEXP __declspec(dllexport) +# else +# define PNG_IMPEXP __declspec(dllimport) +# endif +# endif +# endif /* PNG_IMPEXP */ +#else /* !(DLL || non-cygwin WINDOWS) */ +# if defined(__CYGWIN__) && !defined(PNG_DLL) +# if !defined(PNG_IMPEXP) +# define PNG_IMPEXP +# endif +# define PNGAPI __cdecl +# else +# if (defined(__IBMC__) || defined(IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# define PNG_IMPEXP +# else +# if 0 /* ... other platforms, with other meanings */ +# else +# define PNGAPI +# define PNG_IMPEXP +# endif +# endif +# endif +#endif +#endif + +#ifndef PNGAPI +# define PNGAPI +#endif +#ifndef PNG_IMPEXP +# define PNG_IMPEXP +#endif + +#ifndef PNG_EXPORT +# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol +#endif + +#ifdef PNG_USE_GLOBAL_ARRAYS +# ifndef PNG_EXPORT_VAR +# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type +# endif +#endif + +/* User may want to use these so they are not in PNG_INTERNAL. Any library + * functions that are passed far data must be model independent. + */ + +#ifndef PNG_ABORT +# define PNG_ABORT() abort() +#endif + +#ifdef PNG_SETJMP_SUPPORTED +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED) +#endif + +#if defined(USE_FAR_KEYWORD) /* memory model independent fns */ +/* use this to make far-to-near assignments */ +# define CHECK 1 +# define NOCHECK 0 +# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) +# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) +# define png_strcpy _fstrcpy +# define png_strlen _fstrlen +# define png_memcmp _fmemcmp /* SJT: added */ +# define png_memcpy _fmemcpy +# define png_memset _fmemset +#else /* use the usual functions */ +# define CVT_PTR(ptr) (ptr) +# define CVT_PTR_NOCHECK(ptr) (ptr) +# define png_strcpy strcpy +# define png_strlen strlen +# define png_memcmp memcmp /* SJT: added */ +# define png_memcpy memcpy +# define png_memset memset +#endif +/* End of memory model independent support */ + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536 +#endif + +#ifdef PNG_READ_SUPPORTED +/* Prior to libpng-1.0.9, this block was in pngasmrd.h */ +#if defined(PNG_INTERNAL) + +/* These are the default thresholds before the MMX code kicks in; if either + * rowbytes or bitdepth is below the threshold, plain C code is used. These + * can be overridden at runtime via the png_set_mmx_thresholds() call in + * libpng 1.2.0 and later. The values below were chosen by Intel. + */ + +#ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT +# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */ +#endif +#ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT +# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */ +#endif + +/* Set this in the makefile for VC++ on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pngvcrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGVCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif + +/* Set this in the makefile for gcc/as on Pentium, not here. */ +/* Platform must be Pentium. Makefile must assemble and load pnggccrd.c . + * MMX will be detected at run time and used if present. + */ +#ifdef PNG_USE_PNGGCCRD +# define PNG_HAVE_ASSEMBLER_COMBINE_ROW +# define PNG_HAVE_ASSEMBLER_READ_INTERLACE +# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +#endif +/* - see pnggccrd.c for info about what is currently enabled */ + +#endif /* PNG_INTERNAL */ +#endif /* PNG_READ_SUPPORTED */ + +#endif /* PNGCONF_H */ + diff --git a/freeimage241/Source/LibPNG/pngerror.c b/freeimage241/Source/LibPNG/pngerror.c new file mode 100644 index 0000000..c2285ff --- /dev/null +++ b/freeimage241/Source/LibPNG/pngerror.c @@ -0,0 +1,290 @@ + +/* pngerror.c - stub functions for i/o and memory allocation + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all error handling. Users who + * need special error handling are expected to write replacement functions + * and use png_set_error_fn() to use those functions. See the instructions + * at each function. + */ + +#define PNG_INTERNAL +#include "png.h" + +static void /* PRIVATE */ +png_default_error PNGARG((png_structp png_ptr, + png_const_charp message)); +static void /* PRIVATE */ +png_default_warning PNGARG((png_structp png_ptr, + png_const_charp message)); + +/* This function is called whenever there is a fatal error. This function + * should not be changed. If there is a need to handle errors differently, + * you should supply a replacement error function and use png_set_error_fn() + * to replace the error function at run-time. + */ +void PNGAPI +png_error(png_structp png_ptr, png_const_charp message) +{ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + { + int offset = 0; + if (*message == '#') + { + for (offset=1; offset<15; offset++) + if (*(message+offset) == ' ') + break; + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + int i; + for (i=0; iflags&PNG_FLAG_STRIP_ERROR_TEXT) + { + msg[0]='0'; + msg[1]='\0'; + message=msg; + } + } + } +#endif + if (png_ptr->error_fn != NULL) + (*(png_ptr->error_fn))(png_ptr, message); + + /* if the following returns or doesn't exist, use the default function, + which will not return */ + png_default_error(png_ptr, message); +} + +/* This function is called whenever there is a non-fatal error. This function + * should not be changed. If there is a need to handle warnings differently, + * you should supply a replacement warning function and use + * png_set_error_fn() to replace the warning function at run-time. + */ +void PNGAPI +png_warning(png_structp png_ptr, png_const_charp message) +{ + int offset = 0; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) +#endif + { + if (*message == '#') + { + for (offset=1; offset<15; offset++) + if (*(message+offset) == ' ') + break; + } + } + if (png_ptr->warning_fn != NULL) + (*(png_ptr->warning_fn))(png_ptr, (png_const_charp)(message+offset)); + else + png_default_warning(png_ptr, (png_const_charp)(message+offset)); +} + +/* These utilities are used internally to build an error message that relates + * to the current chunk. The chunk name comes from png_ptr->chunk_name, + * this is used to prefix the message. The message is limited in length + * to 63 bytes, the name characters are output as hex digits wrapped in [] + * if the character is invalid. + */ +#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97)) +static PNG_CONST char png_digit[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', + 'F' }; + +static void /* PRIVATE */ +png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp + message) +{ + int iout = 0, iin = 0; + + while (iin < 4) + { + int c = png_ptr->chunk_name[iin++]; + if (isnonalpha(c)) + { + buffer[iout++] = '['; + buffer[iout++] = png_digit[(c & 0xf0) >> 4]; + buffer[iout++] = png_digit[c & 0x0f]; + buffer[iout++] = ']'; + } + else + { + buffer[iout++] = (png_byte)c; + } + } + + if (message == NULL) + buffer[iout] = 0; + else + { + buffer[iout++] = ':'; + buffer[iout++] = ' '; + png_memcpy(buffer+iout, message, 64); + buffer[iout+63] = 0; + } +} + +void PNGAPI +png_chunk_error(png_structp png_ptr, png_const_charp message) +{ + char msg[18+64]; + png_format_buffer(png_ptr, msg, message); + png_error(png_ptr, msg); +} + +void PNGAPI +png_chunk_warning(png_structp png_ptr, png_const_charp message) +{ + char msg[18+64]; + png_format_buffer(png_ptr, msg, message); + png_warning(png_ptr, msg); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void /* PRIVATE */ +png_default_error(png_structp png_ptr, png_const_charp message) +{ +#ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*message == '#') + { + int offset; + char error_number[16]; + for (offset=0; offset<15; offset++) + { + error_number[offset] = *(message+offset+1); + if (*(message+offset) == ' ') + break; + } + if((offset > 1) && (offset < 15)) + { + error_number[offset-1]='\0'; + fprintf(stderr, "libpng error no. %s: %s\n", error_number, message+offset); + } + else + fprintf(stderr, "libpng error: %s, offset=%d\n", message,offset); + } + else +#endif + fprintf(stderr, "libpng error: %s\n", message); +#else + if (message) + /* make compiler happy */ ; +#endif + +#ifdef PNG_SETJMP_SUPPORTED +# ifdef USE_FAR_KEYWORD + { + jmp_buf jmpbuf; + png_memcpy(jmpbuf,png_ptr->jmpbuf,sizeof(jmp_buf)); + longjmp(jmpbuf, 1); + } +# else + longjmp(png_ptr->jmpbuf, 1); +# endif +#else + if (png_ptr) + /* make compiler happy */ ; + PNG_ABORT(); +#endif +} + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want them to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void /* PRIVATE */ +png_default_warning(png_structp png_ptr, png_const_charp message) +{ +#ifndef PNG_NO_CONSOLE_IO +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*message == '#') + { + int offset; + char warning_number[16]; + for (offset=0; offset<15; offset++) + { + warning_number[offset]=*(message+offset+1); + if (*(message+offset) == ' ') + break; + } + if((offset > 1) && (offset < 15)) + { + warning_number[offset-1]='\0'; + fprintf(stderr, "libpng warning no. %s: %s\n", warning_number, + message+offset); + } + else + fprintf(stderr, "libpng warning: %s\n", message); + } + else +# endif + fprintf(stderr, "libpng warning: %s\n", message); +#else + if (message) + /* appease compiler */ ; +#endif + if (png_ptr) + return; +} + +/* This function is called when the application wants to use another method + * of handling errors and warnings. Note that the error function MUST NOT + * return to the calling routine or serious problems will occur. The return + * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1) + */ +void PNGAPI +png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warning_fn) +{ + png_ptr->error_ptr = error_ptr; + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; +} + + +/* This function returns a pointer to the error_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_error_ptr(png_structp png_ptr) +{ + return ((png_voidp)png_ptr->error_ptr); +} + + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +void +png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) +{ + if(png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } +} +#endif + diff --git a/freeimage241/Source/LibPNG/pnggccrd.c b/freeimage241/Source/LibPNG/pnggccrd.c new file mode 100644 index 0000000..62ea690 --- /dev/null +++ b/freeimage241/Source/LibPNG/pnggccrd.c @@ -0,0 +1,5208 @@ +/* pnggccrd.c - mixed C/assembler version of utilities to read a PNG file + * + * For Intel x86 CPU (Pentium-MMX or later) and GNU C compiler. + * + * See http://www.intel.com/drg/pentiumII/appnotes/916/916.htm + * and http://www.intel.com/drg/pentiumII/appnotes/923/923.htm + * for Intel's performance analysis of the MMX vs. non-MMX code. + * + * libpng version 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * Copyright (c) 1998, Intel Corporation + * + * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998. + * Interface to libpng contributed by Gilles Vollant, 1999. + * GNU C port by Greg Roelofs, 1999-2001. + * + * Lines 2350-4300 converted in place with intel2gas 1.3.1: + * + * intel2gas -mdI pnggccrd.c.partially-msvc -o pnggccrd.c + * + * and then cleaned up by hand. See http://hermes.terminal.at/intel2gas/ . + * + * NOTE: A sufficiently recent version of GNU as (or as.exe under DOS/Windows) + * is required to assemble the newer MMX instructions such as movq. + * For djgpp, see + * + * ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bnu281b.zip + * + * (or a later version in the same directory). For Linux, check your + * distribution's web site(s) or try these links: + * + * http://rufus.w3.org/linux/RPM/binutils.html + * http://www.debian.org/Packages/stable/devel/binutils.html + * ftp://ftp.slackware.com/pub/linux/slackware/slackware/slakware/d1/ + * binutils.tgz + * + * For other platforms, see the main GNU site: + * + * ftp://ftp.gnu.org/pub/gnu/binutils/ + * + * Version 2.5.2l.15 is definitely too old... + */ + +/* + * TEMPORARY PORTING NOTES AND CHANGELOG (mostly by Greg Roelofs) + * ===================================== + * + * 19991006: + * - fixed sign error in post-MMX cleanup code (16- & 32-bit cases) + * + * 19991007: + * - additional optimizations (possible or definite): + * x [DONE] write MMX code for 64-bit case (pixel_bytes == 8) [not tested] + * - write MMX code for 48-bit case (pixel_bytes == 6) + * - figure out what's up with 24-bit case (pixel_bytes == 3): + * why subtract 8 from width_mmx in the pass 4/5 case? + * (only width_mmx case) (near line 1606) + * x [DONE] replace pixel_bytes within each block with the true + * constant value (or are compilers smart enough to do that?) + * - rewrite all MMX interlacing code so it's aligned with + * the *beginning* of the row buffer, not the end. This + * would not only allow one to eliminate half of the memory + * writes for odd passes (that is, pass == odd), it may also + * eliminate some unaligned-data-access exceptions (assuming + * there's a penalty for not aligning 64-bit accesses on + * 64-bit boundaries). The only catch is that the "leftover" + * pixel(s) at the end of the row would have to be saved, + * but there are enough unused MMX registers in every case, + * so this is not a problem. A further benefit is that the + * post-MMX cleanup code (C code) in at least some of the + * cases could be done within the assembler block. + * x [DONE] the "v3 v2 v1 v0 v7 v6 v5 v4" comments are confusing, + * inconsistent, and don't match the MMX Programmer's Reference + * Manual conventions anyway. They should be changed to + * "b7 b6 b5 b4 b3 b2 b1 b0," where b0 indicates the byte that + * was lowest in memory (e.g., corresponding to a left pixel) + * and b7 is the byte that was highest (e.g., a right pixel). + * + * 19991016: + * - Brennan's Guide notwithstanding, gcc under Linux does *not* + * want globals prefixed by underscores when referencing them-- + * i.e., if the variable is const4, then refer to it as const4, + * not _const4. This seems to be a djgpp-specific requirement. + * Also, such variables apparently *must* be declared outside + * of functions; neither static nor automatic variables work if + * defined within the scope of a single function, but both + * static and truly global (multi-module) variables work fine. + * + * 19991023: + * - fixed png_combine_row() non-MMX replication bug (odd passes only?) + * - switched from string-concatenation-with-macros to cleaner method of + * renaming global variables for djgpp--i.e., always use prefixes in + * inlined assembler code (== strings) and conditionally rename the + * variables, not the other way around. Hence _const4, _mask8_0, etc. + * + * 19991024: + * - fixed mmxsupport()/png_do_read_interlace() first-row bug + * This one was severely weird: even though mmxsupport() doesn't touch + * ebx (where "row" pointer was stored), it nevertheless managed to zero + * the register (even in static/non-fPIC code--see below), which in turn + * caused png_do_read_interlace() to return prematurely on the first row of + * interlaced images (i.e., without expanding the interlaced pixels). + * Inspection of the generated assembly code didn't turn up any clues, + * although it did point at a minor optimization (i.e., get rid of + * mmx_supported_local variable and just use eax). Possibly the CPUID + * instruction is more destructive than it looks? (Not yet checked.) + * - "info gcc" was next to useless, so compared fPIC and non-fPIC assembly + * listings... Apparently register spillage has to do with ebx, since + * it's used to index the global offset table. Commenting it out of the + * input-reg lists in png_combine_row() eliminated compiler barfage, so + * ifdef'd with __PIC__ macro: if defined, use a global for unmask + * + * 19991107: + * - verified CPUID clobberage: 12-char string constant ("GenuineIntel", + * "AuthenticAMD", etc.) placed in ebx:ecx:edx. Still need to polish. + * + * 19991120: + * - made "diff" variable (now "_dif") global to simplify conversion of + * filtering routines (running out of regs, sigh). "diff" is still used + * in interlacing routines, however. + * - fixed up both versions of mmxsupport() (ORIG_THAT_USED_TO_CLOBBER_EBX + * macro determines which is used); original not yet tested. + * + * 20000213: + * - when compiling with gcc, be sure to use -fomit-frame-pointer + * + * 20000319: + * - fixed a register-name typo in png_do_read_interlace(), default (MMX) case, + * pass == 4 or 5, that caused visible corruption of interlaced images + * + * 20000623: + * - Various problems were reported with gcc 2.95.2 in the Cygwin environment, + * many of the form "forbidden register 0 (ax) was spilled for class AREG." + * This is explained at http://gcc.gnu.org/fom_serv/cache/23.html, and + * Chuck Wilson supplied a patch involving dummy output registers. See + * http://sourceforge.net/bugs/?func=detailbug&bug_id=108741&group_id=5624 + * for the original (anonymous) SourceForge bug report. + * + * 20000706: + * - Chuck Wilson passed along these remaining gcc 2.95.2 errors: + * pnggccrd.c: In function `png_combine_row': + * pnggccrd.c:525: more than 10 operands in `asm' + * pnggccrd.c:669: more than 10 operands in `asm' + * pnggccrd.c:828: more than 10 operands in `asm' + * pnggccrd.c:994: more than 10 operands in `asm' + * pnggccrd.c:1177: more than 10 operands in `asm' + * They are all the same problem and can be worked around by using the + * global _unmask variable unconditionally, not just in the -fPIC case. + * Reportedly earlier versions of gcc also have the problem with more than + * 10 operands; they just don't report it. Much strangeness ensues, etc. + * + * 20000729: + * - enabled png_read_filter_row_mmx_up() (shortest remaining unconverted + * MMX routine); began converting png_read_filter_row_mmx_sub() + * - to finish remaining sections: + * - clean up indentation and comments + * - preload local variables + * - add output and input regs (order of former determines numerical + * mapping of latter) + * - avoid all usage of ebx (including bx, bh, bl) register [20000823] + * - remove "$" from addressing of Shift and Mask variables [20000823] + * + * 20000731: + * - global union vars causing segfaults in png_read_filter_row_mmx_sub()? + * + * 20000822: + * - ARGH, stupid png_read_filter_row_mmx_sub() segfault only happens with + * shared-library (-fPIC) version! Code works just fine as part of static + * library. Damn damn damn damn damn, should have tested that sooner. + * ebx is getting clobbered again (explicitly this time); need to save it + * on stack or rewrite asm code to avoid using it altogether. Blargh! + * + * 20000823: + * - first section was trickiest; all remaining sections have ebx -> edx now. + * (-fPIC works again.) Also added missing underscores to various Shift* + * and *Mask* globals and got rid of leading "$" signs. + * + * 20000826: + * - added visual separators to help navigate microscopic printed copies + * (http://pobox.com/~newt/code/gpr-latest.zip, mode 10); started working + * on png_read_filter_row_mmx_avg() + * + * 20000828: + * - finished png_read_filter_row_mmx_avg(): only Paeth left! (930 lines...) + * What the hell, did png_read_filter_row_mmx_paeth(), too. Comments not + * cleaned up/shortened in either routine, but functionality is complete + * and seems to be working fine. + * + * 20000829: + * - ahhh, figured out last(?) bit of gcc/gas asm-fu: if register is listed + * as an input reg (with dummy output variables, etc.), then it *cannot* + * also appear in the clobber list or gcc 2.95.2 will barf. The solution + * is simple enough... + * + * 20000914: + * - bug in png_read_filter_row_mmx_avg(): 16-bit grayscale not handled + * correctly (but 48-bit RGB just fine) + * + * 20000916: + * - fixed bug in png_read_filter_row_mmx_avg(), bpp == 2 case; three errors: + * - "_ShiftBpp.use = 24;" should have been "_ShiftBpp.use = 16;" + * - "_ShiftRem.use = 40;" should have been "_ShiftRem.use = 48;" + * - "psllq _ShiftRem, %%mm2" should have been "psrlq _ShiftRem, %%mm2" + * + * 20010103: + * - renamed mmxsupport() to png_mmx_support(), with auto-set of mmx_supported, + * and made it public + * + * 20010104: + * - removed dependency on png_read_filter_row_c() (C code already duplicated + * within MMX version of png_read_filter_row()) so no longer necessary to + * compile it into pngrutil.o + * + * 20010310: + * - fixed buffer-overrun bug in png_combine_row() C code (non-MMX) + * + * STILL TO DO: + * - test png_do_read_interlace() 64-bit case (pixel_bytes == 8) + * - write MMX code for 48-bit case (pixel_bytes == 6) + * - figure out what's up with 24-bit case (pixel_bytes == 3): + * why subtract 8 from width_mmx in the pass 4/5 case? + * (only width_mmx case) (near line 1606) + * - rewrite all MMX interlacing code so it's aligned with beginning + * of the row buffer, not the end (see 19991007 for details) + * x pick one version of mmxsupport() and get rid of the other + * - add error messages to any remaining bogus default cases + * - enable pixel_depth == 8 cases in png_read_filter_row()? (test speed) + * - add support for runtime enable/disable/query of various MMX routines + */ + +/* +#ifndef PNG_DEBUG +# define PNG_DEBUG 0 +#endif +*/ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_USE_PNGGCCRD) + +int PNGAPI png_mmx_support(void); + +#ifdef PNG_USE_LOCAL_ARRAYS +static const int FARDATA png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; +static const int FARDATA png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +static const int FARDATA png_pass_width[7] = {8, 4, 4, 2, 2, 1, 1}; +#endif + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +/* djgpp, Win32, and Cygwin add their own underscores to global variables, + * so define them without: */ +#if defined(__DJGPP__) || defined(WIN32) || defined(__CYGWIN__) +# define _mmx_supported mmx_supported +# define _unmask unmask +# define _const4 const4 +# define _const6 const6 +# define _mask8_0 mask8_0 +# define _mask16_1 mask16_1 +# define _mask16_0 mask16_0 +# define _mask24_2 mask24_2 +# define _mask24_1 mask24_1 +# define _mask24_0 mask24_0 +# define _mask32_3 mask32_3 +# define _mask32_2 mask32_2 +# define _mask32_1 mask32_1 +# define _mask32_0 mask32_0 +# define _mask48_5 mask48_5 +# define _mask48_4 mask48_4 +# define _mask48_3 mask48_3 +# define _mask48_2 mask48_2 +# define _mask48_1 mask48_1 +# define _mask48_0 mask48_0 +# define _FullLength FullLength +# define _MMXLength MMXLength +# define _dif dif +# define _LBCarryMask LBCarryMask +# define _HBClearMask HBClearMask +# define _ActiveMask ActiveMask +# define _ActiveMask2 ActiveMask2 +# define _ActiveMaskEnd ActiveMaskEnd +# define _ShiftBpp ShiftBpp +# define _ShiftRem ShiftRem +# define _patemp patemp +# define _pbtemp pbtemp +# define _pctemp pctemp +#endif + + +/* These constants are used in the inlined MMX assembly code. + Ignore gcc's "At top level: defined but not used" warnings. */ + +/* GRR 20000706: originally _unmask was needed only when compiling with -fPIC, + * since that case uses the %ebx register for indexing the Global Offset Table + * and there were no other registers available. But gcc 2.95 and later emit + * "more than 10 operands in `asm'" errors when %ebx is used to preload unmask + * in the non-PIC case, so we'll just use the global unconditionally now. + */ +static int _unmask; + +static unsigned long long _mask8_0 = 0x0102040810204080LL; + +static unsigned long long _mask16_1 = 0x0101020204040808LL; +static unsigned long long _mask16_0 = 0x1010202040408080LL; + +static unsigned long long _mask24_2 = 0x0101010202020404LL; +static unsigned long long _mask24_1 = 0x0408080810101020LL; +static unsigned long long _mask24_0 = 0x2020404040808080LL; + +static unsigned long long _mask32_3 = 0x0101010102020202LL; +static unsigned long long _mask32_2 = 0x0404040408080808LL; +static unsigned long long _mask32_1 = 0x1010101020202020LL; +static unsigned long long _mask32_0 = 0x4040404080808080LL; + +static unsigned long long _mask48_5 = 0x0101010101010202LL; +static unsigned long long _mask48_4 = 0x0202020204040404LL; +static unsigned long long _mask48_3 = 0x0404080808080808LL; +static unsigned long long _mask48_2 = 0x1010101010102020LL; +static unsigned long long _mask48_1 = 0x2020202040404040LL; +static unsigned long long _mask48_0 = 0x4040808080808080LL; + +static unsigned long long _const4 = 0x0000000000FFFFFFLL; +//static unsigned long long _const5 = 0x000000FFFFFF0000LL; // NOT USED +static unsigned long long _const6 = 0x00000000000000FFLL; + +// These are used in the row-filter routines and should/would be local +// variables if not for gcc addressing limitations. + +static png_uint_32 _FullLength; +static png_uint_32 _MMXLength; +static int _dif; +static int _patemp; // temp variables for Paeth routine +static int _pbtemp; +static int _pctemp; + +static void /* PRIVATE */ +png_squelch_warnings(void) +{ + _dif = _dif; + _patemp = _patemp; + _pbtemp = _pbtemp; + _pctemp = _pctemp; + _const4 = _const4; + _const6 = _const6; + _MMXLength = _MMXLength; + _mask8_0 = _mask8_0; + _mask16_1 = _mask16_1; + _mask16_0 = _mask16_0; + _mask24_2 = _mask24_2; + _mask24_1 = _mask24_1; + _mask24_0 = _mask24_0; + _mask32_3 = _mask32_3; + _mask32_2 = _mask32_2; + _mask32_1 = _mask32_1; + _mask32_0 = _mask32_0; + _mask48_5 = _mask48_5; + _mask48_4 = _mask48_4; + _mask48_3 = _mask48_3; + _mask48_2 = _mask48_2; + _mask48_1 = _mask48_1; + _mask48_0 = _mask48_0; +} +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +static int _mmx_supported = 2; + +/*===========================================================================*/ +/* */ +/* P N G _ C O M B I N E _ R O W */ +/* */ +/*===========================================================================*/ + +#if defined(PNG_HAVE_ASSEMBLER_COMBINE_ROW) + +#define BPP2 2 +#define BPP3 3 /* bytes per pixel (a.k.a. pixel_bytes) */ +#define BPP4 4 +#define BPP6 6 /* (defined only to help avoid cut-and-paste errors) */ +#define BPP8 8 + +/* Combines the row recently read in with the previous row. + This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined; a + zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. + If you want all pixels to be combined, pass 0xff (255) in mask. */ + +/* Use this routine for the x86 platform - it uses a faster MMX routine + if the machine supports MMX. */ + +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ + png_debug(1, "in png_combine_row (pnggccrd.c)\n"); + + if (_mmx_supported == 2) { + png_mmx_support(); + } + + if (mask == 0xff) + { + png_debug(2,"mask == 0xff: doing single png_memcpy()\n"); + png_memcpy(row, png_ptr->row_buf + 1, + (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3)); + } + else /* (png_combine_row() is never called with mask == 0) */ + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: /* png_ptr->row_info.pixel_depth */ + { + png_bytep sp; + png_bytep dp; + int s_inc, s_start, s_end; + int m; + int shift; + png_uint_32 i; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x1; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 2: /* png_ptr->row_info.pixel_depth */ + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x3; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 4: /* png_ptr->row_info.pixel_depth */ + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 8: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported ) + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask8_0, %%mm0 \n\t" + "pand %%mm7, %%mm0 \n\t" // nonzero if keep byte + "pcmpeqb %%mm6, %%mm0 \n\t" // zeros->1s, v versa + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" // len == 0 ? + "je mainloop8end \n\t" + + "mainloop8: \n\t" + "movq (%%esi), %%mm4 \n\t" // *srcptr + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "pandn (%%edi), %%mm6 \n\t" // *dstptr + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + "addl $8, %%esi \n\t" // inc by 8 bytes processed + "addl $8, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop8 \n\t" + + "mainloop8end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end8 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop8: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip8 \n\t" // if CF = 0 + "movb (%%esi), %%al \n\t" + "movb %%al, (%%edi) \n\t" + + "skip8: \n\t" + "incl %%esi \n\t" + "incl %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop8 \n\t" + + "end8: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm4", "%mm6", "%mm7" // clobber list +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff /* *BPP1 */ ; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + + } /* end of else (_mmx_supported) */ + + break; + } /* end 8 bpp */ + + case 16: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported ) + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask16_0, %%mm0 \n\t" + "movq _mask16_1, %%mm1 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop16end \n\t" + + "mainloop16: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "addl $16, %%esi \n\t" // inc by 16 bytes processed + "addl $16, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop16 \n\t" + + "mainloop16end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end16 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop16: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip16 \n\t" // if CF = 0 + "movw (%%esi), %%ax \n\t" + "movw %%ax, (%%edi) \n\t" + + "skip16: \n\t" + "addl $2, %%esi \n\t" + "addl $2, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop16 \n\t" + + "end16: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=c" (dummy_value_c), + "=d" (dummy_value_d), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (diff), // eax // input regs +// was (unmask) " " RESERVED // ebx // Global Offset Table idx + "1" (len), // ecx + "2" (mask), // edx + "3" (srcptr), // esi + "4" (dstptr) // edi + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm4" // clobber list + , "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP2 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP2 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP2 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP2 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP2; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 16 bpp */ + + case 24: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported ) + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask24_0, %%mm0 \n\t" + "movq _mask24_1, %%mm1 \n\t" + "movq _mask24_2, %%mm2 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop24end \n\t" + + "mainloop24: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm4 \n\t" + "movq 16(%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm4 \n\t" + "por %%mm4, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "addl $24, %%esi \n\t" // inc by 24 bytes processed + "addl $24, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + + "ja mainloop24 \n\t" + + "mainloop24end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end24 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop24: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip24 \n\t" // if CF = 0 + "movw (%%esi), %%ax \n\t" + "movw %%ax, (%%edi) \n\t" + "xorl %%eax, %%eax \n\t" + "movb 2(%%esi), %%al \n\t" + "movb %%al, 2(%%edi) \n\t" + + "skip24: \n\t" + "addl $3, %%esi \n\t" + "addl $3, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop24 \n\t" + + "end24: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP3 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP3 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP3 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP3 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP3; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 24 bpp */ + + case 32: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported ) + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask32_0, %%mm0 \n\t" + "movq _mask32_1, %%mm1 \n\t" + "movq _mask32_2, %%mm2 \n\t" + "movq _mask32_3, %%mm3 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm3 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + "pcmpeqb %%mm6, %%mm3 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" // lcr + "jz mainloop32end \n\t" + + "mainloop32: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm4 \n\t" + "movq 16(%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm4 \n\t" + "por %%mm4, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "movq 24(%%esi), %%mm7 \n\t" + "pand %%mm3, %%mm7 \n\t" + "movq %%mm3, %%mm5 \n\t" + "movq 24(%%edi), %%mm4 \n\t" + "pandn %%mm4, %%mm5 \n\t" + "por %%mm5, %%mm7 \n\t" + "movq %%mm7, 24(%%edi) \n\t" + + "addl $32, %%esi \n\t" // inc by 32 bytes processed + "addl $32, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop32 \n\t" + + "mainloop32end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end32 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // low byte => high byte + + "secondloop32: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip32 \n\t" // if CF = 0 + "movl (%%esi), %%eax \n\t" + "movl %%eax, (%%edi) \n\t" + + "skip32: \n\t" + "addl $4, %%esi \n\t" + "addl $4, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop32 \n\t" + + "end32: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP4 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP4 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP4 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP4 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP4; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 32 bpp */ + + case 48: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported ) + { + png_uint_32 len; + int diff; + int dummy_value_a; // fix 'forbidden register spilled' error + int dummy_value_d; + int dummy_value_c; + int dummy_value_S; + int dummy_value_D; + _unmask = ~mask; // global variable for -fPIC version + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = (int) (png_ptr->width & 7); // amount lost // + + __asm__ __volatile__ ( + "movd _unmask, %%mm7 \n\t" // load bit pattern + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask48_0, %%mm0 \n\t" + "movq _mask48_1, %%mm1 \n\t" + "movq _mask48_2, %%mm2 \n\t" + "movq _mask48_3, %%mm3 \n\t" + "movq _mask48_4, %%mm4 \n\t" + "movq _mask48_5, %%mm5 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pand %%mm7, %%mm4 \n\t" + "pand %%mm7, %%mm5 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + "pcmpeqb %%mm6, %%mm3 \n\t" + "pcmpeqb %%mm6, %%mm4 \n\t" + "pcmpeqb %%mm6, %%mm5 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop48end \n\t" + + "mainloop48: \n\t" + "movq (%%esi), %%mm7 \n\t" + "pand %%mm0, %%mm7 \n\t" + "movq %%mm0, %%mm6 \n\t" + "pandn (%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, (%%edi) \n\t" + + "movq 8(%%esi), %%mm6 \n\t" + "pand %%mm1, %%mm6 \n\t" + "movq %%mm1, %%mm7 \n\t" + "pandn 8(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm7 \n\t" + "pandn 16(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "movq 24(%%esi), %%mm7 \n\t" + "pand %%mm3, %%mm7 \n\t" + "movq %%mm3, %%mm6 \n\t" + "pandn 24(%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, 24(%%edi) \n\t" + + "movq 32(%%esi), %%mm6 \n\t" + "pand %%mm4, %%mm6 \n\t" + "movq %%mm4, %%mm7 \n\t" + "pandn 32(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 32(%%edi) \n\t" + + "movq 40(%%esi), %%mm7 \n\t" + "pand %%mm5, %%mm7 \n\t" + "movq %%mm5, %%mm6 \n\t" + "pandn 40(%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, 40(%%edi) \n\t" + + "addl $48, %%esi \n\t" // inc by 48 bytes processed + "addl $48, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + + "ja mainloop48 \n\t" + + "mainloop48end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end48 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop48: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip48 \n\t" // if CF = 0 + "movl (%%esi), %%eax \n\t" + "movl %%eax, (%%edi) \n\t" + + "skip48: \n\t" + "addl $4, %%esi \n\t" + "addl $4, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop48 \n\t" + + "end48: \n\t" + "EMMS \n\t" // DONE + + : "=a" (dummy_value_a), // output regs (dummy) + "=d" (dummy_value_d), + "=c" (dummy_value_c), + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "3" (srcptr), // esi // input regs + "4" (dstptr), // edi + "0" (diff), // eax +// was (unmask) "b" RESERVED // ebx // Global Offset Table idx + "2" (len), // ecx + "1" (mask) // edx + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + register png_uint_32 i; + png_uint_32 initial_val = BPP6 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP6 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP6 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP6 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP6; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + } /* end of else (_mmx_supported) */ + + break; + } /* end 48 bpp */ + + case 64: /* png_ptr->row_info.pixel_depth */ + { + png_bytep srcptr; + png_bytep dstptr; + register png_uint_32 i; + png_uint_32 initial_val = BPP8 * png_pass_start[png_ptr->pass]; + /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */ + register int stride = BPP8 * png_pass_inc[png_ptr->pass]; + /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */ + register int rep_bytes = BPP8 * png_pass_width[png_ptr->pass]; + /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ + png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */ + int diff = (int) (png_ptr->width & 7); /* amount lost */ + register png_uint_32 final_val = BPP8 * len; /* GRR bugfix */ + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + if (diff) /* number of leftover pixels: 3 for pngtest */ + { + final_val+=diff*BPP8; + for (; i < final_val; i += stride) + { + if (rep_bytes > (int)(final_val-i)) + rep_bytes = (int)(final_val-i); + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } + + break; + } /* end 64 bpp */ + + default: /* png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 */ + { + /* this should never happen */ + fprintf(stderr, + "libpng internal error: png_ptr->row_info.pixel_depth = %d\n", + png_ptr->row_info.pixel_depth); + fflush(stderr); + break; + } + } /* end switch (png_ptr->row_info.pixel_depth) */ + + } /* end if (non-trivial mask) */ + +} /* end png_combine_row() */ + +#endif /* PNG_HAVE_ASSEMBLER_COMBINE_ROW */ + + + + +/*===========================================================================*/ +/* */ +/* P N G _ D O _ R E A D _ I N T E R L A C E */ +/* */ +/*===========================================================================*/ + +#if defined(PNG_READ_INTERLACING_SUPPORTED) +#if defined(PNG_HAVE_ASSEMBLER_READ_INTERLACE) + +/* png_do_read_interlace() is called after any 16-bit to 8-bit conversion + * has taken place. [GRR: what other steps come before and/or after?] + */ + +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + png_uint_32 transformations = png_ptr->transformations; +#endif + + png_debug(1, "in png_do_read_interlace (pnggccrd.c)\n"); + + if (_mmx_supported == 2) { + png_mmx_support(); + } + + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_byte v; + png_uint_32 i; + int j; + + sp = row + (png_size_t)((row_info->width - 1) >> 3); + dp = row + (png_size_t)((final_width - 1) >> 3); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 7); + dshift = (int)((final_width + 7) & 7); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 7); + dshift = 7 - (int)((final_width + 7) & 7); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = row_info->width; i; i--) + { + v = (png_byte)((*sp >> sshift) & 0x1); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 2: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 2); + dp = row + (png_size_t)((final_width - 1) >> 2); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 3) & 3) << 1); + dshift = (png_size_t)(((final_width + 3) & 3) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1); + dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 4: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 1); + dp = row + (png_size_t)((final_width - 1) >> 1); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 1) & 1) << 2); + dshift = (png_size_t)(((final_width + 1) & 1) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2); + dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0xf); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + /*====================================================================*/ + + default: /* 8-bit or larger (this is where the routine is modified) */ + { +#if 0 +// static unsigned long long _const4 = 0x0000000000FFFFFFLL; no good +// static unsigned long long const4 = 0x0000000000FFFFFFLL; no good +// unsigned long long _const4 = 0x0000000000FFFFFFLL; no good +// unsigned long long const4 = 0x0000000000FFFFFFLL; no good +#endif + png_bytep sptr, dp; + png_uint_32 i; + png_size_t pixel_bytes; + int width = (int)row_info->width; + + pixel_bytes = (row_info->pixel_depth >> 3); + + /* point sptr at the last pixel in the pre-expanded row: */ + sptr = row + (width - 1) * pixel_bytes; + + /* point dp at the last pixel position in the expanded row: */ + dp = row + (final_width - 1) * pixel_bytes; + + /* New code by Nirav Chhatrapati - Intel Corporation */ + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported ) + { + //-------------------------------------------------------------- + if (pixel_bytes == 3) + { + if (((pass == 0) || (pass == 1)) && width) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $21, %%edi \n\t" + // (png_pass_inc[pass] - 1)*pixel_bytes + + ".loop3_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0 + "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0 + "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0 + "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z + "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z + "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z + "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1 + "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z + "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1 + "movq %%mm0, %%mm3 \n\t" // 2 1 0 2 1 0 2 1 + "psllq $16, %%mm0 \n\t" // 0 2 1 0 2 1 z z + "movq %%mm3, %%mm4 \n\t" // 2 1 0 2 1 0 2 1 + "punpckhdq %%mm0, %%mm3 \n\t" // 0 2 1 0 2 1 0 2 + "movq %%mm4, 16(%%edi) \n\t" + "psrlq $32, %%mm0 \n\t" // z z z z 0 2 1 0 + "movq %%mm3, 8(%%edi) \n\t" + "punpckldq %%mm4, %%mm0 \n\t" // 1 0 2 1 0 2 1 0 + "subl $3, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $24, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop3_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx +// doesn't work "i" (0x0000000000FFFFFFLL) // %1 (a.k.a. _const4) + +#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list + , "%mm3", "%mm4" +#endif + ); + } + else if (((pass == 2) || (pass == 3)) && width) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $9, %%edi \n\t" + // (png_pass_inc[pass] - 1)*pixel_bytes + + ".loop3_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0 + "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0 + "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0 + "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z + "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z + "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z + "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1 + "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z + "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1 + "movq %%mm0, 4(%%edi) \n\t" + "psrlq $16, %%mm0 \n\t" // z z 2 1 0 2 1 0 + "subl $3, %%esi \n\t" + "movd %%mm0, (%%edi) \n\t" + "subl $12, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop3_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx + +#if 0 /* %mm0, ..., %mm2 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list +#endif + ); + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 1) << 1) - 8; // GRR: huh? + if (width_mmx < 0) + width_mmx = 0; + width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes + if (width_mmx) + { + // png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + // sptr points at last pixel in pre-expanded row + // dp points at last pixel position in expanded row + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $3, %%esi \n\t" + "subl $9, %%edi \n\t" + // (png_pass_inc[pass] + 1)*pixel_bytes + + ".loop3_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // x x 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // x x 5 4 3 2 1 0 + "movq %%mm0, %%mm2 \n\t" // x x 5 4 3 2 1 0 + "psllq $24, %%mm0 \n\t" // 4 3 2 1 0 z z z + "pand _const4, %%mm1 \n\t" // z z z z z 2 1 0 + "psrlq $24, %%mm2 \n\t" // z z z x x 5 4 3 + "por %%mm1, %%mm0 \n\t" // 4 3 2 1 0 2 1 0 + "movq %%mm2, %%mm3 \n\t" // z z z x x 5 4 3 + "psllq $8, %%mm2 \n\t" // z z x x 5 4 3 z + "movq %%mm0, (%%edi) \n\t" + "psrlq $16, %%mm3 \n\t" // z z z z z x x 5 + "pand _const6, %%mm3 \n\t" // z z z z z z z 5 + "por %%mm3, %%mm2 \n\t" // z z x x 5 4 3 5 + "subl $6, %%esi \n\t" + "movd %%mm2, 8(%%edi) \n\t" + "subl $12, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop3_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, ..., %mm3 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list + , "%mm2", "%mm3" +#endif + ); + } + + sptr -= width_mmx*3; + dp -= width_mmx*6; + for (i = width; i; i--) + { + png_byte v[8]; + int j; + + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + } /* end of pixel_bytes == 3 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 1) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $3, %%esi \n\t" + "subl $31, %%edi \n\t" + + ".loop1_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // x x x x 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "movq %%mm0, %%mm2 \n\t" // 3 3 2 2 1 1 0 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0 + "movq %%mm0, %%mm3 \n\t" // 1 1 1 1 0 0 0 0 + "punpckldq %%mm0, %%mm0 \n\t" // 0 0 0 0 0 0 0 0 + "punpckhdq %%mm3, %%mm3 \n\t" // 1 1 1 1 1 1 1 1 + "movq %%mm0, (%%edi) \n\t" + "punpckhwd %%mm2, %%mm2 \n\t" // 3 3 3 3 2 2 2 2 + "movq %%mm3, 8(%%edi) \n\t" + "movq %%mm2, %%mm4 \n\t" // 3 3 3 3 2 2 2 2 + "punpckldq %%mm2, %%mm2 \n\t" // 2 2 2 2 2 2 2 2 + "punpckhdq %%mm4, %%mm4 \n\t" // 3 3 3 3 3 3 3 3 + "movq %%mm2, 16(%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm4, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "subl $4, %%ecx \n\t" + "jnz .loop1_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1", "%mm2" // clobber list + , "%mm3", "%mm4" +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*8; + for (i = width; i; i--) + { + int j; + + /* I simplified this part in version 1.0.4e + * here and in several other instances where + * pixel_bytes == 1 -- GR-P + * + * Original code: + * + * png_byte v[8]; + * png_memcpy(v, sptr, pixel_bytes); + * for (j = 0; j < png_pass_inc[pass]; j++) + * { + * png_memcpy(dp, v, pixel_bytes); + * dp -= pixel_bytes; + * } + * sptr -= pixel_bytes; + * + * Replacement code is in the next three lines: + */ + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $3, %%esi \n\t" + "subl $15, %%edi \n\t" + + ".loop1_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "movq %%mm0, %%mm1 \n\t" // 3 3 2 2 1 1 0 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0 + "punpckhwd %%mm1, %%mm1 \n\t" // 3 3 3 3 2 2 2 2 + "movq %%mm0, (%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $4, %%ecx \n\t" + "jnz .loop1_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*4; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 3) << 3); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $7, %%esi \n\t" + "subl $15, %%edi \n\t" + + ".loop1_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "punpckhbw %%mm1, %%mm1 \n\t" // 7 7 6 6 5 5 4 4 + "movq %%mm1, 8(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $8, %%ecx \n\t" + "jnz .loop1_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (none) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*2; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + } /* end of pixel_bytes == 1 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 2) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $2, %%esi \n\t" + "subl $30, %%edi \n\t" + + ".loop2_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm1, 16(%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*16 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $2, %%esi \n\t" + "subl $14, %%edi \n\t" + + ".loop2_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2 + "movq %%mm0, (%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*8 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $2, %%esi \n\t" + "subl $6, %%edi \n\t" + + ".loop2_pass4: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "subl $4, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*4 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + } /* end of pixel_bytes == 2 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 4) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $4, %%esi \n\t" + "subl $60, %%edi \n\t" + + ".loop4_pass0: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "movq %%mm1, 32(%%edi) \n\t" + "movq %%mm1, 40(%%edi) \n\t" + "movq %%mm1, 48(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm1, 56(%%edi) \n\t" + "subl $64, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*32 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $4, %%esi \n\t" + "subl $28, %%edi \n\t" + + ".loop4_pass2: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm1, 16(%%edi) \n\t" + "movq %%mm1, 24(%%edi) \n\t" + "subl $8, %%esi \n\t" + "subl $32, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*16 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $4, %%esi \n\t" + "subl $12, %%edi \n\t" + + ".loop4_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width_mmx) // ecx + +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0", "%mm1" // clobber list +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*8 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + } /* end of pixel_bytes == 4 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 8) + { +// GRR TEST: should work, but needs testing (special 64-bit version of rpng2?) + // GRR NOTE: no need to combine passes here! + if (((pass == 0) || (pass == 1)) && width) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + // source is 8-byte RRGGBBAA + // dest is 64-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA ... + __asm__ __volatile__ ( + "subl $56, %%edi \n\t" // start of last block + + ".loop8_pass0: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "movq %%mm0, 32(%%edi) \n\t" + "movq %%mm0, 40(%%edi) \n\t" + "movq %%mm0, 48(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 56(%%edi) \n\t" + "subl $64, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass0 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + else if (((pass == 2) || (pass == 3)) && width) + { + // source is 8-byte RRGGBBAA + // dest is 32-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $24, %%edi \n\t" // start of last block + + ".loop8_pass2: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass2 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + } + else if (width) // pass == 4 or 5 + { + // source is 8-byte RRGGBBAA + // dest is 16-byte RRGGBBAA RRGGBBAA + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + int dummy_value_c; // fix 'forbidden register spilled' + int dummy_value_S; + int dummy_value_D; + + __asm__ __volatile__ ( + "subl $8, %%edi \n\t" // start of last block + + ".loop8_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass4 \n\t" + "EMMS \n\t" // DONE + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "1" (sptr), // esi // input regs + "2" (dp), // edi + "0" (width) // ecx + +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + : "%mm0" // clobber list +#endif + ); + } + } + + } /* end of pixel_bytes == 8 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } /* end of pixel_bytes == 6 */ + + //-------------------------------------------------------------- + else + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr-= pixel_bytes; + } + } + } // end of _mmx_supported ======================================== + + else /* MMX not supported: use modified C code - takes advantage + * of inlining of png_memcpy for a constant */ + /* GRR 19991007: does it? or should pixel_bytes in each + * block be replaced with immediate value (e.g., 1)? */ + /* GRR 19991017: replaced with constants in each case */ +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + if (pixel_bytes == 1) + { + for (i = width; i; i--) + { + int j; + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + --sptr; + } + } + else if (pixel_bytes == 3) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + else if (pixel_bytes == 2) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 2); + dp -= 2; + } + sptr -= 2; + } + } + else if (pixel_bytes == 4) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { +#ifdef PNG_DEBUG + if (dp < row || dp+3 > row+png_ptr->row_buf_size) + { + printf("dp out of bounds: row=%d, dp=%d, rp=%d\n",row, dp, + row+png_ptr->row_buf_size); + printf("row_buf=%d\n",png_ptr->row_buf_size); + } +#endif + png_memcpy(dp, v, 4); + dp -= 4; + } + sptr -= 4; + } + } + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } + else if (pixel_bytes == 8) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 8); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 8); + dp -= 8; + } + sptr -= 8; + } + } + else /* GRR: should never be reached */ + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + + } /* end if (MMX not supported) */ + break; + } + } /* end switch (row_info->pixel_depth) */ + + row_info->width = final_width; + row_info->rowbytes = ((final_width * + (png_uint_32)row_info->pixel_depth + 7) >> 3); + } + +} /* end png_do_read_interlace() */ + +#endif /* PNG_HAVE_ASSEMBLER_READ_INTERLACE */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + + + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + +// These variables are utilized in the functions below. They are declared +// globally here to ensure alignment on 8-byte boundaries. + +union uAll { + long long use; + double align; +} _LBCarryMask = {0x0101010101010101LL}, + _HBClearMask = {0x7f7f7f7f7f7f7f7fLL}, + _ActiveMask, _ActiveMask2, _ActiveMaskEnd, _ShiftBpp, _ShiftRem; + + + +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ A V G // +// // +//===========================================================================// + +// Optimized code for PNG Average filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + int bpp; + int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error + int dummy_value_S; + int dummy_value_D; + + bpp = (row_info->pixel_depth + 7) >> 3; // get # bytes per pixel + _FullLength = row_info->rowbytes; // # of bytes to filter + + __asm__ __volatile__ ( + // initialize address pointers and offset +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif +//pre "movl row, %%edi \n\t" // edi: Avg(x) + "xorl %%ebx, %%ebx \n\t" // ebx: x + "movl %%edi, %%edx \n\t" +//pre "movl prev_row, %%esi \n\t" // esi: Prior(x) +//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp) + + "xorl %%eax,%%eax \n\t" + + // Compute the Raw value for the first bpp bytes + // Raw(x) = Avg(x) + (Prior(x)/2) + "avg_rlp: \n\t" + "movb (%%esi,%%ebx,),%%al \n\t" // load al with Prior(x) + "incl %%ebx \n\t" + "shrb %%al \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,),%%al \n\t" // add Avg(x); -1 to offset inc ebx +//pre "cmpl bpp, %%ebx \n\t" // (bpp is preloaded into ecx) + "cmpl %%ecx, %%ebx \n\t" + "movb %%al,-1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx + "jb avg_rlp \n\t" // mov does not affect flags + + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl %%ebx, _dif \n\t" // add bpp + "addl $0xf, _dif \n\t" // add 7+8 to incr past alignment bdry + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start => value ebx at + "jz avg_go \n\t" // alignment + + // fix alignment + // Compute the Raw value for the bytes up to the alignment boundary + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%ecx, %%ecx \n\t" + + "avg_lp1: \n\t" + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx + "cmpl _dif, %%ebx \n\t" // check if at alignment boundary + "movb %%al, -1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx + "jb avg_lp1 \n\t" // repeat until at alignment boundary + + "avg_go: \n\t" + "movl _FullLength, %%eax \n\t" + "movl %%eax, %%ecx \n\t" + "subl %%ebx, %%eax \n\t" // subtract alignment fix + "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8 + "subl %%eax, %%ecx \n\t" // drop over bytes from original length + "movl %%ecx, _MMXLength \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + // GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength) + // (seems to work fine without...) + ); + + // now do the math for the rest of the row + switch (bpp) + { + case 3: + { + _ActiveMask.use = 0x0000000000ffffffLL; + _ShiftBpp.use = 24; // == 3 * 8 + _ShiftRem.use = 40; // == 64 - 24 + + __asm__ __volatile__ ( + // re-init address pointers and offset + "movq _ActiveMask, %%mm7 \n\t" + "movl _dif, %%ecx \n\t" // ecx: x = offset to + "movq _LBCarryMask, %%mm5 \n\t" // alignment boundary +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (correct pos. in loop below) + "avg_3lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" // load mm0 with Avg(x) + "movq %%mm5, %%mm3 \n\t" + "psrlq _ShiftRem, %%mm2 \n\t" // correct position Raw(x-bpp) data + "movq (%%esi,%%ecx,), %%mm1 \n\t" // load mm1 with Prior(x) + "movq %%mm7, %%mm6 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + // add 1st active group (Raw(x-bpp)/2) to average with LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 3-5 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + + // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift mm6 mask to cover last two + // bytes + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 bytes to add to Avg + "addl $8, %%ecx \n\t" + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + // move updated Raw(x) to use as Raw(x-bpp) for next loop + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm0, %%mm2 \n\t" // mov updated Raw(x) to mm2 + "jb avg_3lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 3 bpp + + case 6: + case 4: + //case 7: // who wrote this? PNG doesn't support 5 or 7 bytes/pixel + //case 5: // GRR BOGUS + { + _ActiveMask.use = 0xffffffffffffffffLL; // use shift below to clear + // appropriate inactive bytes + _ShiftBpp.use = bpp << 3; + _ShiftRem.use = 64 - _ShiftBpp.use; + + __asm__ __volatile__ ( + "movq _HBClearMask, %%mm4 \n\t" + + // re-init address pointers and offset + "movl _dif, %%ecx \n\t" // ecx: x = offset to alignment boundary + + // load _ActiveMask and clear all bytes except for 1st active group + "movq _ActiveMask, %%mm7 \n\t" +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "psrlq _ShiftRem, %%mm7 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + "movq %%mm7, %%mm6 \n\t" + "movq _LBCarryMask, %%mm5 \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" // create mask for 2nd active group + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (we correct pos. in loop below) + "avg_4lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" + "psrlq _ShiftRem, %%mm2 \n\t" // shift data to pos. correctly + "movq (%%esi,%%ecx,), %%mm1 \n\t" + // add (Prev_row/2) to average + "movq %%mm5, %%mm3 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm7, %%mm2 \n\t" // leave only Active Group 1 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "addl $8, %%ecx \n\t" + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + "cmpl _MMXLength, %%ecx \n\t" + // now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + // prep Raw(x-bpp) for next loop + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "jb avg_4lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 4,6 bpp + + case 2: + { + _ActiveMask.use = 0x000000000000ffffLL; + _ShiftBpp.use = 16; // == 2 * 8 + _ShiftRem.use = 48; // == 64 - 16 + + __asm__ __volatile__ ( + // load _ActiveMask + "movq _ActiveMask, %%mm7 \n\t" + // re-init address pointers and offset + "movl _dif, %%ecx \n\t" // ecx: x = offset to alignment boundary + "movq _LBCarryMask, %%mm5 \n\t" +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (we correct pos. in loop below) + "avg_2lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" + "psrlq _ShiftRem, %%mm2 \n\t" // shift data to pos. correctly + "movq (%%esi,%%ecx,), %%mm1 \n\t" // (GRR BUGFIX: was psllq) + // add (Prev_row/2) to average + "movq %%mm5, %%mm3 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "movq %%mm7, %%mm6 \n\t" + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + + // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + + // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 2 & 3 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + + // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 4 & 5 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + + // add 4th active group (Raw(x-bpp)/2) to average with _LBCarry + "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 6 & 7 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly + "addl $8, %%ecx \n\t" + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + + "cmpl _MMXLength, %%ecx \n\t" + // now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + // prep Raw(x-bpp) for next loop + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "jb avg_2lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 2 bpp + + case 1: + { + __asm__ __volatile__ ( + // re-init address pointers and offset +#ifdef __PIC__ + "pushl %%ebx \n\t" // save Global Offset Table index +#endif + "movl _dif, %%ebx \n\t" // ebx: x = offset to alignment boundary +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "cmpl _FullLength, %%ebx \n\t" // test if offset at end of array + "jnb avg_1end \n\t" + // do Paeth decode for remaining bytes +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + "movl %%edi, %%edx \n\t" +// preload "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp) + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx + // in loop below + "avg_1lp: \n\t" + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx + "cmpl _FullLength, %%ebx \n\t" // check if at end of array + "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + "jb avg_1lp \n\t" + + "avg_1end: \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // Global Offset Table index +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + } + return; // end 1 bpp + + case 8: + { + __asm__ __volatile__ ( + // re-init address pointers and offset + "movl _dif, %%ecx \n\t" // ecx: x == offset to alignment + "movq _LBCarryMask, %%mm5 \n\t" // boundary +// preload "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" +// preload "movl prev_row, %%esi \n\t" // esi: Prior(x) + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes + // (NO NEED to correct pos. in loop below) + + "avg_8lp: \n\t" + "movq (%%edi,%%ecx,), %%mm0 \n\t" + "movq %%mm5, %%mm3 \n\t" + "movq (%%esi,%%ecx,), %%mm1 \n\t" + "addl $8, %%ecx \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte + // where both lsb's were == 1 + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7, each byte + "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg, each byte + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7, each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg, each + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm0, -8(%%edi,%%ecx,) \n\t" + "movq %%mm0, %%mm2 \n\t" // reuse as Raw(x-bpp) + "jb avg_8lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm5 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2" + , "%mm3", "%mm4", "%mm5" +#endif + ); + } + break; // end 8 bpp + + default: // bpp greater than 8 (!= 1,2,3,4,[5],6,[7],8) + { + + // GRR: PRINT ERROR HERE: SHOULD NEVER BE REACHED + fprintf(stderr, + "libpng: internal logic error (png_read_filter_row_mmx_avg())\n"); + +#if 0 + __asm__ __volatile__ ( + "movq _LBCarryMask, %%mm5 \n\t" + // re-init address pointers and offset + "movl _dif, %%ebx \n\t" // ebx: x = offset to alignment boundary + "movl row, %%edi \n\t" // edi: Avg(x) + "movq _HBClearMask, %%mm4 \n\t" + "movl %%edi, %%edx \n\t" + "movl prev_row, %%esi \n\t" // esi: Prior(x) + "subl bpp, %%edx \n\t" // edx: Raw(x-bpp) + "avg_Alp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq %%mm5, %%mm3 \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "movq (%%edx,%%ebx,), %%mm2 \n\t" + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg for each byte + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + "addl $8, %%ebx \n\t" + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each byte + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + "jb avg_Alp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); +#endif /* 0 - NEVER REACHED */ + } + break; + + } // end switch (bpp) + + __asm__ __volatile__ ( + // MMX acceleration complete; now do clean-up + // check if any remaining bytes left to decode +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif + "movl _MMXLength, %%ebx \n\t" // ebx: x == offset bytes after MMX +//pre "movl row, %%edi \n\t" // edi: Avg(x) + "cmpl _FullLength, %%ebx \n\t" // test if offset at end of array + "jnb avg_end \n\t" + + // do Avg decode for remaining bytes +//pre "movl prev_row, %%esi \n\t" // esi: Prior(x) + "movl %%edi, %%edx \n\t" +//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp) + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below + + "avg_lp2: \n\t" + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx + "cmpl _FullLength, %%ebx \n\t" // check if at end of array + "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x) [mov does not + "jb avg_lp2 \n\t" // affect flags; -1 to offset inc ebx] + + "avg_end: \n\t" + "EMMS \n\t" // end MMX; prep for poss. FP instrs. +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + +} /* end png_read_filter_row_mmx_avg() */ + + + + +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ P A E T H // +// // +//===========================================================================// + +// Optimized code for PNG Paeth filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + int bpp; + int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error + int dummy_value_S; + int dummy_value_D; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + _FullLength = row_info->rowbytes; // # of bytes to filter + + __asm__ __volatile__ ( +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif + "xorl %%ebx, %%ebx \n\t" // ebx: x offset +//pre "movl row, %%edi \n\t" + "xorl %%edx, %%edx \n\t" // edx: x-bpp offset +//pre "movl prev_row, %%esi \n\t" + "xorl %%eax, %%eax \n\t" + + // Compute the Raw value for the first bpp bytes + // Note: the formula works out to be always + // Paeth(x) = Raw(x) + Prior(x) where x < bpp + "paeth_rlp: \n\t" + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" +//pre "cmpl bpp, %%ebx \n\t" (bpp is preloaded into ecx) + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" + "jb paeth_rlp \n\t" + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl %%ebx, _dif \n\t" // add bpp + "xorl %%ecx, %%ecx \n\t" + "addl $0xf, _dif \n\t" // add 7 + 8 to incr past alignment boundary + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start ==> value ebx at alignment + "jz paeth_go \n\t" + // fix alignment + + "paeth_lp1: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, _patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl _patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_pca \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_pca: \n\t" + "movl %%eax, _pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_pba \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + + "paeth_pba: \n\t" + "movl %%ecx, _pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl _patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_paa \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_paa: \n\t" + "movl %%eax, _patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_abb \n\t" + // pa > pb; now test if pb <= pc + "cmpl _pctemp, %%ecx \n\t" + "jna paeth_bbc \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth \n\t" + + "paeth_bbc: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_paeth \n\t" + + "paeth_abb: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl _pctemp, %%eax \n\t" + "jna paeth_abc \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth \n\t" + + "paeth_abc: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + + "paeth_paeth: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _dif, %%ebx \n\t" + "jb paeth_lp1 \n\t" + + "paeth_go: \n\t" + "movl _FullLength, %%ecx \n\t" + "movl %%ecx, %%eax \n\t" + "subl %%ebx, %%eax \n\t" // subtract alignment fix + "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8 + "subl %%eax, %%ecx \n\t" // drop over bytes from original length + "movl %%ecx, _MMXLength \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + + // now do the math for the rest of the row + switch (bpp) + { + case 3: + { + _ActiveMask.use = 0x0000000000ffffffLL; + _ActiveMaskEnd.use = 0xffff000000000000LL; + _ShiftBpp.use = 24; // == bpp(3) * 8 + _ShiftRem.use = 40; // == 64 - 24 + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" + "paeth_3lp: \n\t" + "psrlq _ShiftRem, %%mm1 \n\t" // shift last 3 bytes to 1st 3 bytes + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // prep c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "psrlq _ShiftRem, %%mm3 \n\t" // shift last 3 bytes to 1st 3 bytes + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq (%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand _ActiveMask, %%mm7 \n\t" + "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as Raw(x-bpp) + // now do Paeth for 2nd set of bytes (3-5) + "psrlq _ShiftBpp, %%mm2 \n\t" // load b=Prior(x) step 2 + "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + "pxor %%mm7, %%mm7 \n\t" + "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "psubw %%mm3, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = + // pav + pbv = pbv + pav + "movq %%mm5, %%mm6 \n\t" + "paddw %%mm4, %%mm6 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm5, %%mm0 \n\t" // create mask pbv bytes < 0 + "pcmpgtw %%mm4, %%mm7 \n\t" // create mask pav bytes < 0 + "pand %%mm5, %%mm0 \n\t" // only pbv bytes < 0 in mm0 + "pand %%mm4, %%mm7 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm5 \n\t" + "psubw %%mm7, %%mm4 \n\t" + "psubw %%mm0, %%mm5 \n\t" + "psubw %%mm7, %%mm4 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq %%mm2, %%mm3 \n\t" // load c=Prior(x-bpp) step 1 + "pand _ActiveMask, %%mm7 \n\t" + "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "psllq _ShiftBpp, %%mm7 \n\t" // shift bytes to 2nd group of 3 bytes + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "psllq _ShiftBpp, %%mm3 \n\t" // load c=Prior(x-bpp) step 2 + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "psllq _ShiftBpp, %%mm1 \n\t" // shift bytes + // now mm1 will be used as Raw(x-bpp) + // now do Paeth for 3rd, and final, set of bytes (6-7) + "pxor %%mm7, %%mm7 \n\t" + "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + "psubw %%mm3, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "paddw %%mm5, %%mm6 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "packuswb %%mm7, %%mm1 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "pand _ActiveMaskEnd, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + + "cmpl _MMXLength, %%ecx \n\t" + "pxor %%mm0, %%mm0 \n\t" // pxor does not affect flags + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + // mm3 ready to be used as Prior(x-bpp) next loop + "jb paeth_3lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 3 bpp + + case 6: + //case 7: // GRR BOGUS + //case 5: // GRR BOGUS + { + _ActiveMask.use = 0x00000000ffffffffLL; + _ActiveMask2.use = 0xffffffff00000000LL; + _ShiftBpp.use = bpp << 3; // == bpp * 8 + _ShiftRem.use = 64 - _ShiftBpp.use; + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" + "pxor %%mm0, %%mm0 \n\t" + + "paeth_6lp: \n\t" + // must shift to position Raw(x-bpp) data + "psrlq _ShiftRem, %%mm1 \n\t" + // do first set of 4 bytes + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b + // must shift to position Prior(x-bpp) data + "psrlq _ShiftRem, %%mm3 \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand _ActiveMask, %%mm7 \n\t" + "psrlq _ShiftRem, %%mm3 \n\t" + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor and Raw(x) + "movq %%mm2, %%mm6 \n\t" + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" + "movq %%mm7, %%mm5 \n\t" + "psrlq _ShiftRem, %%mm1 \n\t" + "por %%mm6, %%mm3 \n\t" + "psllq _ShiftBpp, %%mm5 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "por %%mm5, %%mm1 \n\t" + // do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_6lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 6 bpp + + case 4: + { + _ActiveMask.use = 0x00000000ffffffffLL; + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read + // a=Raw(x-bpp) bytes + "paeth_4lp: \n\t" + // do first set of 4 bytes + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpckhbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq (%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand _ActiveMask, %%mm7 \n\t" + "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as Raw(x-bpp) + // do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b + "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add predictor with Raw(x) + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_4lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 4 bpp + + case 8: // bpp == 8 + { + _ActiveMask.use = 0x00000000ffffffffLL; + + __asm__ __volatile__ ( + "movl _dif, %%ecx \n\t" +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read + // a=Raw(x-bpp) bytes + "paeth_8lp: \n\t" + // do first set of 4 bytes + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "pand _ActiveMask, %%mm7 \n\t" + "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) + "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c + "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value + "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // read a=Raw(x-bpp) bytes + + // do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b + "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // step ecx to next set of 8 bytes and repeat loop til done + "addl $8, %%ecx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + "cmpl _MMXLength, %%ecx \n\t" + "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_8lp \n\t" + + : "=S" (dummy_value_S), // output regs (dummy) + "=D" (dummy_value_D) + + : "0" (prev_row), // esi // input regs + "1" (row) // edi + + : "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; // end 8 bpp + + case 1: // bpp = 1 + case 2: // bpp = 2 + default: // bpp > 8 + { + __asm__ __volatile__ ( +#ifdef __PIC__ + "pushl %%ebx \n\t" // save Global Offset Table index +#endif + "movl _dif, %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb paeth_dend \n\t" + +// preload "movl row, %%edi \n\t" +// preload "movl prev_row, %%esi \n\t" + // do Paeth decode for remaining bytes + "movl %%ebx, %%edx \n\t" +// preload "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx = ebx - bpp + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx + + "paeth_dlp: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, _patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl _patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_dpca \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_dpca: \n\t" + "movl %%eax, _pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_dpba \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + + "paeth_dpba: \n\t" + "movl %%ecx, _pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl _patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_dpaa \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_dpaa: \n\t" + "movl %%eax, _patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_dabb \n\t" + // pa > pb; now test if pb <= pc + "cmpl _pctemp, %%ecx \n\t" + "jna paeth_dbbc \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_dpaeth \n\t" + + "paeth_dbbc: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_dpaeth \n\t" + + "paeth_dabb: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl _pctemp, %%eax \n\t" + "jna paeth_dabc \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_dpaeth \n\t" + + "paeth_dabc: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + + "paeth_dpaeth: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb paeth_dlp \n\t" + + "paeth_dend: \n\t" +#ifdef __PIC__ + "popl %%ebx \n\t" // index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list +#ifndef __PIC__ + , "%ebx" +#endif + ); + } + return; // No need to go further with this one + + } // end switch (bpp) + + __asm__ __volatile__ ( + // MMX acceleration complete; now do clean-up + // check if any remaining bytes left to decode +#ifdef __PIC__ + "pushl %%ebx \n\t" // save index to Global Offset Table +#endif + "movl _MMXLength, %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb paeth_end \n\t" +//pre "movl row, %%edi \n\t" +//pre "movl prev_row, %%esi \n\t" + // do Paeth decode for remaining bytes + "movl %%ebx, %%edx \n\t" +//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx = ebx - bpp + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below + + "paeth_lp2: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, _patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl _patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_pca2 \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_pca2: \n\t" + "movl %%eax, _pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_pba2 \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + + "paeth_pba2: \n\t" + "movl %%ecx, _pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl _patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_paa2 \n\t" + "negl %%eax \n\t" // reverse sign of neg values + + "paeth_paa2: \n\t" + "movl %%eax, _patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_abb2 \n\t" + // pa > pb; now test if pb <= pc + "cmpl _pctemp, %%ecx \n\t" + "jna paeth_bbc2 \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth2 \n\t" + + "paeth_bbc2: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_paeth2 \n\t" + + "paeth_abb2: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl _pctemp, %%eax \n\t" + "jna paeth_abc2 \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth2 \n\t" + + "paeth_abc2: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + + "paeth_paeth2: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb paeth_lp2 \n\t" + + "paeth_end: \n\t" + "EMMS \n\t" // end MMX; prep for poss. FP instrs. +#ifdef __PIC__ + "popl %%ebx \n\t" // restore index to Global Offset Table +#endif + + : "=c" (dummy_value_c), // output regs (dummy) + "=S" (dummy_value_S), + "=D" (dummy_value_D) + + : "0" (bpp), // ecx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%edx" // clobber list (no input regs!) +#ifndef __PIC__ + , "%ebx" +#endif + ); + +} /* end png_read_filter_row_mmx_paeth() */ + + + + +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ S U B // +// // +//===========================================================================// + +// Optimized code for PNG Sub filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row) +{ + int bpp; + int dummy_value_a; + int dummy_value_D; + + bpp = (row_info->pixel_depth + 7) >> 3; // calc number of bytes per pixel + _FullLength = row_info->rowbytes - bpp; // number of bytes to filter + + __asm__ __volatile__ ( +//pre "movl row, %%edi \n\t" + "movl %%edi, %%esi \n\t" // lp = row +//pre "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp +//irr "xorl %%eax, %%eax \n\t" + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl $0xf, _dif \n\t" // add 7 + 8 to incr past + // alignment boundary + "xorl %%ecx, %%ecx \n\t" + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start ==> value + "jz sub_go \n\t" // ecx at alignment + + "sub_lp1: \n\t" // fix alignment + "movb (%%esi,%%ecx,), %%al \n\t" + "addb %%al, (%%edi,%%ecx,) \n\t" + "incl %%ecx \n\t" + "cmpl _dif, %%ecx \n\t" + "jb sub_lp1 \n\t" + + "sub_go: \n\t" + "movl _FullLength, %%eax \n\t" + "movl %%eax, %%edx \n\t" + "subl %%ecx, %%edx \n\t" // subtract alignment fix + "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8 + "subl %%edx, %%eax \n\t" // drop over bytes from length + "movl %%eax, _MMXLength \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%ebx", "%ecx", "%edx" // clobber list + , "%esi" + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + + // now do the math for the rest of the row + switch (bpp) + { + case 3: + { + _ActiveMask.use = 0x0000ffffff000000LL; + _ShiftBpp.use = 24; // == 3 * 8 + _ShiftRem.use = 40; // == 64 - 24 + + __asm__ __volatile__ ( +// preload "movl row, %%edi \n\t" + "movq _ActiveMask, %%mm7 \n\t" // load _ActiveMask for 2nd + // active byte group + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "movq %%mm7, %%mm6 \n\t" + "movl _dif, %%edx \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" // move mask in mm6 to cover + // 3rd active byte group + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm1 \n\t" + + "sub_3lp: \n\t" // shift data for adding first + "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask; + // shift clears inactive bytes) + // add 1st active group + "movq (%%edi,%%edx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + + // add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group + "paddb %%mm1, %%mm0 \n\t" + + // add 3rd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array + "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop + "jb sub_3lp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm6", "%mm7" +#endif + ); + } + break; + + case 1: + { + __asm__ __volatile__ ( + "movl _dif, %%edx \n\t" +// preload "movl row, %%edi \n\t" + "cmpl _FullLength, %%edx \n\t" + "jnb sub_1end \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "xorl %%eax, %%eax \n\t" +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + + "sub_1lp: \n\t" + "movb (%%esi,%%edx,), %%al \n\t" + "addb %%al, (%%edi,%%edx,) \n\t" + "incl %%edx \n\t" + "cmpl _FullLength, %%edx \n\t" + "jb sub_1lp \n\t" + + "sub_1end: \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list + ); + } + return; + + case 6: + case 4: + //case 7: // GRR BOGUS + //case 5: // GRR BOGUS + { + _ShiftBpp.use = bpp << 3; + _ShiftRem.use = 64 - _ShiftBpp.use; + + __asm__ __volatile__ ( +// preload "movl row, %%edi \n\t" + "movl _dif, %%edx \n\t" + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm1 \n\t" + + "sub_4lp: \n\t" // shift data for adding first + "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask; + // shift clears inactive bytes) + "movq (%%edi,%%edx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + + // add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" + "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop + "jb sub_4lp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + break; + + case 2: + { + _ActiveMask.use = 0x00000000ffff0000LL; + _ShiftBpp.use = 16; // == 2 * 8 + _ShiftRem.use = 48; // == 64 - 16 + + __asm__ __volatile__ ( + "movq _ActiveMask, %%mm7 \n\t" // load _ActiveMask for 2nd + // active byte group + "movl _dif, %%edx \n\t" + "movq %%mm7, %%mm6 \n\t" +// preload "movl row, %%edi \n\t" + "psllq _ShiftBpp, %%mm6 \n\t" // move mask in mm6 to cover + // 3rd active byte group + "movl %%edi, %%esi \n\t" // lp = row + "movq %%mm6, %%mm5 \n\t" +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "psllq _ShiftBpp, %%mm5 \n\t" // move mask in mm5 to cover + // 4th active byte group + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm1 \n\t" + + "sub_2lp: \n\t" // shift data for adding first + "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask; + // shift clears inactive bytes) + // add 1st active group + "movq (%%edi,%%edx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + + // add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group + "paddb %%mm1, %%mm0 \n\t" + + // add 3rd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group + "paddb %%mm1, %%mm0 \n\t" + + // add 4th active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly + "pand %%mm5, %%mm1 \n\t" // mask to use 4th active group + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array + "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop + "jb sub_2lp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; + + case 8: + { + __asm__ __volatile__ ( +// preload "movl row, %%edi \n\t" + "movl _dif, %%edx \n\t" + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "movl _MMXLength, %%ecx \n\t" + + // prime the pump: load the first Raw(x-bpp) data set + "movq -8(%%edi,%%edx,), %%mm7 \n\t" + "andl $0x0000003f, %%ecx \n\t" // calc bytes over mult of 64 + + "sub_8lp: \n\t" + "movq (%%edi,%%edx,), %%mm0 \n\t" // load Sub(x) for 1st 8 bytes + "paddb %%mm7, %%mm0 \n\t" + "movq 8(%%edi,%%edx,), %%mm1 \n\t" // load Sub(x) for 2nd 8 bytes + "movq %%mm0, (%%edi,%%edx,) \n\t" // write Raw(x) for 1st 8 bytes + + // Now mm0 will be used as Raw(x-bpp) for the 2nd group of 8 bytes. + // This will be repeated for each group of 8 bytes with the 8th + // group being used as the Raw(x-bpp) for the 1st group of the + // next loop. + + "paddb %%mm0, %%mm1 \n\t" + "movq 16(%%edi,%%edx,), %%mm2 \n\t" // load Sub(x) for 3rd 8 bytes + "movq %%mm1, 8(%%edi,%%edx,) \n\t" // write Raw(x) for 2nd 8 bytes + "paddb %%mm1, %%mm2 \n\t" + "movq 24(%%edi,%%edx,), %%mm3 \n\t" // load Sub(x) for 4th 8 bytes + "movq %%mm2, 16(%%edi,%%edx,) \n\t" // write Raw(x) for 3rd 8 bytes + "paddb %%mm2, %%mm3 \n\t" + "movq 32(%%edi,%%edx,), %%mm4 \n\t" // load Sub(x) for 5th 8 bytes + "movq %%mm3, 24(%%edi,%%edx,) \n\t" // write Raw(x) for 4th 8 bytes + "paddb %%mm3, %%mm4 \n\t" + "movq 40(%%edi,%%edx,), %%mm5 \n\t" // load Sub(x) for 6th 8 bytes + "movq %%mm4, 32(%%edi,%%edx,) \n\t" // write Raw(x) for 5th 8 bytes + "paddb %%mm4, %%mm5 \n\t" + "movq 48(%%edi,%%edx,), %%mm6 \n\t" // load Sub(x) for 7th 8 bytes + "movq %%mm5, 40(%%edi,%%edx,) \n\t" // write Raw(x) for 6th 8 bytes + "paddb %%mm5, %%mm6 \n\t" + "movq 56(%%edi,%%edx,), %%mm7 \n\t" // load Sub(x) for 8th 8 bytes + "movq %%mm6, 48(%%edi,%%edx,) \n\t" // write Raw(x) for 7th 8 bytes + "addl $64, %%edx \n\t" + "paddb %%mm6, %%mm7 \n\t" + "cmpl %%ecx, %%edx \n\t" + "movq %%mm7, -8(%%edi,%%edx,) \n\t" // write Raw(x) for 8th 8 bytes + "jb sub_8lp \n\t" + + "cmpl _MMXLength, %%edx \n\t" + "jnb sub_8lt8 \n\t" + + "sub_8lpA: \n\t" + "movq (%%edi,%%edx,), %%mm0 \n\t" + "addl $8, %%edx \n\t" + "paddb %%mm7, %%mm0 \n\t" + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // -8 to offset early addl edx + "movq %%mm0, %%mm7 \n\t" // move calculated Raw(x) data + // to mm1 to be new Raw(x-bpp) + // for next loop + "jb sub_8lpA \n\t" + + "sub_8lt8: \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%ecx", "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + break; + + default: // bpp greater than 8 bytes GRR BOGUS + { + __asm__ __volatile__ ( + "movl _dif, %%edx \n\t" +// preload "movl row, %%edi \n\t" + "movl %%edi, %%esi \n\t" // lp = row +// preload "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + + "sub_Alp: \n\t" + "movq (%%edi,%%edx,), %%mm0 \n\t" + "movq (%%esi,%%edx,), %%mm1 \n\t" + "addl $8, %%edx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%edx \n\t" + "movq %%mm0, -8(%%edi,%%edx,) \n\t" // mov does not affect flags; + // -8 to offset addl edx + "jb sub_Alp \n\t" + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + break; + + } // end switch (bpp) + + __asm__ __volatile__ ( + "movl _MMXLength, %%edx \n\t" +//pre "movl row, %%edi \n\t" + "cmpl _FullLength, %%edx \n\t" + "jnb sub_end \n\t" + + "movl %%edi, %%esi \n\t" // lp = row +//pre "movl bpp, %%eax \n\t" + "addl %%eax, %%edi \n\t" // rp = row + bpp + "xorl %%eax, %%eax \n\t" + + "sub_lp2: \n\t" + "movb (%%esi,%%edx,), %%al \n\t" + "addb %%al, (%%edi,%%edx,) \n\t" + "incl %%edx \n\t" + "cmpl _FullLength, %%edx \n\t" + "jb sub_lp2 \n\t" + + "sub_end: \n\t" + "EMMS \n\t" // end MMX instructions + + : "=a" (dummy_value_a), // 0 // output regs (dummy) + "=D" (dummy_value_D) // 1 + + : "0" (bpp), // eax // input regs + "1" (row) // edi + + : "%edx", "%esi" // clobber list + ); + +} // end of png_read_filter_row_mmx_sub() + + + + +//===========================================================================// +// // +// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ U P // +// // +//===========================================================================// + +// Optimized code for PNG Up filter decoder + +static void /* PRIVATE */ +png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + png_uint_32 len; + int dummy_value_d; // fix 'forbidden register 3 (dx) was spilled' error + int dummy_value_S; + int dummy_value_D; + + len = row_info->rowbytes; // number of bytes to filter + + __asm__ __volatile__ ( +//pre "movl row, %%edi \n\t" + // get # of bytes to alignment + "movl %%edi, %%ecx \n\t" + "xorl %%ebx, %%ebx \n\t" + "addl $0x7, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "andl $0xfffffff8, %%ecx \n\t" +//pre "movl prev_row, %%esi \n\t" + "subl %%edi, %%ecx \n\t" + "jz up_go \n\t" + + "up_lp1: \n\t" // fix alignment + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to + "jb up_lp1 \n\t" // offset incl ebx + + "up_go: \n\t" +//pre "movl len, %%edx \n\t" + "movl %%edx, %%ecx \n\t" + "subl %%ebx, %%edx \n\t" // subtract alignment fix + "andl $0x0000003f, %%edx \n\t" // calc bytes over mult of 64 + "subl %%edx, %%ecx \n\t" // drop over bytes from length + + // unrolled loop - use all MMX registers and interleave to reduce + // number of branch instructions (loops) and reduce partial stalls + "up_loop: \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq 8(%%esi,%%ebx,), %%mm3 \n\t" + "paddb %%mm1, %%mm0 \n\t" + "movq 8(%%edi,%%ebx,), %%mm2 \n\t" + "movq %%mm0, (%%edi,%%ebx,) \n\t" + "paddb %%mm3, %%mm2 \n\t" + "movq 16(%%esi,%%ebx,), %%mm5 \n\t" + "movq %%mm2, 8(%%edi,%%ebx,) \n\t" + "movq 16(%%edi,%%ebx,), %%mm4 \n\t" + "movq 24(%%esi,%%ebx,), %%mm7 \n\t" + "paddb %%mm5, %%mm4 \n\t" + "movq 24(%%edi,%%ebx,), %%mm6 \n\t" + "movq %%mm4, 16(%%edi,%%ebx,) \n\t" + "paddb %%mm7, %%mm6 \n\t" + "movq 32(%%esi,%%ebx,), %%mm1 \n\t" + "movq %%mm6, 24(%%edi,%%ebx,) \n\t" + "movq 32(%%edi,%%ebx,), %%mm0 \n\t" + "movq 40(%%esi,%%ebx,), %%mm3 \n\t" + "paddb %%mm1, %%mm0 \n\t" + "movq 40(%%edi,%%ebx,), %%mm2 \n\t" + "movq %%mm0, 32(%%edi,%%ebx,) \n\t" + "paddb %%mm3, %%mm2 \n\t" + "movq 48(%%esi,%%ebx,), %%mm5 \n\t" + "movq %%mm2, 40(%%edi,%%ebx,) \n\t" + "movq 48(%%edi,%%ebx,), %%mm4 \n\t" + "movq 56(%%esi,%%ebx,), %%mm7 \n\t" + "paddb %%mm5, %%mm4 \n\t" + "movq 56(%%edi,%%ebx,), %%mm6 \n\t" + "movq %%mm4, 48(%%edi,%%ebx,) \n\t" + "addl $64, %%ebx \n\t" + "paddb %%mm7, %%mm6 \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movq %%mm6, -8(%%edi,%%ebx,) \n\t" // (+56)movq does not affect flags; + "jb up_loop \n\t" // -8 to offset addl ebx + + "cmpl $0, %%edx \n\t" // test for bytes over mult of 64 + "jz up_end \n\t" + + "cmpl $8, %%edx \n\t" // test for less than 8 bytes + "jb up_lt8 \n\t" // [added by lcreeve@netins.net] + + "addl %%edx, %%ecx \n\t" + "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8 + "subl %%edx, %%ecx \n\t" // drop over bytes from length + "jz up_lt8 \n\t" + + "up_lpA: \n\t" // use MMX regs to update 8 bytes sim. + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "addl $8, %%ebx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // movq does not affect flags; -8 to + "jb up_lpA \n\t" // offset add ebx + "cmpl $0, %%edx \n\t" // test for bytes over mult of 8 + "jz up_end \n\t" + + "up_lt8: \n\t" + "xorl %%eax, %%eax \n\t" + "addl %%edx, %%ecx \n\t" // move over byte count into counter + + "up_lp2: \n\t" // use x86 regs for remaining bytes + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to + "jb up_lp2 \n\t" // offset inc ebx + + "up_end: \n\t" + "EMMS \n\t" // conversion of filtered row complete + + : "=d" (dummy_value_d), // 0 // output regs (dummy) + "=S" (dummy_value_S), // 1 + "=D" (dummy_value_D) // 2 + + : "0" (len), // edx // input regs + "1" (prev_row), // esi + "2" (row) // edi + + : "%eax", "%ebx", "%ecx" // clobber list (no input regs!) + +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" + , "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + +} // end of png_read_filter_row_mmx_up() + +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + + + + +/*===========================================================================*/ +/* */ +/* P N G _ R E A D _ F I L T E R _ R O W */ +/* */ +/*===========================================================================*/ + +#if defined(PNG_HAVE_ASSEMBLER_READ_FILTER_ROW) + +/* Optimized png_read_filter_row routines */ + +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep + row, png_bytep prev_row, int filter) +{ +#ifdef PNG_DEBUG + char filnm[10]; +#endif + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) +/* GRR: these are superseded by png_ptr->asm_flags: */ +#define UseMMX_sub 1 // GRR: converted 20000730 +#define UseMMX_up 1 // GRR: converted 20000729 +#define UseMMX_avg 1 // GRR: converted 20000828 (+ 16-bit bugfix 20000916) +#define UseMMX_paeth 1 // GRR: converted 20000828 + + if (_mmx_supported == 2) { + png_mmx_support(); + } +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + +#ifdef PNG_DEBUG + png_debug(1, "in png_read_filter_row (pnggccrd.c)\n"); + switch (filter) + { + case 0: sprintf(filnm, "none"); + break; + case 1: sprintf(filnm, "sub-%s", "MMX"); + break; + case 2: sprintf(filnm, "up-%s", "MMX"); + break; + case 3: sprintf(filnm, "avg-%s", "MMX"); + break; + case 4: sprintf(filnm, "Paeth-%s", "MMX"); + break; + default: sprintf(filnm, "unknw"); + break; + } + png_debug2(0, "row_number=%5ld, %5s, ", png_ptr->row_number, filnm); + png_debug1(0, "row=0x%08lx, ", (unsigned long)row); + png_debug2(0, "pixdepth=%2d, bytes=%d, ", (int)row_info->pixel_depth, + (int)((row_info->pixel_depth + 7) >> 3)); + png_debug1(0,"rowbytes=%8ld\n", row_info->rowbytes); +#endif /* PNG_DEBUG */ + + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + + case PNG_FILTER_VALUE_SUB: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported && + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_sub(row_info, row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + } /* end !UseMMX_sub */ + break; + + case PNG_FILTER_VALUE_UP: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported && + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_up(row_info, row, prev_row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; ++i) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + } /* end !UseMMX_up */ + break; + + case PNG_FILTER_VALUE_AVG: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported && + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_avg(row_info, row, prev_row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) >> 1)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++ + *lp++) >> 1)) & 0xff); + rp++; + } + } /* end !UseMMX_avg */ + break; + + case PNG_FILTER_VALUE_PAETH: +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) + if ( _mmx_supported && + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_paeth(row_info, row, prev_row); + } + else +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */ + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) /* use leftover rp,pp */ + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + } /* end !UseMMX_paeth */ + break; + + default: + png_warning(png_ptr, "Ignoring bad row-filter type"); + *row=0; + break; + } +} + +#endif /* PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */ + + +/*===========================================================================*/ +/* */ +/* P N G _ M M X _ S U P P O R T */ +/* */ +/*===========================================================================*/ + +/* GRR NOTES: (1) the following code assumes 386 or better (pushfl/popfl) + * (2) all instructions compile with gcc 2.7.2.3 and later + * (3) the function is moved down here to prevent gcc from + * inlining it in multiple places and then barfing be- + * cause the ".NOT_SUPPORTED" label is multiply defined + * [is there a way to signal that a *single* function should + * not be inlined? is there a way to modify the label for + * each inlined instance, e.g., by appending _1, _2, etc.? + * maybe if don't use leading "." in label name? (nope...sigh)] + */ + +int PNGAPI +png_mmx_support(void) +{ +#if defined(PNG_MMX_CODE_SUPPORTED) + __asm__ __volatile__ ( + "pushl %%ebx \n\t" // ebx gets clobbered by CPUID instruction + "pushl %%ecx \n\t" // so does ecx... + "pushl %%edx \n\t" // ...and edx (but ecx & edx safe on Linux) +// ".byte 0x66 \n\t" // convert 16-bit pushf to 32-bit pushfd +// "pushf \n\t" // 16-bit pushf + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack into eax + "movl %%eax, %%ecx \n\t" // make another copy of Eflag in ecx + "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21) + "pushl %%eax \n\t" // save modified Eflag back to stack +// ".byte 0x66 \n\t" // convert 16-bit popf to 32-bit popfd +// "popf \n\t" // 16-bit popf + "popfl \n\t" // restore modified value to Eflag reg + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack + "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag + "jz .NOT_SUPPORTED \n\t" // if same, CPUID instr. is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero +// ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode) + "cpuid \n\t" // get the CPU identification info + "cmpl $1, %%eax \n\t" // make sure eax return non-zero value + "jl .NOT_SUPPORTED \n\t" // if eax is zero, MMX is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero and... + "incl %%eax \n\t" // ...increment eax to 1. This pair is + // faster than the instruction "mov eax, 1" + "cpuid \n\t" // get the CPU identification info again + "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23) + "cmpl $0, %%edx \n\t" // 0 = MMX not supported + "jz .NOT_SUPPORTED \n\t" // non-zero = yes, MMX IS supported + + "movl $1, %%eax \n\t" // set return value to 1 + "jmp .RETURN \n\t" // DONE: have MMX support + + ".NOT_SUPPORTED: \n\t" // target label for jump instructions + "movl $0, %%eax \n\t" // set return value to 0 + ".RETURN: \n\t" // target label for jump instructions + "movl %%eax, _mmx_supported \n\t" // save in global static variable, too + "popl %%edx \n\t" // restore edx + "popl %%ecx \n\t" // restore ecx + "popl %%ebx \n\t" // restore ebx + +// "ret \n\t" // DONE: no MMX support + // (fall through to standard C "ret") + + : // output list (none) + + : // any variables used on input (none) + + : "%eax" // clobber list +// , "%ebx", "%ecx", "%edx" // GRR: we handle these manually +// , "memory" // if write to a variable gcc thought was in a reg +// , "cc" // "condition codes" (flag bits) + ); +#else + _mmx_supported = 0; +#endif /* PNG_MMX_CODE_SUPPORTED */ + + return _mmx_supported; +} + +#endif /* PNG_USE_PNGGCCRD */ diff --git a/freeimage241/Source/LibPNG/pngget.c b/freeimage241/Source/LibPNG/pngget.c new file mode 100644 index 0000000..208918f --- /dev/null +++ b/freeimage241/Source/LibPNG/pngget.c @@ -0,0 +1,829 @@ + +/* pngget.c - retrieval of values from info struct + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" + +png_uint_32 PNGAPI +png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->valid & flag); + else + return(0); +} + +png_uint_32 PNGAPI +png_get_rowbytes(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->rowbytes); + else + return(0); +} + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +png_bytepp PNGAPI +png_get_rows(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->row_pointers); + else + return(0); +} +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* easy access to info, added in libpng-0.99 */ +png_uint_32 PNGAPI +png_get_image_width(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->width; + } + return (0); +} + +png_uint_32 PNGAPI +png_get_image_height(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->height; + } + return (0); +} + +png_byte PNGAPI +png_get_bit_depth(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->bit_depth; + } + return (0); +} + +png_byte PNGAPI +png_get_color_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->color_type; + } + return (0); +} + +png_byte PNGAPI +png_get_filter_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->filter_type; + } + return (0); +} + +png_byte PNGAPI +png_get_interlace_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->interlace_type; + } + return (0); +} + +png_byte PNGAPI +png_get_compression_type(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + { + return info_ptr->compression_type; + } + return (0); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_x_pixels_per_meter"); + if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + else return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_y_pixels_per_meter"); + if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER) + return (0); + else return (info_ptr->y_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +png_uint_32 PNGAPI +png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_pixels_per_meter"); + if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER || + info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit) + return (0); + else return (info_ptr->x_pixels_per_unit); + } +#else + return (0); +#endif + return (0); +} + +#ifdef PNG_FLOATING_POINT_SUPPORTED +float PNGAPI +png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) + { + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_aspect_ratio"); + if (info_ptr->x_pixels_per_unit == 0) + return ((float)0.0); + else + return ((float)((float)info_ptr->y_pixels_per_unit + /(float)info_ptr->x_pixels_per_unit)); + } +#else + return (0.0); +#endif + return ((float)0.0); +} +#endif + +png_int_32 PNGAPI +png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + else return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) + return (0); + else return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + else return (info_ptr->x_offset); + } +#else + return (0); +#endif + return (0); +} + +png_int_32 PNGAPI +png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) +#if defined(PNG_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + { + png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns"); + if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) + return (0); + else return (info_ptr->y_offset); + } +#else + return (0); +#endif + return (0); +} + +#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) +png_uint_32 PNGAPI +png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +png_uint_32 PNGAPI +png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) +{ + return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr) + *.0254 +.5)); +} + +float PNGAPI +png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_x_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +float PNGAPI +png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr) +{ + return ((float)png_get_y_offset_microns(png_ptr, info_ptr) + *.00003937); +} + +#if defined(PNG_pHYs_SUPPORTED) +png_uint_32 PNGAPI +png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function\n", "pHYs"); + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + if(*unit_type == 1) + { + if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); + if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); + } + } + } + return (retval); +} +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */ + +/* png_get_channels really belongs in here, too, but it's been around longer */ + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +png_byte PNGAPI +png_get_channels(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->channels); + else + return (0); +} + +png_bytep PNGAPI +png_get_signature(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr != NULL && info_ptr != NULL) + return(info_ptr->signature); + else + return (NULL); +} + +#if defined(PNG_bKGD_SUPPORTED) +png_uint_32 PNGAPI +png_get_bKGD(png_structp png_ptr, png_infop info_ptr, + png_color_16p *background) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) + && background != NULL) + { + png_debug1(1, "in %s retrieval function\n", "bKGD"); + *background = &(info_ptr->background); + return (PNG_INFO_bKGD); + } + return (0); +} +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM(png_structp png_ptr, png_infop info_ptr, + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_debug1(1, "in %s retrieval function\n", "cHRM"); + if (white_x != NULL) + *white_x = (double)info_ptr->x_white; + if (white_y != NULL) + *white_y = (double)info_ptr->y_white; + if (red_x != NULL) + *red_x = (double)info_ptr->x_red; + if (red_y != NULL) + *red_y = (double)info_ptr->y_red; + if (green_x != NULL) + *green_x = (double)info_ptr->x_green; + if (green_y != NULL) + *green_y = (double)info_ptr->y_green; + if (blue_x != NULL) + *blue_x = (double)info_ptr->x_blue; + if (blue_y != NULL) + *blue_y = (double)info_ptr->y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_debug1(1, "in %s retrieval function\n", "cHRM"); + if (white_x != NULL) + *white_x = info_ptr->int_x_white; + if (white_y != NULL) + *white_y = info_ptr->int_y_white; + if (red_x != NULL) + *red_x = info_ptr->int_x_red; + if (red_y != NULL) + *red_y = info_ptr->int_y_red; + if (green_x != NULL) + *green_x = info_ptr->int_x_green; + if (green_y != NULL) + *green_y = info_ptr->int_y_green; + if (blue_x != NULL) + *blue_x = info_ptr->int_x_blue; + if (blue_y != NULL) + *blue_y = info_ptr->int_y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && file_gamma != NULL) + { + png_debug1(1, "in %s retrieval function\n", "gAMA"); + *file_gamma = (double)info_ptr->gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *int_file_gamma) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && int_file_gamma != NULL) + { + png_debug1(1, "in %s retrieval function\n", "gAMA"); + *int_file_gamma = info_ptr->int_gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#endif + +#if defined(PNG_sRGB_SUPPORTED) +png_uint_32 PNGAPI +png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) + && file_srgb_intent != NULL) + { + png_debug1(1, "in %s retrieval function\n", "sRGB"); + *file_srgb_intent = (int)info_ptr->srgb_intent; + return (PNG_INFO_sRGB); + } + return (0); +} +#endif + +#if defined(PNG_iCCP_SUPPORTED) +png_uint_32 PNGAPI +png_get_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charpp name, int *compression_type, + png_charpp profile, png_uint_32 *proflen) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) + && name != NULL && profile != NULL && proflen != NULL) + { + png_debug1(1, "in %s retrieval function\n", "iCCP"); + *name = info_ptr->iccp_name; + *profile = info_ptr->iccp_profile; + /* compression_type is a dummy so the API won't have to change + if we introduce multiple compression types later. */ + *proflen = (int)info_ptr->iccp_proflen; + *compression_type = (int)info_ptr->iccp_compression; + return (PNG_INFO_iCCP); + } + return (0); +} +#endif + +#if defined(PNG_sPLT_SUPPORTED) +png_uint_32 PNGAPI +png_get_sPLT(png_structp png_ptr, png_infop info_ptr, + png_sPLT_tpp spalettes) +{ + if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) + *spalettes = info_ptr->splt_palettes; + return ((png_uint_32)info_ptr->splt_palettes_num); +} +#endif + +#if defined(PNG_hIST_SUPPORTED) +png_uint_32 PNGAPI +png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) + && hist != NULL) + { + png_debug1(1, "in %s retrieval function\n", "hIST"); + *hist = info_ptr->hist; + return (PNG_INFO_hIST); + } + return (0); +} +#endif + +png_uint_32 PNGAPI +png_get_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *width, png_uint_32 *height, int *bit_depth, + int *color_type, int *interlace_type, int *compression_type, + int *filter_type) + +{ + if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL && + bit_depth != NULL && color_type != NULL) + { + int pixel_depth, channels; + png_uint_32 rowbytes_per_pixel; + + png_debug1(1, "in %s retrieval function\n", "IHDR"); + *width = info_ptr->width; + *height = info_ptr->height; + *bit_depth = info_ptr->bit_depth; + *color_type = info_ptr->color_type; + if (compression_type != NULL) + *compression_type = info_ptr->compression_type; + if (filter_type != NULL) + *filter_type = info_ptr->filter_type; + if (interlace_type != NULL) + *interlace_type = info_ptr->interlace_type; + + /* check for potential overflow of rowbytes */ + if (*color_type == PNG_COLOR_TYPE_PALETTE) + channels = 1; + else if (*color_type & PNG_COLOR_MASK_COLOR) + channels = 3; + else + channels = 1; + if (*color_type & PNG_COLOR_MASK_ALPHA) + channels++; + pixel_depth = *bit_depth * channels; + rowbytes_per_pixel = (pixel_depth + 7) >> 3; + if ((*width > PNG_MAX_UINT/rowbytes_per_pixel)) + { + png_warning(png_ptr, + "Width too large for libpng to process image data."); + } + return (1); + } + return (0); +} + +#if defined(PNG_oFFs_SUPPORTED) +png_uint_32 PNGAPI +png_get_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) + && offset_x != NULL && offset_y != NULL && unit_type != NULL) + { + png_debug1(1, "in %s retrieval function\n", "oFFs"); + *offset_x = info_ptr->x_offset; + *offset_y = info_ptr->y_offset; + *unit_type = (int)info_ptr->offset_unit_type; + return (PNG_INFO_oFFs); + } + return (0); +} +#endif + +#if defined(PNG_pCAL_SUPPORTED) +png_uint_32 PNGAPI +png_get_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, + png_charp *units, png_charpp *params) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) + && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + nparams != NULL && units != NULL && params != NULL) + { + png_debug1(1, "in %s retrieval function\n", "pCAL"); + *purpose = info_ptr->pcal_purpose; + *X0 = info_ptr->pcal_X0; + *X1 = info_ptr->pcal_X1; + *type = (int)info_ptr->pcal_type; + *nparams = (int)info_ptr->pcal_nparams; + *units = info_ptr->pcal_units; + *params = info_ptr->pcal_params; + return (PNG_INFO_pCAL); + } + return (0); +} +#endif + +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL(png_structp png_ptr, png_infop info_ptr, + int *unit, double *width, double *height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_pixel_width; + *height = info_ptr->scal_pixel_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sCAL)) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#endif +#endif +#endif + +#if defined(PNG_pHYs_SUPPORTED) +png_uint_32 PNGAPI +png_get_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) +{ + png_uint_32 retval = 0; + + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function\n", "pHYs"); + if (res_x != NULL) + { + *res_x = info_ptr->x_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (res_y != NULL) + { + *res_y = info_ptr->y_pixels_per_unit; + retval |= PNG_INFO_pHYs; + } + if (unit_type != NULL) + { + *unit_type = (int)info_ptr->phys_unit_type; + retval |= PNG_INFO_pHYs; + } + } + return (retval); +} +#endif + +png_uint_32 PNGAPI +png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette, + int *num_palette) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) + && palette != NULL) + { + png_debug1(1, "in %s retrieval function\n", "PLTE"); + *palette = info_ptr->palette; + *num_palette = info_ptr->num_palette; + png_debug1(3, "num_palette = %d\n", *num_palette); + return (PNG_INFO_PLTE); + } + return (0); +} + +#if defined(PNG_sBIT_SUPPORTED) +png_uint_32 PNGAPI +png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) + && sig_bit != NULL) + { + png_debug1(1, "in %s retrieval function\n", "sBIT"); + *sig_bit = &(info_ptr->sig_bit); + return (PNG_INFO_sBIT); + } + return (0); +} +#endif + +#if defined(PNG_TEXT_SUPPORTED) +png_uint_32 PNGAPI +png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, + int *num_text) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) + { + png_debug1(1, "in %s retrieval function\n", + (png_ptr->chunk_name[0] == '\0' ? "text" + : (png_const_charp)png_ptr->chunk_name)); + if (text_ptr != NULL) + *text_ptr = info_ptr->text; + if (num_text != NULL) + *num_text = info_ptr->num_text; + return ((png_uint_32)info_ptr->num_text); + } + if (num_text != NULL) + *num_text = 0; + return(0); +} +#endif + +#if defined(PNG_tIME_SUPPORTED) +png_uint_32 PNGAPI +png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) + && mod_time != NULL) + { + png_debug1(1, "in %s retrieval function\n", "tIME"); + *mod_time = &(info_ptr->mod_time); + return (PNG_INFO_tIME); + } + return (0); +} +#endif + +#if defined(PNG_tRNS_SUPPORTED) +png_uint_32 PNGAPI +png_get_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep *trans, int *num_trans, png_color_16p *trans_values) +{ + png_uint_32 retval = 0; + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_debug1(1, "in %s retrieval function\n", "tRNS"); + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (trans != NULL) + { + *trans = info_ptr->trans; + retval |= PNG_INFO_tRNS; + } + if (trans_values != NULL) + *trans_values = &(info_ptr->trans_values); + } + else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ + { + if (trans_values != NULL) + { + *trans_values = &(info_ptr->trans_values); + retval |= PNG_INFO_tRNS; + } + if(trans != NULL) + *trans = NULL; + } + if(num_trans != NULL) + { + *num_trans = info_ptr->num_trans; + retval |= PNG_INFO_tRNS; + } + } + return (retval); +} +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +png_uint_32 PNGAPI +png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + *unknowns = info_ptr->unknown_chunks; + return ((png_uint_32)info_ptr->unknown_chunks_num); +} +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +png_byte PNGAPI +png_get_rgb_to_gray_status (png_structp png_ptr) +{ + return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0); +} +#endif + +#if defined(PNG_USER_CHUNKS_SUPPORTED) +png_voidp PNGAPI +png_get_user_chunk_ptr(png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_chunk_ptr : NULL); +} +#endif + + +png_uint_32 PNGAPI +png_get_compression_buffer_size(png_structp png_ptr) +{ + return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L); +} + + diff --git a/freeimage241/Source/LibPNG/pngmem.c b/freeimage241/Source/LibPNG/pngmem.c new file mode 100644 index 0000000..dd74715 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngmem.c @@ -0,0 +1,531 @@ + +/* pngmem.c - stub functions for memory allocation + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all memory allocation. Users who + * need special memory handling are expected to supply replacement + * functions for png_malloc() and png_free(), and to use + * png_create_read_struct_2() and png_create_write_struct_2() to + * identify the replacement functions. + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Borland DOS special memory handler */ +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* if you change this, be sure to change the one in png.h also */ + +/* Allocate memory for a png_struct. The malloc and memset can be replaced + by a single call to calloc() if this is thought to improve performance. */ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, NULL, NULL)); +} + +/* Alternate version of png_create_struct, for use with user-defined malloc. */ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = sizeof(png_struct); + else + return ((png_voidp)NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if(malloc_fn != NULL) + { + if (mem_ptr != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, size); + } + else + struct_ptr = (*(malloc_fn))(NULL, size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); + } +#endif /* PNG_USER_MEM_SUPPORTED */ + if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL) + { + png_memset(struct_ptr, 0, size); + } + return (struct_ptr); +} + + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, (png_free_ptr)NULL, (png_voidp)NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if(free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ + farfree (struct_ptr); + } +} + +/* Allocate memory. For reasonable files, size should never exceed + * 64K. However, zlib may allocate more then 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does + * need to allocate exactly 64K, so whatever you call here must + * have the ability to do that. + * + * Borland seems to have a problem in DOS mode for exactly 64K. + * It gives you a segment with an offset of 8 (perhaps to store its + * memory stuff). zlib doesn't like this at all, so we have to + * detect and deal with it. This code should not be needed in + * Windows or OS/2 modes, and only in 16 bit mode. This code has + * been updated by Alexander Lehmann for version 0.89 to waste less + * memory. + * + * Note that we can't use png_size_t for the "size" declaration, + * since on some systems a png_size_t is a 16-bit quantity, and as a + * result, we would be truncating potentially larger memory requests + * (which should cause a fatal error) and introducing major problems. + */ +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_uint_32 size) +{ +#ifndef PNG_USER_MEM_SUPPORTED + png_voidp ret; +#endif + if (png_ptr == NULL || size == 0) + return ((png_voidp)NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if(png_ptr->malloc_fn != NULL) + { + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, size)); + if (ret == NULL) + png_error(png_ptr, "Out of memory!"); + return (ret); + } + else + return png_malloc_default(png_ptr, size); +} + +png_voidp PNGAPI +png_malloc_default(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + png_error(png_ptr, "Cannot Allocate > 64K"); +#endif + + if (size == (png_uint_32)65536L) + { + if (png_ptr->offset_table == NULL) + { + /* try to see if we need to do any of this fancy stuff */ + ret = farmalloc(size); + if (ret == NULL || ((png_size_t)ret & 0xffff)) + { + int num_blocks; + png_uint_32 total_size; + png_bytep table; + int i; + png_byte huge * hptr; + + if (ret != NULL) + { + farfree(ret); + ret = NULL; + } + + if(png_ptr->zlib_window_bits > 14) + num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); + else + num_blocks = 1; + if (png_ptr->zlib_mem_level >= 7) + num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7)); + else + num_blocks++; + + total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; + + table = farmalloc(total_size); + + if (table == NULL) + { + png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */ + } + + if ((png_size_t)table & 0xfff0) + { + png_error(png_ptr, "Farmalloc didn't return normalized pointer"); + } + + png_ptr->offset_table = table; + png_ptr->offset_table_ptr = farmalloc(num_blocks * + sizeof (png_bytep)); + + if (png_ptr->offset_table_ptr == NULL) + { + png_error(png_ptr, "Out Of memory."); + } + + hptr = (png_byte huge *)table; + if ((png_size_t)hptr & 0xf) + { + hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); + hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */ + } + for (i = 0; i < num_blocks; i++) + { + png_ptr->offset_table_ptr[i] = (png_bytep)hptr; + hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */ + } + + png_ptr->offset_table_number = num_blocks; + png_ptr->offset_table_count = 0; + png_ptr->offset_table_count_free = 0; + } + } + + if (png_ptr->offset_table_count >= png_ptr->offset_table_number) + png_error(png_ptr, "Out of Memory."); + + ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; + } + else + ret = farmalloc(size); + + if (ret == NULL) + { + png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */ + } + + return (ret); +} + +/* free a pointer allocated by png_malloc(). In the default + configuration, png_ptr is not used, but is passed in case it + is needed. If ptr is NULL, return without taking any action. */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else png_free_default(png_ptr, ptr); +} + +void PNGAPI +png_free_default(png_structp png_ptr, png_voidp ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + + if (png_ptr->offset_table != NULL) + { + int i; + + for (i = 0; i < png_ptr->offset_table_count; i++) + { + if (ptr == png_ptr->offset_table_ptr[i]) + { + ptr = NULL; + png_ptr->offset_table_count_free++; + break; + } + } + if (png_ptr->offset_table_count_free == png_ptr->offset_table_count) + { + farfree(png_ptr->offset_table); + farfree(png_ptr->offset_table_ptr); + png_ptr->offset_table = NULL; + png_ptr->offset_table_ptr = NULL; + } + } + + if (ptr != NULL) + { + farfree(ptr); + } +} + +#else /* Not the Borland DOS special memory handler */ + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably.*/ +png_voidp /* PRIVATE */ +png_create_struct(int type) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_struct_2(type, NULL, NULL)); +} + +/* Allocate memory for a png_struct or a png_info. The malloc and + memset can be replaced by a single call to calloc() if this is thought + to improve performance noticably.*/ +png_voidp /* PRIVATE */ +png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_size_t size; + png_voidp struct_ptr; + + if (type == PNG_STRUCT_INFO) + size = sizeof(png_info); + else if (type == PNG_STRUCT_PNG) + size = sizeof(png_struct); + else + return ((png_voidp)NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if(malloc_fn != NULL) + { + if (mem_ptr != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + struct_ptr = (*(malloc_fn))(png_ptr, size); + } + else + struct_ptr = (*(malloc_fn))(NULL, size); + if (struct_ptr != NULL) + png_memset(struct_ptr, 0, size); + return (struct_ptr); + } +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL) +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + if ((struct_ptr = (png_voidp)halloc(size,1)) != NULL) +# else + if ((struct_ptr = (png_voidp)malloc(size)) != NULL) +# endif +#endif + { + png_memset(struct_ptr, 0, size); + } + + return (struct_ptr); +} + + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct(png_voidp struct_ptr) +{ +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2(struct_ptr, (png_free_ptr)NULL, (png_voidp)NULL); +} + +/* Free memory allocated by a png_create_struct() call */ +void /* PRIVATE */ +png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, + png_voidp mem_ptr) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + if (struct_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + if(free_fn != NULL) + { + png_struct dummy_struct; + png_structp png_ptr = &dummy_struct; + png_ptr->mem_ptr=mem_ptr; + (*(free_fn))(png_ptr, struct_ptr); + return; + } +#endif /* PNG_USER_MEM_SUPPORTED */ +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(struct_ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(struct_ptr); +# else + free(struct_ptr); +# endif +#endif + } +} + + +/* Allocate memory. For reasonable files, size should never exceed + 64K. However, zlib may allocate more then 64K if you don't tell + it not to. See zconf.h and png.h for more information. zlib does + need to allocate exactly 64K, so whatever you call here must + have the ability to do that. */ + +png_voidp PNGAPI +png_malloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + if (png_ptr == NULL || size == 0) + return ((png_voidp)NULL); + +#ifdef PNG_USER_MEM_SUPPORTED + if(png_ptr->malloc_fn != NULL) + { + ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, size)); + if (ret == NULL) + png_error(png_ptr, "Out of Memory!"); + return (ret); + } + else + return (png_malloc_default(png_ptr, size)); +} +png_voidp /* PRIVATE */ +png_malloc_default(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; +#endif /* PNG_USER_MEM_SUPPORTED */ + +#ifdef PNG_MAX_MALLOC_64K + if (size > (png_uint_32)65536L) + png_error(png_ptr, "Cannot Allocate > 64K"); +#endif + +#if defined(__TURBOC__) && !defined(__FLAT__) + ret = farmalloc(size); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + ret = halloc(size, 1); +# else + ret = malloc((size_t)size); +# endif +#endif + + if (ret == NULL) + png_error(png_ptr, "Out of Memory"); + + return (ret); +} + +/* Free a pointer allocated by png_malloc(). If ptr is NULL, return + without taking any action. */ +void PNGAPI +png_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr->free_fn != NULL) + { + (*(png_ptr->free_fn))(png_ptr, ptr); + return; + } + else png_free_default(png_ptr, ptr); +} +void /* PRIVATE */ +png_free_default(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL || ptr == NULL) + return; + +#endif /* PNG_USER_MEM_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(__FLAT__) + farfree(ptr); +#else +# if defined(_MSC_VER) && defined(MAXSEG_64K) + hfree(ptr); +# else + free(ptr); +# endif +#endif +} + +#endif /* Not Borland DOS special memory handler */ + +png_voidp /* PRIVATE */ +png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2, + png_uint_32 length) +{ + png_size_t size; + + size = (png_size_t)length; + if ((png_uint_32)size != length) + png_error(png_ptr,"Overflow in png_memcpy_check."); + + return(png_memcpy (s1, s2, size)); +} + +png_voidp /* PRIVATE */ +png_memset_check (png_structp png_ptr, png_voidp s1, int value, + png_uint_32 length) +{ + png_size_t size; + + size = (png_size_t)length; + if ((png_uint_32)size != length) + png_error(png_ptr,"Overflow in png_memset_check."); + + return (png_memset (s1, value, size)); + +} + +#ifdef PNG_USER_MEM_SUPPORTED +/* This function is called when the application wants to use another method + * of allocating and freeing memory. + */ +void PNGAPI +png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) +{ + png_ptr->mem_ptr = mem_ptr; + png_ptr->malloc_fn = malloc_fn; + png_ptr->free_fn = free_fn; +} + +/* This function returns a pointer to the mem_ptr associated with the user + * functions. The application should free any memory associated with this + * pointer before png_write_destroy and png_read_destroy are called. + */ +png_voidp PNGAPI +png_get_mem_ptr(png_structp png_ptr) +{ + return ((png_voidp)png_ptr->mem_ptr); +} +#endif /* PNG_USER_MEM_SUPPORTED */ diff --git a/freeimage241/Source/LibPNG/pngpread.c b/freeimage241/Source/LibPNG/pngpread.c new file mode 100644 index 0000000..9b4b77a --- /dev/null +++ b/freeimage241/Source/LibPNG/pngpread.c @@ -0,0 +1,1504 @@ + +/* pngpread.c - read a png file in push mode + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + +/* push model modes */ +#define PNG_READ_SIG_MODE 0 +#define PNG_READ_CHUNK_MODE 1 +#define PNG_READ_IDAT_MODE 2 +#define PNG_SKIP_MODE 3 +#define PNG_READ_tEXt_MODE 4 +#define PNG_READ_zTXt_MODE 5 +#define PNG_READ_DONE_MODE 6 +#define PNG_READ_iTXt_MODE 7 +#define PNG_ERROR_MODE 8 + +void PNGAPI +png_process_data(png_structp png_ptr, png_infop info_ptr, + png_bytep buffer, png_size_t buffer_size) +{ + png_push_restore_buffer(png_ptr, buffer, buffer_size); + + while (png_ptr->buffer_size) + { + png_process_some_data(png_ptr, info_ptr); + } +} + +/* What we do with the incoming data depends on what we were previously + * doing before we ran out of data... + */ +void /* PRIVATE */ +png_process_some_data(png_structp png_ptr, png_infop info_ptr) +{ + switch (png_ptr->process_mode) + { + case PNG_READ_SIG_MODE: + { + png_push_read_sig(png_ptr, info_ptr); + break; + } + case PNG_READ_CHUNK_MODE: + { + png_push_read_chunk(png_ptr, info_ptr); + break; + } + case PNG_READ_IDAT_MODE: + { + png_push_read_IDAT(png_ptr); + break; + } +#if defined(PNG_READ_tEXt_SUPPORTED) + case PNG_READ_tEXt_MODE: + { + png_push_read_tEXt(png_ptr, info_ptr); + break; + } +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + case PNG_READ_zTXt_MODE: + { + png_push_read_zTXt(png_ptr, info_ptr); + break; + } +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + case PNG_READ_iTXt_MODE: + { + png_push_read_iTXt(png_ptr, info_ptr); + break; + } +#endif + case PNG_SKIP_MODE: + { + png_push_crc_finish(png_ptr); + break; + } + default: + { + png_ptr->buffer_size = 0; + break; + } + } +} + +/* Read any remaining signature bytes from the stream and compare them with + * the correct PNG signature. It is possible that this routine is called + * with bytes already read from the signature, either because they have been + * checked by the calling application, or because of multiple calls to this + * routine. + */ +void /* PRIVATE */ +png_push_read_sig(png_structp png_ptr, png_infop info_ptr) +{ + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + + if (png_ptr->buffer_size < num_to_check) + { + num_to_check = png_ptr->buffer_size; + } + + png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), + num_to_check); + png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes+num_to_check); + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + else + { + if (png_ptr->sig_bytes >= 8) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + } +} + +void /* PRIVATE */ +png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#if defined(PNG_READ_bKGD_SUPPORTED) + PNG_bKGD; +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + PNG_cHRM; +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + PNG_gAMA; +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + PNG_hIST; +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + PNG_iCCP; +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + PNG_iTXt; +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + PNG_oFFs; +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + PNG_pCAL; +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + PNG_pHYs; +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + PNG_sBIT; +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + PNG_sCAL; +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + PNG_sRGB; +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + PNG_sPLT; +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + PNG_tEXt; +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + PNG_tIME; +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + PNG_tRNS; +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + PNG_zTXt; +#endif +#endif /* PNG_USE_LOCAL_ARRAYS */ + /* First we make sure we have enough data for the 4 byte chunk name + * and the 4 byte chunk length before proceeding with decoding the + * chunk data. To fully decode each of these chunks, we also make + * sure we have enough data in the buffer for the 4 byte CRC at the + * end of every chunk (except IDAT, which is handled separately). + */ + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_32(chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + } + + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); + } + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); + } + else if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) + { + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + if (png_ptr->mode & PNG_HAVE_IDAT) + { + if (png_ptr->push_length == 0) + return; + + if (png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); + } + + png_ptr->idat_size = png_ptr->push_length; + png_ptr->mode |= PNG_HAVE_IDAT; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + png_push_have_info(png_ptr, info_ptr); + png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; + png_ptr->zstream.next_out = png_ptr->row_buf; + return; + } + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); + png_ptr->process_mode = PNG_READ_DONE_MODE; + png_push_have_end(png_ptr, info_ptr); + } +#if defined(PNG_READ_gAMA_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_bKGD_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + { + png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + { + png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + { + png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + else + { + png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + } + + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; +} + +void /* PRIVATE */ +png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) +{ + png_ptr->process_mode = PNG_SKIP_MODE; + png_ptr->skip_length = skip; +} + +void /* PRIVATE */ +png_push_crc_finish(png_structp png_ptr) +{ + if (png_ptr->skip_length && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->skip_length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size) + save_size = (png_size_t)png_ptr->skip_length; + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->skip_length -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->skip_length) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } +} + +void /* PRIVATE */ +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) +{ + png_bytep ptr; + + ptr = buffer; + if (png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->save_buffer_size) + save_size = length; + else + save_size = png_ptr->save_buffer_size; + + png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + length -= save_size; + ptr += save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (length && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (length < png_ptr->current_buffer_size) + save_size = length; + else + save_size = png_ptr->current_buffer_size; + + png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } +} + +void /* PRIVATE */ +png_push_save_buffer(png_structp png_ptr) +{ + if (png_ptr->save_buffer_size) + { + if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) + { + png_size_t i,istop; + png_bytep sp; + png_bytep dp; + + istop = png_ptr->save_buffer_size; + for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; + i < istop; i++, sp++, dp++) + { + *dp = *sp; + } + } + } + if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > + png_ptr->save_buffer_max) + { + png_size_t new_max; + png_bytep old_buffer; + + new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; + old_buffer = png_ptr->save_buffer; + png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr, + (png_uint_32)new_max); + png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + png_free(png_ptr, old_buffer); + png_ptr->save_buffer_max = new_max; + } + if (png_ptr->current_buffer_size) + { + png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); + png_ptr->save_buffer_size += png_ptr->current_buffer_size; + png_ptr->current_buffer_size = 0; + } + png_ptr->save_buffer_ptr = png_ptr->save_buffer; + png_ptr->buffer_size = 0; +} + +void /* PRIVATE */ +png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + png_ptr->current_buffer = buffer; + png_ptr->current_buffer_size = buffer_length; + png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; + png_ptr->current_buffer_ptr = png_ptr->current_buffer; +} + +void /* PRIVATE */ +png_push_read_IDAT(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + { + png_byte chunk_length[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_32(chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; + + if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) + { + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + png_error(png_ptr, "Not enough compressed data"); + return; + } + + png_ptr->idat_size = png_ptr->push_length; + } + if (png_ptr->idat_size && png_ptr->save_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + /* check for overflow */ + if((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->save_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->idat_size && png_ptr->current_buffer_size) + { + png_size_t save_size; + + if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size) + { + save_size = (png_size_t)png_ptr->idat_size; + /* check for overflow */ + if((png_uint_32)save_size != png_ptr->idat_size) + png_error(png_ptr, "save_size overflowed in pngpread"); + } + else + save_size = png_ptr->current_buffer_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->idat_size -= save_size; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->idat_size) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; + } +} + +void /* PRIVATE */ +png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, + png_size_t buffer_length) +{ + int ret; + + if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length) + png_error(png_ptr, "Extra compression data"); + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = (uInt)buffer_length; + for(;;) + { + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK) + { + if (ret == Z_STREAM_END) + { + if (png_ptr->zstream.avail_in) + png_error(png_ptr, "Extra compressed data"); + if (!(png_ptr->zstream.avail_out)) + { + png_push_process_row(png_ptr); + } + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + else if (ret == Z_BUF_ERROR) + break; + else + png_error(png_ptr, "Decompression Error"); + } + if (!(png_ptr->zstream.avail_out)) + { + png_push_process_row(png_ptr); + png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; + png_ptr->zstream.next_out = png_ptr->row_buf; + } + else + break; + } +} + +void /* PRIVATE */ +png_push_process_row(png_structp png_ptr) +{ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + + png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * + (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); + + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, + png_ptr->rowbytes + 1); + + if (png_ptr->transformations) + png_do_read_transformations(png_ptr); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + /* blow up interlaced rows to full size */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) +/* old interface (pre-1.0.9): + png_do_read_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + switch (png_ptr->pass) + { + case 0: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 0; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); /* updates png_ptr->pass */ + } + if (png_ptr->pass == 2) /* pass 1 might be empty */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + if (png_ptr->pass == 4 && png_ptr->height <= 4) + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + if (png_ptr->pass == 6 && png_ptr->height <= 4) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + break; + } + case 1: + { + int i; + for (i = 0; i < 8 && png_ptr->pass == 1; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 2) /* skip top 4 generated rows */ + { + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + break; + } + case 2: + { + int i; + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + for (i = 0; i < 4 && png_ptr->pass == 2; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 4) /* pass 3 might be empty */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + break; + } + case 3: + { + int i; + for (i = 0; i < 4 && png_ptr->pass == 3; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 4) /* skip top two generated rows */ + { + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + break; + } + case 4: + { + int i; + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + for (i = 0; i < 2 && png_ptr->pass == 4; i++) + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 6) /* pass 5 might be empty */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + break; + } + case 5: + { + int i; + for (i = 0; i < 2 && png_ptr->pass == 5; i++) + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } + if (png_ptr->pass == 6) /* skip top generated row */ + { + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + break; + } + case 6: + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + if (png_ptr->pass != 6) + break; + png_push_have_row(png_ptr, NULL); + png_read_push_finish_row(png_ptr); + } + } + } + else +#endif + { + png_push_have_row(png_ptr, png_ptr->row_buf + 1); + png_read_push_finish_row(png_ptr); + } +} + +void /* PRIVATE */ +png_read_push_finish_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + + /* Width of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + */ + + /* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + */ +#endif + + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset_check(png_ptr, png_ptr->prev_row, 0, + png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if ((png_ptr->pass == 1 && png_ptr->width < 5) || + (png_ptr->pass == 3 && png_ptr->width < 3) || + (png_ptr->pass == 5 && png_ptr->width < 2)) + png_ptr->pass++; + + if (png_ptr->pass >= 7) + break; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + png_ptr->irowbytes = ((png_ptr->iwidth * + png_ptr->pixel_depth + 7) >> 3) + 1; + + if (png_ptr->transformations & PNG_INTERLACE) + break; + + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + + } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); + } +} + +#if defined(PNG_READ_tEXt_SUPPORTED) +void /* PRIVATE */ +png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place tEXt"); + /* to quiet some compiler warnings */ + if(info_ptr == NULL) return; + } + +#ifdef PNG_MAX_MALLOC_64K + png_ptr->skip_length = 0; /* This may not be necessary */ + + if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ + { + png_warning(png_ptr, "tEXt chunk too large to fit in memory"); + png_ptr->skip_length = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(length+1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_tEXt_MODE; +} + +void /* PRIVATE */ +png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + else + text_size = png_ptr->current_text_left; + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp text; + png_charp key; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + +#if defined(PNG_MAX_MALLOC_64K) + if (png_ptr->skip_length) + return; +#endif + + key = png_ptr->current_text; + png_ptr->current_text = 0; + + for (text = key; *text; text++) + /* empty loop */ ; + + if (text != key + png_ptr->current_text_size) + text++; + + text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = (char *)NULL; + text_ptr->lang_key = (char *)NULL; +#endif + text_ptr->text = text; + + png_set_text(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); + } +} +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +void /* PRIVATE */ +png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place zTXt"); + /* to quiet some compiler warnings */ + if(info_ptr == NULL) return; + } + +#ifdef PNG_MAX_MALLOC_64K + /* We can't handle zTXt chunks > 64K, since we don't have enough space + * to be able to store the uncompressed data. Actually, the threshold + * is probably around 32K, but it isn't as definite as 64K is. + */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "zTXt chunk too large to fit in memory"); + png_push_crc_skip(png_ptr, length); + return; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(length+1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_zTXt_MODE; +} + +void /* PRIVATE */ +png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + else + text_size = png_ptr->current_text_left; + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp text; + png_charp key; + int ret; + png_size_t text_size, key_size; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + + key = png_ptr->current_text; + png_ptr->current_text = 0; + + for (text = key; *text; text++) + /* empty loop */ ; + + /* zTXt can't have zero text */ + if (text == key + png_ptr->current_text_size) + { + png_free(png_ptr, key); + return; + } + + text++; + + if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */ + { + png_free(png_ptr, key); + return; + } + + text++; + + png_ptr->zstream.next_in = (png_bytep )text; + png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size - + (text - key)); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + key_size = text - key; + text_size = 0; + text = NULL; + ret = Z_STREAM_END; + + while (png_ptr->zstream.avail_in) + { + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + png_free(png_ptr, key); + png_free(png_ptr, text); + return; + } + if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END) + { + if (text == NULL) + { + text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out + + key_size + 1)); + png_memcpy(text + key_size, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + png_memcpy(text, key, key_size); + text_size = key_size + png_ptr->zbuf_size - + png_ptr->zstream.avail_out; + *(text + text_size) = '\0'; + } + else + { + png_charp tmp; + + tmp = text; + text = (png_charp)png_malloc(png_ptr, text_size + + (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out + + 1)); + png_memcpy(text, tmp, text_size); + png_free(png_ptr, tmp); + png_memcpy(text + text_size, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; + *(text + text_size) = '\0'; + } + if (ret != Z_STREAM_END) + { + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + else + { + break; + } + + if (ret == Z_STREAM_END) + break; + } + + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + if (ret != Z_STREAM_END) + { + png_free(png_ptr, key); + png_free(png_ptr, text); + return; + } + + png_free(png_ptr, key); + key = text; + text += key_size; + + text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = (char *)NULL; + text_ptr->lang_key = (char *)NULL; +#endif + text_ptr->text = text; + + png_set_text(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); + } +} +#endif + +#if defined(PNG_READ_iTXt_SUPPORTED) +void /* PRIVATE */ +png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND)) + { + png_error(png_ptr, "Out of place iTXt"); + /* to quiet some compiler warnings */ + if(info_ptr == NULL) return; + } + +#ifdef PNG_MAX_MALLOC_64K + png_ptr->skip_length = 0; /* This may not be necessary */ + + if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */ + { + png_warning(png_ptr, "iTXt chunk too large to fit in memory"); + png_ptr->skip_length = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_ptr->current_text = (png_charp)png_malloc(png_ptr, + (png_uint_32)(length+1)); + png_ptr->current_text[length] = '\0'; + png_ptr->current_text_ptr = png_ptr->current_text; + png_ptr->current_text_size = (png_size_t)length; + png_ptr->current_text_left = (png_size_t)length; + png_ptr->process_mode = PNG_READ_iTXt_MODE; +} + +void /* PRIVATE */ +png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) +{ + + if (png_ptr->buffer_size && png_ptr->current_text_left) + { + png_size_t text_size; + + if (png_ptr->buffer_size < png_ptr->current_text_left) + text_size = png_ptr->buffer_size; + else + text_size = png_ptr->current_text_left; + png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size); + png_ptr->current_text_left -= text_size; + png_ptr->current_text_ptr += text_size; + } + if (!(png_ptr->current_text_left)) + { + png_textp text_ptr; + png_charp key; + int comp_flag; + png_charp lang; + png_charp lang_key; + png_charp text; + + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_crc_finish(png_ptr); + +#if defined(PNG_MAX_MALLOC_64K) + if (png_ptr->skip_length) + return; +#endif + + key = png_ptr->current_text; + png_ptr->current_text = 0; + + for (lang = key; *lang; lang++) + /* empty loop */ ; + + if (lang != key + png_ptr->current_text_size) + lang++; + + comp_flag = *lang++; + lang++; /* skip comp_type, always zero */ + + for (lang_key = lang; *lang_key; lang_key++) + /* empty loop */ ; + lang_key++; /* skip NUL separator */ + + for (text = lang_key; *text; text++) + /* empty loop */ ; + + if (text != key + png_ptr->current_text_size) + text++; + + text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr->compression = comp_flag + 2; + text_ptr->key = key; + text_ptr->lang = lang; + text_ptr->lang_key = lang_key; + text_ptr->text = text; + text_ptr->text_length = 0; + text_ptr->itxt_length = png_strlen(text); + + png_set_text(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + } +} +#endif + +/* This function is called when we haven't found a handler for this + * chunk. If there isn't a problem with the chunk itself (ie a bad chunk + * name or a critical chunk), the chunk is (currently) silently ignored. + */ +void /* PRIVATE */ +png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 + length) +{ + png_uint_32 skip=0; + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + + if (!(png_ptr->chunk_name[0] & 0x20)) + { +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + HANDLE_CHUNK_ALWAYS +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + && png_ptr->read_user_chunk_fn == NULL +#endif + ) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + + /* to quiet compiler warnings about unused info_ptr */ + if (info_ptr == NULL) + return; + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { + png_unknown_chunk chunk; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name); + chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, chunk.data, length); + chunk.size = length; +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + if(png_ptr->read_user_chunk_fn != NULL) + { + /* callback to user unknown chunk handler */ + if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0) + { + if (!(png_ptr->chunk_name[0] & 0x20)) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + HANDLE_CHUNK_ALWAYS) + png_chunk_error(png_ptr, "unknown critical chunk"); + } + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + } + else +#endif + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + png_free(png_ptr, chunk.data); + } + else +#endif + skip=length; + png_push_crc_skip(png_ptr, skip); +} + +void /* PRIVATE */ +png_push_have_info(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->info_fn != NULL) + (*(png_ptr->info_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_end(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr->end_fn != NULL) + (*(png_ptr->end_fn))(png_ptr, info_ptr); +} + +void /* PRIVATE */ +png_push_have_row(png_structp png_ptr, png_bytep row) +{ + if (png_ptr->row_fn != NULL) + (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, + (int)png_ptr->pass); +} + +void PNGAPI +png_progressive_combine_row (png_structp png_ptr, + png_bytep old_row, png_bytep new_row) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + const int FARDATA png_pass_dsp_mask[7] = + {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; +#endif + if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */ + png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]); +} + +void PNGAPI +png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, + png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, + png_progressive_end_ptr end_fn) +{ + png_ptr->info_fn = info_fn; + png_ptr->row_fn = row_fn; + png_ptr->end_fn = end_fn; + + png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); +} + +png_voidp PNGAPI +png_get_progressive_ptr(png_structp png_ptr) +{ + return png_ptr->io_ptr; +} + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + diff --git a/freeimage241/Source/LibPNG/pngread.c b/freeimage241/Source/LibPNG/pngread.c new file mode 100644 index 0000000..ca69699 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngread.c @@ -0,0 +1,1425 @@ + +/* pngread.c - read a PNG file + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file contains routines that an application calls directly to + * read a PNG file or stream. + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Create a PNG structure for reading, and allocate any memory needed. */ +png_structp PNGAPI +png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ + +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL)); +} + +/* Alternate create PNG structure for reading, and allocate any memory needed. */ +png_structp PNGAPI +png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + + png_structp png_ptr; + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + + int i; + + png_debug(1, "in png_create_read_struct\n"); +#ifdef PNG_USER_MEM_SUPPORTED + if ((png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr)) == NULL) +#else + if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL) +#endif + { + return (png_structp)NULL; + } + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_ptr->jmpbuf)) +#endif + { + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf=NULL; + png_destroy_struct(png_ptr); + return (png_structp)NULL; + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf)); +#endif +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif + + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + i=0; + do + { + if(user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "Incompatible libpng version in application and library"); + } + + /* Libpng 1.0.6 was not binary compatible, due to insertion of the + info_ptr->free_me member. Libpng-1.0.1 and earlier were not + compatible due to insertion of the user transform function. Note + to maintainer: this test can be removed from version 1.2.0 and + beyond because the previous test would have already rejected it. */ + + if (user_png_ver[0] == '1' && user_png_ver[2] == '0' && + (user_png_ver[4] < '2' || user_png_ver[4] == '6') && + user_png_ver[5] == '\0') + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "Application must be recompiled; versions <= 1.0.6 were incompatible"); + } + } + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + + switch (inflateInit(&png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break; + default: png_error(png_ptr, "Unknown zlib error"); + } + + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, NULL, NULL); + + return (png_ptr); +} + +/* Initialize PNG structure for reading, and allocate any memory needed. + This interface is deprecated in favour of the png_create_read_struct(), + and it will eventually disappear. */ +#undef png_read_init +void PNGAPI +png_read_init(png_structp png_ptr) +{ + /* We only come here via pre-1.0.7-compiled applications */ + png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0); +} + +#undef png_read_init_2 +void PNGAPI +png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size, png_size_t png_info_size) +{ + /* We only come here via pre-1.0.12-compiled applications */ +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + if(sizeof(png_struct) > png_struct_size || sizeof(png_info) > png_info_size) + { + char msg[80]; + png_ptr->warning_fn=(png_error_ptr)NULL; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); + } +#endif + if(sizeof(png_struct) > png_struct_size) + { + png_ptr->error_fn=(png_error_ptr)NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The png struct allocated by the application for reading is too small."); + } + if(sizeof(png_info) > png_info_size) + { + png_ptr->error_fn=(png_error_ptr)NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The info struct allocated by application for reading is too small."); + } + png_read_init_3(&png_ptr, user_png_ver, png_struct_size); +} + +void PNGAPI +png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* to save current jump buffer */ +#endif + + int i=0; + + png_structp png_ptr=*ptr_ptr; + + do + { + if(user_png_ver[i] != png_libpng_ver[i]) + { +#ifdef PNG_LEGACY_SUPPORTED + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; +#else + png_ptr->warning_fn=(png_error_ptr)NULL; + png_warning(png_ptr, + "Application uses deprecated png_read_init() and should be recompiled."); + break; +#endif + } + } while (png_libpng_ver[i++]); + + png_debug(1, "in png_read_init_3\n"); + +#ifdef PNG_SETJMP_SUPPORTED + /* save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); +#endif + + if(sizeof(png_struct) > png_struct_size) + { + png_destroy_struct(png_ptr); + *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); + png_ptr = *ptr_ptr; + } + + /* reset all variables to 0 */ + png_memset(png_ptr, 0, sizeof (png_struct)); + +#ifdef PNG_SETJMP_SUPPORTED + /* restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); +#endif + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + + switch (inflateInit(&png_ptr->zstream)) + { + case Z_OK: /* Do nothing */ break; + case Z_MEM_ERROR: + case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break; + case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break; + default: png_error(png_ptr, "Unknown zlib error"); + } + + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_set_read_fn(png_ptr, NULL, NULL); +} + +/* Read the information before the actual image data. This has been + * changed in v0.90 to allow reading a file that already has the magic + * bytes read from the stream. You can tell libpng how many bytes have + * been read from the beginning of the stream (up to the maximum of 8) + * via png_set_sig_bytes(), and we will only check the remaining bytes + * here. The application can then have access to the signature bytes we + * read if it is determined that this isn't a valid PNG file. + */ +void PNGAPI +png_read_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_info\n"); + /* save jump buffer and error functions */ + /* If we haven't checked all of the PNG signature bytes, do so now. */ + if (png_ptr->sig_bytes < 8) + { + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; + + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); + png_ptr->sig_bytes = 8; + + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + { + if (num_checked < 4 && + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) + png_error(png_ptr, "Not a PNG file"); + else + png_error(png_ptr, "PNG file corrupted by ASCII conversion"); + } + if (num_checked < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; + } + + for(;;) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#if defined(PNG_READ_bKGD_SUPPORTED) + PNG_bKGD; +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + PNG_cHRM; +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + PNG_gAMA; +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + PNG_hIST; +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + PNG_iCCP; +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + PNG_iTXt; +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + PNG_oFFs; +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + PNG_pCAL; +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + PNG_pHYs; +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + PNG_sBIT; +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + PNG_sCAL; +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + PNG_sPLT; +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + PNG_sRGB; +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + PNG_tEXt; +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + PNG_tIME; +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + PNG_tRNS; +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + PNG_zTXt; +#endif +#endif /* PNG_GLOBAL_ARRAYS */ + png_byte chunk_length[4]; + png_uint_32 length; + + png_read_data(png_ptr, chunk_length, 4); + length = png_get_uint_32(chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + + png_debug2(0, "Reading %s chunk, length=%lu.\n", png_ptr->chunk_name, + length); + + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_ptr->mode |= PNG_HAVE_IDAT; + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + break; + } + } +#endif + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before IDAT"); + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->idat_size = length; + png_ptr->mode |= PNG_HAVE_IDAT; + break; + } +#if defined(PNG_READ_bKGD_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } +} + +/* optional call to update the users info_ptr structure */ +void PNGAPI +png_read_update_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_update_info\n"); + /* save jump buffer and error functions */ + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + else + png_warning(png_ptr, + "Ignoring extra png_read_update_info() call; row buffer not reallocated"); + png_read_transform_info(png_ptr, info_ptr); +} + +/* Initialize palette, background, etc, after transformations + * are set, but before any reading takes place. This allows + * the user to obtain a gamma-corrected palette, for example. + * If the user doesn't call this, we will do it ourselves. + */ +void PNGAPI +png_start_read_image(png_structp png_ptr) +{ + png_debug(1, "in png_start_read_image\n"); + /* save jump buffer and error functions */ + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); +} + +void PNGAPI +png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; + const int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; + const int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; +#endif + int ret; + png_debug2(1, "in png_read_row (row %lu, pass %d)\n", + png_ptr->row_number, png_ptr->pass); + /* save jump buffer and error functions */ + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + png_read_start_row(png_ptr); + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* check for transforms that have been set but were defined out */ +#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined."); +#endif +#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined."); +#endif + } + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + /* if interlaced and we do not need a new row, combine row and return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + if (dsp_row != NULL && (png_ptr->row_number & 4)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 3) || png_ptr->width < 3) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 3) != 2) + { + if (dsp_row != NULL && (png_ptr->row_number & 2)) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 1) || png_ptr->width < 2) + { + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + png_read_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 1)) + { + png_read_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "Invalid attempt to read row data"); + + png_ptr->zstream.next_out = png_ptr->row_buf; + png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes; + do + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_byte chunk_length[4]; + + png_crc_finish(png_ptr, 0); + + png_read_data(png_ptr, chunk_length, 4); + png_ptr->idat_size = png_get_uint_32(chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, + (png_size_t)png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_error(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression error"); + + } while (png_ptr->zstream.avail_out); + + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->iwidth; + png_ptr->row_info.channels = png_ptr->channels; + png_ptr->row_info.bit_depth = png_ptr->bit_depth; + png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; + png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * + (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); + + if(png_ptr->row_buf[0]) + png_read_filter_row(png_ptr, &(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->prev_row + 1, + (int)(png_ptr->row_buf[0])); + + png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf, + png_ptr->rowbytes + 1); + +#if defined(PNG_MNG_FEATURES_SUPPORTED) + if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + if (png_ptr->transformations) + png_do_read_transformations(png_ptr); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + /* blow up interlaced rows to full size */ + if (png_ptr->interlaced && + (png_ptr->transformations & PNG_INTERLACE)) + { + if (png_ptr->pass < 6) +/* old interface (pre-1.0.9): + png_do_read_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); + */ + png_do_read_interlace(png_ptr); + + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, + png_pass_dsp_mask[png_ptr->pass]); + if (row != NULL) + png_combine_row(png_ptr, row, + png_pass_mask[png_ptr->pass]); + } + else +#endif + { + if (row != NULL) + png_combine_row(png_ptr, row, 0xff); + if (dsp_row != NULL) + png_combine_row(png_ptr, dsp_row, 0xff); + } + png_read_finish_row(png_ptr); + + if (png_ptr->read_row_fn != NULL) + (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +/* Read one or more rows of image data. If the image is interlaced, + * and png_set_interlace_handling() has been called, the rows need to + * contain the contents of the rows from the previous pass. If the + * image has alpha or transparency, and png_handle_alpha()[*] has been + * called, the rows contents must be initialized to the contents of the + * screen. + * + * "row" holds the actual image, and pixels are placed in it + * as they arrive. If the image is displayed after each pass, it will + * appear to "sparkle" in. "display_row" can be used to display a + * "chunky" progressive image, with finer detail added as it becomes + * available. If you do not want this "chunky" display, you may pass + * NULL for display_row. If you do not want the sparkle display, and + * you have not called png_handle_alpha(), you may pass NULL for rows. + * If you have called png_handle_alpha(), and the image has either an + * alpha channel or a transparency chunk, you must provide a buffer for + * rows. In this case, you do not have to provide a display_row buffer + * also, but you may. If the image is not interlaced, or if you have + * not called png_set_interlace_handling(), the display_row buffer will + * be ignored, so pass NULL to it. + * + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.12 + */ + +void PNGAPI +png_read_rows(png_structp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows) +{ + png_uint_32 i; + png_bytepp rp; + png_bytepp dp; + + png_debug(1, "in png_read_rows\n"); + /* save jump buffer and error functions */ + rp = row; + dp = display_row; + if (rp != NULL && dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp++; + png_bytep dptr = *dp++; + + png_read_row(png_ptr, rptr, dptr); + } + else if(rp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep rptr = *rp; + png_read_row(png_ptr, rptr, NULL); + rp++; + } + else if(dp != NULL) + for (i = 0; i < num_rows; i++) + { + png_bytep dptr = *dp; + png_read_row(png_ptr, NULL, dptr); + dp++; + } +} + +/* Read the entire image. If the image has an alpha channel or a tRNS + * chunk, and you have called png_handle_alpha()[*], you will need to + * initialize the image to the current image that PNG will be overlaying. + * We set the num_rows again here, in case it was incorrectly set in + * png_read_start_row() by a call to png_read_update_info() or + * png_start_read_image() if png_set_interlace_handling() wasn't called + * prior to either of these functions like it should have been. You can + * only call this function once. If you desire to have an image for + * each pass of a interlaced image, use png_read_rows() instead. + * + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.12 + */ +void PNGAPI +png_read_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i,image_height; + int pass, j; + png_bytepp rp; + + png_debug(1, "in png_read_image\n"); + /* save jump buffer and error functions */ + +#ifdef PNG_READ_INTERLACING_SUPPORTED + pass = png_set_interlace_handling(png_ptr); +#else + if (png_ptr->interlaced) + png_error(png_ptr, + "Cannot read interlaced image -- interlace handler disabled."); + pass = 1; +#endif + + + image_height=png_ptr->height; + png_ptr->num_rows = image_height; /* Make sure this is set correctly */ + + for (j = 0; j < pass; j++) + { + rp = image; + for (i = 0; i < image_height; i++) + { + png_read_row(png_ptr, *rp, NULL); + rp++; + } + } +} + +/* Read the end of the PNG file. Will not read past the end of the + * file, will verify the end is accurate, and will read any comments + * or time information at the end of the file, if info is not NULL. + */ +void PNGAPI +png_read_end(png_structp png_ptr, png_infop info_ptr) +{ + png_byte chunk_length[4]; + png_uint_32 length; + + png_debug(1, "in png_read_end\n"); + /* save jump buffer and error functions */ + png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ + + do + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; + PNG_IDAT; + PNG_IEND; + PNG_PLTE; +#if defined(PNG_READ_bKGD_SUPPORTED) + PNG_bKGD; +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + PNG_cHRM; +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + PNG_gAMA; +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + PNG_hIST; +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + PNG_iCCP; +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + PNG_iTXt; +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + PNG_oFFs; +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + PNG_pCAL; +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + PNG_pHYs; +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + PNG_sBIT; +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + PNG_sCAL; +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + PNG_sPLT; +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + PNG_sRGB; +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + PNG_tEXt; +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + PNG_tIME; +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + PNG_tRNS; +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + PNG_zTXt; +#endif +#endif /* PNG_GLOBAL_ARRAYS */ + + png_read_data(png_ptr, chunk_length, 4); + length = png_get_uint_32(chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + + png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name); + + if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) + png_handle_IHDR(png_ptr, info_ptr, length); + else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) + png_handle_IEND(png_ptr, info_ptr, length); +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) + { + if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); + } + else + png_ptr->mode |= PNG_AFTER_IDAT; + png_handle_unknown(png_ptr, info_ptr, length); + if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_ptr->mode |= PNG_HAVE_PLTE; + } +#endif + else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) + { + /* Zero length IDATs are legal after the last IDAT has been + * read, but not after other chunks have been read. + */ + if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT) + png_error(png_ptr, "Too many IDAT's found"); + png_crc_finish(png_ptr, length); + } + else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) + png_handle_PLTE(png_ptr, info_ptr, length); +#if defined(PNG_READ_bKGD_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_cHRM_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_gAMA_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_hIST_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) + png_handle_hIST(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_oFFs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_pHYs_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sBIT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sRGB_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iCCP_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tEXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tIME_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) + png_handle_tIME(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_tRNS_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_zTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else + png_handle_unknown(png_ptr, info_ptr, length); + } while (!(png_ptr->mode & PNG_HAVE_IEND)); +} + +/* free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL, end_info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn = NULL; + png_voidp mem_ptr = NULL; +#endif + + png_debug(1, "in png_destroy_read_struct\n"); + /* save jump buffer and error functions */ + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (end_info_ptr_ptr != NULL) + end_info_ptr = *end_info_ptr_ptr; + +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; + mem_ptr = png_ptr->mem_ptr; +#endif + + png_read_destroy(png_ptr, info_ptr, end_info_ptr); + + if (info_ptr != NULL) + { +#if defined(PNG_TEXT_SUPPORTED) + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1); +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = (png_infop)NULL; + } + + if (end_info_ptr != NULL) + { +#if defined(PNG_READ_TEXT_SUPPORTED) + png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1); +#endif +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)end_info_ptr); +#endif + *end_info_ptr_ptr = (png_infop)NULL; + } + + if (png_ptr != NULL) + { +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = (png_structp)NULL; + } +} + +/* free all memory used by the read (old method) */ +void /* PRIVATE */ +png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_read_destroy\n"); + /* save jump buffer and error functions */ + if (info_ptr != NULL) + png_info_destroy(png_ptr, info_ptr); + + if (end_info_ptr != NULL) + png_info_destroy(png_ptr, end_info_ptr); + + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->row_buf); + png_free(png_ptr, png_ptr->prev_row); +#if defined(PNG_READ_DITHER_SUPPORTED) + png_free(png_ptr, png_ptr->palette_lookup); + png_free(png_ptr, png_ptr->dither_index); +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_table); +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + png_free(png_ptr, png_ptr->gamma_from_1); + png_free(png_ptr, png_ptr->gamma_to_1); +#endif +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->free_me &= ~PNG_FREE_PLTE; +#else + if (png_ptr->flags & PNG_FLAG_FREE_PLTE) + png_zfree(png_ptr, png_ptr->palette); + png_ptr->flags &= ~PNG_FLAG_FREE_PLTE; +#endif +#if defined(PNG_tRNS_SUPPORTED) || \ + defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans); + png_ptr->free_me &= ~PNG_FREE_TRNS; +#else + if (png_ptr->flags & PNG_FLAG_FREE_TRNS) + png_free(png_ptr, png_ptr->trans); + png_ptr->flags &= ~PNG_FLAG_FREE_TRNS; +#endif +#endif +#if defined(PNG_READ_hIST_SUPPORTED) +#ifdef PNG_FREE_ME_SUPPORTED + if (png_ptr->free_me & PNG_FREE_HIST) + png_free(png_ptr, png_ptr->hist); + png_ptr->free_me &= ~PNG_FREE_HIST; +#else + if (png_ptr->flags & PNG_FLAG_FREE_HIST) + png_free(png_ptr, png_ptr->hist); + png_ptr->flags &= ~PNG_FLAG_FREE_HIST; +#endif +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->gamma_16_table != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_table[i]); + } + png_free(png_ptr, png_ptr->gamma_16_table); + } +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_from_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_from_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_from_1); + } + if (png_ptr->gamma_16_to_1 != NULL) + { + int i; + int istop = (1 << (8 - png_ptr->gamma_shift)); + for (i = 0; i < istop; i++) + { + png_free(png_ptr, png_ptr->gamma_16_to_1[i]); + } + png_free(png_ptr, png_ptr->gamma_16_to_1); + } +#endif +#endif +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_free(png_ptr, png_ptr->time_buffer); +#endif + + inflateEnd(&png_ptr->zstream); +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_free(png_ptr, png_ptr->save_buffer); +#endif + + /* Save the important info out of the png_struct, in case it is + * being used again. + */ +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, sizeof (png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); +#endif + +} + +void PNGAPI +png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) +{ + png_ptr->read_row_fn = read_row_fn; +} + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +void PNGAPI +png_read_png(png_structp png_ptr, png_infop info_ptr, + int transforms, + voidp params) +{ + int row; + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) + /* invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* The call to png_read_info() gives us all of the information from the + * PNG file before the first IDAT (image data chunk). + */ + png_read_info(png_ptr, info_ptr); + + /* -------------- image transformations start here ------------------- */ + +#if defined(PNG_READ_16_TO_8_SUPPORTED) + /* tell libpng to strip 16 bit/color files down to 8 bits/color */ + if (transforms & PNG_TRANSFORM_STRIP_16) + png_set_strip_16(png_ptr); +#endif + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) + /* Strip alpha bytes from the input data without combining with the + * background (not recommended). + */ + if (transforms & PNG_TRANSFORM_STRIP_ALPHA) + png_set_strip_alpha(png_ptr); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) + /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single + * byte into separate bytes (useful for paletted and grayscale images). + */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + /* Change the order of packed pixels to least significant bit first + * (not useful if you are using png_set_packing). */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) + /* Expand paletted colors into true RGB triplets + * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel + * Expand paletted or RGB images with transparency to full alpha + * channels so the data will be available as RGBA quartets. + */ + if (transforms & PNG_TRANSFORM_EXPAND) + if ((png_ptr->bit_depth < 8) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || + (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) + png_set_expand(png_ptr); +#endif + + /* We don't handle background color or gamma transformation or dithering. */ + +#if defined(PNG_READ_INVERT_SUPPORTED) + /* invert monochrome files to have 0 as white and 1 as black */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) + /* If you want to shift the pixel values from the range [0,255] or + * [0,65535] to the original [0,7] or [0,31], or whatever range the + * colors were originally in: + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + png_color_8p sig_bit; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, sig_bit); + } +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) + /* flip the RGB pixels to BGR (or RGBA to BGRA) */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) + /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) + /* swap bytes of 16 bit files to least significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + + /* We don't handle adding filler bytes */ + + /* Optional call to gamma correct and add the background to the palette + * and update info structure. REQUIRED if you are expecting libpng to + * update the palette for you (i.e., you selected such a transform above). + */ + png_read_update_info(png_ptr, info_ptr); + + /* -------------- image transformations end here ------------------- */ + +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); +#endif + if(info_ptr->row_pointers == NULL) + { + info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, + info_ptr->height * sizeof(png_bytep)); +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_ROWS; +#endif + for (row = 0; row < (int)info_ptr->height; row++) + { + info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr)); + } + } + + png_read_image(png_ptr, info_ptr->row_pointers); + info_ptr->valid |= PNG_INFO_IDAT; + + /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ + png_read_end(png_ptr, info_ptr); + + if(transforms == 0 || params == NULL) + /* quiet compiler warnings */ return; + +} +#endif diff --git a/freeimage241/Source/LibPNG/pngrio.c b/freeimage241/Source/LibPNG/pngrio.c new file mode 100644 index 0000000..707a139 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngrio.c @@ -0,0 +1,162 @@ + +/* pngrio.c - functions for data input + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all input. Users who need + * special handling are expected to write a function that has the same + * arguments as this and performs a similar function, but that possibly + * has a different input method. Note that you shouldn't change this + * function, but rather write a replacement function and then make + * libpng use it at run time with png_set_read_fn(...). + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Read the data from whatever input you are using. The default routine + reads from a file pointer. Note that this routine sometimes gets called + with very small lengths, so you should implement some kind of simple + buffering if you are using unbuffered reads. This should never be asked + to read more then 64K on a 16 bit machine. */ +void /* PRIVATE */ +png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_debug1(4,"reading %d bytes\n", (int)length); + if (png_ptr->read_data_fn != NULL) + (*(png_ptr->read_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL read function"); +} + +#if !defined(PNG_NO_STDIO) +/* This is the function that does the actual reading of data. If you are + not reading from a standard C stream, you should create a replacement + read_data function and use it at run time with png_set_read_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +static void /* PRIVATE */ +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = (png_size_t)fread(data, (png_size_t)1, length, + (png_FILE_p)png_ptr->io_ptr); +#endif + + if (check != length) + png_error(png_ptr, "Read Error"); +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void /* PRIVATE */ +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = fread(n_data, 1, length, io_ptr); +#endif + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); +#if defined(_WIN32_WCE) + if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) ) + err = 0; +#else + err = fread(buf, (png_size_t)1, read, io_ptr); +#endif + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if(err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if ((png_uint_32)check != (png_uint_32)length) + png_error(png_ptr, "read Error"); +} +#endif +#endif + +/* This function allows the application to supply a new input function + for libpng if standard C streams aren't being used. + + This function takes as its arguments: + png_ptr - pointer to a png input data structure + io_ptr - pointer to user supplied structure containing info about + the input functions. May be NULL. + read_data_fn - pointer to a new input function that takes as its + arguments a pointer to a png_struct, a pointer to + a location where input data can be stored, and a 32-bit + unsigned int that is the number of bytes to be read. + To exit and output any fatal error messages the new write + function should call png_error(png_ptr, "Error msg"). */ +void PNGAPI +png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn) +{ + png_ptr->io_ptr = io_ptr; + +#if !defined(PNG_NO_STDIO) + if (read_data_fn != NULL) + png_ptr->read_data_fn = read_data_fn; + else + png_ptr->read_data_fn = png_default_read_data; +#else + png_ptr->read_data_fn = read_data_fn; +#endif + + /* It is an error to write to a read device */ + if (png_ptr->write_data_fn != NULL) + { + png_ptr->write_data_fn = NULL; + png_warning(png_ptr, + "It's an error to set both read_data_fn and write_data_fn in the "); + png_warning(png_ptr, + "same structure. Resetting write_data_fn to NULL."); + } + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_ptr->output_flush_fn = NULL; +#endif +} + diff --git a/freeimage241/Source/LibPNG/pngrtran.c b/freeimage241/Source/LibPNG/pngrtran.c new file mode 100644 index 0000000..ef070c8 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngrtran.c @@ -0,0 +1,4115 @@ + +/* pngrtran.c - transforms the data in a row for PNG readers + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file contains functions optionally called by an application + * in order to tell libpng how to handle data when reading a PNG. + * Transformations that are used in both reading and writing are + * in pngtrans.c. + */ + +#define PNG_INTERNAL +#include "png.h" + +/* Set the action on getting a CRC error for an ancillary or critical chunk. */ +void PNGAPI +png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) +{ + png_debug(1, "in png_set_crc_action\n"); + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (crit_action) + { + case PNG_CRC_NO_CHANGE: /* leave setting as is */ + break; + case PNG_CRC_WARN_USE: /* warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; + break; + case PNG_CRC_QUIET_USE: /* quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | + PNG_FLAG_CRC_CRITICAL_IGNORE; + break; + case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */ + png_warning(png_ptr, "Can't discard critical data on CRC error."); + case PNG_CRC_ERROR_QUIT: /* error/quit */ + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; + break; + } + + switch (ancil_action) + { + case PNG_CRC_NO_CHANGE: /* leave setting as is */ + break; + case PNG_CRC_WARN_USE: /* warn/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; + break; + case PNG_CRC_QUIET_USE: /* quiet/use data */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | + PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + case PNG_CRC_ERROR_QUIT: /* error/quit */ + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; + break; + case PNG_CRC_WARN_DISCARD: /* warn/discard data */ + case PNG_CRC_DEFAULT: + default: + png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; + break; + } +} + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* handle alpha and tRNS via a background color */ +void PNGAPI +png_set_background(png_structp png_ptr, + png_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma) +{ + png_debug(1, "in png_set_background\n"); + if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) + { + png_warning(png_ptr, "Application must supply a known background gamma"); + return; + } + + png_ptr->transformations |= PNG_BACKGROUND; + png_memcpy(&(png_ptr->background), background_color, sizeof(png_color_16)); + png_ptr->background_gamma = (float)background_gamma; + png_ptr->background_gamma_type = (png_byte)(background_gamma_code); + png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); + + /* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA + * (in which case need_expand is superfluous anyway), the background color + * might actually be gray yet not be flagged as such. This is not a problem + * for the current code, which uses PNG_BACKGROUND_IS_GRAY only to + * decide when to do the png_do_gray_to_rgb() transformation. + */ + if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) || + (!need_expand && background_color->red == background_color->green && + background_color->red == background_color->blue)) + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; +} +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* strip 16 bit depth files to 8 bit depth */ +void PNGAPI +png_set_strip_16(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_16\n"); + png_ptr->transformations |= PNG_16_TO_8; +} +#endif + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +void PNGAPI +png_set_strip_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_strip_alpha\n"); + png_ptr->transformations |= PNG_STRIP_ALPHA; +} +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +/* Dither file to 8 bit. Supply a palette, the current number + * of elements in the palette, the maximum number of elements + * allowed, and a histogram if possible. If the current number + * of colors is greater then the maximum number, the palette will be + * modified to fit in the maximum number. "full_dither" indicates + * whether we need a dithering cube set up for RGB images, or if we + * simply are reducing the number of colors in a paletted image. + */ + +typedef struct png_dsort_struct +{ + struct png_dsort_struct FAR * next; + png_byte left; + png_byte right; +} png_dsort; +typedef png_dsort FAR * png_dsortp; +typedef png_dsort FAR * FAR * png_dsortpp; + +void PNGAPI +png_set_dither(png_structp png_ptr, png_colorp palette, + int num_palette, int maximum_colors, png_uint_16p histogram, + int full_dither) +{ + png_debug(1, "in png_set_dither\n"); + png_ptr->transformations |= PNG_DITHER; + + if (!full_dither) + { + int i; + + png_ptr->dither_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * sizeof (png_byte))); + for (i = 0; i < num_palette; i++) + png_ptr->dither_index[i] = (png_byte)i; + } + + if (num_palette > maximum_colors) + { + if (histogram != NULL) + { + /* This is easy enough, just throw out the least used colors. + Perhaps not the best solution, but good enough. */ + + int i; + png_bytep sort; + + /* initialize an array to sort colors */ + sort = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette + * sizeof (png_byte))); + + /* initialize the sort array */ + for (i = 0; i < num_palette; i++) + sort[i] = (png_byte)i; + + /* Find the least used palette entries by starting a + bubble sort, and running it until we have sorted + out enough colors. Note that we don't care about + sorting all the colors, just finding which are + least used. */ + + for (i = num_palette - 1; i >= maximum_colors; i--) + { + int done; /* to stop early if the list is pre-sorted */ + int j; + + done = 1; + for (j = 0; j < i; j++) + { + if (histogram[sort[j]] < histogram[sort[j + 1]]) + { + png_byte t; + + t = sort[j]; + sort[j] = sort[j + 1]; + sort[j + 1] = t; + done = 0; + } + } + if (done) + break; + } + + /* swap the palette around, and set up a table, if necessary */ + if (full_dither) + { + int j = num_palette; + + /* put all the useful colors within the max, but don't + move the others */ + for (i = 0; i < maximum_colors; i++) + { + if ((int)sort[i] >= maximum_colors) + { + do + j--; + while ((int)sort[j] >= maximum_colors); + palette[i] = palette[j]; + } + } + } + else + { + int j = num_palette; + + /* move all the used colors inside the max limit, and + develop a translation table */ + for (i = 0; i < maximum_colors; i++) + { + /* only move the colors we need to */ + if ((int)sort[i] >= maximum_colors) + { + png_color tmp_color; + + do + j--; + while ((int)sort[j] >= maximum_colors); + + tmp_color = palette[j]; + palette[j] = palette[i]; + palette[i] = tmp_color; + /* indicate where the color went */ + png_ptr->dither_index[j] = (png_byte)i; + png_ptr->dither_index[i] = (png_byte)j; + } + } + + /* find closest color for those colors we are not using */ + for (i = 0; i < num_palette; i++) + { + if ((int)png_ptr->dither_index[i] >= maximum_colors) + { + int min_d, k, min_k, d_index; + + /* find the closest color to one we threw out */ + d_index = png_ptr->dither_index[i]; + min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); + for (k = 1, min_k = 0; k < maximum_colors; k++) + { + int d; + + d = PNG_COLOR_DIST(palette[d_index], palette[k]); + + if (d < min_d) + { + min_d = d; + min_k = k; + } + } + /* point to closest color */ + png_ptr->dither_index[i] = (png_byte)min_k; + } + } + } + png_free(png_ptr, sort); + } + else + { + /* This is much harder to do simply (and quickly). Perhaps + we need to go through a median cut routine, but those + don't always behave themselves with only a few colors + as input. So we will just find the closest two colors, + and throw out one of them (chosen somewhat randomly). + [We don't understand this at all, so if someone wants to + work on improving it, be our guest - AED, GRP] + */ + int i; + int max_d; + int num_new_palette; + png_dsortpp hash; + png_bytep index_to_palette; + /* where the original index currently is in the palette */ + png_bytep palette_to_index; + /* which original index points to this palette color */ + + /* initialize palette index arrays */ + index_to_palette = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * sizeof (png_byte))); + palette_to_index = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * sizeof (png_byte))); + + /* initialize the sort array */ + for (i = 0; i < num_palette; i++) + { + index_to_palette[i] = (png_byte)i; + palette_to_index[i] = (png_byte)i; + } + + hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 * + sizeof (png_dsortp))); + for (i = 0; i < 769; i++) + hash[i] = NULL; +/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */ + + num_new_palette = num_palette; + + /* initial wild guess at how far apart the farthest pixel + pair we will be eliminating will be. Larger + numbers mean more areas will be allocated, Smaller + numbers run the risk of not saving enough data, and + having to do this all over again. + + I have not done extensive checking on this number. + */ + max_d = 96; + + while (num_new_palette > maximum_colors) + { + for (i = 0; i < num_new_palette - 1; i++) + { + int j; + + for (j = i + 1; j < num_new_palette; j++) + { + int d; + + d = PNG_COLOR_DIST(palette[i], palette[j]); + + if (d <= max_d) + { + png_dsortp t; + + t = (png_dsortp)png_malloc(png_ptr, (png_uint_32)(sizeof + (png_dsort))); + t->next = hash[d]; + t->left = (png_byte)i; + t->right = (png_byte)j; + hash[d] = t; + } + } + } + + for (i = 0; i <= max_d; i++) + { + if (hash[i] != NULL) + { + png_dsortp p; + + for (p = hash[i]; p; p = p->next) + { + if ((int)index_to_palette[p->left] < num_new_palette && + (int)index_to_palette[p->right] < num_new_palette) + { + int j, next_j; + + if (num_new_palette & 0x01) + { + j = p->left; + next_j = p->right; + } + else + { + j = p->right; + next_j = p->left; + } + + num_new_palette--; + palette[index_to_palette[j]] = palette[num_new_palette]; + if (!full_dither) + { + int k; + + for (k = 0; k < num_palette; k++) + { + if (png_ptr->dither_index[k] == + index_to_palette[j]) + png_ptr->dither_index[k] = + index_to_palette[next_j]; + if ((int)png_ptr->dither_index[k] == + num_new_palette) + png_ptr->dither_index[k] = + index_to_palette[j]; + } + } + + index_to_palette[palette_to_index[num_new_palette]] = + index_to_palette[j]; + palette_to_index[index_to_palette[j]] = + palette_to_index[num_new_palette]; + + index_to_palette[j] = (png_byte)num_new_palette; + palette_to_index[num_new_palette] = (png_byte)j; + } + if (num_new_palette <= maximum_colors) + break; + } + if (num_new_palette <= maximum_colors) + break; + } + } + + for (i = 0; i < 769; i++) + { + if (hash[i] != NULL) + { + png_dsortp p = hash[i]; + while (p) + { + png_dsortp t; + + t = p->next; + png_free(png_ptr, p); + p = t; + } + } + hash[i] = 0; + } + max_d += 96; + } + png_free(png_ptr, hash); + png_free(png_ptr, palette_to_index); + png_free(png_ptr, index_to_palette); + } + num_palette = maximum_colors; + } + if (png_ptr->palette == NULL) + { + png_ptr->palette = palette; + } + png_ptr->num_palette = (png_uint_16)num_palette; + + if (full_dither) + { + int i; + png_bytep distance; + int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS + + PNG_DITHER_BLUE_BITS; + int num_red = (1 << PNG_DITHER_RED_BITS); + int num_green = (1 << PNG_DITHER_GREEN_BITS); + int num_blue = (1 << PNG_DITHER_BLUE_BITS); + png_size_t num_entries = ((png_size_t)1 << total_bits); + + png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr, + (png_uint_32)(num_entries * sizeof (png_byte))); + + png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte)); + + distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * + sizeof(png_byte))); + + png_memset(distance, 0xff, num_entries * sizeof(png_byte)); + + for (i = 0; i < num_palette; i++) + { + int ir, ig, ib; + int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS)); + int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS)); + int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS)); + + for (ir = 0; ir < num_red; ir++) + { + int dr = abs(ir - r); + int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS)); + + for (ig = 0; ig < num_green; ig++) + { + int dg = abs(ig - g); + int dt = dr + dg; + int dm = ((dr > dg) ? dr : dg); + int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS); + + for (ib = 0; ib < num_blue; ib++) + { + int d_index = index_g | ib; + int db = abs(ib - b); + int dmax = ((dm > db) ? dm : db); + int d = dmax + dt + db; + + if (d < (int)distance[d_index]) + { + distance[d_index] = (png_byte)d; + png_ptr->palette_lookup[d_index] = (png_byte)i; + } + } + } + } + } + + png_free(png_ptr, distance); + } +} +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) +/* Transform the image from the file_gamma to the screen_gamma. We + * only do transformations on images where the file_gamma and screen_gamma + * are not close reciprocals, otherwise it slows things down slightly, and + * also needlessly introduces small errors. + */ +void PNGAPI +png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) +{ + png_debug(1, "in png_set_gamma\n"); + if (fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) + png_ptr->transformations |= PNG_GAMMA; + png_ptr->gamma = (float)file_gamma; + png_ptr->screen_gamma = (float)scrn_gamma; +} +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expand paletted images to RGB, expand grayscale images of + * less than 8-bit depth to 8-bit depth, and expand tRNS chunks + * to alpha channels. + */ +void PNGAPI +png_set_expand(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} + +/* GRR 19990627: the following three functions currently are identical + * to png_set_expand(). However, it is entirely reasonable that someone + * might wish to expand an indexed image to RGB but *not* expand a single, + * fully transparent palette entry to a full alpha channel--perhaps instead + * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace + * the transparent color with a particular RGB value, or drop tRNS entirely. + * IOW, a future version of the library may make the transformations flag + * a bit more fine-grained, with separate bits for each of these three + * functions. + * + * More to the point, these functions make it obvious what libpng will be + * doing, whereas "expand" can (and does) mean any number of things. + */ + +/* Expand paletted images to RGB. */ +void PNGAPI +png_set_palette_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} + +/* Expand grayscale images of less than 8-bit depth to 8 bits. */ +void PNGAPI +png_set_gray_1_2_4_to_8(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} + +/* Expand tRNS chunks to alpha channels. */ +void PNGAPI +png_set_tRNS_to_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_expand\n"); + png_ptr->transformations |= PNG_EXPAND; +} +#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +void PNGAPI +png_set_gray_to_rgb(png_structp png_ptr) +{ + png_debug(1, "in png_set_gray_to_rgb\n"); + png_ptr->transformations |= PNG_GRAY_TO_RGB; +} +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +#if defined(PNG_FLOATING_POINT_SUPPORTED) +/* Convert a RGB image to a grayscale of the same width. This allows us, + * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. + */ + +void PNGAPI +png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red, + double green) +{ + int red_fixed = (int)((float)red*100000.0 + 0.5); + int green_fixed = (int)((float)green*100000.0 + 0.5); + png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed); +} +#endif + +void PNGAPI +png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, + png_fixed_point red, png_fixed_point green) +{ + png_debug(1, "in png_set_rgb_to_gray\n"); + switch(error_action) + { + case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY; + break; + case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; + break; + case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; + } + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#if defined(PNG_READ_EXPAND_SUPPORTED) + png_ptr->transformations |= PNG_EXPAND; +#else + { + png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED."); + png_ptr->transformations &= ~PNG_RGB_TO_GRAY; + } +#endif + { + png_uint_16 red_int, green_int; + if(red < 0 || green < 0) + { + red_int = 6968; /* .212671 * 32768 + .5 */ + green_int = 23434; /* .715160 * 32768 + .5 */ + } + else if(red + green < 100000L) + { + red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); + green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); + } + else + { + png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); + red_int = 6968; + green_int = 23434; + } + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int); + } +} +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +void PNGAPI +png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + read_user_transform_fn) +{ + png_debug(1, "in png_set_read_user_transform_fn\n"); +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->read_user_transform_fn = read_user_transform_fn; +#endif +#ifdef PNG_LEGACY_SUPPORTED + if(read_user_transform_fn) + png_warning(png_ptr, + "This version of libpng does not support user transforms"); +#endif +} +#endif + +/* Initialize everything needed for the read. This includes modifying + * the palette. + */ +void /* PRIVATE */ +png_init_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_init_read_transformations\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if(png_ptr != NULL) +#endif + { +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \ + || defined(PNG_READ_GAMMA_SUPPORTED) + int color_type = png_ptr->color_type; +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND)) + { + if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ + { + /* expand background chunk. */ + switch (png_ptr->bit_depth) + { + case 1: + png_ptr->background.gray *= (png_uint_16)0xff; + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; + break; + case 2: + png_ptr->background.gray *= (png_uint_16)0x55; + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; + break; + case 4: + png_ptr->background.gray *= (png_uint_16)0x11; + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; + break; + case 8: + case 16: + png_ptr->background.red = png_ptr->background.green = + png_ptr->background.blue = png_ptr->background.gray; + break; + } + } + else if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_ALPHA) + { +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (!(png_ptr->transformations & PNG_EXPAND)) +#endif + { + /* invert the alpha channel (in tRNS) unless the pixels are + going to be expanded, in which case leave it for later */ + int i,istop; + istop=(int)png_ptr->num_trans; + for (i=0; itrans[i] = (png_byte)(255 - png_ptr->trans[i]); + } + } +#endif + + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + png_ptr->background_1 = png_ptr->background; +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + if (png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) + { + png_build_gamma_table(png_ptr); +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND) + { + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_color back, back_1; + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + double g, gs; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + default: + g = 1.0; /* back_1 */ + gs = 1.0; /* back */ + } + + if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD) + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + else + { + back.red = (png_byte)(pow( + (double)png_ptr->background.red/255, gs) * 255.0 + .5); + back.green = (png_byte)(pow( + (double)png_ptr->background.green/255, gs) * 255.0 + .5); + back.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255, gs) * 255.0 + .5); + } + + back_1.red = (png_byte)(pow( + (double)png_ptr->background.red/255, g) * 255.0 + .5); + back_1.green = (png_byte)(pow( + (double)png_ptr->background.green/255, g) * 255.0 + .5); + back_1.blue = (png_byte)(pow( + (double)png_ptr->background.blue/255, g) * 255.0 + .5); + } + for (i = 0; i < num_palette; i++) + { + if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else /* if (png_ptr->trans[i] != 0xff) */ + { + png_byte v, w; + + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/ + else + /* color_type != PNG_COLOR_TYPE_PALETTE */ + { + double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1); + double g = 1.0; + double gs = 1.0; + + switch (png_ptr->background_gamma_type) + { + case PNG_BACKGROUND_GAMMA_SCREEN: + g = (png_ptr->screen_gamma); + gs = 1.0; + break; + case PNG_BACKGROUND_GAMMA_FILE: + g = 1.0 / (png_ptr->gamma); + gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + break; + case PNG_BACKGROUND_GAMMA_UNIQUE: + g = 1.0 / (png_ptr->background_gamma); + gs = 1.0 / (png_ptr->background_gamma * + png_ptr->screen_gamma); + break; + } + + if (color_type & PNG_COLOR_MASK_COLOR) + { + /* RGB or RGBA */ + png_ptr->background_1.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, g) * m + .5); + png_ptr->background_1.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, g) * m + .5); + png_ptr->background_1.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, g) * m + .5); + png_ptr->background.red = (png_uint_16)(pow( + (double)png_ptr->background.red / m, gs) * m + .5); + png_ptr->background.green = (png_uint_16)(pow( + (double)png_ptr->background.green / m, gs) * m + .5); + png_ptr->background.blue = (png_uint_16)(pow( + (double)png_ptr->background.blue / m, gs) * m + .5); + } + else + { + /* GRAY or GRAY ALPHA */ + png_ptr->background_1.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, g) * m + .5); + png_ptr->background.gray = (png_uint_16)(pow( + (double)png_ptr->background.gray / m, gs) * m + .5); + } + } + } + else + /* transformation does not include PNG_BACKGROUND */ +#endif + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + png_colorp palette = png_ptr->palette; + int num_palette = png_ptr->num_palette; + int i; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + else +#endif +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + /* No GAMMA transformation */ + if ((png_ptr->transformations & PNG_BACKGROUND) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + int i; + int istop = (int)png_ptr->num_trans; + png_color back; + png_colorp palette = png_ptr->palette; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < istop; i++) + { + if (png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (png_ptr->trans[i] != 0xff) + { + /* The png_composite() macro is defined in png.h */ + png_composite(palette[i].red, palette[i].red, + png_ptr->trans[i], back.red); + png_composite(palette[i].green, palette[i].green, + png_ptr->trans[i], back.green); + png_composite(palette[i].blue, palette[i].blue, + png_ptr->trans[i], back.blue); + } + } + } +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) + if ((png_ptr->transformations & PNG_SHIFT) && + (color_type == PNG_COLOR_TYPE_PALETTE)) + { + png_uint_16 i; + png_uint_16 istop = png_ptr->num_palette; + int sr = 8 - png_ptr->sig_bit.red; + int sg = 8 - png_ptr->sig_bit.green; + int sb = 8 - png_ptr->sig_bit.blue; + + if (sr < 0 || sr > 8) + sr = 0; + if (sg < 0 || sg > 8) + sg = 0; + if (sb < 0 || sb > 8) + sb = 0; + for (i = 0; i < istop; i++) + { + png_ptr->palette[i].red >>= sr; + png_ptr->palette[i].green >>= sg; + png_ptr->palette[i].blue >>= sb; + } + } +#endif + } +#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ + && !defined(PNG_READ_BACKGROUND_SUPPORTED) + if(png_ptr) + return; +#endif +} + +/* Modify the info structure to reflect the transformations. The + * info should be updated so a PNG file could be written with it, + * assuming the transformations result in valid PNG data. + */ +void /* PRIVATE */ +png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_read_transform_info\n"); +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) + { + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + else + info_ptr->color_type = PNG_COLOR_TYPE_RGB; + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + else + { + if (png_ptr->num_trans) + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; + if (info_ptr->bit_depth < 8) + info_ptr->bit_depth = 8; + info_ptr->num_trans = 0; + } + } +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND) + { + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + info_ptr->num_trans = 0; + info_ptr->background = png_ptr->background; + } +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->transformations & PNG_GAMMA) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = png_ptr->gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_ptr->int_gamma; +#endif + } +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) + if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16)) + info_ptr->bit_depth = 8; +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + if (png_ptr->transformations & PNG_DITHER) + { + if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && + png_ptr->palette_lookup && info_ptr->bit_depth == 8) + { + info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; + } + } +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + info_ptr->bit_depth = 8; +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + info_ptr->color_type |= PNG_COLOR_MASK_COLOR; +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; +#endif + + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_STRIP_ALPHA) + info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; +#endif + + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + +#if defined(PNG_READ_FILLER_SUPPORTED) + /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ + if ((png_ptr->transformations & PNG_FILLER) && + ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + { + info_ptr->channels++; +#if 0 /* if adding a true alpha channel not just filler */ + info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; +#endif + } +#endif + +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ +defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if(png_ptr->transformations & PNG_USER_TRANSFORM) + { + if(info_ptr->bit_depth < png_ptr->user_transform_depth) + info_ptr->bit_depth = png_ptr->user_transform_depth; + if(info_ptr->channels < png_ptr->user_transform_channels) + info_ptr->channels = png_ptr->user_transform_channels; + } +#endif + + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * + info_ptr->bit_depth); + info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3); + +#if !defined(PNG_READ_EXPAND_SUPPORTED) + if(png_ptr) + return; +#endif +} + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_read_transformations\n"); +#if !defined(PNG_USELESS_TESTS_SUPPORTED) + if (png_ptr->row_buf == NULL) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[50]; + + sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number, + png_ptr->pass); + png_error(png_ptr, msg); +#else + png_error(png_ptr, "NULL row buffer"); +#endif + } +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans, png_ptr->num_trans); + } + else + { + if (png_ptr->num_trans) + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_values)); + else + png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, + NULL); + } + } +#endif + +#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_STRIP_ALPHA) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + PNG_FLAG_FILLER_AFTER); +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1); + if(rgb_error) + { + png_ptr->rgb_to_gray_status=1; + if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* +From Andreas Dilger e-mail to png-implement, 26 March 1998: + + In most cases, the "simple transparency" should be done prior to doing + gray-to-RGB, or you will have to test 3x as many bytes to check if a + pixel is transparent. You would also need to make sure that the + transparency information is upgraded to RGB. + + To summarize, the current flow is: + - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + with background "in place" if transparent, + convert to RGB if necessary + - Gray + alpha -> composite with gray background and remove alpha bytes, + convert to RGB if necessary + + To support RGB backgrounds for gray images we need: + - Gray + simple transparency -> convert to RGB + simple transparency, compare + 3 or 6 bytes and composite with background + "in place" if transparent (3x compare/pixel + compared to doing composite with gray bkgrnd) + - Gray + alpha -> convert to RGB + alpha, composite with background and + remove alpha bytes (3x float operations/pixel + compared with composite on gray background) + + Greg's change will do this. The reason it wasn't done before is for + performance, as this increases the per-pixel operations. If we would check + in advance if the background was gray or RGB, and position the gray-to-RGB + transform appropriately, then it would save a lot of work/time. + */ + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + /* if gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if ((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0 ) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) + png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->trans_values), &(png_ptr->background), + &(png_ptr->background_1), + png_ptr->gamma_table, png_ptr->gamma_from_1, + png_ptr->gamma_to_1, png_ptr->gamma_16_table, + png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1, + png_ptr->gamma_shift); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) + if ((png_ptr->transformations & PNG_GAMMA) && +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + !((png_ptr->transformations & PNG_BACKGROUND) && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && +#endif + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->gamma_table, png_ptr->gamma_16_table, + png_ptr->gamma_shift); +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) + if (png_ptr->transformations & PNG_16_TO_8) + png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) + if (png_ptr->transformations & PNG_DITHER) + { + png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->dither_index); + if(png_ptr->row_info.rowbytes == (png_uint_32)0) + png_error(png_ptr, "png_do_dither returned rowbytes=0"); + } +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + /* if gray -> RGB, do so now only if we did not do so above */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if(png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* user read transform function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if(png_ptr->user_transform_depth) + png_ptr->row_info.bit_depth = png_ptr->user_transform_depth; + if(png_ptr->user_transform_channels) + png_ptr->row_info.channels = png_ptr->user_transform_channels; +#endif + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + png_ptr->row_info.rowbytes = (png_ptr->row_info.width * + png_ptr->row_info.pixel_depth+7)>>3; + } +#endif + +} + +#if defined(PNG_READ_PACK_SUPPORTED) +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. + */ +void /* PRIVATE */ +png_do_unpack(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_unpack\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && row_info->bit_depth < 8) +#else + if (row_info->bit_depth < 8) +#endif + { + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + switch (row_info->bit_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + case 2: + { + + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + case 4: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; + } +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +void /* PRIVATE */ +png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits) +{ + png_debug(1, "in png_do_unshift\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && sig_bits != NULL && +#endif + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift[4]; + int channels = 0; + int c; + png_uint_16 value = 0; + png_uint_32 row_width = row_info->width; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift[channels++] = row_info->bit_depth - sig_bits->red; + shift[channels++] = row_info->bit_depth - sig_bits->green; + shift[channels++] = row_info->bit_depth - sig_bits->blue; + } + else + { + shift[channels++] = row_info->bit_depth - sig_bits->gray; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift[channels++] = row_info->bit_depth - sig_bits->alpha; + } + + for (c = 0; c < channels; c++) + { + if (shift[c] <= 0) + shift[c] = 0; + else + value = 1; + } + + if (!value) + return; + + switch (row_info->bit_depth) + { + case 2: + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (bp = row, i = 0; i < istop; i++) + { + *bp >>= 1; + *bp++ &= 0x55; + } + break; + } + case 4: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) | + (png_byte)((int)0xf >> shift[0])); + + for (i = 0; i < istop; i++) + { + *bp >>= shift[0]; + *bp++ &= mask; + } + break; + } + case 8: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = row_width * channels; + + for (i = 0; i < istop; i++) + { + *bp++ >>= shift[i%channels]; + } + break; + } + case 16: + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_width; + + for (i = 0; i < istop; i++) + { + value = (png_uint_16)((*bp << 8) + *(bp + 1)); + value >>= shift[i%channels]; + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + break; + } + } + } +} +#endif + +#if defined(PNG_READ_16_TO_8_SUPPORTED) +/* chop rows of bit depth 16 down to 8 */ +void /* PRIVATE */ +png_do_chop(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_chop\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && row_info->bit_depth == 16) +#else + if (row_info->bit_depth == 16) +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + png_uint_32 istop = row_info->width * row_info->channels; + + for (i = 0; i> 8)) >> 8; + * + * Approximate calculation with shift/add instead of multiply/divide: + * *dp = ((((png_uint_32)(*sp) << 8) | + * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8; + * + * What we actually do to avoid extra shifting and conversion: + */ + + *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0); +#else + /* Simply discard the low order byte */ + *dp = *sp; +#endif + } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_swap_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from RRGGBBAA to AARRGGBB */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + /* This converts from GGAA to AAGG */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } + } + } + } +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_invert_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=3; + dp=sp; + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); + +/* This does nothing: + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + We can replace it with: +*/ + sp-=6; + dp=sp; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = *(--sp); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + *(--dp) = (png_byte)(255 - *(--sp)); + *(--dp) = (png_byte)(255 - *(--sp)); +/* + *(--dp) = *(--sp); + *(--dp) = *(--sp); +*/ + sp-=2; + dp=sp; + } + } + } + } +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) +/* Add filler channel if we have RGB color */ +void /* PRIVATE */ +png_do_read_filler(png_row_infop row_info, png_bytep row, + png_uint_32 filler, png_uint_32 flags) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_byte hi_filler = (png_byte)((filler>>8) & 0xff); + png_byte lo_filler = (png_byte)(filler & 0xff); + + png_debug(1, "in png_do_read_filler\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if(row_info->bit_depth == 8) + { + /* This changes the data from G to GX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + /* This changes the data from G to XG */ + else + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + } + else if(row_info->bit_depth == 16) + { + /* This changes the data from GG to GGXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from GG to XXGG */ + else + { + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 2; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + } /* COLOR_TYPE == GRAY */ + else if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if(row_info->bit_depth == 8) + { + /* This changes the data from RGB to RGBX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + /* This changes the data from RGB to XRGB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + } + } + else if(row_info->bit_depth == 16) + { + /* This changes the data from RRGGBB to RRGGBBXX */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 1; i < row_width; i++) + { + *(--dp) = hi_filler; + *(--dp) = lo_filler; + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + } + *(--dp) = hi_filler; + *(--dp) = lo_filler; + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + /* This changes the data from RRGGBB to XXRRGGBB */ + else + { + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; + for (i = 0; i < row_width; i++) + { + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = hi_filler; + *(--dp) = lo_filler; + } + row_info->channels = 4; + row_info->pixel_depth = 64; + row_info->rowbytes = row_width * 8; + } + } + } /* COLOR_TYPE == RGB */ +} +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +/* expand grayscale files to RGB, with or without alpha */ +void /* PRIVATE */ +png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) +{ + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_gray_to_rgb\n"); + if (row_info->bit_depth >= 8 && +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (row_info->bit_depth == 8) + { + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *sp; + *(dp--) = *(sp--); + } + } + else + { + png_bytep sp = row + (png_size_t)row_width * 4 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; + for (i = 0; i < row_width; i++) + { + *(dp--) = *(sp--); + *(dp--) = *(sp--); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *sp; + *(dp--) = *(sp - 1); + *(dp--) = *(sp--); + *(dp--) = *(sp--); + } + } + } + row_info->channels += (png_byte)2; + row_info->color_type |= PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = ((row_width * + row_info->pixel_depth + 7) >> 3); + } +} +#endif + +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +/* reduce RGB files to grayscale, with or without alpha + * using the equation given in Poynton's ColorFAQ at + * + * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net + * + * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B + * + * We approximate this with + * + * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B + * + * which can be expressed with integers as + * + * Y = (6969 * R + 23434 * G + 2365 * B)/32768 + * + * The calculation is to be done in a linear colorspace. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). + */ +int /* PRIVATE */ +png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) + +{ + png_uint_32 i; + + png_uint_32 row_width = row_info->width; + int rgb_error = 0; + + png_debug(1, "in png_do_rgb_to_gray\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if(red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red+gc*green+bc*blue)>>15]; + } + else + *(dp++) = *(sp-1); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if(red != green || red != blue) + { + rgb_error |= 1; + *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15); + } + else + *(dp++) = *(sp-1); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if(red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if(red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + } + } + } + } + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = png_ptr->gamma_to_1[*(sp++)]; + png_byte green = png_ptr->gamma_to_1[*(sp++)]; + png_byte blue = png_ptr->gamma_to_1[*(sp++)]; + if(red != green || red != blue) + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1 + [(rc*red + gc*green + bc*blue)>>15]; + *(dp++) = *(sp++); /* alpha */ + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + if(red != green || red != blue) + rgb_error |= 1; + *(dp++) = (png_byte)((gc*red + gc*green + bc*blue)>>8); + *(dp++) = *(sp++); /* alpha */ + } + } + } + else /* RGBA bit_depth == 16 */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->gamma_16_to_1 != NULL && + png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2; + + if(red == green && red == blue) + w = red; + else + { + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> + png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc * red_1 + + gc * green_1 + bc * blue_1)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, gray16; + red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2; + if(red != green || red != blue) + rgb_error |= 1; + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); + *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + *(dp++) = *(sp++); /* alpha */ + *(dp++) = *(sp++); + } + } + } + } + row_info->channels -= (png_byte)2; + row_info->color_type &= ~PNG_COLOR_MASK_COLOR; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = ((row_width * + row_info->pixel_depth + 7) >> 3); + } + return rgb_error; +} +#endif + +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. + */ +void /* PRIVATE */ +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette\n"); + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + case 2: + num_palette = 4; + color_inc = 0x55; + break; + case 4: + num_palette = 16; + color_inc = 0x11; + break; + case 8: + num_palette = 256; + color_inc = 1; + break; + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)v; + palette[i].green = (png_byte)v; + palette[i].blue = (png_byte)v; + } +} + +/* This function is currently unused. Do we really need it? */ +#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED) +void /* PRIVATE */ +png_correct_palette(png_structp png_ptr, png_colorp palette, + int num_palette) +{ + png_debug(1, "in png_correct_palette\n"); +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) + if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND)) + { + png_color back, back_1; + + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) + { + back.red = png_ptr->gamma_table[png_ptr->background.red]; + back.green = png_ptr->gamma_table[png_ptr->background.green]; + back.blue = png_ptr->gamma_table[png_ptr->background.blue]; + + back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; + back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; + back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; + } + else + { + double g; + + g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma); + + if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN || + fabs(g - 1.0) < PNG_GAMMA_THRESHOLD) + { + back.red = png_ptr->background.red; + back.green = png_ptr->background.green; + back.blue = png_ptr->background.blue; + } + else + { + back.red = + (png_byte)(pow((double)png_ptr->background.red/255, g) * + 255.0 + 0.5); + back.green = + (png_byte)(pow((double)png_ptr->background.green/255, g) * + 255.0 + 0.5); + back.blue = + (png_byte)(pow((double)png_ptr->background.blue/255, g) * + 255.0 + 0.5); + } + + g = 1.0 / png_ptr->background_gamma; + + back_1.red = + (png_byte)(pow((double)png_ptr->background.red/255, g) * + 255.0 + 0.5); + back_1.green = + (png_byte)(pow((double)png_ptr->background.green/255, g) * + 255.0 + 0.5); + back_1.blue = + (png_byte)(pow((double)png_ptr->background.blue/255, g) * + 255.0 + 0.5); + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_uint_32 i; + + for (i = 0; i < (png_uint_32)num_palette; i++) + { + if (i < png_ptr->num_trans && png_ptr->trans[i] == 0) + { + palette[i] = back; + } + else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff) + { + png_byte v, w; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].red]; + png_composite(w, v, png_ptr->trans[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].green]; + png_composite(w, v, png_ptr->trans[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; + + v = png_ptr->gamma_to_1[png_ptr->palette[i].blue]; + png_composite(w, v, png_ptr->trans[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + else + { + int i; + + for (i = 0; i < num_palette; i++) + { + if (palette[i].red == (png_byte)png_ptr->trans_values.gray) + { + palette[i] = back; + } + else + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } + } + } + else +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (png_ptr->transformations & PNG_GAMMA) + { + int i; + + for (i = 0; i < num_palette; i++) + { + palette[i].red = png_ptr->gamma_table[palette[i].red]; + palette[i].green = png_ptr->gamma_table[palette[i].green]; + palette[i].blue = png_ptr->gamma_table[palette[i].blue]; + } + } +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + else +#endif +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) + if (png_ptr->transformations & PNG_BACKGROUND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_color back; + + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + + for (i = 0; i < (int)png_ptr->num_trans; i++) + { + if (png_ptr->trans[i] == 0) + { + palette[i].red = back.red; + palette[i].green = back.green; + palette[i].blue = back.blue; + } + else if (png_ptr->trans[i] != 0xff) + { + png_composite(palette[i].red, png_ptr->palette[i].red, + png_ptr->trans[i], back.red); + png_composite(palette[i].green, png_ptr->palette[i].green, + png_ptr->trans[i], back.green); + png_composite(palette[i].blue, png_ptr->palette[i].blue, + png_ptr->trans[i], back.blue); + } + } + } + else /* assume grayscale palette (what else could it be?) */ + { + int i; + + for (i = 0; i < num_palette; i++) + { + if (i == (png_byte)png_ptr->trans_values.gray) + { + palette[i].red = (png_byte)png_ptr->background.red; + palette[i].green = (png_byte)png_ptr->background.green; + palette[i].blue = (png_byte)png_ptr->background.blue; + } + } + } + } +#endif +} +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) +/* Replace any alpha or transparency with the supplied background color. + * "background" is already in the screen gamma, while "background_1" is + * at a gamma of 1.0. Paletted files have already been taken care of. + */ +void /* PRIVATE */ +png_do_background(png_row_infop row_info, png_bytep row, + png_color_16p trans_values, png_color_16p background, + png_color_16p background_1, + png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, + png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, + png_uint_16pp gamma_16_to_1, int gamma_shift) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + int shift; + + png_debug(1, "in png_do_background\n"); + if (background != NULL && +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || + (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_GRAY: + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x01) + == trans_values->gray) + { + *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 7; + sp++; + } + else + shift--; + } + break; + } + case 2: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_values->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x03); + png_byte g = (png_byte)((gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03); + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + else +#endif + { + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == trans_values->gray) + { + *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 6; + sp++; + } + else + shift -= 2; + } + } + break; + } + case 4: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_values->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + else + { + png_byte p = (png_byte)((*sp >> shift) & 0x0f); + png_byte g = (png_byte)((gamma_table[p | + (p << 4)] >> 4) & 0x0f); + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(g << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + else +#endif + { + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x0f) + == trans_values->gray) + { + *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *sp |= (png_byte)(background->gray << shift); + } + if (!shift) + { + shift = 4; + sp++; + } + else + shift -= 4; + } + } + break; + } + case 8: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_values->gray) + { + *sp = (png_byte)background->gray; + } + else + { + *sp = gamma_table[*sp]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == trans_values->gray) + { + *sp = (png_byte)background->gray; + } + } + } + break; + } + case 16: + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_values->gray) + { + /* background is already in screen gamma */ + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (v == trans_values->gray) + { + *sp = (png_byte)((background->gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->gray & 0xff); + } + } + } + break; + } + } + break; + } + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_values->red && + *(sp + 1) == trans_values->green && + *(sp + 2) == trans_values->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + else + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 3) + { + if (*sp == trans_values->red && + *(sp + 1) == trans_values->green && + *(sp + 2) == trans_values->blue) + { + *sp = (png_byte)background->red; + *(sp + 1) = (png_byte)background->green; + *(sp + 2) = (png_byte)background->blue; + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + if (r == trans_values->red && g == trans_values->green && + b == trans_values->blue) + { + /* background is already in screen gamma */ + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1)); + png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5)); + + if (r == trans_values->red && g == trans_values->green && + b == trans_values->blue) + { + *sp = (png_byte)((background->red >> 8) & 0xff); + *(sp + 1) = (png_byte)(background->red & 0xff); + *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(sp + 3) = (png_byte)(background->green & 0xff); + *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(background->blue & 0xff); + } + } + } + } + break; + } + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + } + else if (a == 0) + { + /* background is already in screen gamma */ + *dp = (png_byte)background->gray; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->gray); + *dp = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 2, dp++) + { + png_byte a = *(sp + 1); + + if (a == 0xff) + { + *dp = *sp; + } + else if (a == 0) + { + *dp = (png_byte)background->gray; + } + else + { + png_composite(*dp, *sp, a, background_1->gray); + } + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } + else if (a == 0) + { + /* background is already in screen gamma */ + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, background_1->gray); + w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + *dp = (png_byte)((w >> 8) & 0xff); + *(dp + 1) = (png_byte)(w & 0xff); + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 2) + { + png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3)); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 2); + } + else if (a == 0) + { + *dp = (png_byte)((background->gray >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->gray & 0xff); + } + else + { + png_uint_16 g, v; + + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, background_1->gray); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = gamma_table[*sp]; + *(dp + 1) = gamma_table[*(sp + 1)]; + *(dp + 2) = gamma_table[*(sp + 2)]; + } + else if (a == 0) + { + /* background is already in screen gamma */ + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, background_1->red); + *dp = gamma_from_1[w]; + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, background_1->green); + *(dp + 1) = gamma_from_1[w]; + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, background_1->blue); + *(dp + 2) = gamma_from_1[w]; + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 4, dp += 3) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *dp = *sp; + *(dp + 1) = *(sp + 1); + *(dp + 2) = *(sp + 2); + } + else if (a == 0) + { + *dp = (png_byte)background->red; + *(dp + 1) = (png_byte)background->green; + *(dp + 2) = (png_byte)background->blue; + } + else + { + png_composite(*dp, *sp, a, background->red); + png_composite(*(dp + 1), *(sp + 1), a, + background->green); + png_composite(*(dp + 2), *(sp + 2), a, + background->blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#if defined(PNG_READ_GAMMA_SUPPORTED) + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + else if (a == 0) + { + /* background is already in screen gamma */ + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v, w, x; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, background->red); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *dp = (png_byte)((x >> 8) & 0xff); + *(dp + 1) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, background->green); + x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *(dp + 2) = (png_byte)((x >> 8) & 0xff); + *(dp + 3) = (png_byte)(x & 0xff); + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, background->blue); + x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8]; + *(dp + 4) = (png_byte)((x >> 8) & 0xff); + *(dp + 5) = (png_byte)(x & 0xff); + } + } + } + else +#endif + { + sp = row; + dp = row; + for (i = 0; i < row_width; i++, sp += 8, dp += 6) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + if (a == (png_uint_16)0xffff) + { + png_memcpy(dp, sp, 6); + } + else if (a == 0) + { + *dp = (png_byte)((background->red >> 8) & 0xff); + *(dp + 1) = (png_byte)(background->red & 0xff); + *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); + *(dp + 3) = (png_byte)(background->green & 0xff); + *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); + *(dp + 5) = (png_byte)(background->blue & 0xff); + } + else + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, background->red); + *dp = (png_byte)((v >> 8) & 0xff); + *(dp + 1) = (png_byte)(v & 0xff); + png_composite_16(v, g, a, background->green); + *(dp + 2) = (png_byte)((v >> 8) & 0xff); + *(dp + 3) = (png_byte)(v & 0xff); + png_composite_16(v, b, a, background->blue); + *(dp + 4) = (png_byte)((v >> 8) & 0xff); + *(dp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + } + + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + row_info->channels--; + row_info->pixel_depth = (png_byte)(row_info->channels * + row_info->bit_depth); + row_info->rowbytes = ((row_width * + row_info->pixel_depth + 7) >> 3); + } + } +} +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) +/* Gamma correct the image, avoiding the alpha channel. Make sure + * you do this after you deal with the transparency issue on grayscale + * or RGB images. If your bit depth is 8, use gamma_table, if it + * is 16, use gamma_16_table and gamma_shift. Build these with + * build_gamma_table(). + */ +void /* PRIVATE */ +png_do_gamma(png_row_infop row_info, png_bytep row, + png_bytep gamma_table, png_uint_16pp gamma_16_table, + int gamma_shift) +{ + png_bytep sp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_gamma\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + ((row_info->bit_depth <= 8 && gamma_table != NULL) || + (row_info->bit_depth == 16 && gamma_16_table != NULL))) + { + switch (row_info->color_type) + { + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v; + + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + *sp = gamma_table[*sp]; + sp++; + sp++; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp += 2; + } + } + else /* if (row_info->bit_depth == 16) */ + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 4; + } + } + break; + } + case PNG_COLOR_TYPE_GRAY: + { + if (row_info->bit_depth == 2) + { + sp = row; + for (i = 0; i < row_width; i += 4) + { + int a = *sp & 0xc0; + int b = *sp & 0x30; + int c = *sp & 0x0c; + int d = *sp & 0x03; + + *sp = (png_byte)( + ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| + ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| + ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| + ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); + sp++; + } + } + if (row_info->bit_depth == 4) + { + sp = row; + for (i = 0; i < row_width; i += 2) + { + int msb = *sp & 0xf0; + int lsb = *sp & 0x0f; + + *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) + | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); + sp++; + } + } + else if (row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++) + { + *sp = gamma_table[*sp]; + sp++; + } + } + else if (row_info->bit_depth == 16) + { + sp = row; + for (i = 0; i < row_width; i++) + { + png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + sp += 2; + } + } + break; + } + } + } +} +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) +/* Expands a palette row to an RGB or RGBA row depending + * upon whether you supply trans and num_trans. + */ +void /* PRIVATE */ +png_do_expand_palette(png_row_infop row_info, png_bytep row, + png_colorp palette, png_bytep trans, int num_trans) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand_palette\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 1; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + case 2: + { + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)value; + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + case 4: + { + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((row_width & 0x01) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)value; + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift += 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + switch (row_info->bit_depth) + { + case 8: + { + if (trans != NULL) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + + for (i = 0; i < row_width; i++) + { + if ((int)(*sp) >= num_trans) + *dp-- = 0xff; + else + *dp-- = trans[*sp]; + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 32; + row_info->rowbytes = row_width * 4; + row_info->color_type = 6; + row_info->channels = 4; + } + else + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width * 3) - 1; + + for (i = 0; i < row_width; i++) + { + *dp-- = palette[*sp].blue; + *dp-- = palette[*sp].green; + *dp-- = palette[*sp].red; + sp--; + } + row_info->bit_depth = 8; + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + row_info->color_type = 2; + row_info->channels = 3; + } + break; + } + } + } +} + +/* If the bit depth < 8, it is expanded to 8. Also, if the + * transparency value is supplied, an alpha channel is built. + */ +void /* PRIVATE */ +png_do_expand(png_row_infop row_info, png_bytep row, + png_color_16p trans_value) +{ + int shift, value; + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_expand\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); + + if (row_info->bit_depth < 8) + { + switch (row_info->bit_depth) + { + case 1: + { + gray = (png_uint_16)(gray*0xff); + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + if ((*sp >> shift) & 0x01) + *dp = 0xff; + else + *dp = 0; + if (shift == 7) + { + shift = 0; + sp--; + } + else + shift++; + + dp--; + } + break; + } + case 2: + { + gray = (png_uint_16)(gray*0x55); + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + else + shift += 2; + + dp--; + } + break; + } + case 4: + { + gray = (png_uint_16)(gray*0x11); + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + else + shift = 4; + + dp--; + } + break; + } + } + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + + if (trans_value != NULL) + { + if (row_info->bit_depth == 8) + { + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*sp == gray) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (((png_uint_16)*(sp) | + ((png_uint_16)*(sp - 1) << 8)) == gray) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = + ((row_width * row_info->pixel_depth) >> 3); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) + { + if (row_info->bit_depth == 8) + { + sp = row + (png_size_t)row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 2) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 2) == trans_value->red && + *(sp - 1) == trans_value->green && + *(sp - 0) == trans_value->blue) + *dp-- = 0; + else + *dp-- = 0xff; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + else if (row_info->bit_depth == 16) + { + sp = row + row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 3) - 1; + for (i = 0; i < row_width; i++) + { + if ((((png_uint_16)*(sp - 4) | + ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) && + (((png_uint_16)*(sp - 2) | + ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) && + (((png_uint_16)*(sp - 0) | + ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue)) + { + *dp-- = 0; + *dp-- = 0; + } + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + } + } + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = + ((row_width * row_info->pixel_depth) >> 3); + } + } +} +#endif + +#if defined(PNG_READ_DITHER_SUPPORTED) +void /* PRIVATE */ +png_do_dither(png_row_infop row_info, png_bytep row, + png_bytep palette_lookup, png_bytep dither_lookup) +{ + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width=row_info->width; + + png_debug(1, "in png_do_dither\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB && + palette_lookup && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + + /* this looks real messy, but the compiler will reduce + it down to a reasonable formula. For example, with + 5 bits per color, we get: + p = (((r >> 3) & 0x1f) << 10) | + (((g >> 3) & 0x1f) << 5) | + ((b >> 3) & 0x1f); + */ + p = (((r >> (8 - PNG_DITHER_RED_BITS)) & + ((1 << PNG_DITHER_RED_BITS) - 1)) << + (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | + (((g >> (8 - PNG_DITHER_GREEN_BITS)) & + ((1 << PNG_DITHER_GREEN_BITS) - 1)) << + (PNG_DITHER_BLUE_BITS)) | + ((b >> (8 - PNG_DITHER_BLUE_BITS)) & + ((1 << PNG_DITHER_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = + ((row_width * row_info->pixel_depth + 7) >> 3); + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + palette_lookup != NULL && row_info->bit_depth == 8) + { + int r, g, b, p; + sp = row; + dp = row; + for (i = 0; i < row_width; i++) + { + r = *sp++; + g = *sp++; + b = *sp++; + sp++; + + p = (((r >> (8 - PNG_DITHER_RED_BITS)) & + ((1 << PNG_DITHER_RED_BITS) - 1)) << + (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) | + (((g >> (8 - PNG_DITHER_GREEN_BITS)) & + ((1 << PNG_DITHER_GREEN_BITS) - 1)) << + (PNG_DITHER_BLUE_BITS)) | + ((b >> (8 - PNG_DITHER_BLUE_BITS)) & + ((1 << PNG_DITHER_BLUE_BITS) - 1)); + + *dp++ = palette_lookup[p]; + } + row_info->color_type = PNG_COLOR_TYPE_PALETTE; + row_info->channels = 1; + row_info->pixel_depth = row_info->bit_depth; + row_info->rowbytes = + ((row_width * row_info->pixel_depth + 7) >> 3); + } + else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + dither_lookup && row_info->bit_depth == 8) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + *sp = dither_lookup[*sp]; + } + } + } +} +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +#if defined(PNG_READ_GAMMA_SUPPORTED) +static int png_gamma_shift[] = + {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0}; + +/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit + * tables, we don't make a full table if we are reducing to 8-bit in + * the future. Note also how the gamma_16 tables are segmented so that + * we don't need to allocate > 64K chunks for a full 16-bit table. + */ +void /* PRIVATE */ +png_build_gamma_table(png_structp png_ptr) +{ + png_debug(1, "in png_build_gamma_table\n"); + if(png_ptr->gamma != 0.0) + { + if (png_ptr->bit_depth <= 8) + { + int i; + double g; + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + else + g = 1.0; + + png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + } + + + png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr, + (png_uint_32)256); + + if(png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + else + g = png_ptr->gamma; /* probably doing rgb_to_gray */ + + for (i = 0; i < 256; i++) + { + png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0, + g) * 255.0 + .5); + + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } + else + { + double g; + int i, j, shift, num; + int sig_bit; + png_uint_32 ig; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit = (int)png_ptr->sig_bit.red; + if ((int)png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + if ((int)png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + { + sig_bit = (int)png_ptr->sig_bit.gray; + } + + if (sig_bit > 0) + shift = 16 - sig_bit; + else + shift = 0; + + if (png_ptr->transformations & PNG_16_TO_8) + { + if (shift < (16 - PNG_MAX_GAMMA_8)) + shift = (16 - PNG_MAX_GAMMA_8); + } + + if (shift > 8) + shift = 8; + if (shift < 0) + shift = 0; + + png_ptr->gamma_shift = (png_byte)shift; + + num = (1 << (8 - shift)); + + if (png_ptr->screen_gamma > .000001) + g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma); + else + g = 1.0; + + png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr, + (png_uint_32)(num * sizeof (png_uint_16p))); + + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) + { + double fin, fout; + png_uint_32 last, max; + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * sizeof (png_uint_16))); + } + + g = 1.0 / g; + last = 0; + for (i = 0; i < 256; i++) + { + fout = ((double)i + 0.5) / 256.0; + fin = pow(fout, g); + max = (png_uint_32)(fin * (double)((png_uint_32)num << 8)); + while (last <= max) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)( + (png_uint_16)i | ((png_uint_16)i << 8)); + last++; + } + } + while (last < ((png_uint_32)num << 8)) + { + png_ptr->gamma_16_table[(int)(last & (0xff >> shift))] + [(int)(last >> (8 - shift))] = (png_uint_16)65535L; + last++; + } + } + else + { + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * sizeof (png_uint_16))); + + ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_table[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY)) + { + + g = 1.0 / (png_ptr->gamma); + + png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr, + (png_uint_32)(num * sizeof (png_uint_16p ))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * sizeof (png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_to_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + + if(png_ptr->screen_gamma > 0.000001) + g = 1.0 / png_ptr->screen_gamma; + else + g = png_ptr->gamma; /* probably doing rgb_to_gray */ + + png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr, + (png_uint_32)(num * sizeof (png_uint_16p))); + + for (i = 0; i < num; i++) + { + png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(256 * sizeof (png_uint_16))); + + ig = (((png_uint_32)i * + (png_uint_32)png_gamma_shift[shift]) >> 4); + for (j = 0; j < 256; j++) + { + png_ptr->gamma_16_from_1[i][j] = + (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) / + 65535.0, g) * 65535.0 + .5); + } + } + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ + } + } +} +#endif +/* To do: install integer version of png_build_gamma_table here */ +#endif + +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_intrapixel\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff); + *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0=*(rp )<<8 | *(rp+1); + png_uint_32 s1=*(rp+2)<<8 | *(rp+3); + png_uint_32 s2=*(rp+4)<<8 | *(rp+5); + png_uint_32 red=(65536+s0+s1)&0xffff; + png_uint_32 blue=(65536+s2+s1)&0xffff; + *(rp ) = (png_byte)((red>>8)&0xff); + *(rp+1) = (png_byte)(red&0xff); + *(rp+4) = (png_byte)((blue>>8)&0xff); + *(rp+5) = (png_byte)(blue&0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ diff --git a/freeimage241/Source/LibPNG/pngrutil.c b/freeimage241/Source/LibPNG/pngrutil.c new file mode 100644 index 0000000..ec970ce --- /dev/null +++ b/freeimage241/Source/LibPNG/pngrutil.c @@ -0,0 +1,3000 @@ + +/* pngrutil.c - utilities to read a PNG file + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file contains routines that are only called from within + * libpng itself during the course of reading an image. + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(_WIN32_WCE) +/* strtod() function is not supported on WindowsCE */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +__inline double strtod(const char *nptr, char **endptr) +{ + double result = 0; + int len; + wchar_t *str, *end; + + len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0); + str = (wchar_t *)malloc(len * sizeof(wchar_t)); + if ( NULL != str ) + { + MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len); + result = wcstod(str, &end); + len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL); + *endptr = (char *)nptr + (png_strlen(nptr) - len + 1); + free(str); + } + return result; +} +# endif +#endif + +#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ +png_uint_32 /* PRIVATE */ +png_get_uint_32(png_bytep buf) +{ + png_uint_32 i = ((png_uint_32)(*buf) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + (png_uint_32)(*(buf + 3)); + + return (i); +} + +#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_oFFs_SUPPORTED) +/* Grab a signed 32-bit integer from a buffer in big-endian format. The + * data is stored in the PNG file in two's complement format, and it is + * assumed that the machine format for signed integers is the same. */ +png_int_32 /* PRIVATE */ +png_get_int_32(png_bytep buf) +{ + png_int_32 i = ((png_int_32)(*buf) << 24) + + ((png_int_32)(*(buf + 1)) << 16) + + ((png_int_32)(*(buf + 2)) << 8) + + (png_int_32)(*(buf + 3)); + + return (i); +} +#endif /* PNG_READ_pCAL_SUPPORTED */ + +/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ +png_uint_16 /* PRIVATE */ +png_get_uint_16(png_bytep buf) +{ + png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) + + (png_uint_16)(*(buf + 1))); + + return (i); +} +#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */ + +/* Read data, and (optionally) run it through the CRC. */ +void /* PRIVATE */ +png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) +{ + png_read_data(png_ptr, buf, length); + png_calculate_crc(png_ptr, buf, length); +} + +/* Optionally skip data and then check the CRC. Depending on whether we + are reading a ancillary or critical chunk, and how the program has set + things up, we may calculate the CRC on the data and print a message. + Returns '1' if there was a CRC error, '0' otherwise. */ +int /* PRIVATE */ +png_crc_finish(png_structp png_ptr, png_uint_32 skip) +{ + png_size_t i; + png_size_t istop = png_ptr->zbuf_size; + + for (i = (png_size_t)skip; i > istop; i -= istop) + { + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + } + if (i) + { + png_crc_read(png_ptr, png_ptr->zbuf, i); + } + + if (png_crc_error(png_ptr)) + { + if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || + (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) + { + png_chunk_warning(png_ptr, "CRC error"); + } + else + { + png_chunk_error(png_ptr, "CRC error"); + } + return (1); + } + + return (0); +} + +/* Compare the CRC stored in the PNG file with that calculated by libpng from + the data it has read thus far. */ +int /* PRIVATE */ +png_crc_error(png_structp png_ptr) +{ + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + else + return (0); +} + +#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ + defined(PNG_READ_iCCP_SUPPORTED) +/* + * Decompress trailing data in a chunk. The assumption is that chunkdata + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +png_charp /* PRIVATE */ +png_decompress_chunk(png_structp png_ptr, int comp_type, + png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_size, png_size_t *newlength) +{ + static char msg[] = "Error decoding compressed text"; + png_charp text = NULL; + png_size_t text_size; + + if (comp_type == PNG_COMPRESSION_TYPE_BASE) + { + int ret = Z_OK; + png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size); + png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + text_size = 0; + text = NULL; + + while (png_ptr->zstream.avail_in) + { + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + if (png_ptr->zstream.msg != NULL) + png_warning(png_ptr, png_ptr->zstream.msg); + else + png_warning(png_ptr, msg); + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + if (text == NULL) + { + text_size = prefix_size + sizeof(msg) + 1; + text = (png_charp)png_malloc(png_ptr, text_size); + png_memcpy(text, chunkdata, prefix_size); + } + + text[text_size - 1] = 0x00; + + /* Copy what we can of the error message into the text chunk */ + text_size = (png_size_t)(chunklength - (text - chunkdata) - 1); + text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); + png_memcpy(text + prefix_size, msg, text_size + 1); + break; + } + if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) + { + if (text == NULL) + { + text_size = prefix_size + + png_ptr->zbuf_size - png_ptr->zstream.avail_out; + text = (png_charp)png_malloc(png_ptr, text_size + 1); + png_memcpy(text + prefix_size, png_ptr->zbuf, + text_size - prefix_size); + png_memcpy(text, chunkdata, prefix_size); + *(text + text_size) = 0x00; + } + else + { + png_charp tmp; + + tmp = text; + text = (png_charp)png_malloc(png_ptr, (png_uint_32)(text_size + + png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1)); + png_memcpy(text, tmp, text_size); + png_free(png_ptr, tmp); + png_memcpy(text + text_size, png_ptr->zbuf, + (png_ptr->zbuf_size - png_ptr->zstream.avail_out)); + text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; + *(text + text_size) = 0x00; + } + if (ret == Z_STREAM_END) + break; + else + { + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + } + if (ret != Z_STREAM_END) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char umsg[50]; + + if (ret == Z_BUF_ERROR) + sprintf(umsg,"Buffer error in compressed datastream in %s chunk", + png_ptr->chunk_name); + else if (ret == Z_DATA_ERROR) + sprintf(umsg,"Data error in compressed datastream in %s chunk", + png_ptr->chunk_name); + else + sprintf(umsg,"Incomplete compressed datastream in %s chunk", + png_ptr->chunk_name); + png_warning(png_ptr, umsg); +#else + png_warning(png_ptr, + "Incomplete compressed datastream in chunk other than IDAT"); +#endif + text_size=prefix_size; + if (text == NULL) + { + text = (png_charp)png_malloc(png_ptr, text_size+1); + png_memcpy(text, chunkdata, prefix_size); + } + *(text + text_size) = 0x00; + } + + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + png_free(png_ptr, chunkdata); + chunkdata = text; + *newlength=text_size; + } + else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char umsg[50]; + + sprintf(umsg, "Unknown zTXt compression type %d", comp_type); + png_warning(png_ptr, umsg); +#else + png_warning(png_ptr, "Unknown zTXt compression type"); +#endif + + *(chunkdata + prefix_size) = 0x00; + *newlength=prefix_size; + } + + return chunkdata; +} +#endif + +/* read and check the IDHR chunk */ +void /* PRIVATE */ +png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[13]; + png_uint_32 width, height; + int bit_depth, color_type, compression_type, filter_type; + int interlace_type; + + png_debug(1, "in png_handle_IHDR\n"); + + if (png_ptr->mode & PNG_HAVE_IHDR) + png_error(png_ptr, "Out of place IHDR"); + + /* check the length */ + if (length != 13) + png_error(png_ptr, "Invalid IHDR chunk"); + + png_ptr->mode |= PNG_HAVE_IHDR; + + png_crc_read(png_ptr, buf, 13); + png_crc_finish(png_ptr, 0); + + width = png_get_uint_32(buf); + height = png_get_uint_32(buf + 4); + bit_depth = buf[8]; + color_type = buf[9]; + compression_type = buf[10]; + filter_type = buf[11]; + interlace_type = buf[12]; + + + /* set internal variables */ + png_ptr->width = width; + png_ptr->height = height; + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->interlaced = (png_byte)interlace_type; + png_ptr->color_type = (png_byte)color_type; +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_ptr->filter_type = (png_byte)filter_type; +#endif + + /* find number of channels */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_PALETTE: + png_ptr->channels = 1; + break; + case PNG_COLOR_TYPE_RGB: + png_ptr->channels = 3; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_ptr->channels = 2; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + png_ptr->channels = 4; + break; + } + + /* set up other useful info */ + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * + png_ptr->channels); + png_ptr->rowbytes = ((png_ptr->width * + (png_uint_32)png_ptr->pixel_depth + 7) >> 3); + png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth); + png_debug1(3,"channels = %d\n", png_ptr->channels); + png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes); + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, + color_type, interlace_type, compression_type, filter_type); +} + +/* read and check the palette */ +void /* PRIVATE */ +png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_color palette[PNG_MAX_PALETTE_LENGTH]; + int num, i; +#ifndef PNG_NO_POINTER_INDEXING + png_colorp pal_ptr; +#endif + + png_debug(1, "in png_handle_PLTE\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before PLTE"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid PLTE after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + png_error(png_ptr, "Duplicate PLTE chunk"); + + png_ptr->mode |= PNG_HAVE_PLTE; + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring PLTE chunk in grayscale PNG"); + png_crc_finish(png_ptr, length); + return; + } +#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_crc_finish(png_ptr, length); + return; + } +#endif + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) + { + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + png_warning(png_ptr, "Invalid palette chunk"); + png_crc_finish(png_ptr, length); + return; + } + else + { + png_error(png_ptr, "Invalid palette chunk"); + } + } + + num = (int)length / 3; + +#ifndef PNG_NO_POINTER_INDEXING + for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + pal_ptr->red = buf[0]; + pal_ptr->green = buf[1]; + pal_ptr->blue = buf[2]; + } +#else + for (i = 0; i < num; i++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + /* don't depend upon png_color being any order */ + palette[i].red = buf[0]; + palette[i].green = buf[1]; + palette[i].blue = buf[2]; + } +#endif + + /* If we actually NEED the PLTE chunk (ie for a paletted image), we do + whatever the normal CRC configuration tells us. However, if we + have an RGB image, the PLTE can be considered ancillary, so + we will act as though it is. */ +#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif + { + png_crc_finish(png_ptr, 0); + } +#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + { + /* If we don't want to use the data from an ancillary chunk, + we have two options: an error abort, or a warning and we + ignore the data in this chunk (which should be OK, since + it's considered ancillary for a RGB or RGBA image). */ + if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + { + if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) + { + png_chunk_error(png_ptr, "CRC error"); + } + else + { + png_chunk_warning(png_ptr, "CRC error"); + return; + } + } + /* Otherwise, we (optionally) emit a warning and use the chunk. */ + else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) + { + png_chunk_warning(png_ptr, "CRC error"); + } + } +#endif + + png_set_PLTE(png_ptr, info_ptr, palette, num); + +#if defined(PNG_READ_tRNS_SUPPORTED) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + if (png_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); + png_ptr->num_trans = (png_uint_16)num; + } + if (info_ptr->num_trans > (png_uint_16)num) + { + png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); + info_ptr->num_trans = (png_uint_16)num; + } + } + } +#endif + +} + +void /* PRIVATE */ +png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_debug(1, "in png_handle_IEND\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) + { + png_error(png_ptr, "No image in file"); + + info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */ + } + + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + + if (length != 0) + { + png_warning(png_ptr, "Incorrect IEND chunk length"); + } + png_crc_finish(png_ptr, length); +} + +#if defined(PNG_READ_gAMA_SUPPORTED) +void /* PRIVATE */ +png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_fixed_point igamma; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif + png_byte buf[4]; + + png_debug(1, "in png_handle_gAMA\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before gAMA"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid gAMA after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place gAMA chunk"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) +#if defined(PNG_READ_sRGB_SUPPORTED) + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate gAMA chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 4) + { + png_warning(png_ptr, "Incorrect gAMA chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 4); + if (png_crc_finish(png_ptr, 0)) + return; + + igamma = (png_fixed_point)png_get_uint_32(buf); + /* check for zero gamma */ + if (igamma == 0) + { + png_warning(png_ptr, + "Ignoring gAMA chunk with gamma=0"); + return; + } + +#if defined(PNG_READ_sRGB_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sRGB) + if(igamma < 45000L || igamma > 46000L) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifndef PNG_NO_CONSOLE_IO + fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma); +#endif + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float)igamma / (float)100000.0; +# ifdef PNG_READ_GAMMA_SUPPORTED + png_ptr->gamma = file_gamma; +# endif + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_gAMA_fixed(png_ptr, info_ptr, igamma); +#endif +} +#endif + +#if defined(PNG_READ_sBIT_SUPPORTED) +void /* PRIVATE */ +png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[4]; + + png_debug(1, "in png_handle_sBIT\n"); + + buf[0] = buf[1] = buf[2] = buf[3] = 0; + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sBIT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sBIT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + { + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sBIT chunk"); + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + { + png_warning(png_ptr, "Duplicate sBIT chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 3; + else + truelen = (png_size_t)png_ptr->channels; + + if (length != truelen) + { + png_warning(png_ptr, "Incorrect sBIT chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[1]; + png_ptr->sig_bit.blue = buf[2]; + png_ptr->sig_bit.alpha = buf[3]; + } + else + { + png_ptr->sig_bit.gray = buf[0]; + png_ptr->sig_bit.red = buf[0]; + png_ptr->sig_bit.green = buf[0]; + png_ptr->sig_bit.blue = buf[0]; + png_ptr->sig_bit.alpha = buf[1]; + } + png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); +} +#endif + +#if defined(PNG_READ_cHRM_SUPPORTED) +void /* PRIVATE */ +png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[4]; +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif + png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue; + + png_debug(1, "in png_handle_cHRM\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before cHRM"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid cHRM after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Missing PLTE before cHRM"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) +#if defined(PNG_READ_sRGB_SUPPORTED) + && !(info_ptr->valid & PNG_INFO_sRGB) +#endif + ) + { + png_warning(png_ptr, "Duplicate cHRM chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 32) + { + png_warning(png_ptr, "Incorrect cHRM chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 4); + int_x_white = (png_fixed_point)png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + int_y_white = (png_fixed_point)png_get_uint_32(buf); + + if (int_x_white > 80000L || int_y_white > 80000L || + int_x_white + int_y_white > 100000L) + { + png_warning(png_ptr, "Invalid cHRM white point"); + png_crc_finish(png_ptr, 24); + return; + } + + png_crc_read(png_ptr, buf, 4); + int_x_red = (png_fixed_point)png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + int_y_red = (png_fixed_point)png_get_uint_32(buf); + + if (int_x_red > 80000L || int_y_red > 80000L || + int_x_red + int_y_red > 100000L) + { + png_warning(png_ptr, "Invalid cHRM red point"); + png_crc_finish(png_ptr, 16); + return; + } + + png_crc_read(png_ptr, buf, 4); + int_x_green = (png_fixed_point)png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + int_y_green = (png_fixed_point)png_get_uint_32(buf); + + if (int_x_green > 80000L || int_y_green > 80000L || + int_x_green + int_y_green > 100000L) + { + png_warning(png_ptr, "Invalid cHRM green point"); + png_crc_finish(png_ptr, 8); + return; + } + + png_crc_read(png_ptr, buf, 4); + int_x_blue = (png_fixed_point)png_get_uint_32(buf); + + png_crc_read(png_ptr, buf, 4); + int_y_blue = (png_fixed_point)png_get_uint_32(buf); + + if (int_x_blue > 80000L || int_y_blue > 80000L || + int_x_blue + int_y_blue > 100000L) + { + png_warning(png_ptr, "Invalid cHRM blue point"); + png_crc_finish(png_ptr, 0); + return; + } +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float)int_x_white / (float)100000.0; + white_y = (float)int_y_white / (float)100000.0; + red_x = (float)int_x_red / (float)100000.0; + red_y = (float)int_y_red / (float)100000.0; + green_x = (float)int_x_green / (float)100000.0; + green_y = (float)int_y_green / (float)100000.0; + blue_x = (float)int_x_blue / (float)100000.0; + blue_y = (float)int_y_blue / (float)100000.0; +#endif + +#if defined(PNG_READ_sRGB_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sRGB) + { + if (abs(int_x_white - 31270L) > 1000 || + abs(int_y_white - 32900L) > 1000 || + abs( int_x_red - 64000L) > 1000 || + abs( int_y_red - 33000L) > 1000 || + abs(int_x_green - 30000L) > 1000 || + abs(int_y_green - 60000L) > 1000 || + abs( int_x_blue - 15000L) > 1000 || + abs( int_y_blue - 6000L) > 1000) + { + + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); +#ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n", + white_x, white_y, red_x, red_y); + fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n", + green_x, green_y, blue_x, blue_y); +#else + fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", + int_x_white, int_y_white, int_x_red, int_y_red); + fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n", + int_x_green, int_y_green, int_x_blue, int_y_blue); +#endif +#endif /* PNG_NO_CONSOLE_IO */ + } + png_crc_finish(png_ptr, 0); + return; + } +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue); +#endif + if (png_crc_finish(png_ptr, 0)) + return; +} +#endif + +#if defined(PNG_READ_sRGB_SUPPORTED) +void /* PRIVATE */ +png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + int intent; + png_byte buf[1]; + + png_debug(1, "in png_handle_sRGB\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sRGB"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sRGB after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place sRGB chunk"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + { + png_warning(png_ptr, "Duplicate sRGB chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 1) + { + png_warning(png_ptr, "Incorrect sRGB chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 1); + if (png_crc_finish(png_ptr, 0)) + return; + + intent = buf[0]; + /* check for bad intent */ + if (intent >= PNG_sRGB_INTENT_LAST) + { + png_warning(png_ptr, "Unknown sRGB intent"); + return; + } + +#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + if ((info_ptr->valid & PNG_INFO_gAMA)) + { + int igamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + igamma=(int)info_ptr->int_gamma; +#else +# ifdef PNG_FLOATING_POINT_SUPPORTED + igamma=(int)(info_ptr->gamma * 100000.); +# endif +#endif +#if 0 && defined(PNG_cHRM_SUPPORTED) && !defined(PNG_FIXED_POINT_SUPPORTED) +/* We need to define these here because they aren't in png.h */ + png_fixed_point int_x_white; + png_fixed_point int_y_white; + png_fixed_point int_x_red; + png_fixed_point int_y_red; + png_fixed_point int_x_green; + png_fixed_point int_y_green; + png_fixed_point int_x_blue; + png_fixed_point int_y_blue; +#endif + if(igamma < 45000L || igamma > 46000L) + { + png_warning(png_ptr, + "Ignoring incorrect gAMA value when sRGB is also present"); +#ifndef PNG_NO_CONSOLE_IO +# ifdef PNG_FIXED_POINT_SUPPORTED + fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma); +# else +# ifdef PNG_FLOATING_POINT_SUPPORTED + fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma); +# endif +# endif +#endif + } + } +#endif /* PNG_READ_gAMA_SUPPORTED */ + +#ifdef PNG_READ_cHRM_SUPPORTED +#ifdef PNG_FIXED_POINT_SUPPORTED + if (info_ptr->valid & PNG_INFO_cHRM) + if (abs(info_ptr->int_x_white - 31270L) > 1000 || + abs(info_ptr->int_y_white - 32900L) > 1000 || + abs( info_ptr->int_x_red - 64000L) > 1000 || + abs( info_ptr->int_y_red - 33000L) > 1000 || + abs(info_ptr->int_x_green - 30000L) > 1000 || + abs(info_ptr->int_y_green - 60000L) > 1000 || + abs( info_ptr->int_x_blue - 15000L) > 1000 || + abs( info_ptr->int_y_blue - 6000L) > 1000) + { + png_warning(png_ptr, + "Ignoring incorrect cHRM value when sRGB is also present"); + } +#endif /* PNG_FIXED_POINT_SUPPORTED */ +#endif /* PNG_READ_cHRM_SUPPORTED */ + + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); +} +#endif /* PNG_READ_sRGB_SUPPORTED */ + +#if defined(PNG_READ_iCCP_SUPPORTED) +void /* PRIVATE */ +png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_charp chunkdata; + png_byte compression_type; + png_charp profile; + png_uint_32 skip = 0; + png_uint_32 profile_size = 0; + png_uint_32 profile_length = 0; + png_size_t slength, prefix_length, data_length; + + png_debug(1, "in png_handle_iCCP\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iCCP"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid iCCP after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->mode & PNG_HAVE_PLTE) + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Out of place iCCP chunk"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) + { + png_warning(png_ptr, "Duplicate iCCP chunk"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "iCCP chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (profile = chunkdata; *profile; profile++) + /* empty loop to find end of name */ ; + + ++profile; + + /* there should be at least one zero (the compression type byte) + following the separator, and we should be on it */ + if ( profile >= chunkdata + slength) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Malformed iCCP chunk"); + return; + } + + /* compression_type should always be zero */ + compression_type = *profile++; + if (compression_type) + { + png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); + compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 + wrote nonzero) */ + } + + prefix_length = profile - chunkdata; + chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata, + slength, prefix_length, &data_length); + + profile_length = data_length - prefix_length; + + if ( profile_length < 4) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Profile size field missing from iCCP chunk"); + return; + } + + /* Check the profile_size recorded in the first 32 bits of the ICC profile */ + profile_size = ((*(chunkdata+prefix_length))<<24) | + ((*(chunkdata+prefix_length+1))<<16) | + ((*(chunkdata+prefix_length+2))<< 8) | + ((*(chunkdata+prefix_length+3)) ); + + if(profile_size < profile_length) + profile_length = profile_size; + + if(profile_size > profile_length) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Ignoring truncated iCCP profile.\n"); + return; + } + + png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type, + chunkdata + prefix_length, profile_length); + png_free(png_ptr, chunkdata); +} +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#if defined(PNG_READ_sPLT_SUPPORTED) +void /* PRIVATE */ +png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +{ + png_bytep chunkdata; + png_bytep entry_start; + png_sPLT_t new_palette; +#ifdef PNG_NO_POINTER_INDEXING + png_sPLT_entryp pp; +#endif + int data_length, entry_size, i; + png_uint_32 skip = 0; + png_size_t slength; + + png_debug(1, "in png_handle_sPLT\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sPLT"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sPLT after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "sPLT chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + chunkdata = (png_bytep)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (entry_start = chunkdata; *entry_start; entry_start++) + /* empty loop to find end of name */ ; + ++entry_start; + + /* a sample depth should follow the separator, and we should be on it */ + if (entry_start > chunkdata + slength) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "malformed sPLT chunk"); + return; + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + data_length = (slength - (entry_start - chunkdata)); + + /* integrity-check the data length */ + if (data_length % entry_size) + { + png_free(png_ptr, chunkdata); + png_warning(png_ptr, "sPLT chunk has bad length"); + return; + } + + new_palette.nentries = data_length / entry_size; + new_palette.entries = (png_sPLT_entryp)png_malloc( + png_ptr, new_palette.nentries * sizeof(png_sPLT_entry)); + +#ifndef PNG_NO_POINTER_INDEXING + for (i = 0; i < new_palette.nentries; i++) + { + png_sPLT_entryp pp = new_palette.entries + i; + + if (new_palette.depth == 8) + { + pp->red = *entry_start++; + pp->green = *entry_start++; + pp->blue = *entry_start++; + pp->alpha = *entry_start++; + } + else + { + pp->red = png_get_uint_16(entry_start); entry_start += 2; + pp->green = png_get_uint_16(entry_start); entry_start += 2; + pp->blue = png_get_uint_16(entry_start); entry_start += 2; + pp->alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#else + pp = new_palette.entries; + for (i = 0; i < new_palette.nentries; i++) + { + + if (new_palette.depth == 8) + { + pp[i].red = *entry_start++; + pp[i].green = *entry_start++; + pp[i].blue = *entry_start++; + pp[i].alpha = *entry_start++; + } + else + { + pp[i].red = png_get_uint_16(entry_start); entry_start += 2; + pp[i].green = png_get_uint_16(entry_start); entry_start += 2; + pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; + pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; + } + pp->frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#endif + + /* discard all chunk data except the name and stash that */ + new_palette.name = (png_charp)chunkdata; + + png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, chunkdata); + png_free(png_ptr, new_palette.entries); +} +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#if defined(PNG_READ_tRNS_SUPPORTED) +void /* PRIVATE */ +png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_tRNS\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tRNS"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid tRNS after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_warning(png_ptr, "Duplicate tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + /* Should be an error, but we can cope with it */ + png_warning(png_ptr, "Missing PLTE before tRNS"); + } + else if (length > (png_uint_32)png_ptr->num_palette) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + if (length == 0) + { + png_warning(png_ptr, "Zero length tRNS chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, readbuf, (png_size_t)length); + png_ptr->num_trans = (png_uint_16)length; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_byte buf[6]; + + if (length != 6) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, (png_size_t)length); + png_ptr->num_trans = 1; + png_ptr->trans_values.red = png_get_uint_16(buf); + png_ptr->trans_values.green = png_get_uint_16(buf + 2); + png_ptr->trans_values.blue = png_get_uint_16(buf + 4); + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + png_byte buf[6]; + + if (length != 2) + { + png_warning(png_ptr, "Incorrect tRNS chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 2); + png_ptr->num_trans = 1; + png_ptr->trans_values.gray = png_get_uint_16(buf); + } + else + { + png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_crc_finish(png_ptr, 0)) + return; + + png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, + &(png_ptr->trans_values)); +} +#endif + +#if defined(PNG_READ_bKGD_SUPPORTED) +void /* PRIVATE */ +png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_size_t truelen; + png_byte buf[6]; + + png_debug(1, "in png_handle_bKGD\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before bKGD"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid bKGD after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before bKGD"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) + { + png_warning(png_ptr, "Duplicate bKGD chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 1; + else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + truelen = 6; + else + truelen = 2; + + if (length != truelen) + { + png_warning(png_ptr, "Incorrect bKGD chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, truelen); + if (png_crc_finish(png_ptr, 0)) + return; + + /* We convert the index value into RGB components so that we can allow + * arbitrary RGB values for background when we have transparency, and + * so it is easy to determine the RGB values of the background color + * from the info_ptr struct. */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_ptr->background.index = buf[0]; + if(info_ptr->num_palette) + { + if(buf[0] > info_ptr->num_palette) + { + png_warning(png_ptr, "Incorrect bKGD chunk index value"); + return; + } + png_ptr->background.red = + (png_uint_16)png_ptr->palette[buf[0]].red; + png_ptr->background.green = + (png_uint_16)png_ptr->palette[buf[0]].green; + png_ptr->background.blue = + (png_uint_16)png_ptr->palette[buf[0]].blue; + } + } + else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ + { + png_ptr->background.red = + png_ptr->background.green = + png_ptr->background.blue = + png_ptr->background.gray = png_get_uint_16(buf); + } + else + { + png_ptr->background.red = png_get_uint_16(buf); + png_ptr->background.green = png_get_uint_16(buf + 2); + png_ptr->background.blue = png_get_uint_16(buf + 4); + } + + png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); +} +#endif + +#if defined(PNG_READ_hIST_SUPPORTED) +void /* PRIVATE */ +png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + int num, i; + png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; + + png_debug(1, "in png_handle_hIST\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before hIST"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid hIST after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_warning(png_ptr, "Missing PLTE before hIST"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) + { + png_warning(png_ptr, "Duplicate hIST chunk"); + png_crc_finish(png_ptr, length); + return; + } + + num = (int)length / 2 ; + if (num != png_ptr->num_palette) + { + png_warning(png_ptr, "Incorrect hIST chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + for (i = 0; i < num; i++) + { + png_byte buf[2]; + + png_crc_read(png_ptr, buf, 2); + readbuf[i] = png_get_uint_16(buf); + } + + if (png_crc_finish(png_ptr, 0)) + return; + + png_set_hIST(png_ptr, info_ptr, readbuf); +} +#endif + +#if defined(PNG_READ_pHYs_SUPPORTED) +void /* PRIVATE */ +png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_uint_32 res_x, res_y; + int unit_type; + + png_debug(1, "in png_handle_pHYs\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pHYs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pHYs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_warning(png_ptr, "Duplicate pHYs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect pHYs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + res_x = png_get_uint_32(buf); + res_y = png_get_uint_32(buf + 4); + unit_type = buf[8]; + png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); +} +#endif + +#if defined(PNG_READ_oFFs_SUPPORTED) +void /* PRIVATE */ +png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[9]; + png_int_32 offset_x, offset_y; + int unit_type; + + png_debug(1, "in png_handle_oFFs\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before oFFs"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid oFFs after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_warning(png_ptr, "Duplicate oFFs chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (length != 9) + { + png_warning(png_ptr, "Incorrect oFFs chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 9); + if (png_crc_finish(png_ptr, 0)) + return; + + offset_x = png_get_int_32(buf); + offset_y = png_get_int_32(buf + 4); + unit_type = buf[8]; + png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); +} +#endif + +#if defined(PNG_READ_pCAL_SUPPORTED) +/* read the pCAL chunk (described in the PNG Extensions document) */ +void /* PRIVATE */ +png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_charp purpose; + png_int_32 X0, X1; + png_byte type, nparams; + png_charp buf, units, endptr; + png_charpp params; + png_size_t slength; + int i; + + png_debug(1, "in png_handle_pCAL\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before pCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid pCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + { + png_warning(png_ptr, "Duplicate pCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n", + length + 1); + purpose = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)purpose, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, purpose); + return; + } + + purpose[slength] = 0x00; /* null terminate the last string */ + + png_debug(3, "Finding end of pCAL purpose string\n"); + for (buf = purpose; *buf; buf++) + /* empty loop */ ; + + endptr = purpose + slength; + + /* We need to have at least 12 bytes after the purpose string + in order to get the parameter information. */ + if (endptr <= buf + 12) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, purpose); + return; + } + + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n"); + X0 = png_get_int_32((png_bytep)buf+1); + X1 = png_get_int_32((png_bytep)buf+5); + type = buf[9]; + nparams = buf[10]; + units = buf + 11; + + png_debug(3, "Checking pCAL equation type and number of parameters\n"); + /* Check that we have the right number of parameters for known + equation types. */ + if ((type == PNG_EQUATION_LINEAR && nparams != 2) || + (type == PNG_EQUATION_BASE_E && nparams != 3) || + (type == PNG_EQUATION_ARBITRARY && nparams != 3) || + (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) + { + png_warning(png_ptr, "Invalid pCAL parameters for equation type"); + png_free(png_ptr, purpose); + return; + } + else if (type >= PNG_EQUATION_LAST) + { + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + } + + for (buf = units; *buf; buf++) + /* Empty loop to move past the units string. */ ; + + png_debug(3, "Allocating pCAL parameters array\n"); + params = (png_charpp)png_malloc(png_ptr, (png_uint_32)(nparams + *sizeof(png_charp))) ; + + /* Get pointers to the start of each parameter string. */ + for (i = 0; i < (int)nparams; i++) + { + buf++; /* Skip the null string terminator from previous parameter. */ + + png_debug1(3, "Reading pCAL parameter %d\n", i); + for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++) + /* Empty loop to move past each parameter string */ ; + + /* Make sure we haven't run out of data yet */ + if (buf > endptr) + { + png_warning(png_ptr, "Invalid pCAL data"); + png_free(png_ptr, purpose); + png_free(png_ptr, params); + return; + } + } + + png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams, + units, params); + + png_free(png_ptr, purpose); + png_free(png_ptr, params); +} +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) +/* read the sCAL chunk */ +void /* PRIVATE */ +png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_charp buffer, ep; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double width, height; + png_charp vp; +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp swidth, sheight; +#endif +#endif + png_size_t slength; + + png_debug(1, "in png_handle_sCAL\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + { + png_warning(png_ptr, "Duplicate sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n", + length + 1); + buffer = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)buffer, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, buffer); + return; + } + + buffer[slength] = 0x00; /* null terminate the last string */ + + ep = buffer + 1; /* skip unit byte */ + +#ifdef PNG_FLOATING_POINT_SUPPORTED + width = strtod(ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed width string in sCAL chunk"); + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + swidth = (png_charp)png_malloc(png_ptr, png_strlen(ep) + 1); + png_memcpy(swidth, ep, (png_size_t)png_strlen(ep)); +#endif +#endif + + for (ep = buffer; *ep; ep++) + /* empty loop */ ; + ep++; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + height = strtod(ep, &vp); + if (*vp) + { + png_warning(png_ptr, "malformed height string in sCAL chunk"); + return; + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + sheight = (png_charp)png_malloc(png_ptr, png_strlen(ep) + 1); + png_memcpy(sheight, ep, (png_size_t)png_strlen(ep)); +#endif +#endif + + if (buffer + slength < ep +#ifdef PNG_FLOATING_POINT_SUPPORTED + || width <= 0. || height <= 0. +#endif + ) + { + png_warning(png_ptr, "Invalid sCAL data"); + png_free(png_ptr, buffer); +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif + return; + } + + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight); +#endif +#endif + + png_free(png_ptr, buffer); +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif +} +#endif + +#if defined(PNG_READ_tIME_SUPPORTED) +void /* PRIVATE */ +png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_byte buf[7]; + png_time mod_time; + + png_debug(1, "in png_handle_tIME\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Out of place tIME chunk"); + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + { + png_warning(png_ptr, "Duplicate tIME chunk"); + png_crc_finish(png_ptr, length); + return; + } + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + if (length != 7) + { + png_warning(png_ptr, "Incorrect tIME chunk length"); + png_crc_finish(png_ptr, length); + return; + } + + png_crc_read(png_ptr, buf, 7); + if (png_crc_finish(png_ptr, 0)) + return; + + mod_time.second = buf[6]; + mod_time.minute = buf[5]; + mod_time.hour = buf[4]; + mod_time.day = buf[3]; + mod_time.month = buf[2]; + mod_time.year = png_get_uint_16(buf); + + png_set_tIME(png_ptr, info_ptr, &mod_time); +} +#endif + +#if defined(PNG_READ_tEXt_SUPPORTED) +/* Note: this does not properly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp key; + png_charp text; + png_uint_32 skip = 0; + png_size_t slength; + + png_debug(1, "in png_handle_tEXt\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before tEXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "tEXt chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + key = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)key, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, key); + return; + } + + key[slength] = 0x00; + + for (text = key; *text; text++) + /* empty loop to find end of key */ ; + + if (text != key + slength) + text++; + + text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->key = key; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = text; + text_ptr->text_length = png_strlen(text); + + png_set_text(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, key); + png_free(png_ptr, text_ptr); +} +#endif + +#if defined(PNG_READ_zTXt_SUPPORTED) +/* note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp chunkdata; + png_charp text; + int comp_type; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_zTXt\n"); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before zTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr,"zTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (text = chunkdata; *text; text++) + /* empty loop */ ; + + /* zTXt must have some text after the chunkdataword */ + if (text == chunkdata + slength) + { + comp_type = PNG_TEXT_COMPRESSION_NONE; + png_warning(png_ptr, "Zero length zTXt chunk"); + } + else + { + comp_type = *(++text); + if (comp_type != PNG_TEXT_COMPRESSION_zTXt) + { + png_warning(png_ptr, "Unknown compression type in zTXt chunk"); + comp_type = PNG_TEXT_COMPRESSION_zTXt; + } + text++; /* skip the compression_method byte */ + } + prefix_len = text - chunkdata; + + chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata, + (png_size_t)length, prefix_len, &data_len); + + text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr->compression = comp_type; + text_ptr->key = chunkdata; +#ifdef PNG_iTXt_SUPPORTED + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; + text_ptr->itxt_length = 0; +#endif + text_ptr->text = chunkdata + prefix_len; + text_ptr->text_length = data_len; + + png_set_text(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, chunkdata); +} +#endif + +#if defined(PNG_READ_iTXt_SUPPORTED) +/* note: this does not correctly handle chunks that are > 64K under DOS */ +void /* PRIVATE */ +png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp chunkdata; + png_charp key, lang, text, lang_key; + int comp_flag; + int comp_type = 0; + png_size_t slength, prefix_len, data_len; + + png_debug(1, "in png_handle_iTXt\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iTXt"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr,"iTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; + } +#endif + + chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (lang = chunkdata; *lang; lang++) + /* empty loop */ ; + lang++; /* skip NUL separator */ + + /* iTXt must have a language tag (possibly empty), two compression bytes, + translated keyword (possibly empty), and possibly some text after the + keyword */ + + if (lang >= chunkdata + slength) + { + comp_flag = PNG_TEXT_COMPRESSION_NONE; + png_warning(png_ptr, "Zero length iTXt chunk"); + } + else + { + comp_flag = *lang++; + comp_type = *lang++; + } + + for (lang_key = lang; *lang_key; lang_key++) + /* empty loop */ ; + lang_key++; /* skip NUL separator */ + + for (text = lang_key; *text; text++) + /* empty loop */ ; + text++; /* skip NUL separator */ + + prefix_len = text - chunkdata; + + key=chunkdata; + if (comp_flag) + chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata, + (size_t)length, prefix_len, &data_len); + else + data_len=png_strlen(chunkdata + prefix_len); + text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr->compression = (int)comp_flag + 1; + text_ptr->lang_key = chunkdata+(lang_key-key); + text_ptr->lang = chunkdata+(lang-key); + text_ptr->itxt_length = data_len; + text_ptr->text_length = 0; + text_ptr->key = chunkdata; + text_ptr->text = chunkdata + prefix_len; + + png_set_text(png_ptr, info_ptr, text_ptr, 1); + + png_free(png_ptr, text_ptr); + png_free(png_ptr, chunkdata); +} +#endif + +/* This function is called when we haven't found a handler for a + chunk. If there isn't a problem with the chunk itself (ie bad + chunk name, CRC, or a critical chunk), the chunk is silently ignored + -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which + case it will be saved away to be written out later. */ +void /* PRIVATE */ +png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_uint_32 skip = 0; + + png_debug(1, "in png_handle_unknown\n"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */ + png_ptr->mode |= PNG_AFTER_IDAT; + } + + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + + if (!(png_ptr->chunk_name[0] & 0x20)) + { +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + HANDLE_CHUNK_ALWAYS +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + && png_ptr->read_user_chunk_fn == NULL +#endif + ) +#endif + png_chunk_error(png_ptr, "unknown critical chunk"); + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { + png_unknown_chunk chunk; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name); + chunk.data = (png_bytep)png_malloc(png_ptr, length); + chunk.size = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunk.data, length); +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) + if(png_ptr->read_user_chunk_fn != NULL) + { + /* callback to user unknown chunk handler */ + if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0) + { + if (!(png_ptr->chunk_name[0] & 0x20)) + if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != + HANDLE_CHUNK_ALWAYS) + png_chunk_error(png_ptr, "unknown critical chunk"); + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + } + } + else +#endif + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + png_free(png_ptr, chunk.data); + } + else +#endif + skip = length; + + png_crc_finish(png_ptr, skip); + +#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED) + info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */ +#endif +} + +/* This function is called to verify that a chunk name is valid. + This function can't have the "critical chunk check" incorporated + into it, since in the future we will need to be able to call user + functions to handle unknown critical chunks after we check that + the chunk name itself is valid. */ + +#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97)) + +void /* PRIVATE */ +png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) +{ + png_debug(1, "in png_check_chunk_name\n"); + if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || + isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) + { + png_chunk_error(png_ptr, "invalid chunk type"); + } +} + +/* Combines the row recently read in with the existing pixels in the + row. This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined, + a zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. If + you want all pixels to be combined, pass 0xff (255) in mask. */ +#ifndef PNG_HAVE_ASSEMBLER_COMBINE_ROW +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ + png_debug(1,"in png_combine_row\n"); + if (mask == 0xff) + { + png_memcpy(row, png_ptr->row_buf + 1, + (png_size_t)((png_ptr->width * + png_ptr->row_info.pixel_depth + 7) >> 3)); + } + else + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_inc, s_start, s_end; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x01; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 2: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x03; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + case 4: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + int s_start, s_end, s_inc; + int m = 0x80; + int shift; + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + int value; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + default: + { + png_bytep sp = png_ptr->row_buf + 1; + png_bytep dp = row; + png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + png_uint_32 i; + png_uint_32 row_width = png_ptr->width; + png_byte m = 0x80; + + + for (i = 0; i < row_width; i++) + { + if (m & mask) + { + png_memcpy(dp, sp, pixel_bytes); + } + + sp += pixel_bytes; + dp += pixel_bytes; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + } + } +} +#endif /* !PNG_HAVE_ASSEMBLER_COMBINE_ROW */ + +#ifdef PNG_READ_INTERLACING_SUPPORTED +#ifndef PNG_HAVE_ASSEMBLER_READ_INTERLACE /* else in pngvcrd.c, pnggccrd.c */ +/* OLD pre-1.0.9 interface: +void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations) + */ +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; + png_uint_32 transformations = png_ptr->transformations; +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* offset to next interlace block */ + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1,"in png_do_read_interlace (stock C version)\n"); + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_byte v; + png_uint_32 i; + int j; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 0x07); + dshift = (int)((final_width + 7) & 0x07); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 0x07); + dshift = 7 - (int)((final_width + 7) & 0x07); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = 0; i < row_info->width; i++) + { + v = (png_byte)((*sp >> sshift) & 0x01); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 2: + { + png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); + png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; + png_uint_32 i; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 3) & 0x03) << 1); + dshift = (int)(((final_width + 3) & 0x03) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x03); + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + case 4: + { + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + int jstop = png_pass_inc[pass]; + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)(((row_info->width + 1) & 0x01) << 2); + dshift = (int)(((final_width + 1) & 0x01) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = 0; i < row_info->width; i++) + { + png_byte v = (png_byte)((*sp >> sshift) & 0xf); + int j; + + for (j = 0; j < jstop; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + default: + { + png_size_t pixel_bytes = (row_info->pixel_depth >> 3); + png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes; + png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; + + int jstop = png_pass_inc[pass]; + png_uint_32 i; + + for (i = 0; i < row_info->width; i++) + { + png_byte v[8]; + int j; + + png_memcpy(v, sp, pixel_bytes); + for (j = 0; j < jstop; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sp -= pixel_bytes; + } + break; + } + } + row_info->width = final_width; + row_info->rowbytes = ((final_width * + (png_uint_32)row_info->pixel_depth + 7) >> 3); + } +#if !defined(PNG_READ_PACKSWAP_SUPPORTED) + transformations = transformations; /* silence compiler warning */ +#endif +} +#endif /* !PNG_HAVE_ASSEMBLER_READ_INTERLACE */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + +#ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, + png_bytep prev_row, int filter) +{ + png_debug(1, "in png_read_filter_row\n"); + png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter); + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + case PNG_FILTER_VALUE_SUB: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_UP: + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_AVG: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *lp++) / 2 ) & 0xff); + rp++; + } + break; + } + case PNG_FILTER_VALUE_PAETH: + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop=row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) /* use leftover rp,pp */ + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + break; + } + default: + png_warning(png_ptr, "Ignoring bad adaptive filter type"); + *row=0; + break; + } +} +#endif /* !PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */ + +void /* PRIVATE */ +png_read_finish_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_debug(1, "in png_read_finish_row\n"); + png_ptr->row_number++; + if (png_ptr->row_number < png_ptr->num_rows) + return; + + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + png_ptr->irowbytes = ((png_ptr->iwidth * + (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1; + + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (!(png_ptr->num_rows)) + continue; + } + else /* if (png_ptr->transformations & PNG_INTERLACE) */ + break; + } while (png_ptr->iwidth == 0); + + if (png_ptr->pass < 7) + return; + } + + if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + { +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + char extra; + int ret; + + png_ptr->zstream.next_out = (Byte *)&extra; + png_ptr->zstream.avail_out = (uInt)1; + for(;;) + { + if (!(png_ptr->zstream.avail_in)) + { + while (!png_ptr->idat_size) + { + png_byte chunk_length[4]; + + png_crc_finish(png_ptr, 0); + + png_read_data(png_ptr, chunk_length, 4); + png_ptr->idat_size = png_get_uint_32(chunk_length); + + png_reset_crc(png_ptr); + png_crc_read(png_ptr, png_ptr->chunk_name, 4); + if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) + png_error(png_ptr, "Not enough image data"); + + } + png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = png_ptr->zbuf; + if (png_ptr->zbuf_size > png_ptr->idat_size) + png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; + png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); + png_ptr->idat_size -= png_ptr->zstream.avail_in; + } + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret == Z_STREAM_END) + { + if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || + png_ptr->idat_size) + png_error(png_ptr, "Extra compressed data"); + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + break; + } + if (ret != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : + "Decompression Error"); + + if (!(png_ptr->zstream.avail_out)) + png_error(png_ptr, "Extra compressed data"); + + } + png_ptr->zstream.avail_out = 0; + } + + if (png_ptr->idat_size || png_ptr->zstream.avail_in) + png_error(png_ptr, "Extra compression data"); + + inflateReset(&png_ptr->zstream); + + png_ptr->mode |= PNG_AFTER_IDAT; +} + +void /* PRIVATE */ +png_read_start_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int max_pixel_depth; + png_uint_32 row_bytes; + + png_debug(1, "in png_read_start_row\n"); + png_ptr->zstream.avail_in = 0; + png_init_read_transformations(png_ptr); + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + else + png_ptr->num_rows = png_ptr->height; + + png_ptr->iwidth = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + + row_bytes = ((png_ptr->iwidth * + (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1; + png_ptr->irowbytes = (png_size_t)row_bytes; + if((png_uint_32)png_ptr->irowbytes != row_bytes) + png_error(png_ptr, "Rowbytes overflow in png_read_start_row"); + } + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->iwidth = png_ptr->width; + png_ptr->irowbytes = png_ptr->rowbytes + 1; + } + max_pixel_depth = png_ptr->pixel_depth; + +#if defined(PNG_READ_PACK_SUPPORTED) + if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + max_pixel_depth = 8; +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + if (png_ptr->num_trans) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth < 8) + max_pixel_depth = 8; + if (png_ptr->num_trans) + max_pixel_depth *= 2; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (png_ptr->num_trans) + { + max_pixel_depth *= 4; + max_pixel_depth /= 3; + } + } + } +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & (PNG_FILLER)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + max_pixel_depth = 32; + else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + { + if (max_pixel_depth <= 8) + max_pixel_depth = 16; + else + max_pixel_depth = 32; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + if (max_pixel_depth <= 32) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + } +#endif + +#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + { + if ( +#if defined(PNG_READ_EXPAND_SUPPORTED) + (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || +#endif +#if defined(PNG_READ_FILLER_SUPPORTED) + (png_ptr->transformations & (PNG_FILLER)) || +#endif + png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (max_pixel_depth <= 16) + max_pixel_depth = 32; + else + max_pixel_depth = 64; + } + else + { + if (max_pixel_depth <= 8) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 32; + else + max_pixel_depth = 24; + } + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + max_pixel_depth = 64; + else + max_pixel_depth = 48; + } + } +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ +defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + if(png_ptr->transformations & PNG_USER_TRANSFORM) + { + int user_pixel_depth=png_ptr->user_transform_depth* + png_ptr->user_transform_channels; + if(user_pixel_depth > max_pixel_depth) + max_pixel_depth=user_pixel_depth; + } +#endif + + /* align the width on the next larger 8 pixels. Mainly used + for interlacing */ + row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); + /* calculate the maximum bytes needed, adding a byte and a pixel + for safety's sake */ + row_bytes = ((row_bytes * (png_uint_32)max_pixel_depth + 7) >> 3) + + 1 + ((max_pixel_depth + 7) >> 3); +#ifdef PNG_MAX_MALLOC_64K + if (row_bytes > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, row_bytes); +#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD) + png_ptr->row_buf_size = row_bytes; +#endif + +#ifdef PNG_MAX_MALLOC_64K + if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L) + png_error(png_ptr, "This image requires a row greater than 64KB"); +#endif + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( + png_ptr->rowbytes + 1)); + + png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %lu,\n", png_ptr->width); + png_debug1(3, "height = %lu,\n", png_ptr->height); + png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth); + png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes); + + png_ptr->flags |= PNG_FLAG_ROW_INIT; +} diff --git a/freeimage241/Source/LibPNG/pngset.c b/freeimage241/Source/LibPNG/pngset.c new file mode 100644 index 0000000..ddc4d0c --- /dev/null +++ b/freeimage241/Source/LibPNG/pngset.c @@ -0,0 +1,972 @@ + +/* pngset.c - storage of image information into info struct + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * The functions here are used during reads to store data from the file + * into the info struct, and during writes to store application data + * into the info struct for writing into the file. This abstracts the + * info struct and allows us to change the structure in the future. + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_bKGD_SUPPORTED) +void PNGAPI +png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) +{ + png_debug1(1, "in %s storage function\n", "bKGD"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->background), background, sizeof(png_color_16)); + info_ptr->valid |= PNG_INFO_bKGD; +} +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_cHRM(png_structp png_ptr, png_infop info_ptr, + double white_x, double white_y, double red_x, double red_y, + double green_x, double green_y, double blue_x, double blue_y) +{ + png_debug1(1, "in %s storage function\n", "cHRM"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_white = (float)white_x; + info_ptr->y_white = (float)white_y; + info_ptr->x_red = (float)red_x; + info_ptr->y_red = (float)red_y; + info_ptr->x_green = (float)green_x; + info_ptr->y_green = (float)green_y; + info_ptr->x_blue = (float)blue_x; + info_ptr->y_blue = (float)blue_y; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5); + info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5); + info_ptr->int_x_red = (png_fixed_point)(red_x*100000.+0.5); + info_ptr->int_y_red = (png_fixed_point)(red_y*100000.+0.5); + info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5); + info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5); + info_ptr->int_x_blue = (png_fixed_point)(blue_x*100000.+0.5); + info_ptr->int_y_blue = (png_fixed_point)(blue_y*100000.+0.5); +#endif + info_ptr->valid |= PNG_INFO_cHRM; +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_debug1(1, "in %s storage function\n", "cHRM"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->int_x_white = white_x; + info_ptr->int_y_white = white_y; + info_ptr->int_x_red = red_x; + info_ptr->int_y_red = red_y; + info_ptr->int_x_green = green_x; + info_ptr->int_y_green = green_y; + info_ptr->int_x_blue = blue_x; + info_ptr->int_y_blue = blue_y; +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->x_white = (float)(white_x/100000.); + info_ptr->y_white = (float)(white_y/100000.); + info_ptr->x_red = (float)(red_x/100000.); + info_ptr->y_red = (float)(red_y/100000.); + info_ptr->x_green = (float)(green_x/100000.); + info_ptr->y_green = (float)(green_y/100000.); + info_ptr->x_blue = (float)(blue_x/100000.); + info_ptr->y_blue = (float)(blue_y/100000.); +#endif + info_ptr->valid |= PNG_INFO_cHRM; +} +#endif +#endif + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) +{ + png_debug1(1, "in %s storage function\n", "gAMA"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->gamma = (float)file_gamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = (int)(file_gamma*100000.+.5); +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if(file_gamma == 0.0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif +void PNGAPI +png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point + int_gamma) +{ + png_debug1(1, "in %s storage function\n", "gAMA"); + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = (float)(int_gamma/100000.); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = int_gamma; +#endif + info_ptr->valid |= PNG_INFO_gAMA; + if(int_gamma == 0) + png_warning(png_ptr, "Setting gamma=0"); +} +#endif + +#if defined(PNG_hIST_SUPPORTED) +void PNGAPI +png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) +{ + int i; + + png_debug1(1, "in %s storage function\n", "hIST"); + if (png_ptr == NULL || info_ptr == NULL) + return; + if (info_ptr->num_palette == 0) + { + png_warning(png_ptr, + "Palette size 0, hIST allocation skipped."); + return; + } + +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); +#endif + png_ptr->hist = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(info_ptr->num_palette * sizeof (png_uint_16))); + + for (i = 0; i < info_ptr->num_palette; i++) + png_ptr->hist[i] = hist[i]; + info_ptr->hist = png_ptr->hist; + info_ptr->valid |= PNG_INFO_hIST; + +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_HIST; +#else + png_ptr->flags |= PNG_FLAG_FREE_HIST; +#endif +} +#endif + +void PNGAPI +png_set_IHDR(png_structp png_ptr, png_infop info_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) +{ + int rowbytes_per_pixel; + png_debug1(1, "in %s storage function\n", "IHDR"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* check for width and height valid values */ + if (width == 0 || height == 0) + png_error(png_ptr, "Image width or height is zero in IHDR"); + if (width > PNG_MAX_UINT || height > PNG_MAX_UINT) + png_error(png_ptr, "Invalid image size in IHDR"); + + /* check other values */ + if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && + bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth in IHDR"); + + if (color_type < 0 || color_type == 1 || + color_type == 5 || color_type > 6) + png_error(png_ptr, "Invalid color type in IHDR"); + + if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || + ((color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) + png_error(png_ptr, "Invalid color type/bit depth combination in IHDR"); + + if (interlace_type >= PNG_INTERLACE_LAST) + png_error(png_ptr, "Unknown interlace method in IHDR"); + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_error(png_ptr, "Unknown compression method in IHDR"); + +#if defined(PNG_MNG_FEATURES_SUPPORTED) + /* Accept filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not read a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&png_ptr->mng_features_permitted) + png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n"); + if(filter_type != PNG_FILTER_TYPE_BASE) + { + if(!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA))) + png_error(png_ptr, "Unknown filter method in IHDR"); + if(png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) + png_warning(png_ptr, "Invalid filter method in IHDR"); + } +#else + if(filter_type != PNG_FILTER_TYPE_BASE) + png_error(png_ptr, "Unknown filter method in IHDR"); +#endif + + info_ptr->width = width; + info_ptr->height = height; + info_ptr->bit_depth = (png_byte)bit_depth; + info_ptr->color_type =(png_byte) color_type; + info_ptr->compression_type = (png_byte)compression_type; + info_ptr->filter_type = (png_byte)filter_type; + info_ptr->interlace_type = (png_byte)interlace_type; + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + info_ptr->channels = 1; + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + info_ptr->channels = 3; + else + info_ptr->channels = 1; + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + info_ptr->channels++; + info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); + + /* check for overflow */ + rowbytes_per_pixel = (info_ptr->pixel_depth + 7) >> 3; + if (( width > PNG_MAX_UINT/rowbytes_per_pixel)) + { + png_warning(png_ptr, + "Width too large to process image data; rowbytes will overflow."); + info_ptr->rowbytes = (png_size_t)0; + } + else + info_ptr->rowbytes = (info_ptr->width * info_ptr->pixel_depth + 7) >> 3; +} + +#if defined(PNG_oFFs_SUPPORTED) +void PNGAPI +png_set_oFFs(png_structp png_ptr, png_infop info_ptr, + png_int_32 offset_x, png_int_32 offset_y, int unit_type) +{ + png_debug1(1, "in %s storage function\n", "oFFs"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_offset = offset_x; + info_ptr->y_offset = offset_y; + info_ptr->offset_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_oFFs; +} +#endif + +#if defined(PNG_pCAL_SUPPORTED) +void PNGAPI +png_set_pCAL(png_structp png_ptr, png_infop info_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_charp units, png_charpp params) +{ + png_uint_32 length; + int i; + + png_debug1(1, "in %s storage function\n", "pCAL"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + length = png_strlen(purpose) + 1; + png_debug1(3, "allocating purpose for info (%lu bytes)\n", length); + info_ptr->pcal_purpose = (png_charp)png_malloc(png_ptr, length); + png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length); + + png_debug(3, "storing X0, X1, type, and nparams in info\n"); + info_ptr->pcal_X0 = X0; + info_ptr->pcal_X1 = X1; + info_ptr->pcal_type = (png_byte)type; + info_ptr->pcal_nparams = (png_byte)nparams; + + length = png_strlen(units) + 1; + png_debug1(3, "allocating units for info (%lu bytes)\n", length); + info_ptr->pcal_units = (png_charp)png_malloc(png_ptr, length); + png_memcpy(info_ptr->pcal_units, units, (png_size_t)length); + + info_ptr->pcal_params = (png_charpp)png_malloc(png_ptr, + (png_uint_32)((nparams + 1) * sizeof(png_charp))); + + info_ptr->pcal_params[nparams] = NULL; + + for (i = 0; i < nparams; i++) + { + length = png_strlen(params[i]) + 1; + png_debug2(3, "allocating parameter %d for info (%lu bytes)\n", i, length); + info_ptr->pcal_params[i] = (png_charp)png_malloc(png_ptr, length); + png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length); + } + + info_ptr->valid |= PNG_INFO_pCAL; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_PCAL; +#endif +} +#endif + +#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_sCAL(png_structp png_ptr, png_infop info_ptr, + int unit, double width, double height) +{ + png_debug1(1, "in %s storage function\n", "sCAL"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + info_ptr->scal_pixel_width = width; + info_ptr->scal_pixel_height = height; + + info_ptr->valid |= PNG_INFO_sCAL; +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void PNGAPI +png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int unit, png_charp swidth, png_charp sheight) +{ + png_uint_32 length; + + png_debug1(1, "in %s storage function\n", "sCAL"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + + length = png_strlen(swidth) + 1; + png_debug1(3, "allocating unit for info (%d bytes)\n", length); + info_ptr->scal_s_width = (png_charp)png_malloc(png_ptr, length); + png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length); + + length = png_strlen(sheight) + 1; + png_debug1(3, "allocating unit for info (%d bytes)\n", length); + info_ptr->scal_s_height = (png_charp)png_malloc(png_ptr, length); + png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length); + + info_ptr->valid |= PNG_INFO_sCAL; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_SCAL; +#endif +} +#endif +#endif +#endif + +#if defined(PNG_pHYs_SUPPORTED) +void PNGAPI +png_set_pHYs(png_structp png_ptr, png_infop info_ptr, + png_uint_32 res_x, png_uint_32 res_y, int unit_type) +{ + png_debug1(1, "in %s storage function\n", "pHYs"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->x_pixels_per_unit = res_x; + info_ptr->y_pixels_per_unit = res_y; + info_ptr->phys_unit_type = (png_byte)unit_type; + info_ptr->valid |= PNG_INFO_pHYs; +} +#endif + +void PNGAPI +png_set_PLTE(png_structp png_ptr, png_infop info_ptr, + png_colorp palette, int num_palette) +{ + + png_debug1(1, "in %s storage function\n", "PLTE"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + /* + * It may not actually be necessary to set png_ptr->palette here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); +#endif + png_ptr->palette = (png_colorp)png_zalloc(png_ptr, (uInt)num_palette, + sizeof (png_color)); + png_memcpy(png_ptr->palette, palette, num_palette * sizeof (png_color)); + info_ptr->palette = png_ptr->palette; + info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_PLTE; +#else + png_ptr->flags |= PNG_FLAG_FREE_PLTE; +#endif + + info_ptr->valid |= PNG_INFO_PLTE; +} + +#if defined(PNG_sBIT_SUPPORTED) +void PNGAPI +png_set_sBIT(png_structp png_ptr, png_infop info_ptr, + png_color_8p sig_bit) +{ + png_debug1(1, "in %s storage function\n", "sBIT"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_memcpy(&(info_ptr->sig_bit), sig_bit, sizeof (png_color_8)); + info_ptr->valid |= PNG_INFO_sBIT; +} +#endif + +#if defined(PNG_sRGB_SUPPORTED) +void PNGAPI +png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent) +{ + png_debug1(1, "in %s storage function\n", "sRGB"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->srgb_intent = (png_byte)intent; + info_ptr->valid |= PNG_INFO_sRGB; +} + +void PNGAPI +png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, + int intent) +{ +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + float file_gamma; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_file_gamma; +#endif +#endif +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, + int_green_y, int_blue_x, int_blue_y; +#endif +#endif + png_debug1(1, "in %s storage function\n", "sRGB_gAMA_and_cHRM"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + png_set_sRGB(png_ptr, info_ptr, intent); + +#if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + file_gamma = (float).45455; + png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + int_file_gamma = 45455L; + png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); +#endif +#endif + +#if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FIXED_POINT_SUPPORTED + int_white_x = 31270L; + int_white_y = 32900L; + int_red_x = 64000L; + int_red_y = 33000L; + int_green_x = 30000L; + int_green_y = 60000L; + int_blue_x = 15000L; + int_blue_y = 6000L; + + png_set_cHRM_fixed(png_ptr, info_ptr, + int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, int_green_y, + int_blue_x, int_blue_y); +#endif +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float).3127; + white_y = (float).3290; + red_x = (float).64; + red_y = (float).33; + green_x = (float).30; + green_y = (float).60; + blue_x = (float).15; + blue_y = (float).06; + + png_set_cHRM(png_ptr, info_ptr, + white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#endif +} +#endif + + +#if defined(PNG_iCCP_SUPPORTED) +void PNGAPI +png_set_iCCP(png_structp png_ptr, png_infop info_ptr, + png_charp name, int compression_type, + png_charp profile, png_uint_32 proflen) +{ + png_charp new_iccp_name; + png_charp new_iccp_profile; + + png_debug1(1, "in %s storage function\n", "iCCP"); + if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) + return; + + new_iccp_name = (png_charp)png_malloc(png_ptr, png_strlen(name)+1); + png_strcpy(new_iccp_name, name); + new_iccp_profile = (png_charp)png_malloc(png_ptr, proflen); + png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); + + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); + + info_ptr->iccp_proflen = proflen; + info_ptr->iccp_name = new_iccp_name; + info_ptr->iccp_profile = new_iccp_profile; + /* Compression is always zero but is here so the API and info structure + * does not have to change if we introduce multiple compression types */ + info_ptr->iccp_compression = (png_byte)compression_type; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_ICCP; +#endif + info_ptr->valid |= PNG_INFO_iCCP; +} +#endif + +#if defined(PNG_TEXT_SUPPORTED) +void PNGAPI +png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, + int num_text) +{ + int i; + + png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ? + "text" : (png_const_charp)png_ptr->chunk_name)); + + if (png_ptr == NULL || info_ptr == NULL || num_text == 0) + return; + + /* Make sure we have enough space in the "text" array in info_struct + * to hold all of the incoming text_ptr objects. + */ + if (info_ptr->num_text + num_text > info_ptr->max_text) + { + if (info_ptr->text != NULL) + { + png_textp old_text; + int old_max; + + old_max = info_ptr->max_text; + info_ptr->max_text = info_ptr->num_text + num_text + 8; + old_text = info_ptr->text; + info_ptr->text = (png_textp)png_malloc(png_ptr, + (png_uint_32)(info_ptr->max_text * sizeof (png_text))); + png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max * + sizeof(png_text))); + png_free(png_ptr, old_text); + } + else + { + info_ptr->max_text = num_text + 8; + info_ptr->num_text = 0; + info_ptr->text = (png_textp)png_malloc(png_ptr, + (png_uint_32)(info_ptr->max_text * sizeof (png_text))); +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_TEXT; +#endif + } + png_debug1(3, "allocated %d entries for info_ptr->text\n", + info_ptr->max_text); + } + for (i = 0; i < num_text; i++) + { + png_size_t text_length,key_len; + png_size_t lang_len,lang_key_len; + png_textp textp = &(info_ptr->text[info_ptr->num_text]); + + if (text_ptr[i].key == NULL) + continue; + + key_len = png_strlen(text_ptr[i].key); + + if(text_ptr[i].compression <= 0) + { + lang_len = 0; + lang_key_len = 0; + } + else +#ifdef PNG_iTXt_SUPPORTED + { + /* set iTXt data */ + if (text_ptr[i].key != NULL) + lang_len = png_strlen(text_ptr[i].lang); + else + lang_len = 0; + if (text_ptr[i].lang_key != NULL) + lang_key_len = png_strlen(text_ptr[i].lang_key); + else + lang_key_len = 0; + } +#else + { + png_warning(png_ptr, "iTXt chunk not supported."); + continue; + } +#endif + + if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') + { + text_length = 0; +#ifdef PNG_iTXt_SUPPORTED + if(text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + else +#endif + textp->compression = PNG_TEXT_COMPRESSION_NONE; + } + else + { + text_length = png_strlen(text_ptr[i].text); + textp->compression = text_ptr[i].compression; + } + + textp->key = (png_charp)png_malloc(png_ptr, + (png_uint_32)(key_len + text_length + lang_len + lang_key_len + 4)); + png_debug2(2, "Allocated %lu bytes at %x in png_set_text\n", + (png_uint_32)(key_len + lang_len + lang_key_len + text_length + 4), + (int)textp->key); + + png_memcpy(textp->key, text_ptr[i].key, + (png_size_t)(key_len)); + *(textp->key+key_len) = '\0'; +#ifdef PNG_iTXt_SUPPORTED + if (text_ptr[i].compression > 0) + { + textp->lang=textp->key + key_len + 1; + png_memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang+lang_len) = '\0'; + textp->lang_key=textp->lang + lang_len + 1; + png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key+lang_key_len) = '\0'; + textp->text=textp->lang_key + lang_key_len + 1; + } + else +#endif + { +#ifdef PNG_iTXt_SUPPORTED + textp->lang=(png_charp)NULL; + textp->lang_key=(png_charp)NULL; +#endif + textp->text=textp->key + key_len + 1; + } + if(text_length) + png_memcpy(textp->text, text_ptr[i].text, + (png_size_t)(text_length)); + *(textp->text+text_length) = '\0'; + +#ifdef PNG_iTXt_SUPPORTED + if(textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + else +#endif + { + textp->text_length = text_length; +#ifdef PNG_iTXt_SUPPORTED + textp->itxt_length = 0; +#endif + } + info_ptr->text[info_ptr->num_text]= *textp; + info_ptr->num_text++; + png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text); + } +} +#endif + +#if defined(PNG_tIME_SUPPORTED) +void PNGAPI +png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time) +{ + png_debug1(1, "in %s storage function\n", "tIME"); + if (png_ptr == NULL || info_ptr == NULL || + (png_ptr->mode & PNG_WROTE_tIME)) + return; + + png_memcpy(&(info_ptr->mod_time), mod_time, sizeof (png_time)); + info_ptr->valid |= PNG_INFO_tIME; +} +#endif + +#if defined(PNG_tRNS_SUPPORTED) +void PNGAPI +png_set_tRNS(png_structp png_ptr, png_infop info_ptr, + png_bytep trans, int num_trans, png_color_16p trans_values) +{ + png_debug1(1, "in %s storage function\n", "tRNS"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + if (trans != NULL) + { + /* + * It may not actually be necessary to set png_ptr->trans here; + * we do it for backward compatibility with the way the png_handle_tRNS + * function used to do the allocation. + */ +#ifdef PNG_FREE_ME_SUPPORTED + png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); +#endif + png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr, + num_trans); + png_memcpy(info_ptr->trans, trans, num_trans); +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_TRNS; +#else + png_ptr->flags |= PNG_FLAG_FREE_TRNS; +#endif + } + + if (trans_values != NULL) + { + png_memcpy(&(info_ptr->trans_values), trans_values, + sizeof(png_color_16)); + if (num_trans == 0) + num_trans = 1; + } + info_ptr->num_trans = (png_uint_16)num_trans; + info_ptr->valid |= PNG_INFO_tRNS; +} +#endif + +#if defined(PNG_sPLT_SUPPORTED) +void PNGAPI +png_set_sPLT(png_structp png_ptr, + png_infop info_ptr, png_sPLT_tp entries, int nentries) +{ + png_sPLT_tp np; + int i; + + np = (png_sPLT_tp)png_malloc(png_ptr, + (info_ptr->splt_palettes_num + nentries) * sizeof(png_sPLT_t)); + + png_memcpy(np, info_ptr->splt_palettes, + info_ptr->splt_palettes_num * sizeof(png_sPLT_t)); + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes=NULL; + + for (i = 0; i < nentries; i++) + { + png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; + png_sPLT_tp from = entries + i; + + to->name = (png_charp)png_malloc(png_ptr, + png_strlen(from->name) + 1); + png_strcpy(to->name, from->name); + to->entries = (png_sPLT_entryp)png_malloc(png_ptr, + from->nentries * sizeof(png_sPLT_t)); + png_memcpy(to->entries, from->entries, + from->nentries * sizeof(png_sPLT_t)); + to->nentries = from->nentries; + to->depth = from->depth; + } + + info_ptr->splt_palettes = np; + info_ptr->splt_palettes_num += nentries; + info_ptr->valid |= PNG_INFO_sPLT; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_SPLT; +#endif +} +#endif /* PNG_sPLT_SUPPORTED */ + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +void PNGAPI +png_set_unknown_chunks(png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + int i; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + return; + + np = (png_unknown_chunkp)png_malloc(png_ptr, + (info_ptr->unknown_chunks_num + num_unknowns) * + sizeof(png_unknown_chunk)); + + png_memcpy(np, info_ptr->unknown_chunks, + info_ptr->unknown_chunks_num * sizeof(png_unknown_chunk)); + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks=NULL; + + for (i = 0; i < num_unknowns; i++) + { + png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; + png_unknown_chunkp from = unknowns + i; + + png_strcpy((png_charp)to->name, (png_charp)from->name); + to->data = (png_bytep)png_malloc(png_ptr, from->size); + png_memcpy(to->data, from->data, from->size); + to->size = from->size; + + /* note our location in the read or write sequence */ + to->location = (png_byte)(png_ptr->mode & 0xff); + } + + info_ptr->unknown_chunks = np; + info_ptr->unknown_chunks_num += num_unknowns; +#ifdef PNG_FREE_ME_SUPPORTED + info_ptr->free_me |= PNG_FREE_UNKN; +#endif +} +void PNGAPI +png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, + int chunk, int location) +{ + if(png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < + (int)info_ptr->unknown_chunks_num) + info_ptr->unknown_chunks[chunk].location = (png_byte)location; +} +#endif + +#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +void PNGAPI +png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted) +{ + /* This function is deprecated in favor of png_permit_mng_features() + and will be removed from libpng-2.0.0 */ + png_debug(1, "in png_permit_empty_plte, DEPRECATED.\n"); + if (png_ptr == NULL) + return; + png_ptr->mng_features_permitted = (png_byte) + ((png_ptr->mng_features_permitted & (~(PNG_FLAG_MNG_EMPTY_PLTE))) | + ((empty_plte_permitted & PNG_FLAG_MNG_EMPTY_PLTE))); +} +#endif + +#if defined(PNG_MNG_FEATURES_SUPPORTED) +png_uint_32 PNGAPI +png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) +{ + png_debug(1, "in png_permit_mng_features\n"); + if (png_ptr == NULL) + return (png_uint_32)0; + png_ptr->mng_features_permitted = + (png_byte)(mng_features & PNG_ALL_MNG_FEATURES); + return (png_uint_32)png_ptr->mng_features_permitted; +} +#endif + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +void PNGAPI +png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep + chunk_list, int num_chunks) +{ + png_bytep new_list, p; + int i, old_num_chunks; + if (num_chunks == 0) + { + if(keep == HANDLE_CHUNK_ALWAYS || keep == HANDLE_CHUNK_IF_SAFE) + png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + + if(keep == HANDLE_CHUNK_ALWAYS) + png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; + return; + } + if (chunk_list == NULL) + return; + old_num_chunks=png_ptr->num_chunk_list; + new_list=(png_bytep)png_malloc(png_ptr,5*(num_chunks+old_num_chunks)); + if(png_ptr->chunk_list != NULL) + { + png_memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + } + png_memcpy(new_list+5*old_num_chunks, chunk_list, 5*num_chunks); + for (p=new_list+5*old_num_chunks+4, i=0; inum_chunk_list=old_num_chunks+num_chunks; + png_ptr->chunk_list=new_list; +#ifdef PNG_FREE_ME_SUPPORTED + png_ptr->free_me |= PNG_FREE_LIST; +#endif +} +#endif + +#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) +void PNGAPI +png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, + png_user_chunk_ptr read_user_chunk_fn) +{ + png_debug(1, "in png_set_read_user_chunk_fn\n"); + png_ptr->read_user_chunk_fn = read_user_chunk_fn; + png_ptr->user_chunk_ptr = user_chunk_ptr; +} +#endif + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +void PNGAPI +png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) +{ + png_debug1(1, "in %s storage function\n", "rows"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + if(info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); + info_ptr->row_pointers = row_pointers; + if(row_pointers) + info_ptr->valid |= PNG_INFO_IDAT; +} +#endif + +void PNGAPI +png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size) +{ + if(png_ptr->zbuf) + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf_size = (png_size_t)size; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; +} + +void PNGAPI +png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) +{ + if (png_ptr && info_ptr) + info_ptr->valid &= ~(mask); +} + + diff --git a/freeimage241/Source/LibPNG/pngtest.c b/freeimage241/Source/LibPNG/pngtest.c new file mode 100644 index 0000000..9b954b3 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngtest.c @@ -0,0 +1,1514 @@ + +/* pngtest.c - a simple test program to test libpng + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This program reads in a PNG image, writes it out again, and then + * compares the two files. If the files are identical, this shows that + * the basic chunk handling, filtering, and (de)compression code is working + * properly. It does not currently test all of the transforms, although + * it probably should. + * + * The program will report "FAIL" in certain legitimate cases: + * 1) when the compression level or filter selection method is changed. + * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. + * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks + * exist in the input file. + * 4) others not listed here... + * In these cases, it is best to check with another tool such as "pngcheck" + * to see what the differences between the two files are. + * + * If a filename is given on the command-line, then this file is used + * for the input, rather than the default "pngtest.png". This allows + * testing a wide variety of files easily. You can also test a number + * of files at once by typing "pngtest -m file1.png file2.png ..." + */ + +#if defined(_WIN32_WCE) +# if _WIN32_WCE < 211 + __error__ (f|w)printf functions are not supported on old WindowsCE.; +# endif +# include +# include +# define READFILE(file, data, length, check) \ + if (ReadFile(file, data, length, &check,NULL)) check = 0 +# define WRITEFILE(file, data, length, check)) \ + if (WriteFile(file, data, length, &check, NULL)) check = 0 +# define FCLOSE(file) CloseHandle(file) +#else +# include +# include +# include +# define READFILE(file, data, length, check) \ + check=(png_size_t)fread(data,(png_size_t)1,length,file) +# define WRITEFILE(file, data, length, check) \ + check=(png_size_t)fwrite(data,(png_size_t)1, length, file) +# define FCLOSE(file) fclose(file) +#endif + +#if defined(PNG_NO_STDIO) +# if defined(_WIN32_WCE) + typedef HANDLE png_FILE_p; +# else + typedef FILE * png_FILE_p; +# endif +#endif + +/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ +#ifndef PNG_DEBUG +# define PNG_DEBUG 0 +#endif + +#if !PNG_DEBUG +# define SINGLE_ROWBUF_ALLOC /* makes buffer overruns easier to nail */ +#endif + +/* Turn on CPU timing +#define PNGTEST_TIMING +*/ + +#ifdef PNG_NO_FLOATING_POINT_SUPPORTED +#undef PNGTEST_TIMING +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#include +#endif + +#include "png.h" + +/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) png_ptr->jmpbuf +#endif + +#ifdef PNGTEST_TIMING +static float t_start, t_stop, t_decode, t_encode, t_misc; +#if !defined(PNG_tIME_SUPPORTED) +#include +#endif +#endif + +#if defined(PNG_TIME_RFC1123_SUPPORTED) +static int tIME_chunk_present=0; +static char tIME_string[30] = "no tIME chunk present in file"; +#endif + +static int verbose = 0; + +int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); + +#ifdef __TURBOC__ +#include +#endif + +/* defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* for DOS */ + +/* example of using row callbacks to make a simple progress meter */ +static int status_pass=1; +static int status_dots_requested=0; +static int status_dots=1; + +void +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if(png_ptr == NULL || row_number > PNG_MAX_UINT) return; + if(status_pass != pass) + { + fprintf(stdout,"\n Pass %d: ",pass); + status_pass = pass; + status_dots = 31; + } + status_dots--; + if(status_dots == 0) + { + fprintf(stdout, "\n "); + status_dots=30; + } + fprintf(stdout, "r"); +} + +void +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); +void +write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return; + fprintf(stdout, "w"); +} + + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) +/* Example of using user transform callback (we don't transform anything, + but merely examine the row filters. We set this to 256 rather than + 5 in case illegal filter values are present.) */ +static png_uint_32 filters_used[256]; +void +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + if(png_ptr != NULL && row_info != NULL) + ++filters_used[*(data-1)]; +} +#endif + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +/* example of using user transform callback (we don't transform anything, + but merely count the zero samples) */ + +static png_uint_32 zero_samples; + +void +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); +void +count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) +{ + png_bytep dp = data; + if(png_ptr == NULL)return; + + /* contents of row_info: + * png_uint_32 width width of row + * png_uint_32 rowbytes number of bytes in row + * png_byte color_type color type of pixels + * png_byte bit_depth bit depth of samples + * png_byte channels number of channels (1-4) + * png_byte pixel_depth bits per pixel (depth*channels) + */ + + + /* counts the number of zero samples (or zero pixels if color_type is 3 */ + + if(row_info->color_type == 0 || row_info->color_type == 3) + { + int pos=0; + png_uint_32 n, nstop; + for (n=0, nstop=row_info->width; nbit_depth == 1) + { + if(((*dp << pos++ ) & 0x80) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 2) + { + if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 4) + { + if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++; + if(pos == 8) + { + pos = 0; + dp++; + } + } + if(row_info->bit_depth == 8) + if(*dp++ == 0) zero_samples++; + if(row_info->bit_depth == 16) + { + if((*dp | *(dp+1)) == 0) zero_samples++; + dp+=2; + } + } + } + else /* other color types */ + { + png_uint_32 n, nstop; + int channel; + int color_channels = row_info->channels; + if(row_info->color_type > 3)color_channels--; + + for (n=0, nstop=row_info->width; nbit_depth == 8) + if(*dp++ == 0) zero_samples++; + if(row_info->bit_depth == 16) + { + if((*dp | *(dp+1)) == 0) zero_samples++; + dp+=2; + } + } + if(row_info->color_type > 3) + { + dp++; + if(row_info->bit_depth == 16)dp++; + } + } + } +} +#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ + +static int wrote_question = 0; + +#if defined(PNG_NO_STDIO) +/* START of code to validate stdio-free compilation */ +/* These copies of the default read/write functions come from pngrio.c and */ +/* pngwio.c. They allow "don't include stdio" testing of the library. */ +/* This is the function that does the actual reading of data. If you are + not reading from a standard C stream, you should create a replacement + read_data function and use it at run time with png_set_read_fn(), rather + than changing the library. */ + +#ifndef USE_FAR_KEYWORD +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_size_t check; + + /* fread() returns 0 on error, so it is OK to store this in a png_size_t + * instead of an int, which is what fread() actually returns. + */ + READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); + + if (check != length) + { + png_error(png_ptr, "Read Error!"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + int check; + png_byte *n_data; + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + n_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)n_data == data) + { + READFILE(io_ptr, n_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t read, remaining, err; + check = 0; + remaining = length; + do + { + read = MIN(NEAR_BUF_SIZE, remaining); + READFILE(io_ptr, buf, 1, err); + png_memcpy(data, buf, read); /* copy far buffer to near buffer */ + if(err != read) + break; + else + check += err; + data += read; + remaining -= read; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "read Error"); + } +} +#endif /* USE_FAR_KEYWORD */ + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +static void +pngtest_flush(png_structp png_ptr) +{ +#if !defined(_WIN32_WCE) + png_FILE_p io_ptr; + io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +#endif +} +#endif + +/* This is the function that does the actual writing of data. If you are + not writing to a standard C stream, you should create a replacement + write_data function and use it at run time with png_set_write_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + + WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { + WRITEFILE(io_ptr, near_data, length, check); + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* copy far buffer to near buffer */ + WRITEFILE(io_ptr, buf, written, err); + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + { + png_error(png_ptr, "Write Error"); + } +} + +#endif /* USE_FAR_KEYWORD */ + +/* This function is called when there is a warning, but the library thinks + * it can continue anyway. Replacement functions don't have to do anything + * here if you don't want to. In the default configuration, png_ptr is + * not used, but it is passed in case it may be useful. + */ +static void +pngtest_warning(png_structp png_ptr, png_const_charp message) +{ + PNG_CONST char *name = "UNKNOWN (ERROR!)"; + if (png_ptr != NULL && png_ptr->error_ptr != NULL) + name = png_ptr->error_ptr; + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); +} + +/* This is the default error handling function. Note that replacements for + * this function MUST NOT RETURN, or the program will likely crash. This + * function is used by default, or if the program supplies NULL for the + * error function pointer in png_set_error_fn(). + */ +static void +pngtest_error(png_structp png_ptr, png_const_charp message) +{ + pngtest_warning(png_ptr, message); + /* We can return because png_error calls the default handler, which is + * actually OK in this case. */ +} +#endif /* PNG_NO_STDIO */ +/* END of code to validate stdio-free compilation */ + +/* START of code to validate memory allocation and deallocation */ +#ifdef PNG_USER_MEM_SUPPORTED + +/* Allocate memory. For reasonable files, size should never exceed + 64K. However, zlib may allocate more then 64K if you don't tell + it not to. See zconf.h and png.h for more information. zlib does + need to allocate exactly 64K, so whatever you call here must + have the ability to do that. + + This piece of code can be compiled to validate max 64K allocations + by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */ +typedef struct memory_information +{ + png_uint_32 size; + png_voidp pointer; + struct memory_information FAR *next; +} memory_information; +typedef memory_information FAR *memory_infop; + +static memory_infop pinformation = NULL; +static int current_allocation = 0; +static int maximum_allocation = 0; +static int total_allocation = 0; +static int num_allocations = 0; + +extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr, + png_uint_32 size)); +extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr, + png_voidp ptr)); + +png_voidp +png_debug_malloc(png_structp png_ptr, png_uint_32 size) +{ + + /* png_malloc has already tested for NULL; png_create_struct calls + png_debug_malloc directly, with png_ptr == NULL which is OK */ + + if (size == 0) + return (png_voidp)(NULL); + + /* This calls the library allocator twice, once to get the requested + buffer and once to get a new free list entry. */ + { + memory_infop pinfo = (memory_infop)png_malloc_default(png_ptr, + sizeof *pinfo); + pinfo->size = size; + current_allocation += size; + total_allocation += size; + num_allocations ++; + if (current_allocation > maximum_allocation) + maximum_allocation = current_allocation; + pinfo->pointer = (png_voidp)png_malloc_default(png_ptr, size); + pinfo->next = pinformation; + pinformation = pinfo; + /* Make sure the caller isn't assuming zeroed memory. */ + png_memset(pinfo->pointer, 0xdd, pinfo->size); +#if PNG_DEBUG + if(verbose) + printf("png_malloc %d bytes at %x\n",size,pinfo->pointer); +#endif + assert(pinfo->size != 12345678); + return (png_voidp)(pinfo->pointer); + } +} + +/* Free a pointer. It is removed from the list at the same time. */ +void +png_debug_free(png_structp png_ptr, png_voidp ptr) +{ + if (png_ptr == NULL) + fprintf(STDERR, "NULL pointer to png_debug_free.\n"); + if (ptr == 0) + { +#if 0 /* This happens all the time. */ + fprintf(STDERR, "WARNING: freeing NULL pointer\n"); +#endif + return; + } + + /* Unlink the element from the list. */ + { + memory_infop FAR *ppinfo = &pinformation; + for (;;) + { + memory_infop pinfo = *ppinfo; + if (pinfo->pointer == ptr) + { + *ppinfo = pinfo->next; + current_allocation -= pinfo->size; + if (current_allocation < 0) + fprintf(STDERR, "Duplicate free of memory\n"); + /* We must free the list element too, but first kill + the memory that is to be freed. */ + png_memset(ptr, 0x55, pinfo->size); + png_free_default(png_ptr, pinfo); + pinfo=NULL; + break; + } + if (pinfo->next == NULL) + { + fprintf(STDERR, "Pointer %x not found\n", ptr); + break; + } + ppinfo = &pinfo->next; + } + } + + /* Finally free the data. */ +#if PNG_DEBUG + if(verbose) + printf("Freeing %x\n",ptr); +#endif + png_free_default(png_ptr, ptr); + ptr=NULL; +} +#endif /* PNG_USER_MEM_SUPPORTED */ +/* END of code to test memory allocation/deallocation */ + +/* Test one file */ +int +test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) +{ + static png_FILE_p fpin; + static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + png_structp read_ptr; + png_infop read_info_ptr, end_info_ptr; +#ifdef PNG_WRITE_SUPPORTED + png_structp write_ptr; + png_infop write_info_ptr; + png_infop write_end_info_ptr; +#else + png_structp write_ptr = NULL; + png_infop write_info_ptr = NULL; + png_infop write_end_info_ptr = NULL; +#endif + png_bytep row_buf; + png_uint_32 y; + png_uint_32 width, height; + int num_pass, pass; + int bit_depth, color_type; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + +#if defined(_WIN32_WCE) + TCHAR path[MAX_PATH]; +#endif + char inbuf[256], outbuf[256]; + + row_buf = (png_bytep)NULL; + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find input file %s\n", inname); + return (1); + } + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "wb")) == NULL) +#endif + { + fprintf(STDERR, "Could not open output file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + png_debug(0, "Allocating read and write structures\n"); +#ifdef PNG_USER_MEM_SUPPORTED + read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, + (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, + (png_error_ptr)NULL, (png_error_ptr)NULL); +#endif +#if defined(PNG_NO_STDIO) + png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_USER_MEM_SUPPORTED + write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, + (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL, + (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); +#else + write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, + (png_error_ptr)NULL, (png_error_ptr)NULL); +#endif +#if defined(PNG_NO_STDIO) + png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, + pngtest_warning); +#endif +#endif + png_debug(0, "Allocating read_info, write_info and end_info structures\n"); + read_info_ptr = png_create_info_struct(read_ptr); + end_info_ptr = png_create_info_struct(read_ptr); +#ifdef PNG_WRITE_SUPPORTED + write_info_ptr = png_create_info_struct(write_ptr); + write_end_info_ptr = png_create_info_struct(write_ptr); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_debug(0, "Setting jmpbuf for read struct\n"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(read_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(read_ptr),jmpbuf,sizeof(jmp_buf)); +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "Setting jmpbuf for write struct\n"); +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(write_ptr))) +#endif + { + fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(write_ptr),jmpbuf,sizeof(jmp_buf)); +#endif +#endif +#endif + + png_debug(0, "Initializing input and output streams\n"); +#if !defined(PNG_NO_STDIO) + png_init_io(read_ptr, fpin); +# ifdef PNG_WRITE_SUPPORTED + png_init_io(write_ptr, fpout); +# endif +#else + png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); +# ifdef PNG_WRITE_SUPPORTED + png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, +# if defined(PNG_WRITE_FLUSH_SUPPORTED) + pngtest_flush); +# else + NULL); +# endif +# endif +#endif + if(status_dots_requested == 1) + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, write_row_callback); +#endif + png_set_read_status_fn(read_ptr, read_row_callback); + } + else + { +#ifdef PNG_WRITE_SUPPORTED + png_set_write_status_fn(write_ptr, NULL); +#endif + png_set_read_status_fn(read_ptr, NULL); + } + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + { + int i; + for(i=0; i<256; i++) + filters_used[i]=0; + png_set_read_user_transform_fn(read_ptr, count_filters); + } +#endif +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + zero_samples=0; + png_set_write_user_transform_fn(write_ptr, count_zero_samples); +#endif + +#define HANDLE_CHUNK_IF_SAFE 2 +#define HANDLE_CHUNK_ALWAYS 3 +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, NULL, 0); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, NULL, 0); +#endif + + png_debug(0, "Reading info struct\n"); + png_read_info(read_ptr, read_info_ptr); + + png_debug(0, "Transferring info struct\n"); + { + int interlace_type, compression_type, filter_type; + + if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, + &color_type, &interlace_type, &compression_type, &filter_type)) + { + png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + color_type, interlace_type, compression_type, filter_type); +#else + color_type, PNG_INTERLACE_NONE, compression_type, filter_type); +#endif + } + } +#if defined(PNG_FIXED_POINT_SUPPORTED) +#if defined(PNG_cHRM_SUPPORTED) + { + png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#if defined(PNG_gAMA_SUPPORTED) + { + png_fixed_point gamma; + + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) + { + png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); + } + } +#endif +#else /* Use floating point versions */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) +#if defined(PNG_cHRM_SUPPORTED) + { + double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, + blue_y; + if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y)) + { + png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, + red_y, green_x, green_y, blue_x, blue_y); + } + } +#endif +#if defined(PNG_gAMA_SUPPORTED) + { + double gamma; + + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) + { + png_set_gAMA(write_ptr, write_info_ptr, gamma); + } + } +#endif +#endif /* floating point */ +#endif /* fixed point */ +#if defined(PNG_iCCP_SUPPORTED) + { + png_charp name; + png_charp profile; + png_uint_32 proflen; + int compression_type; + + if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, + &profile, &proflen)) + { + png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, + profile, proflen); + } + } +#endif +#if defined(PNG_sRGB_SUPPORTED) + { + int intent; + + if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) + { + png_set_sRGB(write_ptr, write_info_ptr, intent); + } + } +#endif + { + png_colorp palette; + int num_palette; + + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) + { + png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); + } + } +#if defined(PNG_bKGD_SUPPORTED) + { + png_color_16p background; + + if (png_get_bKGD(read_ptr, read_info_ptr, &background)) + { + png_set_bKGD(write_ptr, write_info_ptr, background); + } + } +#endif +#if defined(PNG_hIST_SUPPORTED) + { + png_uint_16p hist; + + if (png_get_hIST(read_ptr, read_info_ptr, &hist)) + { + png_set_hIST(write_ptr, write_info_ptr, hist); + } + } +#endif +#if defined(PNG_oFFs_SUPPORTED) + { + png_int_32 offset_x, offset_y; + int unit_type; + + if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type)) + { + png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); + } + } +#endif +#if defined(PNG_pCAL_SUPPORTED) + { + png_charp purpose, units; + png_charpp params; + png_int_32 X0, X1; + int type, nparams; + + if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, + &nparams, &units, ¶ms)) + { + png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, + nparams, units, params); + } + } +#endif +#if defined(PNG_pHYs_SUPPORTED) + { + png_uint_32 res_x, res_y; + int unit_type; + + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) + { + png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); + } + } +#endif +#if defined(PNG_sBIT_SUPPORTED) + { + png_color_8p sig_bit; + + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) + { + png_set_sBIT(write_ptr, write_info_ptr, sig_bit); + } + } +#endif +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + { + int unit; + double scal_width, scal_height; + + if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + { + int unit; + png_charp scal_width, scal_height; + + if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, + &scal_height)) + { + png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } + } +#endif +#endif +#endif +#if defined(PNG_TEXT_SUPPORTED) + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text); + png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); + } + } +#endif +#if defined(PNG_tIME_SUPPORTED) + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_info_ptr, mod_time); +#if defined(PNG_TIME_RFC1123_SUPPORTED) + /* we have to use png_strcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time)); + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#if defined(PNG_tRNS_SUPPORTED) + { + png_bytep trans; + int num_trans; + png_color_16p trans_values; + + if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, + &trans_values)) + { + png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, + trans_values); + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, + num_unknowns); + /* copy the locations from the read_info_ptr. The automatically + generated locations in write_info_ptr are wrong because we + haven't written anything yet */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, + unknowns[i].location); + } + } +#endif + +#ifdef PNG_WRITE_SUPPORTED + png_debug(0, "\nWriting info struct\n"); + +/* If we wanted, we could write info in two steps: + png_write_info_before_PLTE(write_ptr, write_info_ptr); + */ + png_write_info(write_ptr, write_info_ptr); +#endif + +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(0, "\nAllocating row buffer..."); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf); +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(0, "Writing row data\n"); + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) + num_pass = png_set_interlace_handling(read_ptr); +# ifdef PNG_WRITE_SUPPORTED + png_set_interlace_handling(write_ptr); +# endif +#else + num_pass=1; +#endif + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; +#endif + for (pass = 0; pass < num_pass; pass++) + { + png_debug1(0, "Writing row data for pass %d\n",pass); + for (y = 0; y < height; y++) + { +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y); + row_buf = (png_bytep)png_malloc(read_ptr, + png_get_rowbytes(read_ptr, read_info_ptr)); + png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf, + png_get_rowbytes(read_ptr, read_info_ptr)); +#endif /* !SINGLE_ROWBUF_ALLOC */ + png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1); + +#ifdef PNG_WRITE_SUPPORTED +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_decode += (t_stop - t_start); + t_start = t_stop; +#endif + png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_encode += (t_stop - t_start); + t_start = t_stop; +#endif +#endif /* PNG_WRITE_SUPPORTED */ + +#ifndef SINGLE_ROWBUF_ALLOC + png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y); + png_free(read_ptr, row_buf); +#endif /* !SINGLE_ROWBUF_ALLOC */ + } + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); +#endif + + png_debug(0, "Reading and writing end_info data\n"); + + png_read_end(read_ptr, end_info_ptr); +#if defined(PNG_TEXT_SUPPORTED) + { + png_textp text_ptr; + int num_text; + + if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) + { + png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text); + png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); + } + } +#endif +#if defined(PNG_tIME_SUPPORTED) + { + png_timep mod_time; + + if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) + { + png_set_tIME(write_ptr, write_end_info_ptr, mod_time); +#if defined(PNG_TIME_RFC1123_SUPPORTED) + /* we have to use png_strcpy instead of "=" because the string + pointed to by png_convert_to_rfc1123() gets free'ed before + we use it */ + png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time)); + tIME_chunk_present++; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns; + num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, + num_unknowns); + /* copy the locations from the read_info_ptr. The automatically + generated locations in write_end_info_ptr are wrong because we + haven't written the end_info yet */ + for (i = 0; i < (png_size_t)num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, + unknowns[i].location); + } + } +#endif +#ifdef PNG_WRITE_SUPPORTED + png_write_end(write_ptr, write_end_info_ptr); +#endif + +#ifdef PNG_EASY_ACCESS_SUPPORTED + if(verbose) + { + png_uint_32 iwidth, iheight; + iwidth = png_get_image_width(write_ptr, write_info_ptr); + iheight = png_get_image_height(write_ptr, write_info_ptr); + fprintf(STDERR, "Image width = %lu, height = %lu\n", + iwidth, iheight); + } +#endif + + png_debug(0, "Destroying data structs\n"); +#ifdef SINGLE_ROWBUF_ALLOC + png_debug(1, "destroying row_buf for read_ptr\n"); + png_free(read_ptr, row_buf); + row_buf=NULL; +#endif /* SINGLE_ROWBUF_ALLOC */ + png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n"); + png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED + png_debug(1, "destroying write_end_info_ptr\n"); + png_destroy_info_struct(write_ptr, &write_end_info_ptr); + png_debug(1, "destroying write_ptr, write_info_ptr\n"); + png_destroy_write_struct(&write_ptr, &write_info_ptr); +#endif + png_debug(0, "Destruction complete.\n"); + + FCLOSE(fpin); + FCLOSE(fpout); + + png_debug(0, "Opening files for comparison\n"); +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); + if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpin = fopen(inname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", inname); + return (1); + } + +#if defined(_WIN32_WCE) + MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); + if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) +#else + if ((fpout = fopen(outname, "rb")) == NULL) +#endif + { + fprintf(STDERR, "Could not find file %s\n", outname); + FCLOSE(fpin); + return (1); + } + + for(;;) + { + png_size_t num_in, num_out; + + READFILE(fpin, inbuf, 1, num_in); + READFILE(fpout, outbuf, 1, num_out); + + if (num_in != num_out) + { + fprintf(STDERR, "\nFiles %s and %s are of a different size\n", + inname, outname); + if(wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname,PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question=1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + + if (!num_in) + break; + + if (png_memcmp(inbuf, outbuf, num_in)) + { + fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); + if(wrote_question == 0) + { + fprintf(STDERR, + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname,PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question=1; + } + FCLOSE(fpin); + FCLOSE(fpout); + return (0); + } + } + + FCLOSE(fpin); + FCLOSE(fpout); + + return (0); +} + +/* input and output filenames */ +#ifdef RISCOS +static PNG_CONST char *inname = "pngtest/png"; +static PNG_CONST char *outname = "pngout/png"; +#else +static PNG_CONST char *inname = "pngtest.png"; +static PNG_CONST char *outname = "pngout.png"; +#endif + +int +main(int argc, char *argv[]) +{ + int multiple = 0; + int ierror = 0; + + fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); + fprintf(STDERR,"%s",png_get_copyright(NULL)); + /* Show the version of libpng used in building the library */ + fprintf(STDERR," library (%lu):%s", png_access_version_number(), + png_get_header_version(NULL)); + /* Show the version of libpng used in building the application */ + fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, + PNG_HEADER_VERSION_STRING); + fprintf(STDERR," sizeof(png_struct)=%d, sizeof(png_info)=%d\n", + sizeof(png_struct), sizeof(png_info)); + + /* Do some consistency checking on the memory allocation settings, I'm + not sure this matters, but it is nice to know, the first of these + tests should be impossible because of the way the macros are set + in pngconf.h */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); +#endif + /* I think the following can happen. */ +#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) + fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); +#endif + + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) + { + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); + ++ierror; + } + + if (argc > 1) + { + if (strcmp(argv[1], "-m") == 0) + { + multiple = 1; + status_dots_requested = 0; + } + else if (strcmp(argv[1], "-mv") == 0 || + strcmp(argv[1], "-vm") == 0 ) + { + multiple = 1; + verbose = 1; + status_dots_requested = 1; + } + else if (strcmp(argv[1], "-v") == 0) + { + verbose = 1; + status_dots_requested = 1; + inname = argv[2]; + } + else + { + inname = argv[1]; + status_dots_requested = 0; + } + } + + if (!multiple && argc == 3+verbose) + outname = argv[2+verbose]; + + if ((!multiple && argc > 3+verbose) || (multiple && argc < 2)) + { + fprintf(STDERR, + "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", + argv[0], argv[0]); + fprintf(STDERR, + " reads/writes one PNG file (without -m) or multiple files (-m)\n"); + fprintf(STDERR, + " with -m %s is used as a temporary file\n", outname); + exit(1); + } + + if (multiple) + { + int i; +#ifdef PNG_USER_MEM_SUPPORTED + int allocation_now = current_allocation; +#endif + for (i=2; isize, pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#ifdef PNG_USER_MEM_SUPPORTED + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + else + { + int i; + for (i=0; i<3; ++i) + { + int kerror; +#ifdef PNG_USER_MEM_SUPPORTED + int allocation_now = current_allocation; +#endif + if (i == 1) status_dots_requested = 1; + else if(verbose == 0)status_dots_requested = 0; + if (i == 0 || verbose == 1 || ierror != 0) + fprintf(STDERR, "Testing %s:",inname); + kerror = test_one_file(inname, outname); + if(kerror == 0) + { + if(verbose == 1 || i == 2) + { +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + int k; +#endif +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples); +#else + fprintf(STDERR, " PASS\n"); +#endif +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) + for (k=0; k<256; k++) + if(filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k,filters_used[k]); +#endif +#if defined(PNG_TIME_RFC1123_SUPPORTED) + if(tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n",tIME_string); +#endif /* PNG_TIME_RFC1123_SUPPORTED */ + } + } + else + { + if(verbose == 0 && i != 2) + fprintf(STDERR, "Testing %s:",inname); + fprintf(STDERR, " FAIL\n"); + ierror += kerror; + } +#ifdef PNG_USER_MEM_SUPPORTED + if (allocation_now != current_allocation) + fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", + current_allocation-allocation_now); + if (current_allocation != 0) + { + memory_infop pinfo = pinformation; + + fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", + current_allocation); + while (pinfo != NULL) + { + fprintf(STDERR," %d bytes at %x\n", + pinfo->size, pinfo->pointer); + pinfo = pinfo->next; + } + } +#endif + } +#ifdef PNG_USER_MEM_SUPPORTED + fprintf(STDERR, " Current memory allocation: %10d bytes\n", + current_allocation); + fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", + maximum_allocation); + fprintf(STDERR, " Total memory allocation: %10d bytes\n", + total_allocation); + fprintf(STDERR, " Number of allocations: %10d\n", + num_allocations); +#endif + } + +#ifdef PNGTEST_TIMING + t_stop = (float)clock(); + t_misc += (t_stop - t_start); + t_start = t_stop; + fprintf(STDERR," CPU time used = %.3f seconds", + (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); + fprintf(STDERR," (decoding %.3f,\n", + t_decode/(float)CLOCKS_PER_SEC); + fprintf(STDERR," encoding %.3f ,", + t_encode/(float)CLOCKS_PER_SEC); + fprintf(STDERR," other %.3f seconds)\n\n", + t_misc/(float)CLOCKS_PER_SEC); +#endif + + if (ierror == 0) + fprintf(STDERR, "libpng passes test\n"); + else + fprintf(STDERR, "libpng FAILS test\n"); + return (int)(ierror != 0); +} + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef version_1_0_12 your_png_h_is_not_version_1_0_12; diff --git a/freeimage241/Source/LibPNG/pngtrans.c b/freeimage241/Source/LibPNG/pngtrans.c new file mode 100644 index 0000000..3e757c1 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngtrans.c @@ -0,0 +1,611 @@ + +/* pngtrans.c - transforms the data in a row (used by both readers and writers) + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* turn on BGR-to-RGB mapping */ +void PNGAPI +png_set_bgr(png_structp png_ptr) +{ + png_debug(1, "in png_set_bgr\n"); + png_ptr->transformations |= PNG_BGR; +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* turn on 16 bit byte swapping */ +void PNGAPI +png_set_swap(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap\n"); + if (png_ptr->bit_depth == 16) + png_ptr->transformations |= PNG_SWAP_BYTES; +} +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* turn on pixel packing */ +void PNGAPI +png_set_packing(png_structp png_ptr) +{ + png_debug(1, "in png_set_packing\n"); + if (png_ptr->bit_depth < 8) + { + png_ptr->transformations |= PNG_PACK; + png_ptr->usr_bit_depth = 8; + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* turn on packed pixel swapping */ +void PNGAPI +png_set_packswap(png_structp png_ptr) +{ + png_debug(1, "in png_set_packswap\n"); + if (png_ptr->bit_depth < 8) + png_ptr->transformations |= PNG_PACKSWAP; +} +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +void PNGAPI +png_set_shift(png_structp png_ptr, png_color_8p true_bits) +{ + png_debug(1, "in png_set_shift\n"); + png_ptr->transformations |= PNG_SHIFT; + png_ptr->shift = *true_bits; +} +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +int PNGAPI +png_set_interlace_handling(png_structp png_ptr) +{ + png_debug(1, "in png_set_interlace handling\n"); + if (png_ptr->interlaced) + { + png_ptr->transformations |= PNG_INTERLACE; + return (7); + } + + return (1); +} +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte on read, or remove a filler or alpha byte on write. + * The filler type has changed in v0.95 to allow future 2-byte fillers + * for 48-bit input data, as well as to avoid problems with some compilers + * that don't like bytes as parameters. + */ +void PNGAPI +png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) +{ + png_debug(1, "in png_set_filler\n"); + png_ptr->transformations |= PNG_FILLER; + png_ptr->filler = (png_byte)filler; + if (filler_loc == PNG_FILLER_AFTER) + png_ptr->flags |= PNG_FLAG_FILLER_AFTER; + else + png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; + + /* This should probably go in the "do_filler" routine. + * I attempted to do that in libpng-1.0.1a but that caused problems + * so I restored it in libpng-1.0.2a + */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + { + png_ptr->usr_channels = 4; + } + + /* Also I added this in libpng-1.0.2a (what happens when we expand + * a less-than-8-bit grayscale to GA? */ + + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + } +} +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void PNGAPI +png_set_swap_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_swap_alpha\n"); + png_ptr->transformations |= PNG_SWAP_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void PNGAPI +png_set_invert_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_alpha\n"); + png_ptr->transformations |= PNG_INVERT_ALPHA; +} +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +void PNGAPI +png_set_invert_mono(png_structp png_ptr) +{ + png_debug(1, "in png_set_invert_mono\n"); + png_ptr->transformations |= PNG_INVERT_MONO; +} + +/* invert monochrome grayscale data */ +void /* PRIVATE */ +png_do_invert(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_invert\n"); + if (row_info->bit_depth == 1 && +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->color_type == PNG_COLOR_TYPE_GRAY) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(~(*rp)); + rp++; + } + } +} +#endif + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* swaps byte order on 16 bit depth images */ +void /* PRIVATE */ +png_do_swap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_swap\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->bit_depth == 16) + { + png_bytep rp = row; + png_uint_32 i; + png_uint_32 istop= row_info->width * row_info->channels; + + for (i = 0; i < istop; i++, rp += 2) + { + png_byte t = *rp; + *rp = *(rp + 1); + *(rp + 1) = t; + } + } +} +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) +static png_byte onebppswaptable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +static png_byte twobppswaptable[256] = { + 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, + 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, + 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, + 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, + 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, + 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, + 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, + 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, + 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, + 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, + 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, + 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, + 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, + 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, + 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, + 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, + 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, + 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, + 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, + 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, + 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, + 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, + 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, + 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, + 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, + 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, + 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, + 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, + 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, + 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, + 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, + 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF +}; + +static png_byte fourbppswaptable[256] = { + 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, + 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, + 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, + 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, + 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, + 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, + 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, + 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, + 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, + 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, + 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, + 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, + 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, + 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, + 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, + 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, + 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, + 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, + 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, + 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, + 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, + 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, + 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, + 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, + 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, + 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, + 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, + 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF +}; + +/* swaps pixel packing order within bytes */ +void /* PRIVATE */ +png_do_packswap(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_packswap\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->bit_depth < 8) + { + png_bytep rp, end, table; + + end = row + row_info->rowbytes; + + if (row_info->bit_depth == 1) + table = onebppswaptable; + else if (row_info->bit_depth == 2) + table = twobppswaptable; + else if (row_info->bit_depth == 4) + table = fourbppswaptable; + else + return; + + for (rp = row; rp < end; rp++) + *rp = table[*rp]; + } +} +#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +/* remove filler or alpha byte(s) */ +void /* PRIVATE */ +png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags) +{ + png_debug(1, "in png_do_strip_filler\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { +/* + if (row_info->color_type == PNG_COLOR_TYPE_RGB || + row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) +*/ + png_bytep sp=row; + png_bytep dp=row; + png_uint_32 row_width=row_info->width; + png_uint_32 i; + + if (row_info->channels == 4) + { + if (row_info->bit_depth == 8) + { + /* This converts from RGBX or RGBA to RGB */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + dp+=3; sp+=4; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp++; + } + } + /* This converts from XRGB or ARGB to RGB */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 24; + row_info->rowbytes = row_width * 3; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */ + sp += 8; dp += 6; + for (i = 1; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */ + for (i = 0; i < row_width; i++) + { + /* This could be (although png_memcpy is probably slower): + png_memcpy(dp, sp, 6); + sp += 8; + dp += 6; + */ + + sp+=2; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 48; + row_info->rowbytes = row_width * 6; + } + row_info->channels = 3; + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + } +/* + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) +*/ + else if (row_info->channels == 2) + { + if (row_info->bit_depth == 8) + { + /* This converts from GX or GA to G */ + if (flags & PNG_FLAG_FILLER_AFTER) + { + for (i = 0; i < row_width; i++) + { + *dp++ = *sp++; + sp++; + } + } + /* This converts from XG or AG to G */ + else + { + for (i = 0; i < row_width; i++) + { + sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; + } + else /* if (row_info->bit_depth == 16) */ + { + if (flags & PNG_FLAG_FILLER_AFTER) + { + /* This converts from GGXX or GGAA to GG */ + sp += 4; dp += 2; + for (i = 1; i < row_width; i++) + { + *dp++ = *sp++; + *dp++ = *sp++; + sp += 2; + } + } + else + { + /* This converts from XXGG or AAGG to GG */ + for (i = 0; i < row_width; i++) + { + sp += 2; + *dp++ = *sp++; + *dp++ = *sp++; + } + } + row_info->pixel_depth = 16; + row_info->rowbytes = row_width * 2; + } + row_info->channels = 1; + row_info->color_type &= ~PNG_COLOR_MASK_ALPHA; + } + } +} +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* swaps red and blue bytes within a pixel */ +void /* PRIVATE */ +png_do_bgr(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_bgr\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 3) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 4) + { + png_byte save = *rp; + *rp = *(rp + 2); + *(rp + 2) = save; + } + } + } + else if (row_info->bit_depth == 16) + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 6) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + png_bytep rp; + png_uint_32 i; + + for (i = 0, rp = row; i < row_width; i++, rp += 8) + { + png_byte save = *rp; + *rp = *(rp + 4); + *(rp + 4) = save; + save = *(rp + 1); + *(rp + 1) = *(rp + 5); + *(rp + 5) = save; + } + } + } + } +} +#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_LEGACY_SUPPORTED) +void PNGAPI +png_set_user_transform_info(png_structp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) +{ + png_debug(1, "in png_set_user_transform_info\n"); +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + png_ptr->user_transform_ptr = user_transform_ptr; + png_ptr->user_transform_depth = (png_byte)user_transform_depth; + png_ptr->user_transform_channels = (png_byte)user_transform_channels; +#else + if(user_transform_ptr || user_transform_depth || user_transform_channels) + png_warning(png_ptr, + "This version of libpng does not support user transform info"); +#endif +} +#endif + +/* This function returns a pointer to the user_transform_ptr associated with + * the user transform functions. The application should free any memory + * associated with this pointer before png_write_destroy and png_read_destroy + * are called. + */ +png_voidp PNGAPI +png_get_user_transform_ptr(png_structp png_ptr) +{ +#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) + return ((png_voidp)png_ptr->user_transform_ptr); +#else + if(png_ptr) + return (NULL); + return (NULL); +#endif +} + diff --git a/freeimage241/Source/LibPNG/pngvcrd.c b/freeimage241/Source/LibPNG/pngvcrd.c new file mode 100644 index 0000000..f464f34 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngvcrd.c @@ -0,0 +1,3836 @@ +/* pngvcrd.c - mixed C/assembler version of utilities to read a PNG file + * + * For Intel x86 CPU and Microsoft Visual C++ compiler + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * Copyright (c) 1998, Intel Corporation + * + * Contributed by Nirav Chhatrapati, Intel Corporation, 1998 + * Interface to libpng contributed by Gilles Vollant, 1999 + * Debugging and cleanup by Greg Roelofs, 2000, 2001 + * + * In png_do_read_interlace() in libpng versions 1.0.3a through 1.0.4d, + * a sign error in the post-MMX cleanup code for each pixel_depth resulted + * in bad pixels at the beginning of some rows of some images, and also + * (due to out-of-range memory reads and writes) caused heap corruption + * when compiled with MSVC 6.0. The error was fixed in version 1.0.4e. + * + * [png_read_filter_row_mmx_avg() bpp == 2 bugfix, GRR 20000916] + * + */ + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD) + +static int mmx_supported=2; + + +int PNGAPI +png_mmx_support(void) +{ + int mmx_supported_local = 0; + _asm { + push ebx //CPUID will trash these + push ecx + push edx + pushfd //Save Eflag to stack + pop eax //Get Eflag from stack into eax + mov ecx, eax //Make another copy of Eflag in ecx + xor eax, 0x200000 //Toggle ID bit in Eflag [i.e. bit(21)] + push eax //Save modified Eflag back to stack + + popfd //Restored modified value back to Eflag reg + pushfd //Save Eflag to stack + pop eax //Get Eflag from stack + xor eax, ecx //Compare the new Eflag with the original Eflag + jz NOT_SUPPORTED //If the same, CPUID instruction is not supported, + //skip following instructions and jump to + //NOT_SUPPORTED label + + xor eax, eax //Set eax to zero + + _asm _emit 0x0f //CPUID instruction (two bytes opcode) + _asm _emit 0xa2 + + cmp eax, 1 //make sure eax return non-zero value + jl NOT_SUPPORTED //If eax is zero, mmx not supported + + xor eax, eax //set eax to zero + inc eax //Now increment eax to 1. This instruction is + //faster than the instruction "mov eax, 1" + + _asm _emit 0x0f //CPUID instruction + _asm _emit 0xa2 + + and edx, 0x00800000 //mask out all bits but mmx bit(24) + cmp edx, 0 // 0 = mmx not supported + jz NOT_SUPPORTED // non-zero = Yes, mmx IS supported + + mov mmx_supported_local, 1 //set return value to 1 + +NOT_SUPPORTED: + mov eax, mmx_supported_local //move return value to eax + pop edx //CPUID trashed these + pop ecx + pop ebx + } + + //mmx_supported_local=0; // test code for force don't support MMX + //printf("MMX : %u (1=MMX supported)\n",mmx_supported_local); + + mmx_supported = mmx_supported_local; + return mmx_supported_local; +} + +/* Combines the row recently read in with the previous row. + This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined; a + zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. If + you want all pixels to be combined, pass 0xff (255) in mask. */ + +/* Use this routine for x86 platform - uses faster MMX routine if machine + supports MMX */ + +void /* PRIVATE */ +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1,"in png_combine_row_asm\n"); + + if (mmx_supported == 2) { + png_mmx_support(); + } + + if (mask == 0xff) + { + png_memcpy(row, png_ptr->row_buf + 1, + (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3)); + } + /* GRR: add "else if (mask == 0)" case? + * or does png_combine_row() not even get called in that case? */ + else + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + int s_inc, s_start, s_end; + int m; + int shift; + png_uint_32 i; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x1; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 2: + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x3; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 4: + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 8: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int m; + int diff, unmask; + + __int64 mask0=0x0102040810204080; + + if ( mmx_supported ) + { + srcptr = png_ptr->row_buf + 1; + dstptr = row; + m = 0x80; + unmask = ~mask; + len = png_ptr->width &~7; //reduce to multiple of 8 + diff = png_ptr->width & 7; //amount lost + + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + + pand mm0,mm7 //nonzero if keep byte + pcmpeqb mm0,mm6 //zeros->1s, v versa + + mov ecx,len //load length of line (pixels) + mov esi,srcptr //load source + mov ebx,dstptr //load dest + cmp ecx,0 //lcr + je mainloop8end + +mainloop8: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + pandn mm6,[ebx] + por mm4,mm6 + movq [ebx],mm4 + + add esi,8 //inc by 8 bytes processed + add ebx,8 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop8 +mainloop8end: + + mov ecx,diff + cmp ecx,0 + jz end8 + + mov edx,mask + sal edx,24 //make low byte the high byte + +secondloop8: + sal edx,1 //move high bit to CF + jnc skip8 //if CF = 0 + mov al,[esi] + mov [ebx],al +skip8: + inc esi + inc ebx + + dec ecx + jnz secondloop8 +end8: + emms + } + } + else /* mmx not supported - use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + if (pixel_bytes > (png_size_t)(final_val-i)) + pixel_bytes = (png_size_t)(final_val-i); + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 8 bpp + + case 16: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + __int64 mask1=0x0101020204040808, + mask0=0x1010202040408080; + + if ( mmx_supported ) + { + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + + pand mm0,mm7 + pand mm1,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + cmp ecx,0 //lcr + jz mainloop16end + +mainloop16: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + movq mm7,[ebx] + pandn mm6,mm7 + por mm4,mm6 + movq [ebx],mm4 + + movq mm5,[esi+8] + pand mm5,mm1 + movq mm7,mm1 + movq mm6,[ebx+8] + pandn mm7,mm6 + por mm5,mm7 + movq [ebx+8],mm5 + + add esi,16 //inc by 16 bytes processed + add ebx,16 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop16 + +mainloop16end: + mov ecx,diff + cmp ecx,0 + jz end16 + + mov edx,mask + sal edx,24 //make low byte the high byte +secondloop16: + sal edx,1 //move high bit to CF + jnc skip16 //if CF = 0 + mov ax,[esi] + mov [ebx],ax +skip16: + add esi,2 + add ebx,2 + + dec ecx + jnz secondloop16 +end16: + emms + } + } + else /* mmx not supported - use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + if (pixel_bytes > (png_size_t)(final_val-i)) + pixel_bytes = (png_size_t)(final_val-i); + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 16 bpp + + case 24: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + + __int64 mask2=0x0101010202020404, //24bpp + mask1=0x0408080810101020, + mask0=0x2020404040808080; + + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + + if ( mmx_supported ) + { + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + movq mm2,mask2 + + pand mm0,mm7 + pand mm1,mm7 + pand mm2,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + pcmpeqb mm2,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + cmp ecx,0 + jz mainloop24end + +mainloop24: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + movq mm7,[ebx] + pandn mm6,mm7 + por mm4,mm6 + movq [ebx],mm4 + + + movq mm5,[esi+8] + pand mm5,mm1 + movq mm7,mm1 + movq mm6,[ebx+8] + pandn mm7,mm6 + por mm5,mm7 + movq [ebx+8],mm5 + + movq mm6,[esi+16] + pand mm6,mm2 + movq mm4,mm2 + movq mm7,[ebx+16] + pandn mm4,mm7 + por mm6,mm4 + movq [ebx+16],mm6 + + add esi,24 //inc by 24 bytes processed + add ebx,24 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop24 + +mainloop24end: + mov ecx,diff + cmp ecx,0 + jz end24 + + mov edx,mask + sal edx,24 //make low byte the high byte +secondloop24: + sal edx,1 //move high bit to CF + jnc skip24 //if CF = 0 + mov ax,[esi] + mov [ebx],ax + xor eax,eax + mov al,[esi+2] + mov [ebx+2],al +skip24: + add esi,3 + add ebx,3 + + dec ecx + jnz secondloop24 + +end24: + emms + } + } + else /* mmx not supported - use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + if (pixel_bytes > (png_size_t)(final_val-i)) + pixel_bytes = (png_size_t)(final_val-i); + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 24 bpp + + case 32: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + + __int64 mask3=0x0101010102020202, //32bpp + mask2=0x0404040408080808, + mask1=0x1010101020202020, + mask0=0x4040404080808080; + + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + + if ( mmx_supported ) + { + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + movq mm2,mask2 + movq mm3,mask3 + + pand mm0,mm7 + pand mm1,mm7 + pand mm2,mm7 + pand mm3,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + pcmpeqb mm2,mm6 + pcmpeqb mm3,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + + cmp ecx,0 //lcr + jz mainloop32end + +mainloop32: + movq mm4,[esi] + pand mm4,mm0 + movq mm6,mm0 + movq mm7,[ebx] + pandn mm6,mm7 + por mm4,mm6 + movq [ebx],mm4 + + movq mm5,[esi+8] + pand mm5,mm1 + movq mm7,mm1 + movq mm6,[ebx+8] + pandn mm7,mm6 + por mm5,mm7 + movq [ebx+8],mm5 + + movq mm6,[esi+16] + pand mm6,mm2 + movq mm4,mm2 + movq mm7,[ebx+16] + pandn mm4,mm7 + por mm6,mm4 + movq [ebx+16],mm6 + + movq mm7,[esi+24] + pand mm7,mm3 + movq mm5,mm3 + movq mm4,[ebx+24] + pandn mm5,mm4 + por mm7,mm5 + movq [ebx+24],mm7 + + add esi,32 //inc by 32 bytes processed + add ebx,32 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop32 + +mainloop32end: + mov ecx,diff + cmp ecx,0 + jz end32 + + mov edx,mask + sal edx,24 //make low byte the high byte +secondloop32: + sal edx,1 //move high bit to CF + jnc skip32 //if CF = 0 + mov eax,[esi] + mov [ebx],eax +skip32: + add esi,4 + add ebx,4 + + dec ecx + jnz secondloop32 + +end32: + emms + } + } + else /* mmx _not supported - Use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + if (pixel_bytes > (png_size_t)(final_val-i)) + pixel_bytes = (png_size_t)(final_val-i); + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 32 bpp + + case 48: + { + png_bytep srcptr; + png_bytep dstptr; + png_uint_32 len; + int unmask, diff; + + __int64 mask5=0x0101010101010202, + mask4=0x0202020204040404, + mask3=0x0404080808080808, + mask2=0x1010101010102020, + mask1=0x2020202040404040, + mask0=0x4040808080808080; + + if ( mmx_supported ) + { + srcptr = png_ptr->row_buf + 1; + dstptr = row; + + unmask = ~mask; + len = (png_ptr->width)&~7; + diff = (png_ptr->width)&7; + _asm + { + movd mm7, unmask //load bit pattern + psubb mm6,mm6 //zero mm6 + punpcklbw mm7,mm7 + punpcklwd mm7,mm7 + punpckldq mm7,mm7 //fill register with 8 masks + + movq mm0,mask0 + movq mm1,mask1 + movq mm2,mask2 + movq mm3,mask3 + movq mm4,mask4 + movq mm5,mask5 + + pand mm0,mm7 + pand mm1,mm7 + pand mm2,mm7 + pand mm3,mm7 + pand mm4,mm7 + pand mm5,mm7 + + pcmpeqb mm0,mm6 + pcmpeqb mm1,mm6 + pcmpeqb mm2,mm6 + pcmpeqb mm3,mm6 + pcmpeqb mm4,mm6 + pcmpeqb mm5,mm6 + + mov ecx,len //load length of line + mov esi,srcptr //load source + mov ebx,dstptr //load dest + + cmp ecx,0 + jz mainloop48end + +mainloop48: + movq mm7,[esi] + pand mm7,mm0 + movq mm6,mm0 + pandn mm6,[ebx] + por mm7,mm6 + movq [ebx],mm7 + + movq mm6,[esi+8] + pand mm6,mm1 + movq mm7,mm1 + pandn mm7,[ebx+8] + por mm6,mm7 + movq [ebx+8],mm6 + + movq mm6,[esi+16] + pand mm6,mm2 + movq mm7,mm2 + pandn mm7,[ebx+16] + por mm6,mm7 + movq [ebx+16],mm6 + + movq mm7,[esi+24] + pand mm7,mm3 + movq mm6,mm3 + pandn mm6,[ebx+24] + por mm7,mm6 + movq [ebx+24],mm7 + + movq mm6,[esi+32] + pand mm6,mm4 + movq mm7,mm4 + pandn mm7,[ebx+32] + por mm6,mm7 + movq [ebx+32],mm6 + + movq mm7,[esi+40] + pand mm7,mm5 + movq mm6,mm5 + pandn mm6,[ebx+40] + por mm7,mm6 + movq [ebx+40],mm7 + + add esi,48 //inc by 32 bytes processed + add ebx,48 + sub ecx,8 //dec by 8 pixels processed + + ja mainloop48 +mainloop48end: + + mov ecx,diff + cmp ecx,0 + jz end48 + + mov edx,mask + sal edx,24 //make low byte the high byte + +secondloop48: + sal edx,1 //move high bit to CF + jnc skip48 //if CF = 0 + mov eax,[esi] + mov [ebx],eax +skip48: + add esi,4 + add ebx,4 + + dec ecx + jnz secondloop48 + +end48: + emms + } + } + else /* mmx _not supported - Use modified C routine */ + { + register unsigned int incr1, initial_val, final_val; + png_size_t pixel_bytes; + png_uint_32 i; + register int disp = png_pass_inc[png_ptr->pass]; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dstptr = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + if (pixel_bytes > (png_size_t)(final_val-i)) + pixel_bytes = (png_size_t)(final_val-i); + png_memcpy(dstptr, srcptr, pixel_bytes); + srcptr += incr1; + dstptr += incr1; + } + } /* end of else */ + + break; + } // end 48 bpp + + default: + { + png_bytep sptr; + png_bytep dp; + png_size_t pixel_bytes; + int offset_table[7] = {0, 4, 0, 2, 0, 1, 0}; + unsigned int i; + register int disp = png_pass_inc[png_ptr->pass]; // get the offset + register unsigned int incr1, initial_val, final_val; + + pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); + sptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]* + pixel_bytes; + dp = row + offset_table[png_ptr->pass]*pixel_bytes; + initial_val = offset_table[png_ptr->pass]*pixel_bytes; + final_val = png_ptr->width*pixel_bytes; + incr1 = (disp)*pixel_bytes; + for (i = initial_val; i < final_val; i += incr1) + { + if (pixel_bytes > (png_size_t)(final_val-i)) + pixel_bytes = (png_size_t)(final_val-i); + png_memcpy(dp, sptr, pixel_bytes); + sptr += incr1; + dp += incr1; + } + break; + } + } /* end switch (png_ptr->row_info.pixel_depth) */ + } /* end if (non-trivial mask) */ + +} /* end png_combine_row() */ + + +#if defined(PNG_READ_INTERLACING_SUPPORTED) + +void /* PRIVATE */ +png_do_read_interlace(png_structp png_ptr) +{ + png_row_infop row_info = &(png_ptr->row_info); + png_bytep row = png_ptr->row_buf + 1; + int pass = png_ptr->pass; + png_uint_32 transformations = png_ptr->transformations; +#ifdef PNG_USE_LOCAL_ARRAYS + const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1,"in png_do_read_interlace\n"); + + if (mmx_supported == 2) { + png_mmx_support(); + } + + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_byte v; + png_uint_32 i; + int j; + + sp = row + (png_size_t)((row_info->width - 1) >> 3); + dp = row + (png_size_t)((final_width - 1) >> 3); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 7); + dshift = (int)((final_width + 7) & 7); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 7); + dshift = 7 - (int)((final_width + 7) & 7); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = row_info->width; i; i--) + { + v = (png_byte)((*sp >> sshift) & 0x1); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 2: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 2); + dp = row + (png_size_t)((final_width - 1) >> 2); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 3) & 3) << 1); + dshift = (png_size_t)(((final_width + 3) & 3) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1); + dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 4: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 1); + dp = row + (png_size_t)((final_width - 1) >> 1); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 1) & 1) << 2); + dshift = (png_size_t)(((final_width + 1) & 1) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2); + dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0xf); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + default: // This is the place where the routine is modified + { + __int64 const4 = 0x0000000000FFFFFF; + // __int64 const5 = 0x000000FFFFFF0000; // unused... + __int64 const6 = 0x00000000000000FF; + png_bytep sptr, dp; + png_uint_32 i; + png_size_t pixel_bytes; + int width = row_info->width; + + pixel_bytes = (row_info->pixel_depth >> 3); + + sptr = row + (width - 1) * pixel_bytes; + dp = row + (final_width - 1) * pixel_bytes; + // New code by Nirav Chhatrapati - Intel Corporation + // sign fix by GRR + // NOTE: there is NO MMX code for 48-bit and 64-bit images + + // use MMX routine if machine supports it + if ( mmx_supported ) + { + if (pixel_bytes == 3) + { + if (((pass == 0) || (pass == 1)) && width) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width + sub edi, 21 // (png_pass_inc[pass] - 1)*pixel_bytes +loop_pass0: + movd mm0, [esi] ; X X X X X v2 v1 v0 + pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0 + movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0 + psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0 + movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0 + psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0 + psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1 + por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0 + por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1 + movq mm3, mm0 ; v2 v1 v0 v2 v1 v0 v2 v1 + psllq mm0, 16 ; v0 v2 v1 v0 v2 v1 0 0 + movq mm4, mm3 ; v2 v1 v0 v2 v1 v0 v2 v1 + punpckhdq mm3, mm0 ; v0 v2 v1 v0 v2 v1 v0 v2 + movq [edi+16] , mm4 + psrlq mm0, 32 ; 0 0 0 0 v0 v2 v1 v0 + movq [edi+8] , mm3 + punpckldq mm0, mm4 ; v1 v0 v2 v1 v0 v2 v1 v0 + sub esi, 3 + movq [edi], mm0 + sub edi, 24 + //sub esi, 3 + dec ecx + jnz loop_pass0 + EMMS + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width + sub edi, 9 // (png_pass_inc[pass] - 1)*pixel_bytes +loop_pass2: + movd mm0, [esi] ; X X X X X v2 v1 v0 + pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0 + movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0 + psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0 + movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0 + psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0 + psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1 + por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0 + por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1 + movq [edi+4], mm0 ; move to memory + psrlq mm0, 16 ; 0 0 v2 v1 v0 v2 v1 v0 + movd [edi], mm0 ; move to memory + sub esi, 3 + sub edi, 12 + dec ecx + jnz loop_pass2 + EMMS + } + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 1) << 1) - 8; + if (width_mmx < 0) + width_mmx = 0; + width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 3 + sub edi, 9 +loop_pass4: + movq mm0, [esi] ; X X v2 v1 v0 v5 v4 v3 + movq mm7, mm0 ; X X v2 v1 v0 v5 v4 v3 + movq mm6, mm0 ; X X v2 v1 v0 v5 v4 v3 + psllq mm0, 24 ; v1 v0 v5 v4 v3 0 0 0 + pand mm7, const4 ; 0 0 0 0 0 v5 v4 v3 + psrlq mm6, 24 ; 0 0 0 X X v2 v1 v0 + por mm0, mm7 ; v1 v0 v5 v4 v3 v5 v4 v3 + movq mm5, mm6 ; 0 0 0 X X v2 v1 v0 + psllq mm6, 8 ; 0 0 X X v2 v1 v0 0 + movq [edi], mm0 ; move quad to memory + psrlq mm5, 16 ; 0 0 0 0 0 X X v2 + pand mm5, const6 ; 0 0 0 0 0 0 0 v2 + por mm6, mm5 ; 0 0 X X v2 v1 v0 v2 + movd [edi+8], mm6 ; move double to memory + sub esi, 6 + sub edi, 12 + sub ecx, 2 + jnz loop_pass4 + EMMS + } + } + + sptr -= width_mmx*3; + dp -= width_mmx*6; + for (i = width; i; i--) + { + png_byte v[8]; + int j; + + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + } /* end of pixel_bytes == 3 */ + + else if (pixel_bytes == 1) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub edi, 31 + sub esi, 3 +loop1_pass0: + movd mm0, [esi] ; X X X X v0 v1 v2 v3 + movq mm1, mm0 ; X X X X v0 v1 v2 v3 + punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + movq mm2, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3 + movq mm3, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3 + punpckldq mm0, mm0 ; v3 v3 v3 v3 v3 v3 v3 v3 + punpckhdq mm3, mm3 ; v2 v2 v2 v2 v2 v2 v2 v2 + movq [edi], mm0 ; move to memory v3 + punpckhwd mm2, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1 + movq [edi+8], mm3 ; move to memory v2 + movq mm4, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1 + punpckldq mm2, mm2 ; v1 v1 v1 v1 v1 v1 v1 v1 + punpckhdq mm4, mm4 ; v0 v0 v0 v0 v0 v0 v0 v0 + movq [edi+16], mm2 ; move to memory v1 + movq [edi+24], mm4 ; move to memory v0 + sub esi, 4 + sub edi, 32 + sub ecx, 4 + jnz loop1_pass0 + EMMS + } + } + + sptr -= width_mmx; + dp -= width_mmx*8; + for (i = width; i; i--) + { + int j; + + /* I simplified this part in version 1.0.4e + * here and in several other instances where + * pixel_bytes == 1 -- GR-P + * + * Original code: + * + * png_byte v[8]; + * png_memcpy(v, sptr, pixel_bytes); + * for (j = 0; j < png_pass_inc[pass]; j++) + * { + * png_memcpy(dp, v, pixel_bytes); + * dp -= pixel_bytes; + * } + * sptr -= pixel_bytes; + * + * Replacement code is in the next three lines: + */ + + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + sptr--; + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub edi, 15 + sub esi, 3 +loop1_pass2: + movd mm0, [esi] ; X X X X v0 v1 v2 v3 + punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3 + punpckhwd mm1, mm1 ; v0 v0 v0 v0 v1 v1 v1 v1 + movq [edi], mm0 ; move to memory v2 and v3 + sub esi, 4 + movq [edi+8], mm1 ; move to memory v1 and v0 + sub edi, 16 + sub ecx, 4 + jnz loop1_pass2 + EMMS + } + } + + sptr -= width_mmx; + dp -= width_mmx*4; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + sptr --; + } + } + else if (width) /* && ((pass == 4) || (pass == 5))) */ + { + int width_mmx = ((width >> 3) << 3); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub edi, 15 + sub esi, 7 +loop1_pass4: + movq mm0, [esi] ; v0 v1 v2 v3 v4 v5 v6 v7 + movq mm1, mm0 ; v0 v1 v2 v3 v4 v5 v6 v7 + punpcklbw mm0, mm0 ; v4 v4 v5 v5 v6 v6 v7 v7 + //movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3 + punpckhbw mm1, mm1 ;v0 v0 v1 v1 v2 v2 v3 v3 + movq [edi+8], mm1 ; move to memory v0 v1 v2 and v3 + sub esi, 8 + movq [edi], mm0 ; move to memory v4 v5 v6 and v7 + //sub esi, 4 + sub edi, 16 + sub ecx, 8 + jnz loop1_pass4 + EMMS + } + } + + sptr -= width_mmx; + dp -= width_mmx*2; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp-- = *sptr; + } + sptr --; + } + } + } /* end of pixel_bytes == 1 */ + + else if (pixel_bytes == 2) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 2 + sub edi, 30 +loop2_pass0: + movd mm0, [esi] ; X X X X v1 v0 v3 v2 + punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2 + punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0 + movq [edi], mm0 + movq [edi + 8], mm0 + movq [edi + 16], mm1 + movq [edi + 24], mm1 + sub esi, 4 + sub edi, 32 + sub ecx, 2 + jnz loop2_pass0 + EMMS + } + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*16 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 2 + sub edi, 14 +loop2_pass2: + movd mm0, [esi] ; X X X X v1 v0 v3 v2 + punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2 + punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0 + movq [edi], mm0 + sub esi, 4 + movq [edi + 8], mm1 + //sub esi, 4 + sub edi, 16 + sub ecx, 2 + jnz loop2_pass2 + EMMS + } + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*8 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 2 + sub edi, 6 +loop2_pass4: + movd mm0, [esi] ; X X X X v1 v0 v3 v2 + punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2 + sub esi, 4 + movq [edi], mm0 + sub edi, 8 + sub ecx, 2 + jnz loop2_pass4 + EMMS + } + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*4 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + } /* end of pixel_bytes == 2 */ + + else if (pixel_bytes == 4) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 4 + sub edi, 60 +loop4_pass0: + movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4 + movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4 + punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4 + punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0 + movq [edi], mm0 + movq [edi + 8], mm0 + movq [edi + 16], mm0 + movq [edi + 24], mm0 + movq [edi+32], mm1 + movq [edi + 40], mm1 + movq [edi+ 48], mm1 + sub esi, 8 + movq [edi + 56], mm1 + sub edi, 64 + sub ecx, 2 + jnz loop4_pass0 + EMMS + } + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*32 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 4 + sub edi, 28 +loop4_pass2: + movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4 + movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4 + punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4 + punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0 + movq [edi], mm0 + movq [edi + 8], mm0 + movq [edi+16], mm1 + movq [edi + 24], mm1 + sub esi, 8 + sub edi, 32 + sub ecx, 2 + jnz loop4_pass2 + EMMS + } + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*16 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + _asm + { + mov esi, sptr + mov edi, dp + mov ecx, width_mmx + sub esi, 4 + sub edi, 12 +loop4_pass4: + movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4 + movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4 + punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4 + punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0 + movq [edi], mm0 + sub esi, 8 + movq [edi + 8], mm1 + sub edi, 16 + sub ecx, 2 + jnz loop4_pass4 + EMMS + } + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*8 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + + } /* end of pixel_bytes == 4 */ + + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } /* end of pixel_bytes == 6 */ + + else + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr-= pixel_bytes; + } + } + } /* end of mmx_supported */ + + else /* MMX not supported: use modified C code - takes advantage + * of inlining of png_memcpy for a constant */ + { + if (pixel_bytes == 1) + { + for (i = width; i; i--) + { + int j; + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + sptr--; + } + } + else if (pixel_bytes == 3) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else if (pixel_bytes == 2) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else if (pixel_bytes == 4) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + else + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + + } /* end of MMX not supported */ + break; + } + } /* end switch (row_info->pixel_depth) */ + + row_info->width = final_width; + row_info->rowbytes = ((final_width * + (png_uint_32)row_info->pixel_depth + 7) >> 3); + } + +} + +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + +// These variables are utilized in the functions below. They are declared +// globally here to ensure alignment on 8-byte boundaries. + +union uAll { + __int64 use; + double align; +} LBCarryMask = {0x0101010101010101}, + HBClearMask = {0x7f7f7f7f7f7f7f7f}, + ActiveMask, ActiveMask2, ActiveMaskEnd, ShiftBpp, ShiftRem; + + +// Optimized code for PNG Average filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row + , png_bytep prev_row) +{ + int bpp; + png_uint_32 FullLength; + png_uint_32 MMXLength; + //png_uint_32 len; + int diff; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + FullLength = row_info->rowbytes; // # of bytes to filter + _asm { + // Init address pointers and offset + mov edi, row // edi ==> Avg(x) + xor ebx, ebx // ebx ==> x + mov edx, edi + mov esi, prev_row // esi ==> Prior(x) + sub edx, bpp // edx ==> Raw(x-bpp) + + xor eax, eax + // Compute the Raw value for the first bpp bytes + // Raw(x) = Avg(x) + (Prior(x)/2) +davgrlp: + mov al, [esi + ebx] // Load al with Prior(x) + inc ebx + shr al, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, bpp + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davgrlp + // get # of bytes to alignment + mov diff, edi // take start of row + add diff, ebx // add bpp + add diff, 0xf // add 7 + 8 to incr past alignment boundary + and diff, 0xfffffff8 // mask to alignment boundary + sub diff, edi // subtract from start ==> value ebx at alignment + jz davggo + // fix alignment + // Compute the Raw value for the bytes upto the alignment boundary + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + xor ecx, ecx +davglp1: + xor eax, eax + mov cl, [esi + ebx] // load cl with Prior(x) + mov al, [edx + ebx] // load al with Raw(x-bpp) + add ax, cx + inc ebx + shr ax, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, diff // Check if at alignment boundary + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davglp1 // Repeat until at alignment boundary +davggo: + mov eax, FullLength + mov ecx, eax + sub eax, ebx // subtract alignment fix + and eax, 0x00000007 // calc bytes over mult of 8 + sub ecx, eax // drop over bytes from original length + mov MMXLength, ecx + } // end _asm block + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000000000ffffff; + ShiftBpp.use = 24; // == 3 * 8 + ShiftRem.use = 40; // == 64 - 24 + _asm { + // Re-init address pointers and offset + movq mm7, ActiveMask + mov ebx, diff // ebx ==> x = offset to alignment boundary + movq mm5, LBCarryMask + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov esi, prev_row // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (we correct position in loop below) +davg3lp: + movq mm0, [edi + ebx] // Load mm0 with Avg(x) + // Add (Prev_row/2) to Average + movq mm3, mm5 + psrlq mm2, ShiftRem // Correct position Raw(x-bpp) data + movq mm1, [esi + ebx] // Load mm1 with Prior(x) + movq mm6, mm7 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 3-5 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + + // Add 3rd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover the last two + // bytes + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + add ebx, 8 + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + + // Now ready to write back to memory + movq [edi + ebx - 8], mm0 + // Move updated Raw(x) to use as Raw(x-bpp) for next loop + cmp ebx, MMXLength + movq mm2, mm0 // mov updated Raw(x) to mm2 + jb davg3lp + } // end _asm block + } + break; + + case 6: + case 4: + case 7: + case 5: + { + ActiveMask.use = 0xffffffffffffffff; // use shift below to clear + // appropriate inactive bytes + ShiftBpp.use = bpp << 3; + ShiftRem.use = 64 - ShiftBpp.use; + _asm { + movq mm4, HBClearMask + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + // Load ActiveMask and clear all bytes except for 1st active group + movq mm7, ActiveMask + mov edi, row // edi ==> Avg(x) + psrlq mm7, ShiftRem + mov esi, prev_row // esi ==> Prior(x) + movq mm6, mm7 + movq mm5, LBCarryMask + psllq mm6, ShiftBpp // Create mask for 2nd active group + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (we correct position in loop below) +davg4lp: + movq mm0, [edi + ebx] + psrlq mm2, ShiftRem // shift data to position correctly + movq mm1, [esi + ebx] + // Add (Prev_row/2) to Average + movq mm3, mm5 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm7 // Leave only Active Group 1 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + add ebx, 8 + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active + // byte + cmp ebx, MMXLength + // Now ready to write back to memory + movq [edi + ebx - 8], mm0 + // Prep Raw(x-bpp) for next loop + movq mm2, mm0 // mov updated Raws to mm2 + jb davg4lp + } // end _asm block + } + break; + case 2: + { + ActiveMask.use = 0x000000000000ffff; + ShiftBpp.use = 16; // == 2 * 8 [BUGFIX] + ShiftRem.use = 48; // == 64 - 16 [BUGFIX] + _asm { + // Load ActiveMask + movq mm7, ActiveMask + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + movq mm5, LBCarryMask + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov esi, prev_row // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (we correct position in loop below) +davg2lp: + movq mm0, [edi + ebx] + psrlq mm2, ShiftRem // shift data to position correctly [BUGFIX] + movq mm1, [esi + ebx] + // Add (Prev_row/2) to Average + movq mm3, mm5 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + movq mm6, mm7 + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 2 & 3 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + + // Add rdd active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 4 & 5 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + + // Add 4th active group (Raw(x-bpp)/2) to Average with LBCarry + psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 6 & 7 + movq mm2, mm0 // mov updated Raws to mm2 + psllq mm2, ShiftBpp // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + add ebx, 8 + movq mm1, mm3 // now use mm1 for getting LBCarrys + pand mm1, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + psrlq mm2, 1 // divide raw bytes by 2 + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte + pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg + paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte + + cmp ebx, MMXLength + // Now ready to write back to memory + movq [edi + ebx - 8], mm0 + // Prep Raw(x-bpp) for next loop + movq mm2, mm0 // mov updated Raws to mm2 + jb davg2lp + } // end _asm block + } + break; + + case 1: // bpp == 1 + { + _asm { + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + mov edi, row // edi ==> Avg(x) + cmp ebx, FullLength // Test if offset at end of array + jnb davg1end + // Do Paeth decode for remaining bytes + mov esi, prev_row // esi ==> Prior(x) + mov edx, edi + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // edx ==> Raw(x-bpp) +davg1lp: + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + xor eax, eax + mov cl, [esi + ebx] // load cl with Prior(x) + mov al, [edx + ebx] // load al with Raw(x-bpp) + add ax, cx + inc ebx + shr ax, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, FullLength // Check if at end of array + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davg1lp +davg1end: + } // end _asm block + } + return; + + case 8: // bpp == 8 + { + _asm { + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + movq mm5, LBCarryMask + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov esi, prev_row // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes + // (NO NEED to correct position in loop below) +davg8lp: + movq mm0, [edi + ebx] + movq mm3, mm5 + movq mm1, [esi + ebx] + add ebx, 8 + pand mm3, mm1 // get lsb for each prev_row byte + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm3, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 + psrlq mm2, 1 // divide raw bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm3 // add LBCarrys to Avg for each byte + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + paddb mm0, mm2 // add (Raw/2) to Avg for each byte + cmp ebx, MMXLength + movq [edi + ebx - 8], mm0 + movq mm2, mm0 // reuse as Raw(x-bpp) + jb davg8lp + } // end _asm block + } + break; + default: // bpp greater than 8 + { + _asm { + movq mm5, LBCarryMask + // Re-init address pointers and offset + mov ebx, diff // ebx ==> x = offset to alignment boundary + mov edi, row // edi ==> Avg(x) + movq mm4, HBClearMask + mov edx, edi + mov esi, prev_row // esi ==> Prior(x) + sub edx, bpp // edx ==> Raw(x-bpp) +davgAlp: + movq mm0, [edi + ebx] + movq mm3, mm5 + movq mm1, [esi + ebx] + pand mm3, mm1 // get lsb for each prev_row byte + movq mm2, [edx + ebx] + psrlq mm1, 1 // divide prev_row bytes by 2 + pand mm3, mm2 // get LBCarrys for each byte where both + // lsb's were == 1 + psrlq mm2, 1 // divide raw bytes by 2 + pand mm1, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm3 // add LBCarrys to Avg for each byte + pand mm2, mm4 // clear invalid bit 7 of each byte + paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte + add ebx, 8 + paddb mm0, mm2 // add (Raw/2) to Avg for each byte + cmp ebx, MMXLength + movq [edi + ebx - 8], mm0 + jb davgAlp + } // end _asm block + } + break; + } // end switch ( bpp ) + + _asm { + // MMX acceleration complete now do clean-up + // Check if any remaining bytes left to decode + mov ebx, MMXLength // ebx ==> x = offset bytes remaining after MMX + mov edi, row // edi ==> Avg(x) + cmp ebx, FullLength // Test if offset at end of array + jnb davgend + // Do Paeth decode for remaining bytes + mov esi, prev_row // esi ==> Prior(x) + mov edx, edi + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // edx ==> Raw(x-bpp) +davglp2: + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + xor eax, eax + mov cl, [esi + ebx] // load cl with Prior(x) + mov al, [edx + ebx] // load al with Raw(x-bpp) + add ax, cx + inc ebx + shr ax, 1 // divide by 2 + add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx + cmp ebx, FullLength // Check if at end of array + mov [edi+ebx-1], al // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + jb davglp2 +davgend: + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + +// Optimized code for PNG Paeth filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + png_uint_32 FullLength; + png_uint_32 MMXLength; + //png_uint_32 len; + int bpp; + int diff; + //int ptemp; + int patemp, pbtemp, pctemp; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + FullLength = row_info->rowbytes; // # of bytes to filter + _asm + { + xor ebx, ebx // ebx ==> x offset + mov edi, row + xor edx, edx // edx ==> x-bpp offset + mov esi, prev_row + xor eax, eax + + // Compute the Raw value for the first bpp bytes + // Note: the formula works out to be always + // Paeth(x) = Raw(x) + Prior(x) where x < bpp +dpthrlp: + mov al, [edi + ebx] + add al, [esi + ebx] + inc ebx + cmp ebx, bpp + mov [edi + ebx - 1], al + jb dpthrlp + // get # of bytes to alignment + mov diff, edi // take start of row + add diff, ebx // add bpp + xor ecx, ecx + add diff, 0xf // add 7 + 8 to incr past alignment boundary + and diff, 0xfffffff8 // mask to alignment boundary + sub diff, edi // subtract from start ==> value ebx at alignment + jz dpthgo + // fix alignment +dpthlp1: + xor eax, eax + // pav = p - a = (a + b - c) - a = b - c + mov al, [esi + ebx] // load Prior(x) into al + mov cl, [esi + edx] // load Prior(x-bpp) into cl + sub eax, ecx // subtract Prior(x-bpp) + mov patemp, eax // Save pav for later use + xor eax, eax + // pbv = p - b = (a + b - c) - b = a - c + mov al, [edi + edx] // load Raw(x-bpp) into al + sub eax, ecx // subtract Prior(x-bpp) + mov ecx, eax + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + add eax, patemp // pcv = pav + pbv + // pc = abs(pcv) + test eax, 0x80000000 + jz dpthpca + neg eax // reverse sign of neg values +dpthpca: + mov pctemp, eax // save pc for later use + // pb = abs(pbv) + test ecx, 0x80000000 + jz dpthpba + neg ecx // reverse sign of neg values +dpthpba: + mov pbtemp, ecx // save pb for later use + // pa = abs(pav) + mov eax, patemp + test eax, 0x80000000 + jz dpthpaa + neg eax // reverse sign of neg values +dpthpaa: + mov patemp, eax // save pa for later use + // test if pa <= pb + cmp eax, ecx + jna dpthabb + // pa > pb; now test if pb <= pc + cmp ecx, pctemp + jna dpthbbc + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth +dpthbbc: + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + mov cl, [esi + ebx] // load Prior(x) into cl + jmp dpthpaeth +dpthabb: + // pa <= pb; now test if pa <= pc + cmp eax, pctemp + jna dpthabc + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth +dpthabc: + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + mov cl, [edi + edx] // load Raw(x-bpp) into cl +dpthpaeth: + inc ebx + inc edx + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + add [edi + ebx - 1], cl + cmp ebx, diff + jb dpthlp1 +dpthgo: + mov ecx, FullLength + mov eax, ecx + sub eax, ebx // subtract alignment fix + and eax, 0x00000007 // calc bytes over mult of 8 + sub ecx, eax // drop over bytes from original length + mov MMXLength, ecx + } // end _asm block + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000000000ffffff; + ActiveMaskEnd.use = 0xffff000000000000; + ShiftBpp.use = 24; // == bpp(3) * 8 + ShiftRem.use = 40; // == 64 - 24 + _asm + { + mov ebx, diff + mov edi, row + mov esi, prev_row + pxor mm0, mm0 + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dpth3lp: + psrlq mm1, ShiftRem // shift last 3 bytes to 1st 3 bytes + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm1, mm0 // Unpack High bytes of a + movq mm3, [esi+ebx-8] // Prep c=Prior(x-bpp) bytes + punpcklbw mm2, mm0 // Unpack High bytes of b + psrlq mm3, ShiftRem // shift last 3 bytes to 1st 3 bytes + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpcklbw mm3, mm0 // Unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi + ebx] // load c=Prior(x-bpp) + pand mm7, ActiveMask + movq mm2, mm3 // load b=Prior(x) step 1 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + punpcklbw mm3, mm0 // Unpack High bytes of c + movq [edi + ebx], mm7 // write back updated value + movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp) + // Now do Paeth for 2nd set of bytes (3-5) + psrlq mm2, ShiftBpp // load b=Prior(x) step 2 + punpcklbw mm1, mm0 // Unpack High bytes of a + pxor mm7, mm7 + punpcklbw mm2, mm0 // Unpack High bytes of b + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + psubw mm5, mm3 + psubw mm4, mm3 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = + // pav + pbv = pbv + pav + movq mm6, mm5 + paddw mm6, mm4 + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm5 // Create mask pbv bytes < 0 + pcmpgtw mm7, mm4 // Create mask pav bytes < 0 + pand mm0, mm5 // Only pbv bytes < 0 in mm0 + pand mm7, mm4 // Only pav bytes < 0 in mm7 + psubw mm5, mm0 + psubw mm4, mm7 + psubw mm5, mm0 + psubw mm4, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + movq mm2, [esi + ebx] // load b=Prior(x) + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, mm2 // load c=Prior(x-bpp) step 1 + pand mm7, ActiveMask + punpckhbw mm2, mm0 // Unpack High bytes of b + psllq mm7, ShiftBpp // Shift bytes to 2nd group of 3 bytes + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + psllq mm3, ShiftBpp // load c=Prior(x-bpp) step 2 + movq [edi + ebx], mm7 // write back updated value + movq mm1, mm7 + punpckhbw mm3, mm0 // Unpack High bytes of c + psllq mm1, ShiftBpp // Shift bytes + // Now mm1 will be used as Raw(x-bpp) + // Now do Paeth for 3rd, and final, set of bytes (6-7) + pxor mm7, mm7 + punpckhbw mm1, mm0 // Unpack High bytes of a + psubw mm4, mm3 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + pxor mm0, mm0 + paddw mm6, mm5 + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + pandn mm0, mm1 + pandn mm7, mm4 + paddw mm0, mm2 + paddw mm7, mm5 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm1, mm1 + packuswb mm1, mm7 + // Step ebx to next set of 8 bytes and repeat loop til done + add ebx, 8 + pand mm1, ActiveMaskEnd + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + + cmp ebx, MMXLength + pxor mm0, mm0 // pxor does not affect flags + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + // mm3 ready to be used as Prior(x-bpp) next loop + jb dpth3lp + } // end _asm block + } + break; + + case 6: + case 7: + case 5: + { + ActiveMask.use = 0x00000000ffffffff; + ActiveMask2.use = 0xffffffff00000000; + ShiftBpp.use = bpp << 3; // == bpp * 8 + ShiftRem.use = 64 - ShiftBpp.use; + _asm + { + mov ebx, diff + mov edi, row + mov esi, prev_row + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] + pxor mm0, mm0 +dpth6lp: + // Must shift to position Raw(x-bpp) data + psrlq mm1, ShiftRem + // Do first set of 4 bytes + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + punpcklbw mm1, mm0 // Unpack Low bytes of a + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm2, mm0 // Unpack Low bytes of b + // Must shift to position Prior(x-bpp) data + psrlq mm3, ShiftRem + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpcklbw mm3, mm0 // Unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi + ebx - 8] // load c=Prior(x-bpp) + pand mm7, ActiveMask + psrlq mm3, ShiftRem + movq mm2, [esi + ebx] // load b=Prior(x) step 1 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + movq mm6, mm2 + movq [edi + ebx], mm7 // write back updated value + movq mm1, [edi+ebx-8] + psllq mm6, ShiftBpp + movq mm5, mm7 + psrlq mm1, ShiftRem + por mm3, mm6 + psllq mm5, ShiftBpp + punpckhbw mm3, mm0 // Unpack High bytes of c + por mm1, mm5 + // Do second set of 4 bytes + punpckhbw mm2, mm0 // Unpack High bytes of b + punpckhbw mm1, mm0 // Unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + // Step ex to next set of 8 bytes and repeat loop til done + add ebx, 8 + packuswb mm1, mm7 + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + cmp ebx, MMXLength + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + jb dpth6lp + } // end _asm block + } + break; + + case 4: + { + ActiveMask.use = 0x00000000ffffffff; + _asm { + mov ebx, diff + mov edi, row + mov esi, prev_row + pxor mm0, mm0 + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] // Only time should need to read + // a=Raw(x-bpp) bytes +dpth4lp: + // Do first set of 4 bytes + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + punpckhbw mm1, mm0 // Unpack Low bytes of a + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm2, mm0 // Unpack High bytes of b + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpckhbw mm3, mm0 // Unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi + ebx] // load c=Prior(x-bpp) + pand mm7, ActiveMask + movq mm2, mm3 // load b=Prior(x) step 1 + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + punpcklbw mm3, mm0 // Unpack High bytes of c + movq [edi + ebx], mm7 // write back updated value + movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp) + // Do second set of 4 bytes + punpckhbw mm2, mm0 // Unpack Low bytes of b + punpcklbw mm1, mm0 // Unpack Low bytes of a + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + // Step ex to next set of 8 bytes and repeat loop til done + add ebx, 8 + packuswb mm1, mm7 + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + cmp ebx, MMXLength + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + jb dpth4lp + } // end _asm block + } + break; + case 8: // bpp == 8 + { + ActiveMask.use = 0x00000000ffffffff; + _asm { + mov ebx, diff + mov edi, row + mov esi, prev_row + pxor mm0, mm0 + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] // Only time should need to read + // a=Raw(x-bpp) bytes +dpth8lp: + // Do first set of 4 bytes + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + punpcklbw mm1, mm0 // Unpack Low bytes of a + movq mm2, [esi + ebx] // load b=Prior(x) + punpcklbw mm2, mm0 // Unpack Low bytes of b + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + punpcklbw mm3, mm0 // Unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + paddw mm7, mm3 + pxor mm0, mm0 + packuswb mm7, mm1 + movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes + pand mm7, ActiveMask + movq mm2, [esi + ebx] // load b=Prior(x) + paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x) + punpckhbw mm3, mm0 // Unpack High bytes of c + movq [edi + ebx], mm7 // write back updated value + movq mm1, [edi+ebx-8] // read a=Raw(x-bpp) bytes + + // Do second set of 4 bytes + punpckhbw mm2, mm0 // Unpack High bytes of b + punpckhbw mm1, mm0 // Unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + movq mm4, mm2 + // pbv = p - b = (a + b - c) - b = a - c + movq mm5, mm1 + psubw mm4, mm3 + pxor mm7, mm7 + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + movq mm6, mm4 + psubw mm5, mm3 + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + pcmpgtw mm0, mm4 // Create mask pav bytes < 0 + paddw mm6, mm5 + pand mm0, mm4 // Only pav bytes < 0 in mm7 + pcmpgtw mm7, mm5 // Create mask pbv bytes < 0 + psubw mm4, mm0 + pand mm7, mm5 // Only pbv bytes < 0 in mm0 + psubw mm4, mm0 + psubw mm5, mm7 + pxor mm0, mm0 + pcmpgtw mm0, mm6 // Create mask pcv bytes < 0 + pand mm0, mm6 // Only pav bytes < 0 in mm7 + psubw mm5, mm7 + psubw mm6, mm0 + // test pa <= pb + movq mm7, mm4 + psubw mm6, mm0 + pcmpgtw mm7, mm5 // pa > pb? + movq mm0, mm7 + // use mm7 mask to merge pa & pb + pand mm5, mm7 + // use mm0 mask copy to merge a & b + pand mm2, mm0 + pandn mm7, mm4 + pandn mm0, mm1 + paddw mm7, mm5 + paddw mm0, mm2 + // test ((pa <= pb)? pa:pb) <= pc + pcmpgtw mm7, mm6 // pab > pc? + pxor mm1, mm1 + pand mm3, mm7 + pandn mm7, mm0 + pxor mm1, mm1 + paddw mm7, mm3 + pxor mm0, mm0 + // Step ex to next set of 8 bytes and repeat loop til done + add ebx, 8 + packuswb mm1, mm7 + paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x) + cmp ebx, MMXLength + movq [edi + ebx - 8], mm1 // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + jb dpth8lp + } // end _asm block + } + break; + + case 1: // bpp = 1 + case 2: // bpp = 2 + default: // bpp > 8 + { + _asm { + mov ebx, diff + cmp ebx, FullLength + jnb dpthdend + mov edi, row + mov esi, prev_row + // Do Paeth decode for remaining bytes + mov edx, ebx + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // Set edx = ebx - bpp +dpthdlp: + xor eax, eax + // pav = p - a = (a + b - c) - a = b - c + mov al, [esi + ebx] // load Prior(x) into al + mov cl, [esi + edx] // load Prior(x-bpp) into cl + sub eax, ecx // subtract Prior(x-bpp) + mov patemp, eax // Save pav for later use + xor eax, eax + // pbv = p - b = (a + b - c) - b = a - c + mov al, [edi + edx] // load Raw(x-bpp) into al + sub eax, ecx // subtract Prior(x-bpp) + mov ecx, eax + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + add eax, patemp // pcv = pav + pbv + // pc = abs(pcv) + test eax, 0x80000000 + jz dpthdpca + neg eax // reverse sign of neg values +dpthdpca: + mov pctemp, eax // save pc for later use + // pb = abs(pbv) + test ecx, 0x80000000 + jz dpthdpba + neg ecx // reverse sign of neg values +dpthdpba: + mov pbtemp, ecx // save pb for later use + // pa = abs(pav) + mov eax, patemp + test eax, 0x80000000 + jz dpthdpaa + neg eax // reverse sign of neg values +dpthdpaa: + mov patemp, eax // save pa for later use + // test if pa <= pb + cmp eax, ecx + jna dpthdabb + // pa > pb; now test if pb <= pc + cmp ecx, pctemp + jna dpthdbbc + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthdpaeth +dpthdbbc: + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + mov cl, [esi + ebx] // load Prior(x) into cl + jmp dpthdpaeth +dpthdabb: + // pa <= pb; now test if pa <= pc + cmp eax, pctemp + jna dpthdabc + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthdpaeth +dpthdabc: + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + mov cl, [edi + edx] // load Raw(x-bpp) into cl +dpthdpaeth: + inc ebx + inc edx + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + add [edi + ebx - 1], cl + cmp ebx, FullLength + jb dpthdlp +dpthdend: + } // end _asm block + } + return; // No need to go further with this one + } // end switch ( bpp ) + _asm + { + // MMX acceleration complete now do clean-up + // Check if any remaining bytes left to decode + mov ebx, MMXLength + cmp ebx, FullLength + jnb dpthend + mov edi, row + mov esi, prev_row + // Do Paeth decode for remaining bytes + mov edx, ebx + xor ecx, ecx // zero ecx before using cl & cx in loop below + sub edx, bpp // Set edx = ebx - bpp +dpthlp2: + xor eax, eax + // pav = p - a = (a + b - c) - a = b - c + mov al, [esi + ebx] // load Prior(x) into al + mov cl, [esi + edx] // load Prior(x-bpp) into cl + sub eax, ecx // subtract Prior(x-bpp) + mov patemp, eax // Save pav for later use + xor eax, eax + // pbv = p - b = (a + b - c) - b = a - c + mov al, [edi + edx] // load Raw(x-bpp) into al + sub eax, ecx // subtract Prior(x-bpp) + mov ecx, eax + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + add eax, patemp // pcv = pav + pbv + // pc = abs(pcv) + test eax, 0x80000000 + jz dpthpca2 + neg eax // reverse sign of neg values +dpthpca2: + mov pctemp, eax // save pc for later use + // pb = abs(pbv) + test ecx, 0x80000000 + jz dpthpba2 + neg ecx // reverse sign of neg values +dpthpba2: + mov pbtemp, ecx // save pb for later use + // pa = abs(pav) + mov eax, patemp + test eax, 0x80000000 + jz dpthpaa2 + neg eax // reverse sign of neg values +dpthpaa2: + mov patemp, eax // save pa for later use + // test if pa <= pb + cmp eax, ecx + jna dpthabb2 + // pa > pb; now test if pb <= pc + cmp ecx, pctemp + jna dpthbbc2 + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth2 +dpthbbc2: + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + mov cl, [esi + ebx] // load Prior(x) into cl + jmp dpthpaeth2 +dpthabb2: + // pa <= pb; now test if pa <= pc + cmp eax, pctemp + jna dpthabc2 + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + mov cl, [esi + edx] // load Prior(x-bpp) into cl + jmp dpthpaeth2 +dpthabc2: + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + mov cl, [edi + edx] // load Raw(x-bpp) into cl +dpthpaeth2: + inc ebx + inc edx + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + add [edi + ebx - 1], cl + cmp ebx, FullLength + jb dpthlp2 +dpthend: + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + +// Optimized code for PNG Sub filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row) +{ + //int test; + int bpp; + png_uint_32 FullLength; + png_uint_32 MMXLength; + int diff; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + FullLength = row_info->rowbytes - bpp; // # of bytes to filter + _asm { + mov edi, row + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + xor eax, eax + // get # of bytes to alignment + mov diff, edi // take start of row + add diff, 0xf // add 7 + 8 to incr past + // alignment boundary + xor ebx, ebx + and diff, 0xfffffff8 // mask to alignment boundary + sub diff, edi // subtract from start ==> value + // ebx at alignment + jz dsubgo + // fix alignment +dsublp1: + mov al, [esi+ebx] + add [edi+ebx], al + inc ebx + cmp ebx, diff + jb dsublp1 +dsubgo: + mov ecx, FullLength + mov edx, ecx + sub edx, ebx // subtract alignment fix + and edx, 0x00000007 // calc bytes over mult of 8 + sub ecx, edx // drop over bytes from length + mov MMXLength, ecx + } // end _asm block + + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000ffffff000000; + ShiftBpp.use = 24; // == 3 * 8 + ShiftRem.use = 40; // == 64 - 24 + _asm { + mov edi, row + movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + movq mm6, mm7 + mov ebx, diff + psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active + // byte group + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dsub3lp: + psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive bytes + // Add 1st active group + movq mm0, [edi+ebx] + paddb mm0, mm1 + // Add 2nd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm7 // mask to use only 2nd active group + paddb mm0, mm1 + // Add 3rd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm6 // mask to use only 3rd active group + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // Write updated Raws back to array + // Prep for doing 1st add at top of loop + movq mm1, mm0 + jb dsub3lp + } // end _asm block + } + break; + + case 1: + { + // Placed here just in case this is a duplicate of the + // non-MMX code for the SUB filter in png_read_filter_row below + // + // png_bytep rp; + // png_bytep lp; + // png_uint_32 i; + // bpp = (row_info->pixel_depth + 7) >> 3; + // for (i = (png_uint_32)bpp, rp = row + bpp, lp = row; + // i < row_info->rowbytes; i++, rp++, lp++) + // { + // *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff); + // } + _asm { + mov ebx, diff + mov edi, row + cmp ebx, FullLength + jnb dsub1end + mov esi, edi // lp = row + xor eax, eax + add edi, bpp // rp = row + bpp +dsub1lp: + mov al, [esi+ebx] + add [edi+ebx], al + inc ebx + cmp ebx, FullLength + jb dsub1lp +dsub1end: + } // end _asm block + } + return; + + case 6: + case 7: + case 4: + case 5: + { + ShiftBpp.use = bpp << 3; + ShiftRem.use = 64 - ShiftBpp.use; + _asm { + mov edi, row + mov ebx, diff + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dsub4lp: + psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive bytes + movq mm0, [edi+ebx] + paddb mm0, mm1 + // Add 2nd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + // there is no need for any mask + // since shift clears inactive bits/bytes + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 + movq mm1, mm0 // Prep for doing 1st add at top of loop + jb dsub4lp + } // end _asm block + } + break; + + case 2: + { + ActiveMask.use = 0x00000000ffff0000; + ShiftBpp.use = 16; // == 2 * 8 + ShiftRem.use = 48; // == 64 - 16 + _asm { + movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group + mov ebx, diff + movq mm6, mm7 + mov edi, row + psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active + // byte group + mov esi, edi // lp = row + movq mm5, mm6 + add edi, bpp // rp = row + bpp + psllq mm5, ShiftBpp // Move mask in mm5 to cover 4th active + // byte group + // PRIME the pump (load the first Raw(x-bpp) data set + movq mm1, [edi+ebx-8] +dsub2lp: + // Add 1st active group + psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive + // bytes + movq mm0, [edi+ebx] + paddb mm0, mm1 + // Add 2nd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm7 // mask to use only 2nd active group + paddb mm0, mm1 + // Add 3rd active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm6 // mask to use only 3rd active group + paddb mm0, mm1 + // Add 4th active group + movq mm1, mm0 // mov updated Raws to mm1 + psllq mm1, ShiftBpp // shift data to position correctly + pand mm1, mm5 // mask to use only 4th active group + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // Write updated Raws back to array + movq mm1, mm0 // Prep for doing 1st add at top of loop + jb dsub2lp + } // end _asm block + } + break; + case 8: + { + _asm { + mov edi, row + mov ebx, diff + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp + mov ecx, MMXLength + movq mm7, [edi+ebx-8] // PRIME the pump (load the first + // Raw(x-bpp) data set + and ecx, 0x0000003f // calc bytes over mult of 64 +dsub8lp: + movq mm0, [edi+ebx] // Load Sub(x) for 1st 8 bytes + paddb mm0, mm7 + movq mm1, [edi+ebx+8] // Load Sub(x) for 2nd 8 bytes + movq [edi+ebx], mm0 // Write Raw(x) for 1st 8 bytes + // Now mm0 will be used as Raw(x-bpp) for + // the 2nd group of 8 bytes. This will be + // repeated for each group of 8 bytes with + // the 8th group being used as the Raw(x-bpp) + // for the 1st group of the next loop. + paddb mm1, mm0 + movq mm2, [edi+ebx+16] // Load Sub(x) for 3rd 8 bytes + movq [edi+ebx+8], mm1 // Write Raw(x) for 2nd 8 bytes + paddb mm2, mm1 + movq mm3, [edi+ebx+24] // Load Sub(x) for 4th 8 bytes + movq [edi+ebx+16], mm2 // Write Raw(x) for 3rd 8 bytes + paddb mm3, mm2 + movq mm4, [edi+ebx+32] // Load Sub(x) for 5th 8 bytes + movq [edi+ebx+24], mm3 // Write Raw(x) for 4th 8 bytes + paddb mm4, mm3 + movq mm5, [edi+ebx+40] // Load Sub(x) for 6th 8 bytes + movq [edi+ebx+32], mm4 // Write Raw(x) for 5th 8 bytes + paddb mm5, mm4 + movq mm6, [edi+ebx+48] // Load Sub(x) for 7th 8 bytes + movq [edi+ebx+40], mm5 // Write Raw(x) for 6th 8 bytes + paddb mm6, mm5 + movq mm7, [edi+ebx+56] // Load Sub(x) for 8th 8 bytes + movq [edi+ebx+48], mm6 // Write Raw(x) for 7th 8 bytes + add ebx, 64 + paddb mm7, mm6 + cmp ebx, ecx + movq [edi+ebx-8], mm7 // Write Raw(x) for 8th 8 bytes + jb dsub8lp + cmp ebx, MMXLength + jnb dsub8lt8 +dsub8lpA: + movq mm0, [edi+ebx] + add ebx, 8 + paddb mm0, mm7 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // use -8 to offset early add to ebx + movq mm7, mm0 // Move calculated Raw(x) data to mm1 to + // be the new Raw(x-bpp) for the next loop + jb dsub8lpA +dsub8lt8: + } // end _asm block + } + break; + + default: // bpp greater than 8 bytes + { + _asm { + mov ebx, diff + mov edi, row + mov esi, edi // lp = row + add edi, bpp // rp = row + bpp +dsubAlp: + movq mm0, [edi+ebx] + movq mm1, [esi+ebx] + add ebx, 8 + paddb mm0, mm1 + cmp ebx, MMXLength + movq [edi+ebx-8], mm0 // mov does not affect flags; -8 to offset + // add ebx + jb dsubAlp + } // end _asm block + } + break; + + } // end switch ( bpp ) + + _asm { + mov ebx, MMXLength + mov edi, row + cmp ebx, FullLength + jnb dsubend + mov esi, edi // lp = row + xor eax, eax + add edi, bpp // rp = row + bpp +dsublp2: + mov al, [esi+ebx] + add [edi+ebx], al + inc ebx + cmp ebx, FullLength + jb dsublp2 +dsubend: + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + +// Optimized code for PNG Up filter decoder +void /* PRIVATE */ +png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + png_uint_32 len; + len = row_info->rowbytes; // # of bytes to filter + _asm { + mov edi, row + // get # of bytes to alignment + mov ecx, edi + xor ebx, ebx + add ecx, 0x7 + xor eax, eax + and ecx, 0xfffffff8 + mov esi, prev_row + sub ecx, edi + jz dupgo + // fix alignment +duplp1: + mov al, [edi+ebx] + add al, [esi+ebx] + inc ebx + cmp ebx, ecx + mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx + jb duplp1 +dupgo: + mov ecx, len + mov edx, ecx + sub edx, ebx // subtract alignment fix + and edx, 0x0000003f // calc bytes over mult of 64 + sub ecx, edx // drop over bytes from length + // Unrolled loop - use all MMX registers and interleave to reduce + // number of branch instructions (loops) and reduce partial stalls +duploop: + movq mm1, [esi+ebx] + movq mm0, [edi+ebx] + movq mm3, [esi+ebx+8] + paddb mm0, mm1 + movq mm2, [edi+ebx+8] + movq [edi+ebx], mm0 + paddb mm2, mm3 + movq mm5, [esi+ebx+16] + movq [edi+ebx+8], mm2 + movq mm4, [edi+ebx+16] + movq mm7, [esi+ebx+24] + paddb mm4, mm5 + movq mm6, [edi+ebx+24] + movq [edi+ebx+16], mm4 + paddb mm6, mm7 + movq mm1, [esi+ebx+32] + movq [edi+ebx+24], mm6 + movq mm0, [edi+ebx+32] + movq mm3, [esi+ebx+40] + paddb mm0, mm1 + movq mm2, [edi+ebx+40] + movq [edi+ebx+32], mm0 + paddb mm2, mm3 + movq mm5, [esi+ebx+48] + movq [edi+ebx+40], mm2 + movq mm4, [edi+ebx+48] + movq mm7, [esi+ebx+56] + paddb mm4, mm5 + movq mm6, [edi+ebx+56] + movq [edi+ebx+48], mm4 + add ebx, 64 + paddb mm6, mm7 + cmp ebx, ecx + movq [edi+ebx-8], mm6 // (+56)movq does not affect flags; + // -8 to offset add ebx + jb duploop + + cmp edx, 0 // Test for bytes over mult of 64 + jz dupend + + + // 2 lines added by lcreeve@netins.net + // (mail 11 Jul 98 in png-implement list) + cmp edx, 8 //test for less than 8 bytes + jb duplt8 + + + add ecx, edx + and edx, 0x00000007 // calc bytes over mult of 8 + sub ecx, edx // drop over bytes from length + jz duplt8 + // Loop using MMX registers mm0 & mm1 to update 8 bytes simultaneously +duplpA: + movq mm1, [esi+ebx] + movq mm0, [edi+ebx] + add ebx, 8 + paddb mm0, mm1 + cmp ebx, ecx + movq [edi+ebx-8], mm0 // movq does not affect flags; -8 to offset add ebx + jb duplpA + cmp edx, 0 // Test for bytes over mult of 8 + jz dupend +duplt8: + xor eax, eax + add ecx, edx // move over byte count into counter + // Loop using x86 registers to update remaining bytes +duplp2: + mov al, [edi + ebx] + add al, [esi + ebx] + inc ebx + cmp ebx, ecx + mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx + jb duplp2 +dupend: + // Conversion of filtered row completed + emms // End MMX instructions; prep for possible FP instrs. + } // end _asm block +} + + +// Optimized png_read_filter_row routines +void /* PRIVATE */ +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep + row, png_bytep prev_row, int filter) +{ +#ifdef PNG_DEBUG + char filnm[10]; +#endif + + if (mmx_supported == 2) { + png_mmx_support(); + } + +#ifdef PNG_DEBUG + png_debug(1, "in png_read_filter_row\n"); + switch (filter) + { + case 0: sprintf(filnm, "none"); + break; + case 1: sprintf(filnm, "sub-%s", "MMX"); + break; + case 2: sprintf(filnm, "up-%s", "MMX"); + break; + case 3: sprintf(filnm, "avg-%s", "MMX"); + break; + case 4: sprintf(filnm, "Paeth-%s", "MMX"); + break; + default: sprintf(filnm, "unknw"); + break; + } + png_debug2(0,"row=%5d, %s, ", png_ptr->row_number, filnm); + png_debug2(0, "pd=%2d, b=%d, ", (int)row_info->pixel_depth, + (int)((row_info->pixel_depth + 7) >> 3)); + png_debug1(0,"len=%8d, ", row_info->rowbytes); +#endif /* PNG_DEBUG */ + + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + + case PNG_FILTER_VALUE_SUB: + { + if ( + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_sub(row_info, row); + } + else + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + } + break; + } + + case PNG_FILTER_VALUE_UP: + { + if ( + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_up(row_info, row, prev_row); + } + else + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_bytep rp = row; + png_bytep pp = prev_row; + + for (i = 0; i < istop; ++i) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + } + break; + } + + case PNG_FILTER_VALUE_AVG: + { + if ( + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_avg(row_info, row, prev_row); + } + else + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) >> 1)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++ + *lp++) >> 1)) & 0xff); + rp++; + } + } + break; + } + + case PNG_FILTER_VALUE_PAETH: + { + if ( + (row_info->pixel_depth >= PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT) && + (row_info->rowbytes >= PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT)) + { + png_read_filter_row_mmx_paeth(row_info, row, prev_row); + } + else + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop=row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) // use leftover rp,pp + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + } + break; + } + + default: + png_warning(png_ptr, "Ignoring bad row filter type"); + *row=0; + break; + } +} + +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED && PNG_USE_PNGVCRD */ diff --git a/freeimage241/Source/LibPNG/pngwio.c b/freeimage241/Source/LibPNG/pngwio.c new file mode 100644 index 0000000..23f881e --- /dev/null +++ b/freeimage241/Source/LibPNG/pngwio.c @@ -0,0 +1,228 @@ + +/* pngwio.c - functions for data output + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This file provides a location for all output. Users who need + * special handling are expected to write functions that have the same + * arguments as these and perform similar functions, but that possibly + * use different output methods. Note that you shouldn't change these + * functions, but rather write replacement functions and then change + * them at run time with png_set_write_fn(...). + */ + +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Write the data to whatever output you are using. The default routine + writes to a file pointer. Note that this routine sometimes gets called + with very small lengths, so you should implement some kind of simple + buffering if you are using unbuffered writes. This should never be asked + to write more than 64K on a 16 bit machine. */ + +void /* PRIVATE */ +png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + if (png_ptr->write_data_fn != NULL ) + (*(png_ptr->write_data_fn))(png_ptr, data, length); + else + png_error(png_ptr, "Call to NULL write function"); +} + +#if !defined(PNG_NO_STDIO) +/* This is the function that does the actual writing of data. If you are + not writing to a standard C stream, you should create a replacement + write_data function and use it at run time with png_set_write_fn(), rather + than changing the library. */ +#ifndef USE_FAR_KEYWORD +static void /* PRIVATE */ +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + +#if defined(_WIN32_WCE) + if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); +#endif + if (check != length) + png_error(png_ptr, "Write Error"); +} +#else +/* this is the model-independent version. Since the standard I/O library + can't handle far buffers in the medium and small models, we have to copy + the data. +*/ + +#define NEAR_BUF_SIZE 1024 +#define MIN(a,b) (a <= b ? a : b) + +static void /* PRIVATE */ +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_uint_32 check; + png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ + png_FILE_p io_ptr; + + /* Check if data really is near. If so, use usual code. */ + near_data = (png_byte *)CVT_PTR_NOCHECK(data); + io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); + if ((png_bytep)near_data == data) + { +#if defined(_WIN32_WCE) + if ( !WriteFile(io_ptr, near_data, length, &check, NULL) ) + check = 0; +#else + check = fwrite(near_data, 1, length, io_ptr); +#endif + } + else + { + png_byte buf[NEAR_BUF_SIZE]; + png_size_t written, remaining, err; + check = 0; + remaining = length; + do + { + written = MIN(NEAR_BUF_SIZE, remaining); + png_memcpy(buf, data, written); /* copy far buffer to near buffer */ +#if defined(_WIN32_WCE) + if ( !WriteFile(io_ptr, buf, written, &err, NULL) ) + err = 0; +#else + err = fwrite(buf, 1, written, io_ptr); +#endif + if (err != written) + break; + else + check += err; + data += written; + remaining -= written; + } + while (remaining != 0); + } + if (check != length) + png_error(png_ptr, "Write Error"); +} + +#endif +#endif + +/* This function is called to output any data pending writing (normally + to disk). After png_flush is called, there should be no data pending + writing in any buffers. */ +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +void /* PRIVATE */ +png_flush(png_structp png_ptr) +{ + if (png_ptr->output_flush_fn != NULL) + (*(png_ptr->output_flush_fn))(png_ptr); +} + +#if !defined(PNG_NO_STDIO) +static void /* PRIVATE */ +png_default_flush(png_structp png_ptr) +{ +#if !defined(_WIN32_WCE) + png_FILE_p io_ptr; + io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + if (io_ptr != NULL) + fflush(io_ptr); +#endif +} +#endif +#endif + +/* This function allows the application to supply new output functions for + libpng if standard C streams aren't being used. + + This function takes as its arguments: + png_ptr - pointer to a png output data structure + io_ptr - pointer to user supplied structure containing info about + the output functions. May be NULL. + write_data_fn - pointer to a new output function that takes as its + arguments a pointer to a png_struct, a pointer to + data to be written, and a 32-bit unsigned int that is + the number of bytes to be written. The new write + function should call png_error(png_ptr, "Error msg") + to exit and output any fatal error messages. + flush_data_fn - pointer to a new flush function that takes as its + arguments a pointer to a png_struct. After a call to + the flush function, there should be no data in any buffers + or pending transmission. If the output method doesn't do + any buffering of ouput, a function prototype must still be + supplied although it doesn't have to do anything. If + PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile + time, output_flush_fn will be ignored, although it must be + supplied for compatibility. */ +void PNGAPI +png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) +{ + png_ptr->io_ptr = io_ptr; + +#if !defined(PNG_NO_STDIO) + if (write_data_fn != NULL) + png_ptr->write_data_fn = write_data_fn; + else + png_ptr->write_data_fn = png_default_write_data; +#else + png_ptr->write_data_fn = write_data_fn; +#endif + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +#if !defined(PNG_NO_STDIO) + if (output_flush_fn != NULL) + png_ptr->output_flush_fn = output_flush_fn; + else + png_ptr->output_flush_fn = png_default_flush; +#else + png_ptr->output_flush_fn = output_flush_fn; +#endif +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + + /* It is an error to read while writing a png file */ + if (png_ptr->read_data_fn != NULL) + { + png_ptr->read_data_fn = NULL; + png_warning(png_ptr, + "Attempted to set both read_data_fn and write_data_fn in"); + png_warning(png_ptr, + "the same structure. Resetting read_data_fn to NULL."); + } +} + +#if defined(USE_FAR_KEYWORD) +#if defined(_MSC_VER) +void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + FP_OFF(near_ptr) = FP_OFF(ptr); + far_ptr = (void FAR *)near_ptr; + if(check != 0) + if(FP_SEG(ptr) != FP_SEG(far_ptr)) + png_error(png_ptr,"segment lost in conversion"); + return(near_ptr); +} +# else +void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check) +{ + void *near_ptr; + void FAR *far_ptr; + near_ptr = (void FAR *)ptr; + far_ptr = (void FAR *)near_ptr; + if(check != 0) + if(far_ptr != ptr) + png_error(png_ptr,"segment lost in conversion"); + return(near_ptr); +} +# endif +# endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/freeimage241/Source/LibPNG/pngwrite.c b/freeimage241/Source/LibPNG/pngwrite.c new file mode 100644 index 0000000..63208b6 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngwrite.c @@ -0,0 +1,1448 @@ + +/* pngwrite.c - general routines to write a PNG file + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +/* get internal access to png.h */ +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Writes all the PNG information. This is the suggested way to use the + * library. If you have a new chunk to add, make a function to write it, + * and put it in the correct location here. If you want the chunk written + * after the image data, put it in png_write_end(). I strongly encourage + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing + * the chunk, as that will keep the code from breaking if you want to just + * write a plain PNG file. If you have long comments, I suggest writing + * them in png_write_end(), and compressing them. + */ +void PNGAPI +png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_info_before_PLTE\n"); + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + { + png_write_sig(png_ptr); /* write PNG signature */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) + if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted)) + { + png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n"); + png_ptr->mng_features_permitted=0; + } +#endif + /* write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + info_ptr->interlace_type); +#else + 0); +#endif + /* the rest of these check to see if the valid field has the appropriate + flag set, and if it does, writes the chunk. */ +#if defined(PNG_WRITE_gAMA_SUPPORTED) + if (info_ptr->valid & PNG_INFO_gAMA) + { +# ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_gAMA(png_ptr, info_ptr->gamma); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); +# endif +#endif + } +#endif +#if defined(PNG_WRITE_sRGB_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sRGB) + png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); +#endif +#if defined(PNG_WRITE_iCCP_SUPPORTED) + if (info_ptr->valid & PNG_INFO_iCCP) + png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, + info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); +#endif +#if defined(PNG_WRITE_sBIT_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sBIT) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); +#endif +#if defined(PNG_WRITE_cHRM_SUPPORTED) + if (info_ptr->valid & PNG_INFO_cHRM) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_cHRM(png_ptr, + info_ptr->x_white, info_ptr->y_white, + info_ptr->x_red, info_ptr->y_red, + info_ptr->x_green, info_ptr->y_green, + info_ptr->x_blue, info_ptr->y_blue); +#else +# ifdef PNG_FIXED_POINT_SUPPORTED + png_write_cHRM_fixed(png_ptr, + info_ptr->int_x_white, info_ptr->int_y_white, + info_ptr->int_x_red, info_ptr->int_y_red, + info_ptr->int_x_green, info_ptr->int_y_green, + info_ptr->int_x_blue, info_ptr->int_y_blue); +# endif +#endif + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep=png_handle_as_unknown(png_ptr, up->name); + if (keep != HANDLE_CHUNK_NEVER && + up->location && (!(up->location & PNG_HAVE_PLTE)) && + ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; + } +} + +void PNGAPI +png_write_info(png_structp png_ptr, png_infop info_ptr) +{ +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) + int i; +#endif + + png_debug(1, "in png_write_info\n"); + + png_write_info_before_PLTE(png_ptr, info_ptr); + + if (info_ptr->valid & PNG_INFO_PLTE) + png_write_PLTE(png_ptr, info_ptr->palette, + (png_uint_32)info_ptr->num_palette); + else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_error(png_ptr, "Valid palette required for paletted images\n"); + +#if defined(PNG_WRITE_tRNS_SUPPORTED) + if (info_ptr->valid & PNG_INFO_tRNS) + { +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) + /* invert the alpha channel (in tRNS) */ + if ((png_ptr->transformations & PNG_INVERT_ALPHA) && + info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + int j; + for (j=0; j<(int)info_ptr->num_trans; j++) + info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]); + } +#endif + png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values), + info_ptr->num_trans, info_ptr->color_type); + } +#endif +#if defined(PNG_WRITE_bKGD_SUPPORTED) + if (info_ptr->valid & PNG_INFO_bKGD) + png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); +#endif +#if defined(PNG_WRITE_hIST_SUPPORTED) + if (info_ptr->valid & PNG_INFO_hIST) + png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); +#endif +#if defined(PNG_WRITE_oFFs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_oFFs) + png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, + info_ptr->offset_unit_type); +#endif +#if defined(PNG_WRITE_pCAL_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pCAL) + png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, + info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, + info_ptr->pcal_units, info_ptr->pcal_params); +#endif +#if defined(PNG_WRITE_sCAL_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sCAL) +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) + png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#else + png_warning(png_ptr, + "png_write_sCAL not supported; sCAL chunk not written.\n"); +#endif +#endif +#endif +#if defined(PNG_WRITE_pHYs_SUPPORTED) + if (info_ptr->valid & PNG_INFO_pHYs) + png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, + info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); +#endif +#if defined(PNG_WRITE_tIME_SUPPORTED) + if (info_ptr->valid & PNG_INFO_tIME) + { + png_write_tIME(png_ptr, &(info_ptr->mod_time)); + png_ptr->mode |= PNG_WROTE_tIME; + } +#endif +#if defined(PNG_WRITE_sPLT_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sPLT) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif +#if defined(PNG_WRITE_TEXT_SUPPORTED) + /* Check to see if we need to write text chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing header text chunk %d, type %d\n", i, + info_ptr->text[i].compression); + /* an internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#if defined(PNG_WRITE_iTXt_SUPPORTED) + /* write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + /* If we want a compressed text chunk */ + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) + { +#if defined(PNG_WRITE_zTXt_SUPPORTED) + /* write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#if defined(PNG_WRITE_tEXt_SUPPORTED) + /* write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, + 0); +#else + png_warning(png_ptr, "Unable to write uncompressed text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep=png_handle_as_unknown(png_ptr, up->name); + if (keep != HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_HAVE_PLTE) && + !(up->location & PNG_HAVE_IDAT) && + ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif +} + +/* Writes the end of the PNG file. If you don't want to write comments or + * time information, you can pass NULL for info. If you already wrote these + * in png_write_info(), do not write them again here. If you have long + * comments, I suggest writing them here, and compressing them. + */ +void PNGAPI +png_write_end(png_structp png_ptr, png_infop info_ptr) +{ + png_debug(1, "in png_write_end\n"); + if (!(png_ptr->mode & PNG_HAVE_IDAT)) + png_error(png_ptr, "No IDATs written into file"); + + /* see if user wants us to write information chunks */ + if (info_ptr != NULL) + { +#if defined(PNG_WRITE_TEXT_SUPPORTED) + int i; /* local index variable */ +#endif +#if defined(PNG_WRITE_tIME_SUPPORTED) + /* check to see if user has supplied a time chunk */ + if ((info_ptr->valid & PNG_INFO_tIME) && + !(png_ptr->mode & PNG_WROTE_tIME)) + png_write_tIME(png_ptr, &(info_ptr->mod_time)); +#endif +#if defined(PNG_WRITE_TEXT_SUPPORTED) + /* loop through comment chunks */ + for (i = 0; i < info_ptr->num_text; i++) + { + png_debug2(2, "Writing trailer text chunk %d, type %d\n", i, + info_ptr->text[i].compression); + /* an internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#if defined(PNG_WRITE_iTXt_SUPPORTED) + /* write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + { +#if defined(PNG_WRITE_zTXt_SUPPORTED) + /* write compressed chunk */ + png_write_zTXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); +#else + png_warning(png_ptr, "Unable to write compressed text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + } + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + { +#if defined(PNG_WRITE_tEXt_SUPPORTED) + /* write uncompressed chunk */ + png_write_tEXt(png_ptr, info_ptr->text[i].key, + info_ptr->text[i].text, 0); +#else + png_warning(png_ptr, "Unable to write uncompressed text\n"); +#endif + + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + int keep=png_handle_as_unknown(png_ptr, up->name); + if (keep != HANDLE_CHUNK_NEVER && + up->location && (up->location & PNG_AFTER_IDAT) && + ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS || + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif + } + + png_ptr->mode |= PNG_AFTER_IDAT; + + /* write end of PNG file */ + png_write_IEND(png_ptr); +#if 0 +/* This flush, added in libpng-1.0.8, causes some applications to crash + because they do not set png_ptr->output_flush_fn */ + png_flush(png_ptr); +#endif +} + +#if defined(PNG_WRITE_tIME_SUPPORTED) +#if !defined(_WIN32_WCE) +/* "time.h" functions are not supported on WindowsCE */ +void PNGAPI +png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) +{ + png_debug(1, "in png_convert_from_struct_tm\n"); + ptime->year = (png_uint_16)(1900 + ttime->tm_year); + ptime->month = (png_byte)(ttime->tm_mon + 1); + ptime->day = (png_byte)ttime->tm_mday; + ptime->hour = (png_byte)ttime->tm_hour; + ptime->minute = (png_byte)ttime->tm_min; + ptime->second = (png_byte)ttime->tm_sec; +} + +void PNGAPI +png_convert_from_time_t(png_timep ptime, time_t ttime) +{ + struct tm *tbuf; + + png_debug(1, "in png_convert_from_time_t\n"); + tbuf = gmtime(&ttime); + png_convert_from_struct_tm(ptime, tbuf); +} +#endif +#endif + +/* Initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn) +{ +#ifdef PNG_USER_MEM_SUPPORTED + return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL)); +} + +/* Alternate initialize png_ptr structure, and allocate any memory needed */ +png_structp PNGAPI +png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn) +{ +#endif /* PNG_USER_MEM_SUPPORTED */ + png_structp png_ptr; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + int i; + png_debug(1, "in png_create_write_struct\n"); +#ifdef PNG_USER_MEM_SUPPORTED + if ((png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, + (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr)) == NULL) +#else + if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL) +#endif /* PNG_USER_MEM_SUPPORTED */ + { + return ((png_structp)NULL); + } + +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_ptr->jmpbuf)) +#endif + { + png_free(png_ptr, png_ptr->zbuf); + png_ptr->zbuf=NULL; + png_destroy_struct(png_ptr); + return ((png_structp)NULL); + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf)); +#endif +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ + png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); + + i=0; + do + { + if(user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "Incompatible libpng version in application and library"); + } + + /* Libpng 1.0.6 was not binary compatible, due to insertion of the + info_ptr->free_me member. Libpng-1.0.1 and earlier were not + compatible due to insertion of the user transform function. Note + to maintainer: this test can be removed from version 1.2.0 and + beyond because the previous test would have already rejected it. */ + + if (user_png_ver[0] == '1' && user_png_ver[2] == '0' && + (user_png_ver[4] < '2' || user_png_ver[4] == '6') && + user_png_ver[5] == '\0') + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[80]; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); +#endif +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "Application must be recompiled; versions <= 1.0.6 were incompatible"); + } + } + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + + png_set_write_fn(png_ptr, NULL, NULL, NULL); + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, + 1, NULL, NULL); +#endif + + return ((png_structp)png_ptr); +} + +/* Initialize png_ptr structure, and allocate any memory needed */ +#undef png_write_init +void PNGAPI +png_write_init(png_structp png_ptr) +{ + /* We only come here via pre-1.0.7-compiled applications */ + png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0); +} + +#undef png_write_init_2 +void PNGAPI +png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size, png_size_t png_info_size) +{ + /* We only come here via pre-1.0.12-compiled applications */ +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + if(sizeof(png_struct) > png_struct_size || sizeof(png_info) > png_info_size) + { + char msg[80]; + png_ptr->warning_fn=(png_error_ptr)NULL; + if (user_png_ver) + { + sprintf(msg, "Application was compiled with png.h from libpng-%.20s", + user_png_ver); + png_warning(png_ptr, msg); + } + sprintf(msg, "Application is running with png.c from libpng-%.20s", + png_libpng_ver); + png_warning(png_ptr, msg); + } +#endif + if(sizeof(png_struct) > png_struct_size) + { + png_ptr->error_fn=(png_error_ptr)NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The png struct allocated by the application for writing is too small."); + } + if(sizeof(png_info) > png_info_size) + { + png_ptr->error_fn=(png_error_ptr)NULL; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags=0; +#endif + png_error(png_ptr, + "The info struct allocated by the application for writing is too small."); + } + png_write_init_3(&png_ptr, user_png_ver, png_struct_size); +} + + +void PNGAPI +png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, + png_size_t png_struct_size) +{ + png_structp png_ptr=*ptr_ptr; +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* to save current jump buffer */ +#endif + int i = 0; + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + { +#ifdef PNG_LEGACY_SUPPORTED + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; +#else + png_ptr->warning_fn=(png_error_ptr)NULL; + png_warning(png_ptr, + "Application uses deprecated png_write_init() and should be recompiled."); + break; +#endif + } + } while (png_libpng_ver[i++]); + + png_debug(1, "in png_write_init_3\n"); + +#ifdef PNG_SETJMP_SUPPORTED + /* save jump buffer and error functions */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); +#endif + + if (sizeof(png_struct) > png_struct_size) + { + png_destroy_struct(png_ptr); + png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); + *ptr_ptr = png_ptr; + } + + /* reset all variables to 0 */ + png_memset(png_ptr, 0, sizeof (png_struct)); + +#ifdef PNG_SETJMP_SUPPORTED + /* restore jump buffer */ + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); +#endif + + png_set_write_fn(png_ptr, NULL, NULL, NULL); + + /* initialize zbuf - compression buffer */ + png_ptr->zbuf_size = PNG_ZBUF_SIZE; + png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, + 1, NULL, NULL); +#endif +} + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structp png_ptr, png_bytepp row, + png_uint_32 num_rows) +{ + png_uint_32 i; /* row counter */ + png_bytepp rp; /* row pointer */ + + png_debug(1, "in png_write_rows\n"); + /* loop through the rows */ + for (i = 0, rp = row; i < num_rows; i++, rp++) + { + png_write_row(png_ptr, *rp); + } +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structp png_ptr, png_bytepp image) +{ + png_uint_32 i; /* row index */ + int pass, num_pass; /* pass variables */ + png_bytepp rp; /* points to current row */ + + png_debug(1, "in png_write_image\n"); +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* intialize interlace handling. If image is not interlaced, + this will set pass to 1 */ + num_pass = png_set_interlace_handling(png_ptr); +#else + num_pass = 1; +#endif + /* loop through passes */ + for (pass = 0; pass < num_pass; pass++) + { + /* loop through image */ + for (i = 0, rp = image; i < png_ptr->height; i++, rp++) + { + png_write_row(png_ptr, *rp); + } + } +} + +/* called by user to write a row of image data */ +void PNGAPI +png_write_row(png_structp png_ptr, png_bytep row) +{ + png_debug2(1, "in png_write_row (row %ld, pass %d)\n", + png_ptr->row_number, png_ptr->pass); + /* initialize transformations and other stuff if first time */ + if (png_ptr->row_number == 0 && png_ptr->pass == 0) + { + /* check for transforms that have been set but were defined out */ +#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined."); +#endif +#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined."); +#endif + + png_write_start_row(png_ptr); + } + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* if interlaced and not interested in row, return */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + { + switch (png_ptr->pass) + { + case 0: + if (png_ptr->row_number & 0x07) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 1: + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 2: + if ((png_ptr->row_number & 0x07) != 4) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 3: + if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 4: + if ((png_ptr->row_number & 0x03) != 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 5: + if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + { + png_write_finish_row(png_ptr); + return; + } + break; + case 6: + if (!(png_ptr->row_number & 0x01)) + { + png_write_finish_row(png_ptr); + return; + } + break; + } + } +#endif + + /* set up row info for transformations */ + png_ptr->row_info.color_type = png_ptr->color_type; + png_ptr->row_info.width = png_ptr->usr_width; + png_ptr->row_info.channels = png_ptr->usr_channels; + png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; + png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * + png_ptr->row_info.channels); + + png_ptr->row_info.rowbytes = ((png_ptr->row_info.width * + (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3); + + png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type); + png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width); + png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels); + png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes); + + /* Copy user's row into buffer, leaving room for filter byte. */ + png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row, + png_ptr->row_info.rowbytes); + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) + /* handle interlacing */ + if (png_ptr->interlaced && png_ptr->pass < 6 && + (png_ptr->transformations & PNG_INTERLACE)) + { + png_do_write_interlace(&(png_ptr->row_info), + png_ptr->row_buf + 1, png_ptr->pass); + /* this should always get caught above, but still ... */ + if (!(png_ptr->row_info.width)) + { + png_write_finish_row(png_ptr); + return; + } + } +#endif + + /* handle other transformations */ + if (png_ptr->transformations) + png_do_write_transformations(png_ptr); + +#if defined(PNG_MNG_FEATURES_SUPPORTED) + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) + { + /* Intrapixel differencing */ + png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + } +#endif + + /* Find a filter if necessary, filter the row and write it out. */ + png_write_find_filter(png_ptr, &(png_ptr->row_info)); + + if (png_ptr->write_row_fn != NULL) + (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); +} + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush\n"); + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); +} + +/* flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structp png_ptr) +{ + int wrote_IDAT; + + png_debug(1, "in png_write_flush\n"); + /* We have already written out all of the data */ + if (png_ptr->row_number >= png_ptr->num_rows) + return; + + do + { + int ret; + + /* compress the data */ + ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); + wrote_IDAT = 0; + + /* check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + if (!(png_ptr->zstream.avail_out)) + { + /* write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + wrote_IDAT = 1; + } + } while(wrote_IDAT == 1); + + /* If there is any data left to be output, write it into a new IDAT */ + if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) + { + /* write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + png_ptr->flush_rows = 0; + png_flush(png_ptr); +} +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + +/* free all memory used by the write */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn = NULL; + png_voidp mem_ptr = NULL; +#endif + + png_debug(1, "in png_destroy_write_struct\n"); + if (png_ptr_ptr != NULL) + { + png_ptr = *png_ptr_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + } + + if (info_ptr_ptr != NULL) + info_ptr = *info_ptr_ptr; + + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->num_chunk_list) + { + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list=NULL; + png_ptr->num_chunk_list=0; + } +#endif + +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)info_ptr); +#endif + *info_ptr_ptr = (png_infop)NULL; + } + + if (png_ptr != NULL) + { + png_write_destroy(png_ptr); +#ifdef PNG_USER_MEM_SUPPORTED + png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, + (png_voidp)mem_ptr); +#else + png_destroy_struct((png_voidp)png_ptr); +#endif + *png_ptr_ptr = (png_structp)NULL; + } +} + + +/* Free any memory used in png_ptr struct (old method) */ +void /* PRIVATE */ +png_write_destroy(png_structp png_ptr) +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf tmp_jmp; /* save jump buffer */ +#endif + png_error_ptr error_fn; + png_error_ptr warning_fn; + png_voidp error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_free_ptr free_fn; +#endif + + png_debug(1, "in png_write_destroy\n"); + /* free any memory zlib uses */ + deflateEnd(&png_ptr->zstream); + + /* free our memory. png_free checks NULL for us. */ + png_free(png_ptr, png_ptr->zbuf); + png_free(png_ptr, png_ptr->row_buf); + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->sub_row); + png_free(png_ptr, png_ptr->up_row); + png_free(png_ptr, png_ptr->avg_row); + png_free(png_ptr, png_ptr->paeth_row); + +#if defined(PNG_TIME_RFC1123_SUPPORTED) + png_free(png_ptr, png_ptr->time_buffer); +#endif + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + png_free(png_ptr, png_ptr->prev_filters); + png_free(png_ptr, png_ptr->filter_weights); + png_free(png_ptr, png_ptr->inv_filter_weights); + png_free(png_ptr, png_ptr->filter_costs); + png_free(png_ptr, png_ptr->inv_filter_costs); +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* reset structure */ + png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf)); +#endif + + error_fn = png_ptr->error_fn; + warning_fn = png_ptr->warning_fn; + error_ptr = png_ptr->error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + free_fn = png_ptr->free_fn; +#endif + + png_memset(png_ptr, 0, sizeof (png_struct)); + + png_ptr->error_fn = error_fn; + png_ptr->warning_fn = warning_fn; + png_ptr->error_ptr = error_ptr; +#ifdef PNG_USER_MEM_SUPPORTED + png_ptr->free_fn = free_fn; +#endif + +#ifdef PNG_SETJMP_SUPPORTED + png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf)); +#endif +} + +/* Allow the application to select one or more row filters to use. */ +void PNGAPI +png_set_filter(png_structp png_ptr, int method, int filters) +{ + png_debug(1, "in png_set_filter\n"); +#if defined(PNG_MNG_FEATURES_SUPPORTED) + if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + (method == PNG_INTRAPIXEL_DIFFERENCING)) + method = PNG_FILTER_TYPE_BASE; +#endif + if (method == PNG_FILTER_TYPE_BASE) + { + switch (filters & (PNG_ALL_FILTERS | 0x07)) + { + case 5: + case 6: + case 7: png_warning(png_ptr, "Unknown row filter for method 0"); + case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break; + case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break; + case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break; + case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break; + case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break; + default: png_ptr->do_filter = (png_byte)filters; break; + } + + /* If we have allocated the row_buf, this means we have already started + * with the image and we should have allocated all of the filter buffers + * that have been selected. If prev_row isn't already allocated, then + * it is too late to start using the filters that need it, since we + * will be missing the data in the previous row. If an application + * wants to start and stop using particular filters during compression, + * it should start out with all of the filters, and then add and + * remove them after the start of compression. + */ + if (png_ptr->row_buf != NULL) + { + if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Up filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_UP; + } + else + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Average filter after starting"); + png_ptr->do_filter &= ~PNG_FILTER_AVG; + } + else + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + png_ptr->paeth_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Paeth filter after starting"); + png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); + } + else + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + + if (png_ptr->do_filter == PNG_NO_FILTERS) + png_ptr->do_filter = PNG_FILTER_NONE; + } + } + else + png_error(png_ptr, "Unknown custom filter method"); +} + +/* This allows us to influence the way in which libpng chooses the "best" + * filter for the current scanline. While the "minimum-sum-of-absolute- + * differences metric is relatively fast and effective, there is some + * question as to whether it can be improved upon by trying to keep the + * filtered data going to zlib more consistent, hopefully resulting in + * better compression. + */ +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */ +void PNGAPI +png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, + int num_weights, png_doublep filter_weights, + png_doublep filter_costs) +{ + int i; + + png_debug(1, "in png_set_filter_heuristics\n"); + if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) + { + png_warning(png_ptr, "Unknown filter heuristic method"); + return; + } + + if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) + { + heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; + } + + if (num_weights < 0 || filter_weights == NULL || + heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) + { + num_weights = 0; + } + + png_ptr->num_prev_filters = (png_byte)num_weights; + png_ptr->heuristic_method = (png_byte)heuristic_method; + + if (num_weights > 0) + { + if (png_ptr->prev_filters == NULL) + { + png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(sizeof(png_byte) * num_weights)); + + /* To make sure that the weighting starts out fairly */ + for (i = 0; i < num_weights; i++) + { + png_ptr->prev_filters[i] = 255; + } + } + + if (png_ptr->filter_weights == NULL) + { + png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(sizeof(png_uint_16) * num_weights)); + + png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(sizeof(png_uint_16) * num_weights)); + for (i = 0; i < num_weights; i++) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + } + + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] < 0.0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + else + { + png_ptr->inv_filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); + png_ptr->filter_weights[i] = + (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); + } + } + } + + /* If, in the future, there are other filter methods, this would + * need to be based on png_ptr->filter. + */ + if (png_ptr->filter_costs == NULL) + { + png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + if (filter_costs == NULL || filter_costs[i] < 0.0) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + else if (filter_costs[i] >= 1.0) + { + png_ptr->inv_filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); + png_ptr->filter_costs[i] = + (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); + } + } +} +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +void PNGAPI +png_set_compression_level(png_structp png_ptr, int level) +{ + png_debug(1, "in png_set_compression_level\n"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; + png_ptr->zlib_level = level; +} + +void PNGAPI +png_set_compression_mem_level(png_structp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_compression_mem_level\n"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; + png_ptr->zlib_mem_level = mem_level; +} + +void PNGAPI +png_set_compression_strategy(png_structp png_ptr, int strategy) +{ + png_debug(1, "in png_set_compression_strategy\n"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; + png_ptr->zlib_strategy = strategy; +} + +void PNGAPI +png_set_compression_window_bits(png_structp png_ptr, int window_bits) +{ + if (window_bits > 15) + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + else if (window_bits < 8) + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); +#ifndef WBITS_8_OK + /* avoid libpng bug with 256-byte windows */ + if (window_bits == 8) + { + png_warning(png_ptr, "Compression window is being reset to 512"); + window_bits=9; + } +#endif + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; + png_ptr->zlib_window_bits = window_bits; +} + +void PNGAPI +png_set_compression_method(png_structp png_ptr, int method) +{ + png_debug(1, "in png_set_compression_method\n"); + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; + png_ptr->zlib_method = method; +} + +void PNGAPI +png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) +{ + png_ptr->write_row_fn = write_row_fn; +} + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +void PNGAPI +png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr + write_user_transform_fn) +{ + png_debug(1, "in png_set_write_user_transform_fn\n"); + png_ptr->transformations |= PNG_USER_TRANSFORM; + png_ptr->write_user_transform_fn = write_user_transform_fn; +} +#endif + + +#if defined(PNG_INFO_IMAGE_SUPPORTED) +void PNGAPI +png_write_png(png_structp png_ptr, png_infop info_ptr, + int transforms, voidp params) +{ +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) + /* invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + + /* Write the file header information. */ + png_write_info(png_ptr, info_ptr); + + /* ------ these transformations don't touch the info structure ------- */ + +#if defined(PNG_WRITE_INVERT_SUPPORTED) + /* invert monochrome pixels */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) + png_set_invert_mono(png_ptr); +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) + /* Shift the pixels up to a legal bit depth and fill in + * as appropriate to correctly scale the image. + */ + if ((transforms & PNG_TRANSFORM_SHIFT) + && (info_ptr->valid & PNG_INFO_sBIT)) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#endif + +#if defined(PNG_WRITE_PACK_SUPPORTED) + /* pack pixels into bytes */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) + /* swap location of alpha bytes from ARGB to RGBA */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + png_set_swap_alpha(png_ptr); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) + /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into + * RGB (4 channels -> 3 channels). The second parameter is not used. + */ + if (transforms & PNG_TRANSFORM_STRIP_FILLER) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#endif + +#if defined(PNG_WRITE_BGR_SUPPORTED) + /* flip BGR pixels to RGB */ + if (transforms & PNG_TRANSFORM_BGR) + png_set_bgr(png_ptr); +#endif + +#if defined(PNG_WRITE_SWAP_SUPPORTED) + /* swap bytes of 16-bit files to most significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + png_set_swap(png_ptr); +#endif + +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) + /* swap bits of 1, 2, 4 bit packed pixel formats */ + if (transforms & PNG_TRANSFORM_PACKSWAP) + png_set_packswap(png_ptr); +#endif + + /* ----------------------- end of transformations ------------------- */ + + /* write the bits */ + if (info_ptr->valid & PNG_INFO_IDAT) + png_write_image(png_ptr, info_ptr->row_pointers); + + /* It is REQUIRED to call this to finish writing the rest of the file */ + png_write_end(png_ptr, info_ptr); + + if(transforms == 0 || params == NULL) + /* quiet compiler warnings */ return; +} +#endif +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/freeimage241/Source/LibPNG/pngwtran.c b/freeimage241/Source/LibPNG/pngwtran.c new file mode 100644 index 0000000..3cc6067 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngwtran.c @@ -0,0 +1,563 @@ + +/* pngwtran.c - transforms the data in a row for PNG writers + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_do_write_transformations\n"); + + if (png_ptr == NULL) + return; + +#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + if (png_ptr->transformations & PNG_USER_TRANSFORM) + if(png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* user write transform function */ + (png_ptr, /* png_ptr */ + &(png_ptr->row_info), /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_uint_32 rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif +#if defined(PNG_WRITE_FILLER_SUPPORTED) + if (png_ptr->transformations & PNG_FILLER) + png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, + png_ptr->flags); +#endif +#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_PACK_SUPPORTED) + if (png_ptr->transformations & PNG_PACK) + png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif +#if defined(PNG_WRITE_SWAP_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_SHIFT_SUPPORTED) + if (png_ptr->transformations & PNG_SHIFT) + png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_BGR_SUPPORTED) + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +#if defined(PNG_WRITE_INVERT_SUPPORTED) + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif +} + +#if defined(PNG_WRITE_PACK_SUPPORTED) +/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The + * row_info bit depth should be 8 (one pixel per byte). The channels + * should be 1 (this only happens on grayscale and paletted images). + */ +void /* PRIVATE */ +png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) +{ + png_debug(1, "in png_do_pack\n"); + if (row_info->bit_depth == 8 && +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + row_info->channels == 1) + { + switch ((int)bit_depth) + { + case 1: + { + png_bytep sp, dp; + int mask, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + mask = 0x80; + v = 0; + + for (i = 0; i < row_width; i++) + { + if (*sp != 0) + v |= mask; + sp++; + if (mask > 1) + mask >>= 1; + else + { + mask = 0x80; + *dp = (png_byte)v; + dp++; + v = 0; + } + } + if (mask != 0x80) + *dp = (png_byte)v; + break; + } + case 2: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 6; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x03); + v |= (value << shift); + if (shift == 0) + { + shift = 6; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 2; + sp++; + } + if (shift != 6) + *dp = (png_byte)v; + break; + } + case 4: + { + png_bytep sp, dp; + int shift, v; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + sp = row; + dp = row; + shift = 4; + v = 0; + for (i = 0; i < row_width; i++) + { + png_byte value; + + value = (png_byte)(*sp & 0x0f); + v |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp = (png_byte)v; + dp++; + v = 0; + } + else + shift -= 4; + + sp++; + } + if (shift != 4) + *dp = (png_byte)v; + break; + } + } + row_info->bit_depth = (png_byte)bit_depth; + row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); + row_info->rowbytes = + ((row_info->width * row_info->pixel_depth + 7) >> 3); + } +} +#endif + +#if defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Shift pixel values to take advantage of whole range. Pass the + * true number of bits in bit_depth. The row should be packed + * according to row_info->bit_depth. Thus, if you had a row of + * bit depth 4, but the pixels only had values from 0 to 7, you + * would pass 3 as bit_depth, and this routine would translate the + * data to 0 to 15. + */ +void /* PRIVATE */ +png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth) +{ + png_debug(1, "in png_do_shift\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && +#else + if ( +#endif + row_info->color_type != PNG_COLOR_TYPE_PALETTE) + { + int shift_start[4], shift_dec[4]; + int channels = 0; + + if (row_info->color_type & PNG_COLOR_MASK_COLOR) + { + shift_start[channels] = row_info->bit_depth - bit_depth->red; + shift_dec[channels] = bit_depth->red; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->green; + shift_dec[channels] = bit_depth->green; + channels++; + shift_start[channels] = row_info->bit_depth - bit_depth->blue; + shift_dec[channels] = bit_depth->blue; + channels++; + } + else + { + shift_start[channels] = row_info->bit_depth - bit_depth->gray; + shift_dec[channels] = bit_depth->gray; + channels++; + } + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + shift_start[channels] = row_info->bit_depth - bit_depth->alpha; + shift_dec[channels] = bit_depth->alpha; + channels++; + } + + /* with low row depths, could only be grayscale, so one channel */ + if (row_info->bit_depth < 8) + { + png_bytep bp = row; + png_uint_32 i; + png_byte mask; + png_uint_32 row_bytes = row_info->rowbytes; + + if (bit_depth->gray == 1 && row_info->bit_depth == 2) + mask = 0x55; + else if (row_info->bit_depth == 4 && bit_depth->gray == 3) + mask = 0x11; + else + mask = 0xff; + + for (i = 0; i < row_bytes; i++, bp++) + { + png_uint_16 v; + int j; + + v = *bp; + *bp = 0; + for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & mask); + } + } + } + else if (row_info->bit_depth == 8) + { + png_bytep bp = row; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (i = 0; i < istop; i++, bp++) + { + + png_uint_16 v; + int j; + int c = (int)(i%channels); + + v = *bp; + *bp = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + *bp |= (png_byte)((v << j) & 0xff); + else + *bp |= (png_byte)((v >> (-j)) & 0xff); + } + } + } + else + { + png_bytep bp; + png_uint_32 i; + png_uint_32 istop = channels * row_info->width; + + for (bp = row, i = 0; i < istop; i++) + { + int c = (int)(i%channels); + png_uint_16 value, v; + int j; + + v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); + value = 0; + for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) + { + if (j > 0) + value |= (png_uint_16)((v << j) & (png_uint_16)0xffff); + else + value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); + } + *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)(value & 0xff); + } + } + } +} +#endif + +#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_swap_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This converts from ARGB to RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AARRGGBB to RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from AG to GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save; + } + } + /* This converts from AAGG to GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + png_byte save[2]; + save[0] = *(sp++); + save[1] = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = save[0]; + *(dp++) = save[1]; + } + } + } + } +} +#endif + +#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +void /* PRIVATE */ +png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_invert_alpha\n"); +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL) +#endif + { + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This inverts the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in RRGGBBAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This inverts the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + /* This inverts the alpha channel in GGAA */ + else + { + png_bytep sp, dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + for (i = 0, sp = dp = row; i < row_width; i++) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); + *(dp++) = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); + } + } + } + } +} +#endif + +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* undoes intrapixel differencing */ +void /* PRIVATE */ +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel\n"); + if ( +#if defined(PNG_USELESS_TESTS_SUPPORTED) + row != NULL && row_info != NULL && +#endif + (row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((*rp - *(rp+1))&0xff); + *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0=*(rp )<<8 | *(rp+1); + png_uint_32 s1=*(rp+2)<<8 | *(rp+3); + png_uint_32 s2=*(rp+4)<<8 | *(rp+5); + png_uint_32 red=(s0-s1)&0xffff; + png_uint_32 blue=(s2-s1)&0xffff; + *(rp ) = (png_byte)((red>>8)&0xff); + *(rp+1) = (png_byte)(red&0xff); + *(rp+4) = (png_byte)((blue>>8)&0xff); + *(rp+5) = (png_byte)(blue&0xff); + } + } + } +} +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/freeimage241/Source/LibPNG/pngwutil.c b/freeimage241/Source/LibPNG/pngwutil.c new file mode 100644 index 0000000..a1db9c2 --- /dev/null +++ b/freeimage241/Source/LibPNG/pngwutil.c @@ -0,0 +1,2646 @@ + +/* pngwutil.c - utilities to write a PNG file + * + * libpng 1.0.12 - June 8, 2001 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2001 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + */ + +#define PNG_INTERNAL +#include "png.h" +#ifdef PNG_WRITE_SUPPORTED + +/* Place a 32-bit number into a buffer in PNG byte order. We work + * with unsigned numbers for convenience, although one supported + * ancillary chunk uses signed (two's complement) numbers. + */ +void /* PRIVATE */ +png_save_uint_32(png_bytep buf, png_uint_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +/* The png_save_int_32 function assumes integers are stored in two's + * complement format. If this isn't the case, then this routine needs to + * be modified to write data in two's complement format. + */ +void /* PRIVATE */ +png_save_int_32(png_bytep buf, png_int_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +void /* PRIVATE */ +png_save_uint_16(png_bytep buf, unsigned int i) +{ + buf[0] = (png_byte)((i >> 8) & 0xff); + buf[1] = (png_byte)(i & 0xff); +} + +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ +void PNGAPI +png_write_chunk(png_structp png_ptr, png_bytep chunk_name, + png_bytep data, png_size_t length) +{ + png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, length); + png_write_chunk_end(png_ptr); +} + +/* Write the start of a PNG chunk. The type is the chunk type. + * The total_length is the sum of the lengths of all the data you will be + * passing in png_write_chunk_data(). + */ +void PNGAPI +png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, + png_uint_32 length) +{ + png_byte buf[4]; + png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length); + + /* write the length */ + png_save_uint_32(buf, length); + png_write_data(png_ptr, buf, (png_size_t)4); + + /* write the chunk name */ + png_write_data(png_ptr, chunk_name, (png_size_t)4); + /* reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); +} + +/* Write the data of a PNG chunk started with png_write_chunk_start(). + * Note that multiple calls to this function are allowed, and that the + * sum of the lengths from these calls *must* add up to the total_length + * given to png_write_chunk_start(). + */ +void PNGAPI +png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length) +{ + /* write the data, and run the CRC over it */ + if (data != NULL && length > 0) + { + png_calculate_crc(png_ptr, data, length); + png_write_data(png_ptr, data, length); + } +} + +/* Finish a chunk started with png_write_chunk_start(). */ +void PNGAPI +png_write_chunk_end(png_structp png_ptr) +{ + png_byte buf[4]; + + /* write the crc */ + png_save_uint_32(buf, png_ptr->crc); + + png_write_data(png_ptr, buf, (png_size_t)4); +} + +/* Simple function to write the signature. If we have already written + * the magic bytes of the signature, or more likely, the PNG stream is + * being embedded into another stream and doesn't need its own signature, + * we should call png_set_sig_bytes() to tell libpng how many of the + * bytes have already been written. + */ +void /* PRIVATE */ +png_write_sig(png_structp png_ptr) +{ + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + /* write the rest of the 8 byte signature */ + png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], + (png_size_t)8 - png_ptr->sig_bytes); + if(png_ptr->sig_bytes < 3) + png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; +} + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) +/* + * This pair of functions encapsulates the operation of (a) compressing a + * text string, and (b) issuing it later as a series of chunk data writes. + * The compression_state structure is shared context for these functions + * set up by the caller in order to make the whole mess thread-safe. + */ + +typedef struct +{ + char *input; /* the uncompressed input data */ + int input_len; /* its length */ + int num_output_ptr; /* number of output pointers used */ + int max_output_ptr; /* size of output_ptr */ + png_charpp output_ptr; /* array of pointers to output */ +} compression_state; + +/* compress given text into storage in the png_ptr structure */ +static int /* PRIVATE */ +png_text_compress(png_structp png_ptr, + png_charp text, png_size_t text_len, int compression, + compression_state *comp) +{ + int ret; + + comp->num_output_ptr = comp->max_output_ptr = 0; + comp->output_ptr = NULL; + comp->input = NULL; + + /* we may just want to pass the text right through */ + if (compression == PNG_TEXT_COMPRESSION_NONE) + { + comp->input = text; + comp->input_len = text_len; + return((int)text_len); + } + + if (compression >= PNG_TEXT_COMPRESSION_LAST) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[50]; + sprintf(msg, "Unknown compression type %d", compression); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "Unknown compression type"); +#endif + } + + /* We can't write the chunk until we find out how much data we have, + * which means we need to run the compressor first and save the + * output. This shouldn't be a problem, as the vast majority of + * comments should be reasonable, but we will set up an array of + * malloc'd pointers to be sure. + * + * If we knew the application was well behaved, we could simplify this + * greatly by assuming we can always malloc an output buffer large + * enough to hold the compressed text ((1001 * text_len / 1000) + 12) + * and malloc this directly. The only time this would be a bad idea is + * if we can't malloc more than 64K and we have 64K of random input + * data, or if the input string is incredibly large (although this + * wouldn't cause a failure, just a slowdown due to swapping). + */ + + /* set up the compression buffers */ + png_ptr->zstream.avail_in = (uInt)text_len; + png_ptr->zstream.next_in = (Bytef *)text; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf; + + /* this is the same compression loop as in png_write_row() */ + do + { + /* compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + if (ret != Z_OK) + { + /* error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + /* check to see if we need more room */ + if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in) + { + /* make sure the output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); + png_memcpy(comp->output_ptr, old_ptr, old_max + * sizeof (png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * sizeof (png_charp))); + } + + /* save the data */ + comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr, + (png_uint_32)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + /* continue until we don't have any more to compress */ + } while (png_ptr->zstream.avail_in); + + /* finish the compression */ + do + { + /* tell zlib we are finished */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + + if (ret == Z_OK) + { + /* check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + /* check to make sure our output array has room */ + if (comp->num_output_ptr >= comp->max_output_ptr) + { + int old_max; + + old_max = comp->max_output_ptr; + comp->max_output_ptr = comp->num_output_ptr + 4; + if (comp->output_ptr != NULL) + { + png_charpp old_ptr; + + old_ptr = comp->output_ptr; + /* This could be optimized to realloc() */ + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); + png_memcpy(comp->output_ptr, old_ptr, + old_max * sizeof (png_charp)); + png_free(png_ptr, old_ptr); + } + else + comp->output_ptr = (png_charpp)png_malloc(png_ptr, + (png_uint_32)(comp->max_output_ptr * sizeof (png_charp))); + } + + /* save off the data */ + comp->output_ptr[comp->num_output_ptr] = + (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size); + png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, + png_ptr->zbuf_size); + comp->num_output_ptr++; + + /* and reset the buffer pointers */ + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; + } + } + else if (ret != Z_STREAM_END) + { + /* we got an error */ + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* text length is number of buffers plus last buffer */ + text_len = png_ptr->zbuf_size * comp->num_output_ptr; + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; + + return((int)text_len); +} + +/* ship the compressed text out via chunk writes */ +static void /* PRIVATE */ +png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) +{ + int i; + + /* handle the no-compression case */ + if (comp->input) + { + png_write_chunk_data(png_ptr, (png_bytep)comp->input, comp->input_len); + return; + } + + /* write saved output buffers, if any */ + for (i = 0; i < comp->num_output_ptr; i++) + { + png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i], + png_ptr->zbuf_size); + png_free(png_ptr, comp->output_ptr[i]); + comp->output_ptr[i]=NULL; + } + if (comp->max_output_ptr != 0) + png_free(png_ptr, comp->output_ptr); + comp->output_ptr=NULL; + /* write anything left in zbuf */ + if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) + png_write_chunk_data(png_ptr, png_ptr->zbuf, + png_ptr->zbuf_size - png_ptr->zstream.avail_out); + + /* reset zlib for another zTXt/iTXt or the image data */ + deflateReset(&png_ptr->zstream); + +} +#endif + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. Note that the rest of this code depends upon this + * information being correct. + */ +void /* PRIVATE */ +png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, + int bit_depth, int color_type, int compression_type, int filter_type, + int interlace_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IHDR; +#endif + png_byte buf[13]; /* buffer to store the IHDR info */ + + png_debug(1, "in png_write_IHDR\n"); + /* Check that we have valid input data from the application info */ + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: + case 16: png_ptr->channels = 1; break; + default: png_error(png_ptr,"Invalid bit depth for grayscale image"); + } + break; + case PNG_COLOR_TYPE_RGB: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGB image"); + png_ptr->channels = 3; + break; + case PNG_COLOR_TYPE_PALETTE: + switch (bit_depth) + { + case 1: + case 2: + case 4: + case 8: png_ptr->channels = 1; break; + default: png_error(png_ptr, "Invalid bit depth for paletted image"); + } + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); + png_ptr->channels = 2; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + if (bit_depth != 8 && bit_depth != 16) + png_error(png_ptr, "Invalid bit depth for RGBA image"); + png_ptr->channels = 4; + break; + default: + png_error(png_ptr, "Invalid image color type specified"); + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + { + png_warning(png_ptr, "Invalid compression type specified"); + compression_type = PNG_COMPRESSION_TYPE_BASE; + } + + /* Write filter_method 64 (intrapixel differencing) only if + * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and + * 2. Libpng did not write a PNG signature (this filter_method is only + * used in PNG datastreams that are embedded in MNG datastreams) and + * 3. The application called png_permit_mng_features with a mask that + * included PNG_FLAG_MNG_FILTER_64 and + * 4. The filter_method is 64 and + * 5. The color_type is RGB or RGBA + */ + if ( +#if defined(PNG_MNG_FEATURES_SUPPORTED) + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) && + (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && +#endif + filter_type != PNG_FILTER_TYPE_BASE) + { + png_warning(png_ptr, "Invalid filter type specified"); + filter_type = PNG_FILTER_TYPE_BASE; + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (interlace_type != PNG_INTERLACE_NONE && + interlace_type != PNG_INTERLACE_ADAM7) + { + png_warning(png_ptr, "Invalid interlace type specified"); + interlace_type = PNG_INTERLACE_ADAM7; + } +#else + interlace_type=PNG_INTERLACE_NONE; +#endif + + /* save off the relevent information */ + png_ptr->bit_depth = (png_byte)bit_depth; + png_ptr->color_type = (png_byte)color_type; + png_ptr->interlaced = (png_byte)interlace_type; +#if defined(PNG_MNG_FEATURES_SUPPORTED) + png_ptr->filter_type = (png_byte)filter_type; +#endif + png_ptr->width = width; + png_ptr->height = height; + + png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); + png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3); + /* set the usr info, so any transformations can modify it */ + png_ptr->usr_width = png_ptr->width; + png_ptr->usr_bit_depth = png_ptr->bit_depth; + png_ptr->usr_channels = png_ptr->channels; + + /* pack the header information into the buffer */ + png_save_uint_32(buf, width); + png_save_uint_32(buf + 4, height); + buf[8] = (png_byte)bit_depth; + buf[9] = (png_byte)color_type; + buf[10] = (png_byte)compression_type; + buf[11] = (png_byte)filter_type; + buf[12] = (png_byte)interlace_type; + + /* write the chunk */ + png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13); + + /* initialize zlib with PNG info */ + png_ptr->zstream.zalloc = png_zalloc; + png_ptr->zstream.zfree = png_zfree; + png_ptr->zstream.opaque = (voidpf)png_ptr; + if (!(png_ptr->do_filter)) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + png_ptr->bit_depth < 8) + png_ptr->do_filter = PNG_FILTER_NONE; + else + png_ptr->do_filter = PNG_ALL_FILTERS; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) + { + if (png_ptr->do_filter != PNG_FILTER_NONE) + png_ptr->zlib_strategy = Z_FILTERED; + else + png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; + } + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) + png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) + png_ptr->zlib_mem_level = 8; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) + png_ptr->zlib_window_bits = 15; + if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) + png_ptr->zlib_method = 8; + deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, + png_ptr->zlib_method, png_ptr->zlib_window_bits, + png_ptr->zlib_mem_level, png_ptr->zlib_strategy); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + png_ptr->mode = PNG_HAVE_IHDR; +} + +/* write the palette. We are careful not to trust png_color to be in the + * correct order for PNG, so people can redefine it to any convenient + * structure. + */ +void /* PRIVATE */ +png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_PLTE; +#endif + png_uint_32 i; + png_colorp pal_ptr; + png_byte buf[3]; + + png_debug(1, "in png_write_PLTE\n"); + if (( +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) + !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && +#endif + num_pal == 0) || num_pal > 256) + { + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_error(png_ptr, "Invalid number of colors in palette"); + } + else + { + png_warning(png_ptr, "Invalid number of colors in palette"); + return; + } + } + + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + { + png_warning(png_ptr, + "Ignoring request to write a PLTE chunk in grayscale PNG"); + return; + } + + png_ptr->num_palette = (png_uint_16)num_pal; + png_debug1(3, "num_palette = %d\n", png_ptr->num_palette); + + png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3); +#ifndef PNG_NO_POINTER_INDEXING + for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) + { + buf[0] = pal_ptr->red; + buf[1] = pal_ptr->green; + buf[2] = pal_ptr->blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#else + /* This is a little slower but some buggy compilers need to do this instead */ + pal_ptr=palette; + for (i = 0; i < num_pal; i++) + { + buf[0] = pal_ptr[i].red; + buf[1] = pal_ptr[i].green; + buf[2] = pal_ptr[i].blue; + png_write_chunk_data(png_ptr, buf, (png_size_t)3); + } +#endif + png_write_chunk_end(png_ptr); + png_ptr->mode |= PNG_HAVE_PLTE; +} + +/* write an IDAT chunk */ +void /* PRIVATE */ +png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IDAT; +#endif + png_debug(1, "in png_write_IDAT\n"); + png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length); + png_ptr->mode |= PNG_HAVE_IDAT; +} + +/* write an IEND chunk */ +void /* PRIVATE */ +png_write_IEND(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_IEND; +#endif + png_debug(1, "in png_write_IEND\n"); + png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, (png_size_t)0); + png_ptr->mode |= PNG_HAVE_IEND; +} + +#if defined(PNG_WRITE_gAMA_SUPPORTED) +/* write a gAMA chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA(png_structp png_ptr, double file_gamma) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_gAMA; +#endif + png_uint_32 igamma; + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA\n"); + /* file_gamma is saved in 1/100,000ths */ + igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); + png_save_uint_32(buf, igamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_gAMA; +#endif + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA\n"); + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, file_gamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#endif + +#if defined(PNG_WRITE_sRGB_SUPPORTED) +/* write a sRGB chunk */ +void /* PRIVATE */ +png_write_sRGB(png_structp png_ptr, int srgb_intent) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sRGB; +#endif + png_byte buf[1]; + + png_debug(1, "in png_write_sRGB\n"); + if(srgb_intent >= PNG_sRGB_INTENT_LAST) + png_warning(png_ptr, + "Invalid sRGB rendering intent specified"); + buf[0]=(png_byte)srgb_intent; + png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1); +} +#endif + +#if defined(PNG_WRITE_iCCP_SUPPORTED) +/* write an iCCP chunk */ +void /* PRIVATE */ +png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, + png_charp profile, int profile_len) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_iCCP; +#endif + png_size_t name_len; + png_charp new_name; + compression_state comp; + + png_debug(1, "in png_write_iCCP\n"); + if (name == NULL || (name_len = png_check_keyword(png_ptr, name, + &new_name)) == 0) + { + png_warning(png_ptr, "Empty keyword in iCCP chunk"); + return; + } + + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_warning(png_ptr, "Unknown compression type in iCCP chunk"); + + if (profile == NULL) + profile_len = 0; + + if (profile_len) + profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len, + PNG_COMPRESSION_TYPE_BASE, &comp); + + /* make sure we include the NULL after the name and the compression type */ + png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, + (png_uint_32)name_len+profile_len+2); + new_name[name_len+1]=0x00; + png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2); + + if (profile_len) + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#if defined(PNG_WRITE_sPLT_SUPPORTED) +/* write a sPLT chunk */ +void /* PRIVATE */ +png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sPLT; +#endif + png_size_t name_len; + png_charp new_name; + png_byte entrybuf[10]; + int entry_size = (spalette->depth == 8 ? 6 : 10); + int palette_size = entry_size * spalette->nentries; + png_sPLT_entryp ep; +#ifdef PNG_NO_POINTER_INDEXING + int i; +#endif + + png_debug(1, "in png_write_sPLT\n"); + if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr, + spalette->name, &new_name))==0) + { + png_warning(png_ptr, "Empty keyword in sPLT chunk"); + return; + } + + /* make sure we include the NULL after the name */ + png_write_chunk_start(png_ptr, (png_bytep)png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); + png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1); + png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1); + + /* loop through each palette entry, writing appropriately */ +#ifndef PNG_NO_POINTER_INDEXING + for (ep = spalette->entries; epentries+spalette->nentries; ep++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep->red; + entrybuf[1] = (png_byte)ep->green; + entrybuf[2] = (png_byte)ep->blue; + entrybuf[3] = (png_byte)ep->alpha; + png_save_uint_16(entrybuf + 4, ep->frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep->red); + png_save_uint_16(entrybuf + 2, ep->green); + png_save_uint_16(entrybuf + 4, ep->blue); + png_save_uint_16(entrybuf + 6, ep->alpha); + png_save_uint_16(entrybuf + 8, ep->frequency); + } + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#else + ep=spalette->entries; + for (i=0; i>spalette->nentries; i++) + { + if (spalette->depth == 8) + { + entrybuf[0] = (png_byte)ep[i].red; + entrybuf[1] = (png_byte)ep[i].green; + entrybuf[2] = (png_byte)ep[i].blue; + entrybuf[3] = (png_byte)ep[i].alpha; + png_save_uint_16(entrybuf + 4, ep[i].frequency); + } + else + { + png_save_uint_16(entrybuf + 0, ep[i].red); + png_save_uint_16(entrybuf + 2, ep[i].green); + png_save_uint_16(entrybuf + 4, ep[i].blue); + png_save_uint_16(entrybuf + 6, ep[i].alpha); + png_save_uint_16(entrybuf + 8, ep[i].frequency); + } + png_write_chunk_data(png_ptr, entrybuf, entry_size); + } +#endif + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_name); +} +#endif + +#if defined(PNG_WRITE_sBIT_SUPPORTED) +/* write the sBIT chunk */ +void /* PRIVATE */ +png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sBIT; +#endif + png_byte buf[4]; + png_size_t size; + + png_debug(1, "in png_write_sBIT\n"); + /* make sure we don't depend upon the order of PNG_COLOR_8 */ + if (color_type & PNG_COLOR_MASK_COLOR) + { + png_byte maxbits; + + maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : + png_ptr->usr_bit_depth); + if (sbit->red == 0 || sbit->red > maxbits || + sbit->green == 0 || sbit->green > maxbits || + sbit->blue == 0 || sbit->blue > maxbits) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->red; + buf[1] = sbit->green; + buf[2] = sbit->blue; + size = 3; + } + else + { + if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[0] = sbit->gray; + size = 1; + } + + if (color_type & PNG_COLOR_MASK_ALPHA) + { + if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) + { + png_warning(png_ptr, "Invalid sBIT depth specified"); + return; + } + buf[size++] = sbit->alpha; + } + + png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size); +} +#endif + +#if defined(PNG_WRITE_cHRM_SUPPORTED) +/* write the cHRM chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM(png_structp png_ptr, double white_x, double white_y, + double red_x, double red_y, double green_x, double green_y, + double blue_x, double blue_y) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_cHRM; +#endif + png_byte buf[32]; + png_uint_32 itemp; + + png_debug(1, "in png_write_cHRM\n"); + /* each value is saved in 1/100,000ths */ + if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || + white_x + white_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM white point specified"); +#if !defined(PNG_NO_CONSOLE_IO) + fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y); +#endif + return; + } + itemp = (png_uint_32)(white_x * 100000.0 + 0.5); + png_save_uint_32(buf, itemp); + itemp = (png_uint_32)(white_y * 100000.0 + 0.5); + png_save_uint_32(buf + 4, itemp); + + if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 || + red_x + red_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM red point specified"); + return; + } + itemp = (png_uint_32)(red_x * 100000.0 + 0.5); + png_save_uint_32(buf + 8, itemp); + itemp = (png_uint_32)(red_y * 100000.0 + 0.5); + png_save_uint_32(buf + 12, itemp); + + if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 || + green_x + green_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM green point specified"); + return; + } + itemp = (png_uint_32)(green_x * 100000.0 + 0.5); + png_save_uint_32(buf + 16, itemp); + itemp = (png_uint_32)(green_y * 100000.0 + 0.5); + png_save_uint_32(buf + 20, itemp); + + if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 || + blue_x + blue_y > 1.0) + { + png_warning(png_ptr, "Invalid cHRM blue point specified"); + return; + } + itemp = (png_uint_32)(blue_x * 100000.0 + 0.5); + png_save_uint_32(buf + 24, itemp); + itemp = (png_uint_32)(blue_y * 100000.0 + 0.5); + png_save_uint_32(buf + 28, itemp); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, + png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, + png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, + png_fixed_point blue_y) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_cHRM; +#endif + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM\n"); + /* each value is saved in 1/100,000ths */ + if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM white point specified"); +#if !defined(PNG_NO_CONSOLE_IO) + fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y); +#endif + return; + } + png_save_uint_32(buf, white_x); + png_save_uint_32(buf + 4, white_y); + + if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L) + { + png_warning(png_ptr, "Invalid cHRM fixed red point specified"); + return; + } + png_save_uint_32(buf + 8, red_x); + png_save_uint_32(buf + 12, red_y); + + if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM green point specified"); + return; + } + png_save_uint_32(buf + 16, green_x); + png_save_uint_32(buf + 20, green_y); + + if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM blue point specified"); + return; + } + png_save_uint_32(buf + 24, blue_x); + png_save_uint_32(buf + 28, blue_y); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); +} +#endif +#endif + +#if defined(PNG_WRITE_tRNS_SUPPORTED) +/* write the tRNS chunk */ +void /* PRIVATE */ +png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran, + int num_trans, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tRNS; +#endif + png_byte buf[6]; + + png_debug(1, "in png_write_tRNS\n"); + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) + { + png_warning(png_ptr,"Invalid number of transparent colors specified"); + return; + } + /* write the chunk out as it is */ + png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans); + } + else if (color_type == PNG_COLOR_TYPE_GRAY) + { + /* one 16 bit value */ + png_save_uint_16(buf, tran->gray); + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2); + } + else if (color_type == PNG_COLOR_TYPE_RGB) + { + /* three 16 bit values */ + png_save_uint_16(buf, tran->red); + png_save_uint_16(buf + 2, tran->green); + png_save_uint_16(buf + 4, tran->blue); + png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6); + } + else + { + png_warning(png_ptr, "Can't write tRNS with an alpha channel"); + } +} +#endif + +#if defined(PNG_WRITE_bKGD_SUPPORTED) +/* write the background chunk */ +void /* PRIVATE */ +png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_bKGD; +#endif + png_byte buf[6]; + + png_debug(1, "in png_write_bKGD\n"); + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + if ( +#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ + defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) + (png_ptr->num_palette || + (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && +#endif + back->index > png_ptr->num_palette) + { + png_warning(png_ptr, "Invalid background palette index"); + return; + } + buf[0] = back->index; + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1); + } + else if (color_type & PNG_COLOR_MASK_COLOR) + { + png_save_uint_16(buf, back->red); + png_save_uint_16(buf + 2, back->green); + png_save_uint_16(buf + 4, back->blue); + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6); + } + else + { + png_save_uint_16(buf, back->gray); + png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2); + } +} +#endif + +#if defined(PNG_WRITE_hIST_SUPPORTED) +/* write the histogram */ +void /* PRIVATE */ +png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_hIST; +#endif + int i; + png_byte buf[3]; + + png_debug(1, "in png_write_hIST\n"); + if (num_hist > (int)png_ptr->num_palette) + { + png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist, + png_ptr->num_palette); + png_warning(png_ptr, "Invalid number of histogram entries specified"); + return; + } + + png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2)); + for (i = 0; i < num_hist; i++) + { + png_save_uint_16(buf, hist[i]); + png_write_chunk_data(png_ptr, buf, (png_size_t)2); + } + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The new_key is allocated to hold the corrected keyword and must be freed + * by the calling routine. This avoids problems with trying to write to + * static keywords without having to have duplicate copies of the strings. + */ +png_size_t /* PRIVATE */ +png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) +{ + png_size_t key_len; + png_charp kp, dp; + int kflag; + int kwarn=0; + + png_debug(1, "in png_check_keyword\n"); + *new_key = NULL; + + if (key == NULL || (key_len = png_strlen(key)) == 0) + { + png_warning(png_ptr, "zero length keyword"); + return ((png_size_t)0); + } + + png_debug1(2, "Keyword to be checked is '%s'\n", key); + + *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2)); + + /* Replace non-printing characters with a blank and print a warning */ + for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++) + { + if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1)) + { +#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) + char msg[40]; + + sprintf(msg, "invalid keyword character 0x%02X", *kp); + png_warning(png_ptr, msg); +#else + png_warning(png_ptr, "invalid character in keyword"); +#endif + *dp = ' '; + } + else + { + *dp = *kp; + } + } + *dp = '\0'; + + /* Remove any trailing white space. */ + kp = *new_key + key_len - 1; + if (*kp == ' ') + { + png_warning(png_ptr, "trailing spaces removed from keyword"); + + while (*kp == ' ') + { + *(kp--) = '\0'; + key_len--; + } + } + + /* Remove any leading white space. */ + kp = *new_key; + if (*kp == ' ') + { + png_warning(png_ptr, "leading spaces removed from keyword"); + + while (*kp == ' ') + { + kp++; + key_len--; + } + } + + png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp); + + /* Remove multiple internal spaces. */ + for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) + { + if (*kp == ' ' && kflag == 0) + { + *(dp++) = *kp; + kflag = 1; + } + else if (*kp == ' ') + { + key_len--; + kwarn=1; + } + else + { + *(dp++) = *kp; + kflag = 0; + } + } + *dp = '\0'; + if(kwarn) + png_warning(png_ptr, "extra interior spaces removed from keyword"); + + if (key_len == 0) + { + png_free(png_ptr, *new_key); + *new_key=NULL; + png_warning(png_ptr, "Zero length keyword"); + } + + if (key_len > 79) + { + png_warning(png_ptr, "keyword length must be 1 - 79 characters"); + new_key[79] = '\0'; + key_len = 79; + } + + return (key_len); +} +#endif + +#if defined(PNG_WRITE_tEXt_SUPPORTED) +/* write a tEXt chunk */ +void /* PRIVATE */ +png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tEXt; +#endif + png_size_t key_len; + png_charp new_key; + + png_debug(1, "in png_write_tEXt\n"); + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_warning(png_ptr, "Empty keyword in tEXt chunk"); + return; + } + + if (text == NULL || *text == '\0') + text_len = 0; + else + text_len = png_strlen(text); + + /* make sure we include the 0 after the key */ + png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1); + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); + if (text_len) + png_write_chunk_data(png_ptr, (png_bytep)text, text_len); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); +} +#endif + +#if defined(PNG_WRITE_zTXt_SUPPORTED) +/* write a compressed text chunk */ +void /* PRIVATE */ +png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, + png_size_t text_len, int compression) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_zTXt; +#endif + png_size_t key_len; + char buf[1]; + png_charp new_key; + compression_state comp; + + png_debug(1, "in png_write_zTXt\n"); + + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_warning(png_ptr, "Empty keyword in zTXt chunk"); + return; + } + + if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) + { + png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); + png_free(png_ptr, new_key); + return; + } + + text_len = png_strlen(text); + + png_free(png_ptr, new_key); + + /* compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression, + &comp); + + /* write start of chunk */ + png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32) + (key_len+text_len+2)); + /* write key */ + png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1); + buf[0] = (png_byte)compression; + /* write compression */ + png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1); + /* write the compressed data */ + png_write_compressed_data_out(png_ptr, &comp); + + /* close the chunk */ + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_iTXt_SUPPORTED) +/* write an iTXt chunk */ +void /* PRIVATE */ +png_write_iTXt(png_structp png_ptr, int compression, png_charp key, + png_charp lang, png_charp lang_key, png_charp text) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_iTXt; +#endif + png_size_t lang_len, key_len, lang_key_len, text_len; + png_charp new_lang, new_key; + png_byte cbuf[2]; + compression_state comp; + + png_debug(1, "in png_write_iTXt\n"); + + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) + { + png_warning(png_ptr, "Empty keyword in iTXt chunk"); + return; + } + if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, + &new_lang))==0) + { + png_warning(png_ptr, "Empty language field in iTXt chunk"); + return; + } + lang_key_len = png_strlen(lang_key); + text_len = png_strlen(text); + + if (text == NULL || *text == '\0') + text_len = 0; + + /* compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression-2, + &comp); + + /* make sure we include the compression flag, the compression byte, + * and the NULs after the key, lang, and lang_key parts */ + + png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, + (png_uint_32)( + 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ + + key_len + + lang_len + + lang_key_len + + text_len)); + + /* + * We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + */ + png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); + + /* set the compression flag */ + if (compression == PNG_ITXT_COMPRESSION_NONE || \ + compression == PNG_TEXT_COMPRESSION_NONE) + cbuf[0] = 0; + else /* compression == PNG_ITXT_COMPRESSION_zTXt */ + cbuf[0] = 1; + /* set the compression method */ + cbuf[1] = 0; + png_write_chunk_data(png_ptr, cbuf, 2); + + png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1); + png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1); + png_write_chunk_data(png_ptr, '\0', 1); + + png_write_compressed_data_out(png_ptr, &comp); + + png_write_chunk_end(png_ptr); + png_free(png_ptr, new_key); + png_free(png_ptr, new_lang); +} +#endif + +#if defined(PNG_WRITE_oFFs_SUPPORTED) +/* write the oFFs chunk */ +void /* PRIVATE */ +png_write_oFFs(png_structp png_ptr, png_uint_32 x_offset, + png_uint_32 y_offset, + int unit_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_oFFs; +#endif + png_byte buf[9]; + + png_debug(1, "in png_write_oFFs\n"); + if (unit_type >= PNG_OFFSET_LAST) + png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); + + png_save_uint_32(buf, x_offset); + png_save_uint_32(buf + 4, y_offset); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9); +} +#endif + +#if defined(PNG_WRITE_pCAL_SUPPORTED) +/* write the pCAL chunk (described in the PNG extensions document) */ +void /* PRIVATE */ +png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, + png_int_32 X1, int type, int nparams, png_charp units, png_charpp params) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_pCAL; +#endif + png_size_t purpose_len, units_len, total_len; + png_uint_32p params_len; + png_byte buf[10]; + png_charp new_purpose; + int i; + + png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams); + if (type >= PNG_EQUATION_LAST) + png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; + png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len); + units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); + png_debug1(3, "pCAL units length = %d\n", (int)units_len); + total_len = purpose_len + units_len + 10; + + params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams + *sizeof(png_uint_32))); + + /* Find the length of each parameter, making sure we don't count the + null terminator for the last parameter. */ + for (i = 0; i < nparams; i++) + { + params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]); + total_len += (png_size_t)params_len[i]; + } + + png_debug1(3, "pCAL total length = %d\n", (int)total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len); + png_save_int_32(buf, X0); + png_save_int_32(buf + 4, X1); + buf[8] = (png_byte)type; + buf[9] = (png_byte)nparams; + png_write_chunk_data(png_ptr, buf, (png_size_t)10); + png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len); + + png_free(png_ptr, new_purpose); + + for (i = 0; i < nparams; i++) + { + png_write_chunk_data(png_ptr, (png_bytep)params[i], + (png_size_t)params_len[i]); + } + + png_free(png_ptr, params_len); + png_write_chunk_end(png_ptr); +} +#endif + +#if defined(PNG_WRITE_sCAL_SUPPORTED) +/* write the sCAL chunk */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) +void /* PRIVATE */ +png_write_sCAL(png_structp png_ptr, int unit, double width,double height) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sCAL; +#endif + png_size_t total_len; + char wbuf[32], hbuf[32]; + + png_debug(1, "in png_write_sCAL\n"); + +#if defined(_WIN32_WCE) +/* sprintf() function is not supported on WindowsCE */ + { + wchar_t wc_buf[32]; + swprintf(wc_buf, TEXT("%12.12e"), width); + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, wbuf, 32, NULL, NULL); + swprintf(wc_buf, TEXT("%12.12e"), height); + WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, hbuf, 32, NULL, NULL); + } +#else + sprintf(wbuf, "%12.12e", width); + sprintf(hbuf, "%12.12e", height); +#endif + total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf); + + png_debug1(3, "sCAL total length = %d\n", (int)total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)&unit, 1); + png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1); + png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf)); + + png_write_chunk_end(png_ptr); +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void /* PRIVATE */ +png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, + png_charp height) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sCAL; +#endif + png_size_t total_len; + char wbuf[32], hbuf[32]; + + png_debug(1, "in png_write_sCAL_s\n"); + + png_strcpy(wbuf,(const char *)width); + png_strcpy(hbuf,(const char *)height); + total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf); + + png_debug1(3, "sCAL total length = %d\n", total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)&unit, 1); + png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1); + png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf)); + + png_write_chunk_end(png_ptr); +} +#endif +#endif +#endif + +#if defined(PNG_WRITE_pHYs_SUPPORTED) +/* write the pHYs chunk */ +void /* PRIVATE */ +png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, + png_uint_32 y_pixels_per_unit, + int unit_type) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_pHYs; +#endif + png_byte buf[9]; + + png_debug(1, "in png_write_pHYs\n"); + if (unit_type >= PNG_RESOLUTION_LAST) + png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); + + png_save_uint_32(buf, x_pixels_per_unit); + png_save_uint_32(buf + 4, y_pixels_per_unit); + buf[8] = (png_byte)unit_type; + + png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9); +} +#endif + +#if defined(PNG_WRITE_tIME_SUPPORTED) +/* Write the tIME chunk. Use either png_convert_from_struct_tm() + * or png_convert_from_time_t(), or fill in the structure yourself. + */ +void /* PRIVATE */ +png_write_tIME(png_structp png_ptr, png_timep mod_time) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_tIME; +#endif + png_byte buf[7]; + + png_debug(1, "in png_write_tIME\n"); + if (mod_time->month > 12 || mod_time->month < 1 || + mod_time->day > 31 || mod_time->day < 1 || + mod_time->hour > 23 || mod_time->second > 60) + { + png_warning(png_ptr, "Invalid time specified for tIME chunk"); + return; + } + + png_save_uint_16(buf, mod_time->year); + buf[2] = mod_time->month; + buf[3] = mod_time->day; + buf[4] = mod_time->hour; + buf[5] = mod_time->minute; + buf[6] = mod_time->second; + + png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7); +} +#endif + +/* initializes the row writing capability of libpng */ +void /* PRIVATE */ +png_write_start_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + png_size_t buf_size; + + png_debug(1, "in png_write_start_row\n"); + buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels * + png_ptr->usr_bit_depth + 7) >> 3) + 1); + + /* set up row buffer */ + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size); + png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; + + /* set up filtering buffer, if using this filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) + { + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; + } + + /* We only need to keep the previous row if we are using one of these. */ + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + { + /* set up previous row buffer */ + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size); + png_memset(png_ptr->prev_row, 0, buf_size); + + if (png_ptr->do_filter & PNG_FILTER_UP) + { + png_ptr->up_row = (png_bytep )png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + + if (png_ptr->do_filter & PNG_FILTER_AVG) + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH) + { + png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* if interlaced, we need to set up width and height of pass */ + if (png_ptr->interlaced) + { + if (!(png_ptr->transformations & PNG_INTERLACE)) + { + png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - + png_pass_ystart[0]) / png_pass_yinc[0]; + png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - + png_pass_start[0]) / png_pass_inc[0]; + } + else + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + } + else +#endif + { + png_ptr->num_rows = png_ptr->height; + png_ptr->usr_width = png_ptr->width; + } + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_out = png_ptr->zbuf; +} + +/* Internal use only. Called when finished processing a row of data. */ +void /* PRIVATE */ +png_write_finish_row(png_structp png_ptr) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* start of interlace block in the y direction */ + int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* offset to next interlace block in the y direction */ + int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int ret; + + png_debug(1, "in png_write_finish_row\n"); + /* next row */ + png_ptr->row_number++; + + /* see if we are done */ + if (png_ptr->row_number < png_ptr->num_rows) + return; + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* if interlaced, go to next pass */ + if (png_ptr->interlaced) + { + png_ptr->row_number = 0; + if (png_ptr->transformations & PNG_INTERLACE) + { + png_ptr->pass++; + } + else + { + /* loop until we find a non-zero width or height pass */ + do + { + png_ptr->pass++; + if (png_ptr->pass >= 7) + break; + png_ptr->usr_width = (png_ptr->width + + png_pass_inc[png_ptr->pass] - 1 - + png_pass_start[png_ptr->pass]) / + png_pass_inc[png_ptr->pass]; + png_ptr->num_rows = (png_ptr->height + + png_pass_yinc[png_ptr->pass] - 1 - + png_pass_ystart[png_ptr->pass]) / + png_pass_yinc[png_ptr->pass]; + if (png_ptr->transformations & PNG_INTERLACE) + break; + } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); + + } + + /* reset the row above the image for the next pass */ + if (png_ptr->pass < 7) + { + if (png_ptr->prev_row != NULL) + png_memset(png_ptr->prev_row, 0, + (png_size_t) (((png_uint_32)png_ptr->usr_channels * + (png_uint_32)png_ptr->usr_bit_depth * + png_ptr->width + 7) >> 3) + 1); + return; + } + } +#endif + + /* if we get here, we've just written the last row, so we need + to flush the compressor */ + do + { + /* tell the compressor we are done */ + ret = deflate(&png_ptr->zstream, Z_FINISH); + /* check for an error */ + if (ret == Z_OK) + { + /* check to see if we need more room */ + if (!(png_ptr->zstream.avail_out)) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + else if (ret != Z_STREAM_END) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + } while (ret != Z_STREAM_END); + + /* write any extra space */ + if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) + { + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - + png_ptr->zstream.avail_out); + } + + deflateReset(&png_ptr->zstream); +} + +#if defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Pick out the correct pixels for the interlace pass. + * The basic idea here is to go through the row with a source + * pointer and a destination pointer (sp and dp), and copy the + * correct pixels for the pass. As the row gets compacted, + * sp will always be >= dp, so we should never overwrite anything. + * See the default: case for the easiest code to understand. + */ +void /* PRIVATE */ +png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* start of interlace block */ + int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* offset to next interlace block */ + int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; +#endif + + png_debug(1, "in png_do_write_interlace\n"); + /* we don't have to do anything on the last pass (6) */ +#if defined(PNG_USELESS_TESTS_SUPPORTED) + if (row != NULL && row_info != NULL && pass < 6) +#else + if (pass < 6) +#endif + { + /* each pixel depth is handled separately */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + d = 0; + shift = 7; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 3); + value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; + d |= (value << shift); + + if (shift == 0) + { + shift = 7; + *dp++ = (png_byte)d; + d = 0; + } + else + shift--; + + } + if (shift != 7) + *dp = (png_byte)d; + break; + } + case 2: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 6; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 2); + value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; + d |= (value << shift); + + if (shift == 0) + { + shift = 6; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 2; + } + if (shift != 6) + *dp = (png_byte)d; + break; + } + case 4: + { + png_bytep sp; + png_bytep dp; + int shift; + int d; + int value; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + + dp = row; + shift = 4; + d = 0; + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + sp = row + (png_size_t)(i >> 1); + value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; + d |= (value << shift); + + if (shift == 0) + { + shift = 4; + *dp++ = (png_byte)d; + d = 0; + } + else + shift -= 4; + } + if (shift != 4) + *dp = (png_byte)d; + break; + } + default: + { + png_bytep sp; + png_bytep dp; + png_uint_32 i; + png_uint_32 row_width = row_info->width; + png_size_t pixel_bytes; + + /* start at the beginning */ + dp = row; + /* find out how many bytes each pixel takes up */ + pixel_bytes = (row_info->pixel_depth >> 3); + /* loop through the row, only looking at the pixels that + matter */ + for (i = png_pass_start[pass]; i < row_width; + i += png_pass_inc[pass]) + { + /* find out where the original pixel is */ + sp = row + (png_size_t)i * pixel_bytes; + /* move the pixel */ + if (dp != sp) + png_memcpy(dp, sp, pixel_bytes); + /* next pixel */ + dp += pixel_bytes; + } + break; + } + } + /* set new row width */ + row_info->width = (row_info->width + + png_pass_inc[pass] - 1 - + png_pass_start[pass]) / + png_pass_inc[pass]; + row_info->rowbytes = ((row_info->width * + row_info->pixel_depth + 7) >> 3); + } +} +#endif + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +#define PNG_MAXSUM (~((png_uint_32)0) >> 1) +#define PNG_HISHIFT 10 +#define PNG_LOMASK ((png_uint_32)0xffffL) +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) +void /* PRIVATE */ +png_write_find_filter(png_structp png_ptr, png_row_infop row_info) +{ + png_bytep prev_row, best_row, row_buf; + png_uint_32 mins, bpp; + png_byte filter_to_do = png_ptr->do_filter; + png_uint_32 row_bytes = row_info->rowbytes; +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + int num_p_filters = (int)png_ptr->num_prev_filters; +#endif + + png_debug(1, "in png_write_find_filter\n"); + /* find out how many bytes offset each pixel is */ + bpp = (row_info->pixel_depth + 7) / 8; + + prev_row = png_ptr->prev_row; + best_row = row_buf = png_ptr->row_buf; + mins = PNG_MAXSUM; + + /* The prediction method we use is to find which method provides the + * smallest value when summing the absolute values of the distances + * from zero, using anything >= 128 as negative numbers. This is known + * as the "minimum sum of absolute differences" heuristic. Other + * heuristics are the "weighted minimum sum of absolute differences" + * (experimental and can in theory improve compression), and the "zlib + * predictive" method (not implemented yet), which does test compressions + * of lines using different filter methods, and then chooses the + * (series of) filter(s) that give minimum compressed data size (VERY + * computationally expensive). + * + * GRR 980525: consider also + * (1) minimum sum of absolute differences from running average (i.e., + * keep running sum of non-absolute differences & count of bytes) + * [track dispersion, too? restart average if dispersion too large?] + * (1b) minimum sum of absolute differences from sliding average, probably + * with window size <= deflate window (usually 32K) + * (2) minimum sum of squared differences from zero or running average + * (i.e., ~ root-mean-square approach) + */ + + + /* We don't need to test the 'no filter' case if this is the only filter + * that has been chosen, as it doesn't actually do anything to the data. + */ + if ((filter_to_do & PNG_FILTER_NONE) && + filter_to_do != PNG_FILTER_NONE) + { + png_bytep rp; + png_uint_32 sum = 0; + png_uint_32 i; + int v; + + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) + { + v = *rp; + sum += (v < 128) ? v : 256 - v; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + png_uint_32 sumhi, sumlo; + int j; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ + + /* Reduce the sum if we match any of the previous rows */ + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + /* Factor in the cost of this filter (this is here for completeness, + * but it makes no sense to have a "cost" for the NONE filter, as + * it has the minimum possible computational cost - none). + */ + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + mins = sum; + } + + /* sub filter */ + if (filter_to_do == PNG_FILTER_SUB) + /* it's the only filter so no testing is needed */ + { + png_bytep rp, lp, dp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } + best_row = png_ptr->sub_row; + } + + else if (filter_to_do & PNG_FILTER_SUB) + { + png_bytep rp, dp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + /* We temporarily increase the "minimum sum" by the factor we + * would reduce the sum of this filter, so that we can do the + * early exit comparison without scaling the sum each time. + */ + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_info->rowbytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->sub_row; + } + } + + /* up filter */ + if (filter_to_do == PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + } + best_row = png_ptr->up_row; + } + + else if (filter_to_do & PNG_FILTER_UP) + { + png_bytep rp, dp, pp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->up_row; + } + } + + /* avg filter */ + if (filter_to_do == PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } + best_row = png_ptr->avg_row; + } + + else if (filter_to_do & PNG_FILTER_AVG) + { + png_bytep rp, dp, pp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + for (lp = row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = + (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + mins = sum; + best_row = png_ptr->avg_row; + } + } + + /* Paeth filter */ + if (filter_to_do == PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 i; + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } + best_row = png_ptr->paeth_row; + } + + else if (filter_to_do & PNG_FILTER_PAETH) + { + png_bytep rp, dp, pp, cp, lp; + png_uint_32 sum = 0, lmins = mins; + png_uint_32 i; + int v; + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + +#ifndef PNG_SLOW_PAETH + p = b - c; + pc = a - c; +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; +#else /* PNG_SLOW_PAETH */ + p = a + b - c; + pa = abs(p - a); + pb = abs(p - b); + pc = abs(p - c); + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; +#endif /* PNG_SLOW_PAETH */ + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif + + if (sum < mins) + { + best_row = png_ptr->paeth_row; + } + } + + /* Do the actual writing of the filtered row data from the chosen filter. */ + + png_write_filtered_row(png_ptr, best_row); + +#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) + /* Save the type of filter we picked this time for future calculations */ + if (png_ptr->num_prev_filters > 0) + { + int j; + for (j = 1; j < num_p_filters; j++) + { + png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; + } + png_ptr->prev_filters[j] = best_row[0]; + } +#endif +} + + +/* Do the actual writing of a previously filtered row. */ +void /* PRIVATE */ +png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) +{ + png_debug(1, "in png_write_filtered_row\n"); + png_debug1(2, "filter = %d\n", filtered_row[0]); + /* set up the zlib input buffer */ + + png_ptr->zstream.next_in = filtered_row; + png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1; + /* repeat until we have compressed all the data */ + do + { + int ret; /* return of zlib */ + + /* compress the data */ + ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + /* check for compression errors */ + if (ret != Z_OK) + { + if (png_ptr->zstream.msg != NULL) + png_error(png_ptr, png_ptr->zstream.msg); + else + png_error(png_ptr, "zlib error"); + } + + /* see if it is time to write another IDAT */ + if (!(png_ptr->zstream.avail_out)) + { + /* write the IDAT and reset the zlib output buffer */ + png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + /* repeat until all data has been compressed */ + } while (png_ptr->zstream.avail_in); + + /* swap the current and previous rows */ + if (png_ptr->prev_row != NULL) + { + png_bytep tptr; + + tptr = png_ptr->prev_row; + png_ptr->prev_row = png_ptr->row_buf; + png_ptr->row_buf = tptr; + } + + /* finish row - updates counters and flushes zlib if last row */ + png_write_finish_row(png_ptr); + +#if defined(PNG_WRITE_FLUSH_SUPPORTED) + png_ptr->flush_rows++; + + if (png_ptr->flush_dist > 0 && + png_ptr->flush_rows >= png_ptr->flush_dist) + { + png_write_flush(png_ptr); + } +#endif +} +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/freeimage241/Source/LibTIFF/LibTIFF.dsp b/freeimage241/Source/LibTIFF/LibTIFF.dsp new file mode 100644 index 0000000..b9050a7 --- /dev/null +++ b/freeimage241/Source/LibTIFF/LibTIFF.dsp @@ -0,0 +1,260 @@ +# Microsoft Developer Studio Project File - Name="LibTIFF" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=LibTIFF - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LibTIFF.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LibTIFF.mak" CFG="LibTIFF - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LibTIFF - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "LibTIFF - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/FreeImage/LibTIFF", MKAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LibTIFF - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "..\libtiff\libtiff" /I "..\zlib" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "LibTIFF - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\libtiff\libtiff" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "LibTIFF - Win32 Release" +# Name "LibTIFF - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\fax3sm_winnt.c +# End Source File +# Begin Source File + +SOURCE=.\tif_aux.c +# End Source File +# Begin Source File + +SOURCE=.\tif_close.c +# End Source File +# Begin Source File + +SOURCE=.\tif_codec.c +# End Source File +# Begin Source File + +SOURCE=.\tif_compress.c +# End Source File +# Begin Source File + +SOURCE=.\tif_dir.c +# End Source File +# Begin Source File + +SOURCE=.\tif_dirinfo.c +# End Source File +# Begin Source File + +SOURCE=.\tif_dirread.c +# End Source File +# Begin Source File + +SOURCE=.\tif_dirwrite.c +# End Source File +# Begin Source File + +SOURCE=.\tif_dumpmode.c +# End Source File +# Begin Source File + +SOURCE=.\tif_error.c +# End Source File +# Begin Source File + +SOURCE=.\tif_fax3.c +# End Source File +# Begin Source File + +SOURCE=.\tif_flush.c +# End Source File +# Begin Source File + +SOURCE=.\tif_getimage.c +# End Source File +# Begin Source File + +SOURCE=.\tif_jpeg.c +# End Source File +# Begin Source File + +SOURCE=.\tif_luv.c +# End Source File +# Begin Source File + +SOURCE=.\tif_lzw.c +# End Source File +# Begin Source File + +SOURCE=.\tif_next.c +# End Source File +# Begin Source File + +SOURCE=.\tif_open.c +# End Source File +# Begin Source File + +SOURCE=.\tif_packbits.c +# End Source File +# Begin Source File + +SOURCE=.\tif_pixarlog.c +# End Source File +# Begin Source File + +SOURCE=.\tif_predict.c +# End Source File +# Begin Source File + +SOURCE=.\tif_print.c +# End Source File +# Begin Source File + +SOURCE=.\tif_read.c +# End Source File +# Begin Source File + +SOURCE=.\tif_strip.c +# End Source File +# Begin Source File + +SOURCE=.\tif_swab.c +# End Source File +# Begin Source File + +SOURCE=.\tif_thunder.c +# End Source File +# Begin Source File + +SOURCE=.\tif_tile.c +# End Source File +# Begin Source File + +SOURCE=.\tif_version.c +# End Source File +# Begin Source File + +SOURCE=.\tif_warning.c +# End Source File +# Begin Source File + +SOURCE=.\tif_write.c +# End Source File +# Begin Source File + +SOURCE=.\tif_zip.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\t4.h +# End Source File +# Begin Source File + +SOURCE=.\tif_dir.h +# End Source File +# Begin Source File + +SOURCE=.\tif_fax3.h +# End Source File +# Begin Source File + +SOURCE=.\tif_predict.h +# End Source File +# Begin Source File + +SOURCE=.\tiff.h +# End Source File +# Begin Source File + +SOURCE=.\tiffcomp.h +# End Source File +# Begin Source File + +SOURCE=.\tiffconf.h +# End Source File +# Begin Source File + +SOURCE=.\tiffio.h +# End Source File +# Begin Source File + +SOURCE=.\tiffiop.h +# End Source File +# Begin Source File + +SOURCE=.\uvcode.h +# End Source File +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/LibTIFF/Makefile.in b/freeimage241/Source/LibTIFF/Makefile.in new file mode 100644 index 0000000..e36747e --- /dev/null +++ b/freeimage241/Source/LibTIFF/Makefile.in @@ -0,0 +1,376 @@ +# $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\Makefile.in,v 1.0 2001-04-13 00:42:24+02 floris_van_den_berg Exp floris_van_den_berg $ +# +# Tag Image File Format Library +# +# Copyright (c) 1988-1997 Sam Leffler +# Copyright (c) 1991-1997 Silicon Graphics, Inc. +# +# Permission to use, copy, modify, distribute, and sell this software and +# its documentation for any purpose is hereby granted without fee, provided +# that (i) the above copyright notices and this permission notice appear in +# all copies of the software and related documentation, and (ii) the names of +# Sam Leffler and Silicon Graphics may not be used in any advertising or +# publicity relating to the software without the specific, prior written +# permission of Sam Leffler and Silicon Graphics. +# +# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, +# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +# +# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR +# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, +# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF +# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +SRCDIR = @LIBSRCDIR@ + +# +# VERSION: @VERSION@ +# DATE: @DATE@ +# TARGET: @TARGET@ +# CCOMPILER: @CCOMPILER@ +# +SHELL = @SCRIPT_SH@ +NULL = +CC = @CCOMPILER@ +AR = @AR@ +AROPTS = @AROPTS@ +RANLIB = @RANLIB@ +INSTALL = @INSTALL@ + +# +# If JPEG support is to be included and the Independent JPEG +# Software distribution is not installed then DIR_JPEG must +# refer to the directory where the include files reside. +# +# Similarly, if the libgz distribution is not installed, then +# DIR_LIBGZ must refer to the directory where the include files +# are located. Note that recent versions +# +IPATH = -I. -I${SRCDIR} @COPT_LIBINC@ +# +# To enable JPEG support include -DJPEG_SUPPORT here. +# To enable Deflate support add a -DZIP_SUPPORT here. +# Note that where the configure script is used these defines +# are automatically setup when JPEG/ZIP is set to "yes". +# +# Otherwise, consult tiffconf.h for information on controlling +# the configuration of optional library support. +# +CONF_LIBRARY=@CONF_JPEG@ @CONF_ZIP@ +COPTS = @GCOPTS@ +OPTIMIZER=-O +CFLAGS = @ENVOPTS@ @LIBCOPTS@ ${COPTS} ${OPTIMIZER} ${IPATH} ${CONF_LIBRARY} +# +SRCS = \ + tif_aux.c \ + tif_close.c \ + tif_codec.c \ + tif_compress.c \ + tif_dir.c \ + tif_dirinfo.c \ + tif_dirread.c \ + tif_dirwrite.c \ + tif_dumpmode.c \ + tif_error.c \ + tif_fax3.c \ + tif_fax3sm.c \ + tif_getimage.c \ + tif_jpeg.c \ + tif_flush.c \ + tif_luv.c \ + tif_lzw.c \ + tif_next.c \ + tif_open.c \ + tif_packbits.c \ + tif_pixarlog.c \ + tif_predict.c \ + tif_print.c \ + tif_read.c \ + tif_swab.c \ + tif_strip.c \ + tif_thunder.c \ + tif_tile.c \ + tif_unix.c \ + tif_version.c \ + tif_warning.c \ + tif_write.c \ + tif_zip.c \ + ${NULL} +OBJS = \ + tif_aux.o \ + tif_close.o \ + tif_codec.o \ + tif_compress.o \ + tif_dir.o \ + tif_dirinfo.o \ + tif_dirread.o \ + tif_dirwrite.o \ + tif_dumpmode.o \ + tif_error.o \ + tif_fax3.o \ + tif_fax3sm.o \ + tif_getimage.o \ + tif_jpeg.o \ + tif_flush.o \ + tif_luv.o \ + tif_lzw.o \ + tif_next.o \ + tif_open.o \ + tif_packbits.o \ + tif_pixarlog.o \ + tif_predict.o \ + tif_print.o \ + tif_read.o \ + tif_swab.o \ + tif_strip.o \ + tif_thunder.o \ + tif_tile.o \ + tif_unix.o \ + tif_version.o \ + tif_warning.o \ + tif_write.o \ + tif_zip.o \ + ${NULL} +TARGETS = libtiff.a + +all: ${TARGETS} + if [ @DSO@dso != nodso ]; then \ + ${MAKE} @DSO@dso; \ + else \ + true; \ + fi + +libtiff.a: ${OBJS} + ${AR} ${AROPTS} libtiff.a $? + ${RANLIB} libtiff.a + +# +# NB: The configure script verifies that the configured +# tools are capable of producing a DSO before enabling +# their creation/use. The following rules are effectively +# duplicated in the configure script to do this verification. +# This means that if you want to add support for building a +# DSO on another system you'll need to modify this file *and* +# configure if you want the right thing to happen automatically +# (should probably be fixed up). +# + +# default IRIX DSO building rule +IRIXdso: ${OBJS} + @if [ "`basename ${CC}`" = "gcc" ]; then \ + ${LD} -n32 @ENVOPTS@ -o libtiff.@DSOSUF@ -shared -rdata_shared \ + ${OBJS}; \ + else \ + ${CC} @ENVOPTS@ -o libtiff.@DSOSUF@ -shared -rdata_shared \ + -check_registry ${SRCDIR}/../port/irix/so_locations \ + -quickstart_info \ + ${OBJS} @LIBJPEG@ @LIBGZ@; \ + fi + touch $@ +# special rule for IRIX 5.2 +IRIX52dso: ${OBJS} + ${LD} -elf -o libtiff.@DSOSUF@ -shared -no_unresolved -all ${OBJS} \ + @LIBJPEG@ @LIBGZ@ -lc -lm + touch $@ +# Solaris 2.x +SOLARISdso: ${OBJS} + ${LD} -L@DIR_LIB@ -G -h libtiff.@DSOSUF@ -o libtiff.@DSOSUF@ ${OBJS} + touch $@ +# HP-UX A.09.03 +HPUXdso: ${OBJS} + ${LD} +b@DIR_LIB@ -b -o libtiff.@DSOSUF@ ${OBJS} + touch $@ +# AIX 2.3.5 and 4.1.1 +AIXdso: ${OBJS} + rm -f libtiff.syms shr.o + echo "#!" > libtiff.syms + /bin/dump -g libtiff.a | sed -n -e \ + 's/^[ ]*[0-9][0-9]*[ ]*\([^ .][^ ]*\)$$/\1/p' \ + >> libtiff.syms + ${LD} -o shr.o libtiff.a -H512 -T512 -bM\:SRE \ + -bE\:libtiff.syms @LIBJPEG@ @LIBGZ@ -lc -lm -L@DIR_LIB@ + rm -f libtiff.syms libtiff.@DSOSUF@ + ${AR} ${AROPTS} libtiff.@DSOSUF@ shr.o + rm -f shr.o + touch $@ +# GNU linker shared libraries +GNULDdso: ${OBJS} + ${CC} -shared -Wl,-soname,libtiff.@DSOSUF@ \ + -o libtiff.@DSOSUF_VERSION@ ${OBJS} \ + @LIBJPEG@ @LIBGZ@ @MACHDEPLIBS@ + rm -f libtiff.@DSOSUF@ + if [ @DSOSUB_VERSION != @DSOSUF ] ; then \ + @LN@ @LN_S@ libtiff.@DSOSUF_VERSION@ libtiff.@DSOSUF@; \ + fi + touch $@ +# NetBSD 1.1 or FreeBSD (old style) +NETBSDdso FREEBSDdso: ${OBJS} + @rm -f libtiff_pic.a + @${AR} cq libtiff_pic.a `lorder ${OBJS} | tsort -q` + ${RANLIB} libtiff_pic.a + ${LD} -x -Bshareable -Bforcearchive -o libtiff.@DSOSUF@ libtiff_pic.a + rm -f libtiff_pic.a + touch $@ +# linux ELF shared lib rule +LINUXdso: ${OBJS} + ${CC} -shared -Wl,-soname,libtiff.@DSOSUF@ \ + -o libtiff.@DSOSUF_VERSION@ ${OBJS} \ + @LIBJPEG@ @LIBGZ@ @MACHLIBDEPS@ + rm -f libtiff.@DSOSUF@ + @LN@ @LN_S@ libtiff.@DSOSUF_VERSION@ libtiff.@DSOSUF@ + touch $@ +# OSF/1 3.2 shared lib rule +OSFdso: ${OBJS} + ${LD} -o libtiff.@DSOSUF@ -shared -error_unresolved ${OBJS} @LIBJPEG@ @LIBGZ@ -lc -lm + + +${OBJS}: ${SRCDIR}/tiffio.h ${SRCDIR}/tiff.h ${SRCDIR}/tif_dir.h +${OBJS}: ${SRCDIR}/tiffcomp.h ${SRCDIR}/tiffiop.h ${SRCDIR}/tiffconf.h +${OBJS}: ${SRCDIR}/tiffvers.h + +VERSION = @VERSIONFILE@ + +${SRCDIR}/tiffvers.h: ${VERSION} ${SRCDIR}/mkversion.c + ${CC} -o mkversion ${CFLAGS} ${SRCDIR}/mkversion.c + rm -f ${SRCDIR}/tiffvers.h + ./mkversion -v ${VERSION} ${SRCDIR}/tiffvers.h + +# +# The finite state machine tables used by the G3/G4 decoders +# are generated by the mkg3states program. On systems without +# make these rules have to be manually carried out. +# +tif_fax3sm.c: ${SRCDIR}/mkg3states.c ${SRCDIR}/tif_fax3.h + ${CC} -o mkg3states ${CFLAGS} ${SRCDIR}/mkg3states.c + rm -f tif_fax3sm.c; ./mkg3states -c const tif_fax3sm.c + +tif_aux.o: ${SRCDIR}/tif_aux.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_aux.c +tif_close.o: ${SRCDIR}/tif_close.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_close.c +tif_codec.o: ${SRCDIR}/tif_codec.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_codec.c +tif_compress.o: ${SRCDIR}/tif_compress.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_compress.c +tif_dir.o: ${SRCDIR}/tif_dir.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_dir.c +tif_dirinfo.o: ${SRCDIR}/tif_dirinfo.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_dirinfo.c +tif_dirread.o: ${SRCDIR}/tif_dirread.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_dirread.c +tif_dirwrite.o: ${SRCDIR}/tif_dirwrite.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_dirwrite.c +tif_dumpmode.o: ${SRCDIR}/tif_dumpmode.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_dumpmode.c +tif_error.o: ${SRCDIR}/tif_error.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_error.c +tif_fax3.o: ${SRCDIR}/tif_fax3.c ${SRCDIR}/t4.h ${SRCDIR}/tif_fax3.h + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_fax3.c +tif_getimage.o: ${SRCDIR}/tif_getimage.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_getimage.c +tif_jpeg.o: ${SRCDIR}/tif_jpeg.c @DEPEND_JPEGLIB@ + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_jpeg.c +tif_flush.o: ${SRCDIR}/tif_flush.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_flush.c +tif_luv.o: ${SRCDIR}/tif_luv.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_luv.c +tif_lzw.o: ${SRCDIR}/tif_lzw.c ${SRCDIR}/tif_predict.h + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_lzw.c +tif_next.o: ${SRCDIR}/tif_next.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_next.c +tif_open.o: ${SRCDIR}/tif_open.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_open.c +tif_packbits.o: ${SRCDIR}/tif_packbits.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_packbits.c +tif_pixarlog.o: ${SRCDIR}/tif_pixarlog.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_pixarlog.c +tif_predict.o: ${SRCDIR}/tif_predict.c ${SRCDIR}/tif_predict.h + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_predict.c +tif_print.o: ${SRCDIR}/tif_print.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_print.c +tif_read.o: ${SRCDIR}/tif_read.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_read.c +tif_swab.o: ${SRCDIR}/tif_swab.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_swab.c +tif_strip.o: ${SRCDIR}/tif_strip.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_strip.c +tif_thunder.o: ${SRCDIR}/tif_thunder.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_thunder.c +tif_tile.o: ${SRCDIR}/tif_tile.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_tile.c +tif_unix.o: ${SRCDIR}/tif_unix.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_unix.c +tif_version.o: ${SRCDIR}/tif_version.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_version.c +tif_warning.o: ${SRCDIR}/tif_warning.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_warning.c +tif_write.o: ${SRCDIR}/tif_write.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_write.c +tif_zip.o: ${SRCDIR}/tif_zip.c ${SRCDIR}/tif_predict.h @DEPEND_ZLIB@ + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_zip.c + +tif_apple.o: ${SRCDIR}/tif_apple.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_apple.c +tif_atari.o: ${SRCDIR}/tif_atari.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_atari.c +tif_msdos.o: ${SRCDIR}/tif_msdos.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_msdos.c +tif_vms.o: ${SRCDIR}/tif_vms.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_vms.c +tif_win3.o: ${SRCDIR}/tif_win3.c + ${CC} -c ${CFLAGS} ${SRCDIR}/tif_win3.c + +INCS = ${SRCDIR}/tiff.h ${SRCDIR}/tiffio.h ${SRCDIR}/tiffconf.h \ + ${SRCDIR}/tiffvers.h + +INCS_PRIVATE = ${SRCDIR}/tiffiop.h ${SRCDIR}/tif_dir.h ${SRCDIR}/port.h + +installHdrs: ${INCS} + ${INSTALL} -idb tiff.sw.dev -m 755 -dir @DIR_INC@ + for i in ${INCS}; do \ + f=`basename $$i`; \ + ${INSTALL} -idb tiff.sw.dev -m 444 -F @DIR_INC@ \ + -src $$i -O $$f; \ + done + +installPrivateHdrs: ${INCS_PRIVATE} + ${INSTALL} -idb tiff.sw.dev -m 755 -dir @DIR_INC@ + for i in ${INCS_PRIVATE}; do \ + f=`basename $$i`; \ + ${INSTALL} -idb tiff.sw.dev -m 444 -F @DIR_INC@ \ + -src $$i -O $$f; \ + done + +installDSO: @DSO@dso + if [ @DSOSUF_VERSION@ != @DSOSUF@ ]; then \ + ${INSTALL} -idb tiff.sw.tools -m 555 -F @DIR_LIB@ \ + -O libtiff.@DSOSUF_VERSION@; \ + ${INSTALL} -idb tiff.sw.tools -F @DIR_LIB@ \ + -lns libtiff.@DSOSUF_VERSION@ -O libtiff.@DSOSUF@; \ + ${INSTALL} -idb tiff.sw.tools -F @DIR_LIB@ \ + -lns libtiff.@DSOSUF@ -O libtiff.so; \ + else \ + ${INSTALL} -idb tiff.sw.tools -m 555 -F @DIR_LIB@ \ + -O libtiff.@DSOSUF@; \ + fi + +install: all installHdrs + ${INSTALL} -idb tiff.sw.dev -m 755 -dir @DIR_LIB@ + ${INSTALL} -idb tiff.sw.dev -m 444 -F @DIR_LIB@ -O libtiff.a + if [ @DSO@dso != nodso ]; then \ + ${MAKE} installDSO; \ + else \ + true; \ + fi + +install-private: install installPrivateHdrs + +clean: + rm -f ${TARGETS} ${OBJS} core a.out \ + mkg3states tif_fax3sm.c \ + mkversion ${SRCDIR}/tiffvers.h \ + libtiff.a libtiff.@DSOSUF@ libtiff.@DSOSUF_VERSION@ *dso diff --git a/freeimage241/Source/LibTIFF/Makefile.lcc b/freeimage241/Source/LibTIFF/Makefile.lcc new file mode 100644 index 0000000..5afcc1b --- /dev/null +++ b/freeimage241/Source/LibTIFF/Makefile.lcc @@ -0,0 +1,129 @@ +# $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\Makefile.lcc,v 1.0 2001-04-13 00:42:24+02 floris_van_den_berg Exp floris_van_den_berg $ +# +# Tag Image File Format Library +# +# Copyright (c) 1988-1997 Sam Leffler +# Copyright (c) 1991-1997 Silicon Graphics, Inc. +# +# Permission to use, copy, modify, distribute, and sell this software and +# its documentation for any purpose is hereby granted without fee, provided +# that (i) the above copyright notices and this permission notice appear in +# all copies of the software and related documentation, and (ii) the names of +# Sam Leffler and Silicon Graphics may not be used in any advertising or +# publicity relating to the software without the specific, prior written +# permission of Stanford and Silicon Graphics. +# +# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, +# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +# +# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR +# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, +# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF +# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# +DESTDIR=. +# +INSTALL=install +NULL= + +IPATH= -I. -I../jpeg +CONF_LIBRARY=\ + ${NULL} +COPTS= -Oloop -cwagshf -d1 -b0 -v -DNDEBUG -rr -j135i +CFLAGS= ${COPTS} ${IPATH} ${CONF_LIBRARY} +# +INCS= tiff.h tiffio.h +SRCS= tif_fax3.c \ + tif_fax4.c \ + tif_aux.c \ + tif_atari.c \ + tif_ccittrle.c \ + tif_close.c \ + tif_compress.c \ + tif_dir.c \ + tif_dirinfo.c \ + tif_dirread.c \ + tif_dirwrite.c \ + tif_dumpmode.c \ + tif_error.c \ + tif_getimage.c \ + tif_jpeg.c \ + tif_flush.c \ + tif_lzw.c \ + tif_next.c \ + tif_open.c \ + tif_packbits.c \ + tif_print.c \ + tif_read.c \ + tif_swab.c \ + tif_strip.c \ + tif_thunder.c \ + tif_tile.c \ + tif_version.c \ + tif_warning.c \ + tif_write.c \ + ${NULL} +OBJS= tif_fax3.o \ + tif_fax4.o \ + tif_aux.o \ + tif_atari.o \ + tif_ccittrle.o \ + tif_close.o \ + tif_compress.o \ + tif_dir.o \ + tif_dirinfo.o \ + tif_dirread.o \ + tif_dirwrite.o \ + tif_dumpmode.o \ + tif_error.o \ + tif_getimage.o \ + tif_jpeg.o \ + tif_flush.o \ + tif_lzw.o \ + tif_next.o \ + tif_open.o \ + tif_packbits.o \ + tif_print.o \ + tif_read.o \ + tif_swab.o \ + tif_strip.o \ + tif_thunder.o \ + tif_tile.o \ + tif_version.o \ + tif_warning.o \ + tif_write.o \ + ${NULL} +ALL= tiffrnb.lib + +all: ${ALL} + +${ALL}: ${OBJS} + ${AR} ${ARFLAGS} $@ r $< + +${OBJS}: tiffio.h tiff.h tiffcomp.h tiffiop.h tiffconf.h +tif_fax3.o: tif_fax3.c g3states.h t4.h tif_fax3.h + +g3states.h: mkg3states.c t4.h + ${CC} -o mkg3states.ttp ${CFLAGS} mkg3states.c + ./mkg3states -c > g3states.h + +install: all installh + -for i in ${ALL}; do \ + ${INSTALL} -c -m 644 $$i ${DESTDIR}/lib/$$i; \ + done + +installh: ${INCS} + -for i in ${INCS}; do \ + h=`basename $$i`; \ + cmp -s $$i ${DESTDIR}/include/$$h || \ + ${INSTALL} -c -m 444 $$i ${DESTDIR}/include/$$h; \ + done + +clean: + rm -f ${ALL} ${OBJS} mkg3states.ttp mkg3states.o g3states.h + +tags: ${SRCS} + ${CTAGS} ${SRCS} diff --git a/freeimage241/Source/LibTIFF/fax3sm_winnt.c b/freeimage241/Source/LibTIFF/fax3sm_winnt.c new file mode 100644 index 0000000..564c9aa --- /dev/null +++ b/freeimage241/Source/LibTIFF/fax3sm_winnt.c @@ -0,0 +1,1046 @@ +/* WARNING, this file was automatically generated by the + mkg3states program */ +#include "tiff.h" +#include "tif_fax3.h" + const TIFFFaxTabEnt TIFFFaxMainTable[128] = { +12,7,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0, +2,3,0,3,1,0,4,3,1,3,1,0,5,6,2,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0, +1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,5,7,3,3,1,0,5,3,1,3,1,0, +2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0, +4,6,2,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0, +2,3,0,3,1,0,4,3,1,3,1,0,6,7,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0, +1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,5,6,2,3,1,0,5,3,1,3,1,0, +2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0, +4,7,3,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0, +2,3,0,3,1,0,4,3,1,3,1,0,4,6,2,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0, +1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0 +}; +const TIFFFaxTabEnt TIFFFaxWhiteTable[4096] = { +12,11,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6, +7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5, +7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5, +7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15, +9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,11,1792,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6, +7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5, +7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14, +7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6, +7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15, +7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7, +7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6, +7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +11,11,1856,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6, +7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5, +7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5, +7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15, +9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6, +7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5, +7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14, +7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6, +7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,11,12,2112,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15, +7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7, +7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6, +7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6, +7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5, +7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5, +7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15, +9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,12,2368,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6, +7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5, +7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14, +7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6, +7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15, +7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7, +7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6, +7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +11,12,1984,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6, +7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5, +7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5, +7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15, +9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6, +7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5, +7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14, +7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6, +7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,11,11,1920,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15, +7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7, +7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6, +7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6, +7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5, +7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5, +7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15, +9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,12,2240,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6, +7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5, +7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14, +7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6, +7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15, +7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7, +7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6, +7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +11,12,2496,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6, +7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5, +7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5, +7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15, +9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,12,11,0,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6, +7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5, +7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14, +7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6, +7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,11,11,1792,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15, +7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7, +7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6, +7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6, +7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5, +7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5, +7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15, +9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,11,1856,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6, +7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5, +7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14, +7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6, +7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15, +7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7, +7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6, +7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +11,12,2176,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6, +7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5, +7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5, +7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15, +9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6, +7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5, +7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14, +7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6, +7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,11,12,2432,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15, +7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7, +7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6, +7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6, +7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5, +7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5, +7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15, +9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,12,2048,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6, +7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5, +7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14, +7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6, +7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15, +7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7, +7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6, +7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +11,11,1920,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6, +7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5, +7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5, +7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15, +9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6, +7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5, +7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14, +7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6, +7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,11,12,2304,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5, +7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15, +7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7, +7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6, +7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5, +7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14, +7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6, +7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5, +7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6, +7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5, +7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15, +9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6, +7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,12,2560,7,4,3,7,5,11,7,4,5, +7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7, +7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6, +7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5, +7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7, +7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14, +7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6, +7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5, +7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7, +7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64, +7,5,10,7,4,4,7,4,2,7,4,7 +}; +const TIFFFaxTabEnt TIFFFaxBlackTable[8192] = { +12,11,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1792,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,23,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,20,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,25,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,12,128,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,56,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,30,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,11,1856,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,57,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,21,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,54,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,52,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,48,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,12,2112,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,44,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,36,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,12,384,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,28,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,60,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,40,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2368,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,12,1984,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,50,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,34,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,1664,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,26,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,13,1408,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,32,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,11,1920,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,61,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,42,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1024,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,768,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,62,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2240,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,46,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,38,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,13,512,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,19,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,24,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,22,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,12,2496,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,12,11,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,11,1792,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,23,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,20,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,25,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,12,192,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,1280,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,31,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1856,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,58,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,21,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,13,896,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,640,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,49,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,12,2176,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,45,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,37,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,12,448,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,29,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,13,1536,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,41,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,12,2432,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2048,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,51,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,35,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,12,320,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,27,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,59,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,33,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,11,1920,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,12,256,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,43,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,1152,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,55,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,63,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,12,2304,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,47,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,39,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,53,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,19,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,24,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,22,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2560,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,12,11,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,11,1792,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,23,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,20,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,25,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,12,128,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,56,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,30,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,11,1856,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,57,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,21,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,54,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,52,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,48,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2112,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,44,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,36,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,12,384,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,28,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,60,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,40,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,12,2368,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,12,1984,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,50,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,34,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1728,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,26,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,1472,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,32,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1920,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,61,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,42,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,13,1088,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,832,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,62,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,12,2240,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,46,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,38,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,576,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,19,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,24,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,22,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,12,2496,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +12,11,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1792,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,23,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,20,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,25,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,12,192,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1344,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,31,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,11,1856,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,58,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,11,21,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,960,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,13,704,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,49,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,12,2176,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,45,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,37,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,12,448,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,29,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,13,1600,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,41,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2432,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,12,2048,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,51,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,35,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,12,320,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,27,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,59,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,33,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,11,11,1920,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +10,12,256,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,43,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1216,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,55,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,63,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2304,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,12,47,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,39,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,12,53,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,19,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,24,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,11,22,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +11,12,2560,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2, +8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2, +8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2, +8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2, +8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2 +}; diff --git a/freeimage241/Source/LibTIFF/libtiff.def b/freeimage241/Source/LibTIFF/libtiff.def new file mode 100644 index 0000000..74ded6c --- /dev/null +++ b/freeimage241/Source/LibTIFF/libtiff.def @@ -0,0 +1,77 @@ +LIBRARY libtiff +EXPORTS TIFFOpen + TIFFGetVersion + TIFFClose + TIFFFlush + TIFFFlushData + TIFFGetField + TIFFVGetField + TIFFGetFieldDefaulted + TIFFVGetFieldDefaulted + TIFFReadDirectory + TIFFScanlineSize + TIFFStripSize + TIFFVStripSize + TIFFTileRowSize + TIFFTileSize + TIFFVTileSize + TIFFFileno + TIFFGetMode + TIFFIsTiled + TIFFIsByteSwapped + TIFFCurrentRow + TIFFCurrentDirectory + TIFFCurrentStrip + TIFFCurrentTile + TIFFReadBufferSetup + TIFFLastDirectory + TIFFSetDirectory + TIFFSetSubDirectory + TIFFUnlinkDirectory + TIFFSetField + TIFFVSetField + TIFFWriteDirectory + TIFFPrintDirectory + TIFFReadScanline + TIFFWriteScanline + TIFFReadRGBAImage + TIFFPrintDirectory + TIFFReadScanline + TIFFWriteScanline + TIFFReadRGBAImage + TIFFFdOpen + TIFFClientOpen + TIFFFileName + TIFFError + TIFFWarning + TIFFSetErrorHandler + TIFFSetWarningHandler + TIFFComputeTile + TIFFCheckTile + TIFFNumberOfTiles + TIFFReadTile + TIFFWriteTile + TIFFComputeStrip + TIFFNumberOfStrips + TIFFReadEncodedStrip + TIFFReadRawStrip + TIFFReadEncodedTile + TIFFReadRawTile + TIFFWriteEncodedStrip + TIFFWriteRawStrip + TIFFWriteEncodedTile + TIFFWriteRawTile + TIFFSetWriteOffset + TIFFSwabShort + TIFFSwabLong + TIFFSwabArrayOfShort + TIFFSwabArrayOfLong + TIFFReverseBits + TIFFGetBitRevTable + _TIFFmalloc + _TIFFrealloc + _TIFFfree + _TIFFmemset + _TIFFmemcpy + _TIFFmemcmp + diff --git a/freeimage241/Source/LibTIFF/makefile.vc b/freeimage241/Source/LibTIFF/makefile.vc new file mode 100644 index 0000000..afefc69 --- /dev/null +++ b/freeimage241/Source/LibTIFF/makefile.vc @@ -0,0 +1,79 @@ +# +# Simple MS VC++ Makefile +# +# To build: +# C:\libtiff\libtiff> nmake /f makefile.vc all +# + +# +# Select _CONSOLE to build a library which reports errors to stderr, or +# _WINDOWED to build such that errors are reported via MessageBox(). +# +WINMODE = -DTIF_PLATFORM_CONSOLE +#WINMODE = -DTIF_PLATFORM_WINDOWED + +CC = cl +INCL = -I. +LIBS = +CFLAGS = /nologo /W3 $(INCL) $(WINMODE) + +OBJ = \ + tif_aux.obj \ + tif_close.obj \ + tif_codec.obj \ + tif_compress.obj \ + tif_dir.obj \ + tif_dirinfo.obj \ + tif_dirread.obj \ + tif_dirwrite.obj \ + tif_dumpmode.obj \ + tif_error.obj \ + tif_fax3.obj \ + fax3sm_winnt.obj \ + tif_getimage.obj \ + tif_jpeg.obj \ + tif_flush.obj \ + tif_luv.obj \ + tif_lzw.obj \ + tif_next.obj \ + tif_open.obj \ + tif_packbits.obj \ + tif_pixarlog.obj \ + tif_predict.obj \ + tif_print.obj \ + tif_read.obj \ + tif_swab.obj \ + tif_strip.obj \ + tif_thunder.obj \ + tif_tile.obj \ + tif_win32.obj \ + tif_version.obj \ + tif_warning.obj \ + tif_write.obj \ + tif_zip.obj + +VERSION = ..\VERSION +ALPHA = ..\dist\tiff.alpha + +default: libtiff.lib + +all: libtiff.lib libtiff.dll + +libtiff.lib: tiffvers.h $(OBJ) + lib /out:libtiff.lib $(OBJ) + +libtiff.dll: $(OBJ) + link /dll /def:libtiff.def /out:libtiff.dll /implib:libtiff_i.lib \ + $(OBJ) $(LIBS) + +tiffvers.h: $(VERSION) mkversion.c + $(CC) mkversion.c + if exist tiffvers.h del tiffvers.h + .\mkversion.exe -v $(VERSION) tiffvers.h + +clean: + del *.obj *.lib libtiff.dll + +tif_version.obj: tiffvers.h + + diff --git a/freeimage241/Source/LibTIFF/t4.h b/freeimage241/Source/LibTIFF/t4.h new file mode 100644 index 0000000..2565366 --- /dev/null +++ b/freeimage241/Source/LibTIFF/t4.h @@ -0,0 +1,285 @@ +/* $Id: t4.h,v 1.0 2001-04-13 00:42:26+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _T4_ +#define _T4_ +/* + * CCITT T.4 1D Huffman runlength codes and + * related definitions. Given the small sizes + * of these tables it does not seem + * worthwhile to make code & length 8 bits. + */ +typedef struct tableentry { + unsigned short length; /* bit length of g3 code */ + unsigned short code; /* g3 code */ + short runlen; /* run length in bits */ +} tableentry; + +#define EOL 0x001 /* EOL code value - 0000 0000 0000 1 */ + +/* status values returned instead of a run length */ +#define G3CODE_EOL -1 /* NB: ACT_EOL - ACT_WRUNT */ +#define G3CODE_INVALID -2 /* NB: ACT_INVALID - ACT_WRUNT */ +#define G3CODE_EOF -3 /* end of input data */ +#define G3CODE_INCOMP -4 /* incomplete run code */ + +/* + * Note that these tables are ordered such that the + * index into the table is known to be either the + * run length, or (run length / 64) + a fixed offset. + * + * NB: The G3CODE_INVALID entries are only used + * during state generation (see mkg3states.c). + */ +#ifdef G3CODES +const tableentry TIFFFaxWhiteCodes[] = { + { 8, 0x35, 0 }, /* 0011 0101 */ + { 6, 0x7, 1 }, /* 0001 11 */ + { 4, 0x7, 2 }, /* 0111 */ + { 4, 0x8, 3 }, /* 1000 */ + { 4, 0xB, 4 }, /* 1011 */ + { 4, 0xC, 5 }, /* 1100 */ + { 4, 0xE, 6 }, /* 1110 */ + { 4, 0xF, 7 }, /* 1111 */ + { 5, 0x13, 8 }, /* 1001 1 */ + { 5, 0x14, 9 }, /* 1010 0 */ + { 5, 0x7, 10 }, /* 0011 1 */ + { 5, 0x8, 11 }, /* 0100 0 */ + { 6, 0x8, 12 }, /* 0010 00 */ + { 6, 0x3, 13 }, /* 0000 11 */ + { 6, 0x34, 14 }, /* 1101 00 */ + { 6, 0x35, 15 }, /* 1101 01 */ + { 6, 0x2A, 16 }, /* 1010 10 */ + { 6, 0x2B, 17 }, /* 1010 11 */ + { 7, 0x27, 18 }, /* 0100 111 */ + { 7, 0xC, 19 }, /* 0001 100 */ + { 7, 0x8, 20 }, /* 0001 000 */ + { 7, 0x17, 21 }, /* 0010 111 */ + { 7, 0x3, 22 }, /* 0000 011 */ + { 7, 0x4, 23 }, /* 0000 100 */ + { 7, 0x28, 24 }, /* 0101 000 */ + { 7, 0x2B, 25 }, /* 0101 011 */ + { 7, 0x13, 26 }, /* 0010 011 */ + { 7, 0x24, 27 }, /* 0100 100 */ + { 7, 0x18, 28 }, /* 0011 000 */ + { 8, 0x2, 29 }, /* 0000 0010 */ + { 8, 0x3, 30 }, /* 0000 0011 */ + { 8, 0x1A, 31 }, /* 0001 1010 */ + { 8, 0x1B, 32 }, /* 0001 1011 */ + { 8, 0x12, 33 }, /* 0001 0010 */ + { 8, 0x13, 34 }, /* 0001 0011 */ + { 8, 0x14, 35 }, /* 0001 0100 */ + { 8, 0x15, 36 }, /* 0001 0101 */ + { 8, 0x16, 37 }, /* 0001 0110 */ + { 8, 0x17, 38 }, /* 0001 0111 */ + { 8, 0x28, 39 }, /* 0010 1000 */ + { 8, 0x29, 40 }, /* 0010 1001 */ + { 8, 0x2A, 41 }, /* 0010 1010 */ + { 8, 0x2B, 42 }, /* 0010 1011 */ + { 8, 0x2C, 43 }, /* 0010 1100 */ + { 8, 0x2D, 44 }, /* 0010 1101 */ + { 8, 0x4, 45 }, /* 0000 0100 */ + { 8, 0x5, 46 }, /* 0000 0101 */ + { 8, 0xA, 47 }, /* 0000 1010 */ + { 8, 0xB, 48 }, /* 0000 1011 */ + { 8, 0x52, 49 }, /* 0101 0010 */ + { 8, 0x53, 50 }, /* 0101 0011 */ + { 8, 0x54, 51 }, /* 0101 0100 */ + { 8, 0x55, 52 }, /* 0101 0101 */ + { 8, 0x24, 53 }, /* 0010 0100 */ + { 8, 0x25, 54 }, /* 0010 0101 */ + { 8, 0x58, 55 }, /* 0101 1000 */ + { 8, 0x59, 56 }, /* 0101 1001 */ + { 8, 0x5A, 57 }, /* 0101 1010 */ + { 8, 0x5B, 58 }, /* 0101 1011 */ + { 8, 0x4A, 59 }, /* 0100 1010 */ + { 8, 0x4B, 60 }, /* 0100 1011 */ + { 8, 0x32, 61 }, /* 0011 0010 */ + { 8, 0x33, 62 }, /* 0011 0011 */ + { 8, 0x34, 63 }, /* 0011 0100 */ + { 5, 0x1B, 64 }, /* 1101 1 */ + { 5, 0x12, 128 }, /* 1001 0 */ + { 6, 0x17, 192 }, /* 0101 11 */ + { 7, 0x37, 256 }, /* 0110 111 */ + { 8, 0x36, 320 }, /* 0011 0110 */ + { 8, 0x37, 384 }, /* 0011 0111 */ + { 8, 0x64, 448 }, /* 0110 0100 */ + { 8, 0x65, 512 }, /* 0110 0101 */ + { 8, 0x68, 576 }, /* 0110 1000 */ + { 8, 0x67, 640 }, /* 0110 0111 */ + { 9, 0xCC, 704 }, /* 0110 0110 0 */ + { 9, 0xCD, 768 }, /* 0110 0110 1 */ + { 9, 0xD2, 832 }, /* 0110 1001 0 */ + { 9, 0xD3, 896 }, /* 0110 1001 1 */ + { 9, 0xD4, 960 }, /* 0110 1010 0 */ + { 9, 0xD5, 1024 }, /* 0110 1010 1 */ + { 9, 0xD6, 1088 }, /* 0110 1011 0 */ + { 9, 0xD7, 1152 }, /* 0110 1011 1 */ + { 9, 0xD8, 1216 }, /* 0110 1100 0 */ + { 9, 0xD9, 1280 }, /* 0110 1100 1 */ + { 9, 0xDA, 1344 }, /* 0110 1101 0 */ + { 9, 0xDB, 1408 }, /* 0110 1101 1 */ + { 9, 0x98, 1472 }, /* 0100 1100 0 */ + { 9, 0x99, 1536 }, /* 0100 1100 1 */ + { 9, 0x9A, 1600 }, /* 0100 1101 0 */ + { 6, 0x18, 1664 }, /* 0110 00 */ + { 9, 0x9B, 1728 }, /* 0100 1101 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; + +const tableentry TIFFFaxBlackCodes[] = { + { 10, 0x37, 0 }, /* 0000 1101 11 */ + { 3, 0x2, 1 }, /* 010 */ + { 2, 0x3, 2 }, /* 11 */ + { 2, 0x2, 3 }, /* 10 */ + { 3, 0x3, 4 }, /* 011 */ + { 4, 0x3, 5 }, /* 0011 */ + { 4, 0x2, 6 }, /* 0010 */ + { 5, 0x3, 7 }, /* 0001 1 */ + { 6, 0x5, 8 }, /* 0001 01 */ + { 6, 0x4, 9 }, /* 0001 00 */ + { 7, 0x4, 10 }, /* 0000 100 */ + { 7, 0x5, 11 }, /* 0000 101 */ + { 7, 0x7, 12 }, /* 0000 111 */ + { 8, 0x4, 13 }, /* 0000 0100 */ + { 8, 0x7, 14 }, /* 0000 0111 */ + { 9, 0x18, 15 }, /* 0000 1100 0 */ + { 10, 0x17, 16 }, /* 0000 0101 11 */ + { 10, 0x18, 17 }, /* 0000 0110 00 */ + { 10, 0x8, 18 }, /* 0000 0010 00 */ + { 11, 0x67, 19 }, /* 0000 1100 111 */ + { 11, 0x68, 20 }, /* 0000 1101 000 */ + { 11, 0x6C, 21 }, /* 0000 1101 100 */ + { 11, 0x37, 22 }, /* 0000 0110 111 */ + { 11, 0x28, 23 }, /* 0000 0101 000 */ + { 11, 0x17, 24 }, /* 0000 0010 111 */ + { 11, 0x18, 25 }, /* 0000 0011 000 */ + { 12, 0xCA, 26 }, /* 0000 1100 1010 */ + { 12, 0xCB, 27 }, /* 0000 1100 1011 */ + { 12, 0xCC, 28 }, /* 0000 1100 1100 */ + { 12, 0xCD, 29 }, /* 0000 1100 1101 */ + { 12, 0x68, 30 }, /* 0000 0110 1000 */ + { 12, 0x69, 31 }, /* 0000 0110 1001 */ + { 12, 0x6A, 32 }, /* 0000 0110 1010 */ + { 12, 0x6B, 33 }, /* 0000 0110 1011 */ + { 12, 0xD2, 34 }, /* 0000 1101 0010 */ + { 12, 0xD3, 35 }, /* 0000 1101 0011 */ + { 12, 0xD4, 36 }, /* 0000 1101 0100 */ + { 12, 0xD5, 37 }, /* 0000 1101 0101 */ + { 12, 0xD6, 38 }, /* 0000 1101 0110 */ + { 12, 0xD7, 39 }, /* 0000 1101 0111 */ + { 12, 0x6C, 40 }, /* 0000 0110 1100 */ + { 12, 0x6D, 41 }, /* 0000 0110 1101 */ + { 12, 0xDA, 42 }, /* 0000 1101 1010 */ + { 12, 0xDB, 43 }, /* 0000 1101 1011 */ + { 12, 0x54, 44 }, /* 0000 0101 0100 */ + { 12, 0x55, 45 }, /* 0000 0101 0101 */ + { 12, 0x56, 46 }, /* 0000 0101 0110 */ + { 12, 0x57, 47 }, /* 0000 0101 0111 */ + { 12, 0x64, 48 }, /* 0000 0110 0100 */ + { 12, 0x65, 49 }, /* 0000 0110 0101 */ + { 12, 0x52, 50 }, /* 0000 0101 0010 */ + { 12, 0x53, 51 }, /* 0000 0101 0011 */ + { 12, 0x24, 52 }, /* 0000 0010 0100 */ + { 12, 0x37, 53 }, /* 0000 0011 0111 */ + { 12, 0x38, 54 }, /* 0000 0011 1000 */ + { 12, 0x27, 55 }, /* 0000 0010 0111 */ + { 12, 0x28, 56 }, /* 0000 0010 1000 */ + { 12, 0x58, 57 }, /* 0000 0101 1000 */ + { 12, 0x59, 58 }, /* 0000 0101 1001 */ + { 12, 0x2B, 59 }, /* 0000 0010 1011 */ + { 12, 0x2C, 60 }, /* 0000 0010 1100 */ + { 12, 0x5A, 61 }, /* 0000 0101 1010 */ + { 12, 0x66, 62 }, /* 0000 0110 0110 */ + { 12, 0x67, 63 }, /* 0000 0110 0111 */ + { 10, 0xF, 64 }, /* 0000 0011 11 */ + { 12, 0xC8, 128 }, /* 0000 1100 1000 */ + { 12, 0xC9, 192 }, /* 0000 1100 1001 */ + { 12, 0x5B, 256 }, /* 0000 0101 1011 */ + { 12, 0x33, 320 }, /* 0000 0011 0011 */ + { 12, 0x34, 384 }, /* 0000 0011 0100 */ + { 12, 0x35, 448 }, /* 0000 0011 0101 */ + { 13, 0x6C, 512 }, /* 0000 0011 0110 0 */ + { 13, 0x6D, 576 }, /* 0000 0011 0110 1 */ + { 13, 0x4A, 640 }, /* 0000 0010 0101 0 */ + { 13, 0x4B, 704 }, /* 0000 0010 0101 1 */ + { 13, 0x4C, 768 }, /* 0000 0010 0110 0 */ + { 13, 0x4D, 832 }, /* 0000 0010 0110 1 */ + { 13, 0x72, 896 }, /* 0000 0011 1001 0 */ + { 13, 0x73, 960 }, /* 0000 0011 1001 1 */ + { 13, 0x74, 1024 }, /* 0000 0011 1010 0 */ + { 13, 0x75, 1088 }, /* 0000 0011 1010 1 */ + { 13, 0x76, 1152 }, /* 0000 0011 1011 0 */ + { 13, 0x77, 1216 }, /* 0000 0011 1011 1 */ + { 13, 0x52, 1280 }, /* 0000 0010 1001 0 */ + { 13, 0x53, 1344 }, /* 0000 0010 1001 1 */ + { 13, 0x54, 1408 }, /* 0000 0010 1010 0 */ + { 13, 0x55, 1472 }, /* 0000 0010 1010 1 */ + { 13, 0x5A, 1536 }, /* 0000 0010 1101 0 */ + { 13, 0x5B, 1600 }, /* 0000 0010 1101 1 */ + { 13, 0x64, 1664 }, /* 0000 0011 0010 0 */ + { 13, 0x65, 1728 }, /* 0000 0011 0010 1 */ + { 11, 0x8, 1792 }, /* 0000 0001 000 */ + { 11, 0xC, 1856 }, /* 0000 0001 100 */ + { 11, 0xD, 1920 }, /* 0000 0001 101 */ + { 12, 0x12, 1984 }, /* 0000 0001 0010 */ + { 12, 0x13, 2048 }, /* 0000 0001 0011 */ + { 12, 0x14, 2112 }, /* 0000 0001 0100 */ + { 12, 0x15, 2176 }, /* 0000 0001 0101 */ + { 12, 0x16, 2240 }, /* 0000 0001 0110 */ + { 12, 0x17, 2304 }, /* 0000 0001 0111 */ + { 12, 0x1C, 2368 }, /* 0000 0001 1100 */ + { 12, 0x1D, 2432 }, /* 0000 0001 1101 */ + { 12, 0x1E, 2496 }, /* 0000 0001 1110 */ + { 12, 0x1F, 2560 }, /* 0000 0001 1111 */ + { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */ + { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */ + { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */ + { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */ + { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */ +}; +#else +extern const tableentry TIFFFaxWhiteCodes[]; +extern const tableentry TIFFFaxBlackCodes[]; +#endif +#endif /* _T4_ */ diff --git a/freeimage241/Source/LibTIFF/tif_acorn.c b/freeimage241/Source/LibTIFF/tif_acorn.c new file mode 100644 index 0000000..f1b4ea4 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_acorn.c @@ -0,0 +1,519 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_acorn.c,v 1.0 2001-04-13 00:42:27+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library RISC OS specific Routines. + * Developed out of the Unix version. + * Peter Greenham, May 1995 + */ +#include "tiffiop.h" +#include +#include + +/* +Low-level file handling +~~~~~~~~~~~~~~~~~~~~~~~ +The functions in osfcn.h are unavailable when compiling under C, as it's a +C++ header. Therefore they have been implemented here. + +Now, why have I done it this way? + +The definitive API library for RISC OS is Jonathan Coxhead's OSLib, which +uses heavily optimised ARM assembler or even plain inline SWI calls for +maximum performance and minimum runtime size. However, I don't want to make +LIBTIFF need that to survive. Therefore I have also emulated the functions +using macros to _swi() and _swix() defined in the swis.h header, and +borrowing types from kernel.h, which is less efficient but doesn't need any +third-party libraries. + */ + +#ifdef INCLUDE_OSLIB + +#include "osfile.h" +#include "osgbpb.h" +#include "osargs.h" +#include "osfind.h" + +#else + +/* OSLIB EMULATION STARTS */ + +#include "kernel.h" +#include "swis.h" + +/* From oslib:types.h */ +typedef unsigned int bits; +typedef unsigned char byte; +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef NULL +#define NULL 0 +#endif +#ifndef SKIP +#define SKIP 0 +#endif + +/* From oslib:os.h */ +typedef _kernel_oserror os_error; +typedef byte os_f; + +/* From oslib:osfile.h */ +#undef OS_File +#define OS_File 0x8 + +/* From oslib:osgbpb.h */ +#undef OS_GBPB +#define OS_GBPB 0xC +#undef OSGBPB_Write +#define OSGBPB_Write 0x2 +#undef OSGBPB_Read +#define OSGBPB_Read 0x4 + +extern os_error *xosgbpb_write (os_f file, + byte *data, + int size, + int *unwritten); +extern int osgbpb_write (os_f file, + byte *data, + int size); + +#define xosgbpb_write(file, data, size, unwritten) \ + (os_error*) _swix(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_IN(4)|_OUT(3), \ + OSGBPB_WriteAt, \ + file, \ + data, \ + size, \ + unwritten) + +#define osgbpb_write(file, data, size) \ + _swi(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_RETURN(3), \ + OSGBPB_Write, \ + file, \ + data, \ + size) + +extern os_error *xosgbpb_read (os_f file, + byte *buffer, + int size, + int *unread); +extern int osgbpb_read (os_f file, + byte *buffer, + int size); + +#define xosgbpb_read(file, buffer, size, unread) \ + (os_error*) _swix(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_OUT(3), \ + OSGBPB_Read, \ + file, \ + buffer, \ + size, \ + unread) + +#define osgbpb_read(file, buffer, size) \ + _swi(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_RETURN(3), \ + OSGBPB_Read, \ + file, \ + buffer, \ + size) + +/* From oslib:osfind.h */ +#undef OS_Find +#define OS_Find 0xD +#undef OSFind_Openin +#define OSFind_Openin 0x40 +#undef OSFind_Openout +#define OSFind_Openout 0x80 +#undef OSFind_Openup +#define OSFind_Openup 0xC0 +#undef OSFind_Close +#define OSFind_Close 0x0 + +#define xosfind_open(reason, file_name, path, file) \ + (os_error*) _swix(OS_Find, _IN(0)|_IN(1)|_IN(2)|_OUT(0), \ + reason, file_name, path, file) + +#define osfind_open(reason, file_name, path) \ + (os_f) _swi(OS_Find, _IN(0)|_IN(1)|_IN(2)|_RETURN(0), \ + reason, file_name, path) + +extern os_error *xosfind_openin (bits flags, + char *file_name, + char *path, + os_f *file); +extern os_f osfind_openin (bits flags, + char *file_name, + char *path); + +#define xosfind_openin(flags, file_name, path, file) \ + xosfind_open(flags | OSFind_Openin, file_name, path, file) + +#define osfind_openin(flags, file_name, path) \ + osfind_open(flags | OSFind_Openin, file_name, path) + +extern os_error *xosfind_openout (bits flags, + char *file_name, + char *path, + os_f *file); +extern os_f osfind_openout (bits flags, + char *file_name, + char *path); + +#define xosfind_openout(flags, file_name, path, file) \ + xosfind_open(flags | OSFind_Openout, file_name, path, file) + +#define osfind_openout(flags, file_name, path) \ + osfind_open(flags | OSFind_Openout, file_name, path) + +extern os_error *xosfind_openup (bits flags, + char *file_name, + char *path, + os_f *file); +extern os_f osfind_openup (bits flags, + char *file_name, + char *path); + +#define xosfind_openup(flags, file_name, path, file) \ + xosfind_open(flags | OSFind_Openup, file_name, path, file) + +#define osfind_openup(flags, file_name, path) \ + osfind_open(flags | OSFind_Openup, file_name, path) + +extern os_error *xosfind_close (os_f file); +extern void osfind_close (os_f file); + +#define xosfind_close(file) \ + (os_error*) _swix(OS_Find, _IN(0)|_IN(1), \ + OSFind_Close, \ + file) + +#define osfind_close(file) \ + (void) _swi(OS_Find, _IN(0)|_IN(1), \ + OSFind_Close, \ + file) + +/* From oslib:osargs.h */ +#undef OS_Args +#define OS_Args 0x9 +#undef OSArgs_ReadPtr +#define OSArgs_ReadPtr 0x0 +#undef OSArgs_SetPtr +#define OSArgs_SetPtr 0x1 +#undef OSArgs_ReadExt +#define OSArgs_ReadExt 0x2 + +extern os_error *xosargs_read_ptr (os_f file, + int *ptr); +extern int osargs_read_ptr (os_f file); + +#define xosargs_read_ptr(file, ptr) \ + (os_error*) _swix(OS_Args, _IN(0)|_IN(1)|_OUT(2), \ + OSArgs_ReadPtr, \ + file, \ + ptr) + +#define osargs_read_ptr(file) \ + _swi(OS_Args, _IN(0)|_IN(1)|_RETURN(2), \ + OSArgs_ReadPtr, \ + file) + +extern os_error *xosargs_set_ptr (os_f file, + int ptr); +extern void osargs_set_ptr (os_f file, + int ptr); + +#define xosargs_set_ptr(file, ptr) \ + (os_error*) _swix(OS_Args, _IN(0)|_IN(1)|_IN(2), \ + OSArgs_SetPtr, \ + file, \ + ptr) + +#define osargs_set_ptr(file, ptr) \ + (void) _swi(OS_Args, _IN(0)|_IN(1)|_IN(2), \ + OSArgs_SetPtr, \ + file, \ + ptr) + +extern os_error *xosargs_read_ext (os_f file, + int *ext); +extern int osargs_read_ext (os_f file); + +#define xosargs_read_ext(file, ext) \ + (os_error*) _swix(OS_Args, _IN(0)|_IN(1)|_OUT(2), \ + OSArgs_ReadExt, \ + file, \ + ext) + +#define osargs_read_ext(file) \ + _swi(OS_Args, _IN(0)|_IN(1)|_RETURN(2), \ + OSArgs_ReadExt, \ + file) + +/* OSLIB EMULATION ENDS */ + +#endif + +#ifndef __osfcn_h +/* Will be set or not during tiffcomp.h */ +/* You get this to compile under C++? Please say how! */ + +extern int open(const char* name, int flags, int mode) +{ + /* From what I can tell, should return <0 for failure */ + os_error* e = (os_error*) 1; /* Cheeky way to use a pointer eh? :-) */ + os_f file = (os_f) -1; + + flags = flags; + + switch(mode) + { + case O_RDONLY: + { + e = xosfind_openin(SKIP, name, SKIP, &file); + break; + } + case O_WRONLY: + case O_RDWR|O_CREAT: + case O_RDWR|O_CREAT|O_TRUNC: + { + e = xosfind_openout(SKIP, name, SKIP, &file); + break; + } + case O_RDWR: + { + e = xosfind_openup(SKIP, name, SKIP, &file); + break; + } + } + if (e) + { + file = (os_f) -1; + } + return (file); +} + +extern int close(int fd) +{ + return ((int) xosfind_close((os_f) fd)); +} + +extern int write(int fd, const char *buf, int nbytes) +{ + /* Returns number of bytes written */ + return (nbytes - osgbpb_write((os_f) fd, (const byte*) buf, nbytes)); +} + +extern int read(int fd, char *buf, int nbytes) +{ + /* Returns number of bytes read */ + return (nbytes - osgbpb_read((os_f) fd, (byte*) buf, nbytes)); +} + +extern off_t lseek(int fd, off_t offset, int whence) +{ + int absolute = 0; + + switch (whence) + { + case SEEK_SET: + { + absolute = (int) offset; + break; + } + case SEEK_CUR: + { + absolute = osargs_read_ptr((os_f) fd) + (int) offset; + break; + } + case SEEK_END: + { + absolute = osargs_read_ext((os_f) fd) + (int) offset; + break; + } + } + + osargs_set_ptr((os_f) fd, absolute); + + return ((off_t) osargs_read_ptr((os_f) fd)); +} +#endif + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return ((tsize_t) read((int) fd, buf, (size_t) size)); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return ((tsize_t) write((int) fd, buf, (size_t) size)); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + return ((toff_t) lseek((int) fd, (off_t) off, whence)); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (close((int) fd)); +} + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + return (lseek((int) fd, SEEK_END, SEEK_SET)); +} + +#ifdef HAVE_MMAP +#error "I didn't know Acorn had that!" +#endif + +/* !HAVE_MMAP */ +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + (void) fd; (void) pbase; (void) psize; + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + (void) fd; (void) base; (void) size; +} + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + _tiffMapProc, _tiffUnmapProc); + if (tif) + { + tif->tif_fd = fd; + } + return (tif); +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + int m, fd; + + m = _TIFFgetMode(mode, module); + + if (m == -1) + { + return ((TIFF*) 0); + } + + fd = open(name, 0, m); + + if (fd < 0) + { + TIFFError(module, "%s: Cannot open", name); + return ((TIFF *)0); + } + return (TIFFFdOpen(fd, name, mode)); +} + +void* +_TIFFmalloc(tsize_t s) +{ + return (malloc((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + free(p); +} + +void* +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +static void +acornWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + { + fprintf(stderr, "%s: ", module); + } + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = acornWarningHandler; + +static void +acornErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + { + fprintf(stderr, "%s: ", module); + } + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = acornErrorHandler; diff --git a/freeimage241/Source/LibTIFF/tif_apple.c b/freeimage241/Source/LibTIFF/tif_apple.c new file mode 100644 index 0000000..05dc229 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_apple.c @@ -0,0 +1,274 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_apple.c,v 1.0 2001-04-13 00:42:28+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Macintosh-specific routines. + * + * These routines use only Toolbox and high-level File Manager traps. + * They make no calls to the THINK C "unix" compatibility library. Also, + * malloc is not used directly but it is still referenced internally by + * the ANSI library in rare cases. Heap fragmentation by the malloc ring + * buffer is therefore minimized. + * + * O_RDONLY and O_RDWR are treated identically here. The tif_mode flag is + * checked in TIFFWriteCheck(). + * + * Create below fills in a blank creator signature and sets the file type + * to 'TIFF'. It is much better for the application to do this by Create'ing + * the file first and TIFFOpen'ing it later. + * --------- + * This code has been "Carbonized", and may not work with older MacOS versions. + * If so, grab the tif_apple.c out of an older libtiff distribution, like + * 3.5.5 from www.libtiff.org. + */ + +#include "tiffiop.h" +#include +#include +#include +#include + +#if defined(__PPCC__) || defined(__SC__) || defined(__MRC__) || defined(applec) +#define CtoPstr c2pstr +#endif + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (FSRead((short) fd, (long*) &size, (char*) buf) == noErr ? + size : (tsize_t) -1); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (FSWrite((short) fd, (long*) &size, (char*) buf) == noErr ? + size : (tsize_t) -1); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + long fpos, size; + + if (GetEOF((short) fd, &size) != noErr) + return EOF; + (void) GetFPos((short) fd, &fpos); + + switch (whence) { + case SEEK_CUR: + if (off + fpos > size) + SetEOF((short) fd, off + fpos); + if (SetFPos((short) fd, fsFromMark, off) != noErr) + return EOF; + break; + case SEEK_END: + if (off > 0) + SetEOF((short) fd, off + size); + if (SetFPos((short) fd, fsFromStart, off + size) != noErr) + return EOF; + break; + case SEEK_SET: + if (off > size) + SetEOF((short) fd, off); + if (SetFPos((short) fd, fsFromStart, off) != noErr) + return EOF; + break; + } + + return (toff_t)(GetFPos((short) fd, &fpos) == noErr ? fpos : EOF); +} + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (FSClose((short) fd)); +} + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + long size; + + if (GetEOF((short) fd, &size) != noErr) { + TIFFError("_tiffSizeProc", "%s: Cannot get file size"); + return (-1L); + } + return ((toff_t) size); +} + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, + _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +static void ourc2pstr( char* inString ) +{ + int sLen = strlen( inString ); + BlockMoveData( inString, &inString[1], sLen ); + inString[0] = sLen; +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + Str255 pname; + FInfo finfo; + short fref; + OSErr err; + FSSpec fSpec; + + strcpy((char*) pname, name); + ourc2pstr((char*) pname); + + err = FSMakeFSSpec( 0, 0, pname, &fSpec ); + + switch (_TIFFgetMode(mode, module)) { + default: + return ((TIFF*) 0); + case O_RDWR | O_CREAT | O_TRUNC: + if (FSpGetFInfo(&fSpec, &finfo) == noErr) + FSpDelete(&fSpec); + /* fall through */ + case O_RDWR | O_CREAT: + if ((err = FSpGetFInfo(&fSpec, &finfo)) == fnfErr) { + if (FSpCreate(&fSpec, ' ', 'TIFF', smSystemScript) != noErr) + goto badCreate; + if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr) + goto badOpen; + } else if (err == noErr) { + if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr) + goto badOpen; + } else + goto badOpen; + break; + case O_RDONLY: + if (FSpOpenDF(&fSpec, fsRdPerm, &fref) != noErr) + goto badOpen; + break; + case O_RDWR: + if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr) + goto badOpen; + break; + } + return (TIFFFdOpen((int) fref, name, mode)); +badCreate: + TIFFError(module, "%s: Cannot create", name); + return ((TIFF*) 0); +badOpen: + TIFFError(module, "%s: Cannot open", name); + return ((TIFF*) 0); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return (NewPtr((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + DisposePtr(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + Ptr n = p; + + SetPtrSize(p, (size_t) s); + if (MemError() && (n = NewPtr((size_t) s)) != NULL) { + BlockMove(p, n, GetPtrSize(p)); + DisposePtr(p); + } + return ((tdata_t) n); +} + +static void +appleWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = appleWarningHandler; + +static void +appleErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = appleErrorHandler; diff --git a/freeimage241/Source/LibTIFF/tif_atari.c b/freeimage241/Source/LibTIFF/tif_atari.c new file mode 100644 index 0000000..cd4560a --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_atari.c @@ -0,0 +1,243 @@ +/* "$Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_atari.c,v 1.0 2001-04-13 00:42:28+02 floris_van_den_berg Exp floris_van_den_berg $" */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library ATARI-specific Routines. + */ +#include "tiffiop.h" +#if defined(__TURBOC__) +#include +#include +#else +#include +#include +#endif + +#ifndef O_ACCMODE +#define O_ACCMODE 3 +#endif + +#include + +#define AEFILNF -33 + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + long r; + + r = Fread((int) fd, size, buf); + if (r < 0) { + errno = (int)-r; + r = -1; + } + return r; +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + long r; + + r = Fwrite((int) fd, size, buf); + if (r < 0) { + errno = (int)-r; + r = -1; + } + return r; +} + +static toff_t +_tiffSeekProc(thandle_t fd, off_t off, int whence) +{ + char buf[256]; + long current_off, expected_off, new_off; + + if (whence == SEEK_END || off <= 0) + return Fseek(off, (int) fd, whence); + current_off = Fseek(0, (int) fd, SEEK_CUR); /* find out where we are */ + if (whence == SEEK_SET) + expected_off = off; + else + expected_off = off + current_off; + new_off = Fseek(off, (int) fd, whence); + if (new_off == expected_off) + return new_off; + /* otherwise extend file -- zero filling the hole */ + if (new_off < 0) /* error? */ + new_off = Fseek(0, (int) fd, SEEK_END); /* go to eof */ + _TIFFmemset(buf, 0, sizeof(buf)); + while (expected_off > new_off) { + off = expected_off - new_off; + if (off > sizeof(buf)) + off = sizeof(buf); + if ((current_off = Fwrite((int) fd, off, buf)) != off) + return (current_off > 0) ? + new_off + current_off : new_off; + new_off += off; + } + return new_off; +} + +static int +_tiffCloseProc(thandle_t fd) +{ + long r; + + r = Fclose((int) fd); + if (r < 0) { + errno = (int)-r; + r = -1; + } + return (int)r; +} + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + long pos, eof; + + pos = Fseek(0, (int) fd, SEEK_CUR); + eof = Fseek(0, (int) fd, SEEK_END); + Fseek(pos, (int) fd, SEEK_SET); + return eof; +} + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +/* +* Open a TIFF file descriptor for read/writing. +*/ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, + _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +/* +* Open a TIFF file for read/writing. +*/ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + int m; + long fd; + + m = _TIFFgetMode(mode, module); + if (m == -1) + return ((TIFF*)0); + if (m & O_TRUNC) { + fd = Fcreate(name, 0); + } else { + fd = Fopen(name, m & O_ACCMODE); + if (fd == AEFILNF && m & O_CREAT) + fd = Fcreate(name, 0); + } + if (fd < 0) + errno = (int)fd; + if (fd < 0) { + TIFFError(module, "%s: Cannot open", name); + return ((TIFF*)0); + } + return (TIFFFdOpen(fd, name, mode)); +} + +#include + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return (malloc((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + free(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(tdata_t p, int v, size_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, size_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +static void +atariWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = atariWarningHandler; + +static void +atariErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = atariErrorHandler; diff --git a/freeimage241/Source/LibTIFF/tif_aux.c b/freeimage241/Source/LibTIFF/tif_aux.c new file mode 100644 index 0000000..7d331b7 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_aux.c @@ -0,0 +1,206 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_aux.c,v 1.0 2001-04-13 00:42:28+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Auxiliary Support Routines. + */ +#include "tiffiop.h" + +#ifdef COLORIMETRY_SUPPORT +#include + +static void +TIFFDefaultTransferFunction(TIFFDirectory* td) +{ + uint16 **tf = td->td_transferfunction; + long i, n = 1<td_bitspersample; + + tf[0] = (uint16 *)_TIFFmalloc(n * sizeof (uint16)); + tf[0][0] = 0; + for (i = 1; i < n; i++) { + double t = (double)i/((double) n-1.); + tf[0][i] = (uint16)floor(65535.*pow(t, 2.2) + .5); + } + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + tf[1] = (uint16 *)_TIFFmalloc(n * sizeof (uint16)); + _TIFFmemcpy(tf[1], tf[0], n * sizeof (uint16)); + tf[2] = (uint16 *)_TIFFmalloc(n * sizeof (uint16)); + _TIFFmemcpy(tf[2], tf[0], n * sizeof (uint16)); + } +} + +static void +TIFFDefaultRefBlackWhite(TIFFDirectory* td) +{ + int i; + + td->td_refblackwhite = (float *)_TIFFmalloc(6*sizeof (float)); + for (i = 0; i < 3; i++) { + td->td_refblackwhite[2*i+0] = 0; + td->td_refblackwhite[2*i+1] = (float)((1L<td_bitspersample)-1L); + } +} +#endif + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + * + * NB: We use the value in the directory, rather than + * explcit values so that defaults exist only one + * place in the library -- in TIFFDefaultDirectory. + */ +int +TIFFVGetFieldDefaulted(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (TIFFVGetField(tif, tag, ap)) + return (1); + switch (tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32 *) = td->td_subfiletype; + return (1); + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16 *) = td->td_bitspersample; + return (1); + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16 *) = td->td_threshholding; + return (1); + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16 *) = td->td_fillorder; + return (1); + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16 *) = td->td_orientation; + return (1); + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16 *) = td->td_samplesperpixel; + return (1); + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32 *) = td->td_rowsperstrip; + return (1); + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16 *) = td->td_minsamplevalue; + return (1); + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16 *) = td->td_maxsamplevalue; + return (1); + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16 *) = td->td_planarconfig; + return (1); + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16 *) = td->td_resolutionunit; + return (1); +#ifdef CMYK_SUPPORT + case TIFFTAG_DOTRANGE: + *va_arg(ap, uint16 *) = 0; + *va_arg(ap, uint16 *) = (1<td_bitspersample)-1; + return (1); + case TIFFTAG_INKSET: + *va_arg(ap, uint16 *) = td->td_inkset; + return (1); + case TIFFTAG_NUMBEROFINKS: + *va_arg(ap, uint16 *) = td->td_ninks; + return (1); +#endif + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16 *) = td->td_extrasamples; + *va_arg(ap, uint16 **) = td->td_sampleinfo; + return (1); + case TIFFTAG_MATTEING: + *va_arg(ap, uint16 *) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + return (1); + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32 *) = td->td_tiledepth; + return (1); + case TIFFTAG_DATATYPE: + *va_arg(ap, uint16 *) = td->td_sampleformat-1; + return (1); + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16 *) = td->td_sampleformat; + return(1); + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32 *) = td->td_imagedepth; + return (1); +#ifdef YCBCR_SUPPORT + case TIFFTAG_YCBCRCOEFFICIENTS: + if (!td->td_ycbcrcoeffs) { + td->td_ycbcrcoeffs = (float *) + _TIFFmalloc(3*sizeof (float)); + /* defaults are from CCIR Recommendation 601-1 */ + td->td_ycbcrcoeffs[0] = 0.299f; + td->td_ycbcrcoeffs[1] = 0.587f; + td->td_ycbcrcoeffs[2] = 0.114f; + } + *va_arg(ap, float **) = td->td_ycbcrcoeffs; + return (1); + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[1]; + return (1); + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16 *) = td->td_ycbcrpositioning; + return (1); +#endif +#ifdef COLORIMETRY_SUPPORT + case TIFFTAG_TRANSFERFUNCTION: + if (!td->td_transferfunction[0]) + TIFFDefaultTransferFunction(td); + *va_arg(ap, uint16 **) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, uint16 **) = td->td_transferfunction[1]; + *va_arg(ap, uint16 **) = td->td_transferfunction[2]; + } + return (1); + case TIFFTAG_REFERENCEBLACKWHITE: + if (!td->td_refblackwhite) + TIFFDefaultRefBlackWhite(td); + *va_arg(ap, float **) = td->td_refblackwhite; + return (1); +#endif + } + return (0); +} + +/* + * Like TIFFGetField, but return any default + * value if the tag is not present in the directory. + */ +int +TIFFGetFieldDefaulted(TIFF* tif, ttag_t tag, ...) +{ + int ok; + va_list ap; + + va_start(ap, tag); + ok = TIFFVGetFieldDefaulted(tif, tag, ap); + va_end(ap); + return (ok); +} diff --git a/freeimage241/Source/LibTIFF/tif_close.c b/freeimage241/Source/LibTIFF/tif_close.c new file mode 100644 index 0000000..85bb40e --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_close.c @@ -0,0 +1,50 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_close.c,v 1.0 2001-04-13 00:42:29+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +void +TIFFClose(TIFF* tif) +{ + if (tif->tif_mode != O_RDONLY) + /* + * Flush buffered data and directory (if dirty). + */ + TIFFFlush(tif); + (*tif->tif_cleanup)(tif); + TIFFFreeDirectory(tif); + if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER)) + _TIFFfree(tif->tif_rawdata); + if (isMapped(tif)) + TIFFUnmapFileContents(tif, tif->tif_base, tif->tif_size); + (void) TIFFCloseFile(tif); + if (tif->tif_fieldinfo) + _TIFFfree(tif->tif_fieldinfo); + _TIFFfree(tif); +} diff --git a/freeimage241/Source/LibTIFF/tif_codec.c b/freeimage241/Source/LibTIFF/tif_codec.c new file mode 100644 index 0000000..5b35272 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_codec.c @@ -0,0 +1,117 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_codec.c,v 1.0 2001-04-13 00:42:29+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Builtin Compression Scheme Configuration Support. + */ +#include "tiffiop.h" + +static int NotConfigured(TIFF*, int); + +#ifndef LZW_SUPPORT +#define TIFFInitLZW NotConfigured +#endif +#ifndef PACKBITS_SUPPORT +#define TIFFInitPackbits NotConfigured +#endif +#ifndef THUNDER_SUPPORT +#define TIFFInitThunderScan NotConfigured +#endif +#ifndef NEXT_SUPPORT +#define TIFFInitNeXT NotConfigured +#endif +#ifndef JPEG_SUPPORT +#define TIFFInitJPEG NotConfigured +#endif +#ifndef OJPEG_SUPPORT +#define TIFFInitOJPEG NotConfigured +#endif +#ifndef CCITT_SUPPORT +#define TIFFInitCCITTRLE NotConfigured +#define TIFFInitCCITTRLEW NotConfigured +#define TIFFInitCCITTFax3 NotConfigured +#define TIFFInitCCITTFax4 NotConfigured +#endif +#ifndef JBIG_SUPPORT +#define TIFFInitJBIG NotConfigured +#endif +#ifndef ZIP_SUPPORT +#define TIFFInitZIP NotConfigured +#endif +#ifndef PIXARLOG_SUPPORT +#define TIFFInitPixarLog NotConfigured +#endif +#ifndef LOGLUV_SUPPORT +#define TIFFInitSGILog NotConfigured +#endif + +/* + * Compression schemes statically built into the library. + */ +#ifdef VMS +const TIFFCodec _TIFFBuiltinCODECS[] = { +#else +TIFFCodec _TIFFBuiltinCODECS[] = { +#endif + { "None", COMPRESSION_NONE, TIFFInitDumpMode }, + { "LZW", COMPRESSION_LZW, TIFFInitLZW }, + { "PackBits", COMPRESSION_PACKBITS, TIFFInitPackBits }, + { "ThunderScan", COMPRESSION_THUNDERSCAN,TIFFInitThunderScan }, + { "NeXT", COMPRESSION_NEXT, TIFFInitNeXT }, + { "JPEG", COMPRESSION_JPEG, TIFFInitJPEG }, + { "Old-style JPEG", COMPRESSION_OJPEG, TIFFInitOJPEG }, + { "CCITT RLE", COMPRESSION_CCITTRLE, TIFFInitCCITTRLE }, + { "CCITT RLE/W", COMPRESSION_CCITTRLEW, TIFFInitCCITTRLEW }, + { "CCITT Group 3", COMPRESSION_CCITTFAX3, TIFFInitCCITTFax3 }, + { "CCITT Group 4", COMPRESSION_CCITTFAX4, TIFFInitCCITTFax4 }, + { "ISO JBIG", COMPRESSION_JBIG, TIFFInitJBIG }, + { "Deflate", COMPRESSION_DEFLATE, TIFFInitZIP }, + { "AdobeDeflate", COMPRESSION_ADOBE_DEFLATE , TIFFInitZIP }, + { "PixarLog", COMPRESSION_PIXARLOG, TIFFInitPixarLog }, + { "SGILog", COMPRESSION_SGILOG, TIFFInitSGILog }, + { "SGILog24", COMPRESSION_SGILOG24, TIFFInitSGILog }, + { NULL } +}; + +static int +_notConfigured(TIFF* tif) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + TIFFError(tif->tif_name, + "%s compression support is not configured", c->name); + return (0); +} + +static int +NotConfigured(TIFF* tif, int scheme) +{ + tif->tif_setupdecode = _notConfigured; + tif->tif_setupencode = _notConfigured; + return (1); +} diff --git a/freeimage241/Source/LibTIFF/tif_compress.c b/freeimage241/Source/LibTIFF/tif_compress.c new file mode 100644 index 0000000..2feb264 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_compress.c @@ -0,0 +1,231 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_compress.c,v 1.0 2001-04-13 00:42:29+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Compression Scheme Configuration Support. + */ +#include "tiffiop.h" + +static int +TIFFNoEncode(TIFF* tif, char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) { + if (! strncmp(c->name, "LZW", 3) ){ + TIFFError(tif->tif_name, + "%s %s encoding is no longer implemented due to Unisys patent enforcement", + c->name, method); + } else { + TIFFError(tif->tif_name, "%s %s encoding is not implemented", + c->name, method); + } + } + else { + TIFFError(tif->tif_name, + "Compression scheme %u %s encoding is not implemented", + tif->tif_dir.td_compression, method); + } + return (-1); +} + +int +_TIFFNoRowEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "scanline")); +} + +int +_TIFFNoStripEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "strip")); +} + +int +_TIFFNoTileEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoEncode(tif, "tile")); +} + +static int +TIFFNoDecode(TIFF* tif, char* method) +{ + const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression); + + if (c) + TIFFError(tif->tif_name, "%s %s decoding is not implemented", + c->name, method); + else + TIFFError(tif->tif_name, + "Compression scheme %u %s decoding is not implemented", + tif->tif_dir.td_compression, method); + return (-1); +} + +int +_TIFFNoRowDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "scanline")); +} + +int +_TIFFNoStripDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "strip")); +} + +int +_TIFFNoTileDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) pp; (void) cc; (void) s; + return (TIFFNoDecode(tif, "tile")); +} + +int +_TIFFNoSeek(TIFF* tif, uint32 off) +{ + (void) off; + TIFFError(tif->tif_name, + "Compression algorithm does not support random access"); + return (0); +} + +int +_TIFFNoPreCode(TIFF* tif, tsample_t s) +{ + (void) tif; (void) s; + return (1); +} + +static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); } +static void _TIFFvoid(TIFF* tif) { (void) tif; } + +void +_TIFFSetDefaultCompressionState(TIFF* tif) +{ + tif->tif_setupdecode = _TIFFtrue; + tif->tif_predecode = _TIFFNoPreCode; + tif->tif_decoderow = _TIFFNoRowDecode; + tif->tif_decodestrip = _TIFFNoStripDecode; + tif->tif_decodetile = _TIFFNoTileDecode; + tif->tif_setupencode = _TIFFtrue; + tif->tif_preencode = _TIFFNoPreCode; + tif->tif_postencode = _TIFFtrue; + tif->tif_encoderow = _TIFFNoRowEncode; + tif->tif_encodestrip = _TIFFNoStripEncode; + tif->tif_encodetile = _TIFFNoTileEncode; + tif->tif_close = _TIFFvoid; + tif->tif_seek = _TIFFNoSeek; + tif->tif_cleanup = _TIFFvoid; + tif->tif_defstripsize = _TIFFDefaultStripSize; + tif->tif_deftilesize = _TIFFDefaultTileSize; + tif->tif_flags &= ~TIFF_NOBITREV; +} + +int +TIFFSetCompressionScheme(TIFF* tif, int scheme) +{ + const TIFFCodec *c = TIFFFindCODEC((uint16) scheme); + + _TIFFSetDefaultCompressionState(tif); + /* + * Don't treat an unknown compression scheme as an error. + * This permits applications to open files with data that + * the library does not have builtin support for, but which + * may still be meaningful. + */ + return (c ? (*c->init)(tif, scheme) : 1); +} + +/* + * Other compression schemes may be registered. Registered + * schemes can also override the builtin versions provided + * by this library. + */ +typedef struct _codec { + struct _codec* next; + TIFFCodec* info; +} codec_t; +static codec_t* registeredCODECS = NULL; + +const TIFFCodec* +TIFFFindCODEC(uint16 scheme) +{ + const TIFFCodec* c; + codec_t* cd; + + for (cd = registeredCODECS; cd; cd = cd->next) + if (cd->info->scheme == scheme) + return ((const TIFFCodec*) cd->info); + for (c = _TIFFBuiltinCODECS; c->name; c++) + if (c->scheme == scheme) + return (c); + return ((const TIFFCodec*) 0); +} + +TIFFCodec* +TIFFRegisterCODEC(uint16 scheme, const char* name, TIFFInitMethod init) +{ + codec_t* cd = (codec_t*) + _TIFFmalloc(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1); + + if (cd != NULL) { + cd->info = (TIFFCodec*) ((tidata_t) cd + sizeof (codec_t)); + cd->info->name = (char*) + ((tidata_t) cd->info + sizeof (TIFFCodec)); + strcpy(cd->info->name, name); + cd->info->scheme = scheme; + cd->info->init = init; + cd->next = registeredCODECS; + registeredCODECS = cd; + } else + TIFFError("TIFFRegisterCODEC", + "No space to register compression scheme %s", name); + return (cd->info); +} + +void +TIFFUnRegisterCODEC(TIFFCodec* c) +{ + codec_t* cd; + codec_t** pcd; + + for (pcd = ®isteredCODECS; (cd = *pcd); pcd = &cd->next) + if (cd->info == c) { + *pcd = cd->next; + _TIFFfree(cd); + return; + } + TIFFError("TIFFUnRegisterCODEC", + "Cannot remove compression scheme %s; not registered", c->name); +} diff --git a/freeimage241/Source/LibTIFF/tif_dir.c b/freeimage241/Source/LibTIFF/tif_dir.c new file mode 100644 index 0000000..affacdf --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_dir.c @@ -0,0 +1,1303 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_dir.c,v 1.0 2001-04-13 00:42:29+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Tag Get & Set Routines. + * (and also some miscellaneous stuff) + */ +#include "tiffiop.h" + +/* + * These are used in the backwards compatibility code... + */ +#define DATATYPE_VOID 0 /* !untyped data */ +#define DATATYPE_INT 1 /* !signed integer data */ +#define DATATYPE_UINT 2 /* !unsigned integer data */ +#define DATATYPE_IEEEFP 3 /* !IEEE floating point data */ + +void +_TIFFsetByteArray(void** vpp, void* vp, long n) +{ + if (*vpp) + _TIFFfree(*vpp), *vpp = 0; + if (vp && (*vpp = (void*) _TIFFmalloc(n))) + _TIFFmemcpy(*vpp, vp, n); +} +void _TIFFsetString(char** cpp, char* cp) + { _TIFFsetByteArray((void**) cpp, (void*) cp, (long) (strlen(cp)+1)); } +void _TIFFsetNString(char** cpp, char* cp, long n) + { _TIFFsetByteArray((void**) cpp, (void*) cp, n); } +void _TIFFsetShortArray(uint16** wpp, uint16* wp, long n) + { _TIFFsetByteArray((void**) wpp, (void*) wp, n*sizeof (uint16)); } +void _TIFFsetLongArray(uint32** lpp, uint32* lp, long n) + { _TIFFsetByteArray((void**) lpp, (void*) lp, n*sizeof (uint32)); } +void _TIFFsetFloatArray(float** fpp, float* fp, long n) + { _TIFFsetByteArray((void**) fpp, (void*) fp, n*sizeof (float)); } +void _TIFFsetDoubleArray(double** dpp, double* dp, long n) + { _TIFFsetByteArray((void**) dpp, (void*) dp, n*sizeof (double)); } + +/* + * Install extra samples information. + */ +static int +setExtraSamples(TIFFDirectory* td, va_list ap, int* v) +{ + uint16* va; + int i; + + *v = va_arg(ap, int); + if ((uint16) *v > td->td_samplesperpixel) + return (0); + va = va_arg(ap, uint16*); + if (*v > 0 && va == NULL) /* typically missing param */ + return (0); + for (i = 0; i < *v; i++) + if (va[i] > EXTRASAMPLE_UNASSALPHA) + return (0); + td->td_extrasamples = (uint16) *v; + _TIFFsetShortArray(&td->td_sampleinfo, va, td->td_extrasamples); + return (1); +} + +#ifdef CMYK_SUPPORT +static int +checkInkNamesString(TIFF* tif, int slen, const char* s) +{ + TIFFDirectory* td = &tif->tif_dir; + int i = td->td_samplesperpixel; + + if (slen > 0) { + const char* ep = s+slen; + const char* cp = s; + for (; i > 0; i--) { + for (; *cp != '\0'; cp++) + if (cp >= ep) + goto bad; + cp++; /* skip \0 */ + } + return (cp-s); + } +bad: + TIFFError("TIFFSetField", + "%s: Invalid InkNames value; expecting %d names, found %d", + tif->tif_name, + td->td_samplesperpixel, + td->td_samplesperpixel-i); + return (0); +} +#endif + +static int +_TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFDirectory* td = &tif->tif_dir; + int status = 1; + uint32 v32; + int i, v; + double d; + char* s; + + switch (tag) { + case TIFFTAG_SUBFILETYPE: + td->td_subfiletype = va_arg(ap, uint32); + break; + case TIFFTAG_IMAGEWIDTH: + td->td_imagewidth = va_arg(ap, uint32); + break; + case TIFFTAG_IMAGELENGTH: + td->td_imagelength = va_arg(ap, uint32); + break; + case TIFFTAG_BITSPERSAMPLE: + td->td_bitspersample = (uint16) va_arg(ap, int); + /* + * If the data require post-decoding processing + * to byte-swap samples, set it up here. Note + * that since tags are required to be ordered, + * compression code can override this behaviour + * in the setup method if it wants to roll the + * post decoding work in with its normal work. + */ + if (tif->tif_flags & TIFF_SWAB) { + if (td->td_bitspersample == 16) + tif->tif_postdecode = _TIFFSwab16BitData; + else if (td->td_bitspersample == 32) + tif->tif_postdecode = _TIFFSwab32BitData; + else if (td->td_bitspersample == 64) + tif->tif_postdecode = _TIFFSwab64BitData; + } + break; + case TIFFTAG_COMPRESSION: + v = va_arg(ap, int) & 0xffff; + /* + * If we're changing the compression scheme, + * the notify the previous module so that it + * can cleanup any state it's setup. + */ + if (TIFFFieldSet(tif, FIELD_COMPRESSION)) { + if (td->td_compression == v) + break; + (*tif->tif_cleanup)(tif); + tif->tif_flags &= ~TIFF_CODERSETUP; + } + /* + * Setup new compression routine state. + */ + if ( ! tif->tif_mode == O_RDONLY ) { + /* Handle removal of LZW compression */ + if ( v == COMPRESSION_LZW ) { + TIFFError(tif->tif_name, + "LZW compression no longer supported due to Unisys patent enforcement"); + v=COMPRESSION_NONE; + } + } + if( (status = TIFFSetCompressionScheme(tif, v)) != 0 ) + td->td_compression = v; + break; + case TIFFTAG_PHOTOMETRIC: + td->td_photometric = (uint16) va_arg(ap, int); + break; + case TIFFTAG_THRESHHOLDING: + td->td_threshholding = (uint16) va_arg(ap, int); + break; + case TIFFTAG_FILLORDER: + v = va_arg(ap, int); + if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB) + goto badvalue; + td->td_fillorder = (uint16) v; + break; + case TIFFTAG_DOCUMENTNAME: + _TIFFsetString(&td->td_documentname, va_arg(ap, char*)); + break; + case TIFFTAG_ARTIST: + _TIFFsetString(&td->td_artist, va_arg(ap, char*)); + break; + case TIFFTAG_DATETIME: + _TIFFsetString(&td->td_datetime, va_arg(ap, char*)); + break; + case TIFFTAG_HOSTCOMPUTER: + _TIFFsetString(&td->td_hostcomputer, va_arg(ap, char*)); + break; + case TIFFTAG_IMAGEDESCRIPTION: + _TIFFsetString(&td->td_imagedescription, va_arg(ap, char*)); + break; + case TIFFTAG_MAKE: + _TIFFsetString(&td->td_make, va_arg(ap, char*)); + break; + case TIFFTAG_MODEL: + _TIFFsetString(&td->td_model, va_arg(ap, char*)); + break; + case TIFFTAG_SOFTWARE: + _TIFFsetString(&td->td_software, va_arg(ap, char*)); + break; + case TIFFTAG_ORIENTATION: + v = va_arg(ap, int); + if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v) { + TIFFWarning(tif->tif_name, + "Bad value %ld for \"%s\" tag ignored", + v, _TIFFFieldWithTag(tif, tag)->field_name); + } else + td->td_orientation = (uint16) v; + break; + case TIFFTAG_SAMPLESPERPIXEL: + /* XXX should cross check -- e.g. if pallette, then 1 */ + v = va_arg(ap, int); + if (v == 0) + goto badvalue; + td->td_samplesperpixel = (uint16) v; + break; + case TIFFTAG_ROWSPERSTRIP: + v32 = va_arg(ap, uint32); + if (v32 == 0) + goto badvalue32; + td->td_rowsperstrip = v32; + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + td->td_tilelength = v32; + td->td_tilewidth = td->td_imagewidth; + } + break; + case TIFFTAG_MINSAMPLEVALUE: + td->td_minsamplevalue = (uint16) va_arg(ap, int); + break; + case TIFFTAG_MAXSAMPLEVALUE: + td->td_maxsamplevalue = (uint16) va_arg(ap, int); + break; + case TIFFTAG_SMINSAMPLEVALUE: + td->td_sminsamplevalue = (double) va_arg(ap, dblparam_t); + break; + case TIFFTAG_SMAXSAMPLEVALUE: + td->td_smaxsamplevalue = (double) va_arg(ap, dblparam_t); + break; + case TIFFTAG_XRESOLUTION: + td->td_xresolution = (float) va_arg(ap, dblparam_t); + break; + case TIFFTAG_YRESOLUTION: + td->td_yresolution = (float) va_arg(ap, dblparam_t); + break; + case TIFFTAG_PLANARCONFIG: + v = va_arg(ap, int); + if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE) + goto badvalue; + td->td_planarconfig = (uint16) v; + break; + case TIFFTAG_PAGENAME: + _TIFFsetString(&td->td_pagename, va_arg(ap, char*)); + break; + case TIFFTAG_XPOSITION: + td->td_xposition = (float) va_arg(ap, dblparam_t); + break; + case TIFFTAG_YPOSITION: + td->td_yposition = (float) va_arg(ap, dblparam_t); + break; + case TIFFTAG_RESOLUTIONUNIT: + v = va_arg(ap, int); + if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v) + goto badvalue; + td->td_resolutionunit = (uint16) v; + break; + case TIFFTAG_PAGENUMBER: + td->td_pagenumber[0] = (uint16) va_arg(ap, int); + td->td_pagenumber[1] = (uint16) va_arg(ap, int); + break; + case TIFFTAG_HALFTONEHINTS: + td->td_halftonehints[0] = (uint16) va_arg(ap, int); + td->td_halftonehints[1] = (uint16) va_arg(ap, int); + break; + case TIFFTAG_COLORMAP: + v32 = (uint32)(1L<td_bitspersample); + _TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16*), v32); + _TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16*), v32); + _TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16*), v32); + break; + case TIFFTAG_EXTRASAMPLES: + if (!setExtraSamples(td, ap, &v)) + goto badvalue; + break; + case TIFFTAG_MATTEING: + td->td_extrasamples = (uint16) (va_arg(ap, int) != 0); + if (td->td_extrasamples) { + uint16 sv = EXTRASAMPLE_ASSOCALPHA; + _TIFFsetShortArray(&td->td_sampleinfo, &sv, 1); + } + break; + case TIFFTAG_TILEWIDTH: + v32 = va_arg(ap, uint32); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarning(tif->tif_name, + "Nonstandard tile width %d, convert file", v32); + } + td->td_tilewidth = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILELENGTH: + v32 = va_arg(ap, uint32); + if (v32 % 16) { + if (tif->tif_mode != O_RDONLY) + goto badvalue32; + TIFFWarning(tif->tif_name, + "Nonstandard tile length %d, convert file", v32); + } + td->td_tilelength = v32; + tif->tif_flags |= TIFF_ISTILED; + break; + case TIFFTAG_TILEDEPTH: + v32 = va_arg(ap, uint32); + if (v32 == 0) + goto badvalue32; + td->td_tiledepth = v32; + break; + case TIFFTAG_DATATYPE: + v = va_arg(ap, int); + switch (v) { + case DATATYPE_VOID: v = SAMPLEFORMAT_VOID; break; + case DATATYPE_INT: v = SAMPLEFORMAT_INT; break; + case DATATYPE_UINT: v = SAMPLEFORMAT_UINT; break; + case DATATYPE_IEEEFP: v = SAMPLEFORMAT_IEEEFP;break; + default: goto badvalue; + } + td->td_sampleformat = (uint16) v; + break; + case TIFFTAG_SAMPLEFORMAT: + v = va_arg(ap, int); + if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v) + goto badvalue; + td->td_sampleformat = (uint16) v; + break; + case TIFFTAG_IMAGEDEPTH: + td->td_imagedepth = va_arg(ap, uint32); + break; + case TIFFTAG_STONITS: + d = va_arg(ap, dblparam_t); + if (d <= 0.) + goto badvaluedbl; + td->td_stonits = d; + break; + + /* Begin Pixar Tags */ + case TIFFTAG_PIXAR_IMAGEFULLWIDTH: + td->td_imagefullwidth = va_arg(ap, uint32); + break; + case TIFFTAG_PIXAR_IMAGEFULLLENGTH: + td->td_imagefulllength = va_arg(ap, uint32); + break; + case TIFFTAG_PIXAR_TEXTUREFORMAT: + _TIFFsetString(&td->td_textureformat, va_arg(ap, char*)); + break; + case TIFFTAG_PIXAR_WRAPMODES: + _TIFFsetString(&td->td_wrapmodes, va_arg(ap, char*)); + break; + case TIFFTAG_PIXAR_FOVCOT: + td->td_fovcot = (float) va_arg(ap, dblparam_t); + break; + case TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN: + _TIFFsetFloatArray(&td->td_matrixWorldToScreen, + va_arg(ap, float*), 16); + break; + case TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA: + _TIFFsetFloatArray(&td->td_matrixWorldToCamera, + va_arg(ap, float*), 16); + break; + /* End Pixar Tags */ + +#if SUBIFD_SUPPORT + case TIFFTAG_SUBIFD: + if ((tif->tif_flags & TIFF_INSUBIFD) == 0) { + td->td_nsubifd = (uint16) va_arg(ap, int); + _TIFFsetLongArray(&td->td_subifd, va_arg(ap, uint32*), + (long) td->td_nsubifd); + } else { + TIFFError(tif->tif_name, "Sorry, cannot nest SubIFDs"); + status = 0; + } + break; +#endif +#ifdef YCBCR_SUPPORT + case TIFFTAG_YCBCRCOEFFICIENTS: + _TIFFsetFloatArray(&td->td_ycbcrcoeffs, va_arg(ap, float*), 3); + break; + case TIFFTAG_YCBCRPOSITIONING: + td->td_ycbcrpositioning = (uint16) va_arg(ap, int); + break; + case TIFFTAG_YCBCRSUBSAMPLING: + td->td_ycbcrsubsampling[0] = (uint16) va_arg(ap, int); + td->td_ycbcrsubsampling[1] = (uint16) va_arg(ap, int); + break; +#endif +#ifdef COLORIMETRY_SUPPORT + case TIFFTAG_WHITEPOINT: + _TIFFsetFloatArray(&td->td_whitepoint, va_arg(ap, float*), 2); + break; + case TIFFTAG_PRIMARYCHROMATICITIES: + _TIFFsetFloatArray(&td->td_primarychromas, va_arg(ap, float*), 6); + break; + case TIFFTAG_TRANSFERFUNCTION: + v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1; + for (i = 0; i < v; i++) + _TIFFsetShortArray(&td->td_transferfunction[i], + va_arg(ap, uint16*), 1L<td_bitspersample); + break; + case TIFFTAG_REFERENCEBLACKWHITE: + /* XXX should check for null range */ + _TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6); + break; +#endif +#ifdef CMYK_SUPPORT + case TIFFTAG_INKSET: + td->td_inkset = (uint16) va_arg(ap, int); + break; + case TIFFTAG_DOTRANGE: + /* XXX should check for null range */ + td->td_dotrange[0] = (uint16) va_arg(ap, int); + td->td_dotrange[1] = (uint16) va_arg(ap, int); + break; + case TIFFTAG_INKNAMES: + i = va_arg(ap, int); + s = va_arg(ap, char*); + i = checkInkNamesString(tif, i, s); + status = i > 0; + if( i > 0 ) { + _TIFFsetNString(&td->td_inknames, s, i); + td->td_inknameslen = i; + } + break; + case TIFFTAG_NUMBEROFINKS: + td->td_ninks = (uint16) va_arg(ap, int); + break; + case TIFFTAG_TARGETPRINTER: + _TIFFsetString(&td->td_targetprinter, va_arg(ap, char*)); + break; +#endif +#ifdef ICC_SUPPORT + case TIFFTAG_ICCPROFILE: + td->td_profileLength = (uint32) va_arg(ap, uint32); + _TIFFsetByteArray(&td->td_profileData, va_arg(ap, void*), + td->td_profileLength); + break; +#endif +#ifdef PHOTOSHOP_SUPPORT + case TIFFTAG_PHOTOSHOP: + td->td_photoshopLength = (uint32) va_arg(ap, uint32); + _TIFFsetByteArray (&td->td_photoshopData, va_arg(ap, void*), + td->td_photoshopLength); + break; +#endif +#ifdef IPTC_SUPPORT + case TIFFTAG_RICHTIFFIPTC: + td->td_richtiffiptcLength = (uint32) va_arg(ap, uint32); +#ifdef PHOTOSHOP_SUPPORT + _TIFFsetLongArray ((uint32**)&td->td_richtiffiptcData, va_arg(ap, uint32*), + td->td_richtiffiptcLength); +#else + _TIFFsetByteArray (&td->td_photoshopData, va_arg(ap, void*), + td->td_photoshopLength); +#endif + break; +#endif + default: + /* + * This can happen if multiple images are open with + * different codecs which have private tags. The + * global tag information table may then have tags + * that are valid for one file but not the other. + * If the client tries to set a tag that is not valid + * for the image's codec then we'll arrive here. This + * happens, for example, when tiffcp is used to convert + * between compression schemes and codec-specific tags + * are blindly copied. + */ + TIFFError("TIFFSetField", + "%s: Invalid %stag \"%s\" (not supported by codec)", + tif->tif_name, isPseudoTag(tag) ? "pseduo-" : "", + _TIFFFieldWithTag(tif, tag)->field_name); + status = 0; + break; + } + if (status) { + TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit); + tif->tif_flags |= TIFF_DIRTYDIRECT; + } + va_end(ap); + return (status); +badvalue: + TIFFError(tif->tif_name, "%d: Bad value for \"%s\"", v, + _TIFFFieldWithTag(tif, tag)->field_name); + va_end(ap); + return (0); +badvalue32: + TIFFError(tif->tif_name, "%ld: Bad value for \"%s\"", v32, + _TIFFFieldWithTag(tif, tag)->field_name); + va_end(ap); + return (0); +badvaluedbl: + TIFFError(tif->tif_name, "%f: Bad value for \"%s\"", d, + _TIFFFieldWithTag(tif, tag)->field_name); + va_end(ap); + return (0); +} + +/* + * Return 1/0 according to whether or not + * it is permissible to set the tag's value. + * Note that we allow ImageLength to be changed + * so that we can append and extend to images. + * Any other tag may not be altered once writing + * has commenced, unless its value has no effect + * on the format of the data that is written. + */ +static int +OkToChangeTag(TIFF* tif, ttag_t tag) +{ + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + if (!fip) { /* unknown tag */ + TIFFError("TIFFSetField", "%s: Unknown %stag %u", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", tag); + return (0); + } + if (tag != TIFFTAG_IMAGELENGTH && (tif->tif_flags & TIFF_BEENWRITING) && + !fip->field_oktochange) { + /* + * Consult info table to see if tag can be changed + * after we've started writing. We only allow changes + * to those tags that don't/shouldn't affect the + * compression and/or format of the data. + */ + TIFFError("TIFFSetField", + "%s: Cannot modify tag \"%s\" while writing", + tif->tif_name, fip->field_name); + return (0); + } + return (1); +} + +/* + * Record the value of a field in the + * internal directory structure. The + * field will be written to the file + * when/if the directory structure is + * updated. + */ +int +TIFFSetField(TIFF* tif, ttag_t tag, ...) +{ + va_list ap; + int status; + + va_start(ap, tag); + status = TIFFVSetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Like TIFFSetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + return OkToChangeTag(tif, tag) ? + (*tif->tif_vsetfield)(tif, tag, ap) : 0; +} + +static int +_TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFDirectory* td = &tif->tif_dir; + + switch (tag) { + case TIFFTAG_SUBFILETYPE: + *va_arg(ap, uint32*) = td->td_subfiletype; + break; + case TIFFTAG_IMAGEWIDTH: + *va_arg(ap, uint32*) = td->td_imagewidth; + break; + case TIFFTAG_IMAGELENGTH: + *va_arg(ap, uint32*) = td->td_imagelength; + break; + case TIFFTAG_BITSPERSAMPLE: + *va_arg(ap, uint16*) = td->td_bitspersample; + break; + case TIFFTAG_COMPRESSION: + *va_arg(ap, uint16*) = td->td_compression; + break; + case TIFFTAG_PHOTOMETRIC: + *va_arg(ap, uint16*) = td->td_photometric; + break; + case TIFFTAG_THRESHHOLDING: + *va_arg(ap, uint16*) = td->td_threshholding; + break; + case TIFFTAG_FILLORDER: + *va_arg(ap, uint16*) = td->td_fillorder; + break; + case TIFFTAG_DOCUMENTNAME: + *va_arg(ap, char**) = td->td_documentname; + break; + case TIFFTAG_ARTIST: + *va_arg(ap, char**) = td->td_artist; + break; + case TIFFTAG_DATETIME: + *va_arg(ap, char**) = td->td_datetime; + break; + case TIFFTAG_HOSTCOMPUTER: + *va_arg(ap, char**) = td->td_hostcomputer; + break; + case TIFFTAG_IMAGEDESCRIPTION: + *va_arg(ap, char**) = td->td_imagedescription; + break; + case TIFFTAG_MAKE: + *va_arg(ap, char**) = td->td_make; + break; + case TIFFTAG_MODEL: + *va_arg(ap, char**) = td->td_model; + break; + case TIFFTAG_SOFTWARE: + *va_arg(ap, char**) = td->td_software; + break; + case TIFFTAG_ORIENTATION: + *va_arg(ap, uint16*) = td->td_orientation; + break; + case TIFFTAG_SAMPLESPERPIXEL: + *va_arg(ap, uint16*) = td->td_samplesperpixel; + break; + case TIFFTAG_ROWSPERSTRIP: + *va_arg(ap, uint32*) = td->td_rowsperstrip; + break; + case TIFFTAG_MINSAMPLEVALUE: + *va_arg(ap, uint16*) = td->td_minsamplevalue; + break; + case TIFFTAG_MAXSAMPLEVALUE: + *va_arg(ap, uint16*) = td->td_maxsamplevalue; + break; + case TIFFTAG_SMINSAMPLEVALUE: + *va_arg(ap, double*) = td->td_sminsamplevalue; + break; + case TIFFTAG_SMAXSAMPLEVALUE: + *va_arg(ap, double*) = td->td_smaxsamplevalue; + break; + case TIFFTAG_XRESOLUTION: + *va_arg(ap, float*) = td->td_xresolution; + break; + case TIFFTAG_YRESOLUTION: + *va_arg(ap, float*) = td->td_yresolution; + break; + case TIFFTAG_PLANARCONFIG: + *va_arg(ap, uint16*) = td->td_planarconfig; + break; + case TIFFTAG_XPOSITION: + *va_arg(ap, float*) = td->td_xposition; + break; + case TIFFTAG_YPOSITION: + *va_arg(ap, float*) = td->td_yposition; + break; + case TIFFTAG_PAGENAME: + *va_arg(ap, char**) = td->td_pagename; + break; + case TIFFTAG_RESOLUTIONUNIT: + *va_arg(ap, uint16*) = td->td_resolutionunit; + break; + case TIFFTAG_PAGENUMBER: + *va_arg(ap, uint16*) = td->td_pagenumber[0]; + *va_arg(ap, uint16*) = td->td_pagenumber[1]; + break; + case TIFFTAG_HALFTONEHINTS: + *va_arg(ap, uint16*) = td->td_halftonehints[0]; + *va_arg(ap, uint16*) = td->td_halftonehints[1]; + break; + case TIFFTAG_COLORMAP: + *va_arg(ap, uint16**) = td->td_colormap[0]; + *va_arg(ap, uint16**) = td->td_colormap[1]; + *va_arg(ap, uint16**) = td->td_colormap[2]; + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + *va_arg(ap, uint32**) = td->td_stripoffset; + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + *va_arg(ap, uint32**) = td->td_stripbytecount; + break; + case TIFFTAG_MATTEING: + *va_arg(ap, uint16*) = + (td->td_extrasamples == 1 && + td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA); + break; + case TIFFTAG_EXTRASAMPLES: + *va_arg(ap, uint16*) = td->td_extrasamples; + *va_arg(ap, uint16**) = td->td_sampleinfo; + break; + case TIFFTAG_TILEWIDTH: + *va_arg(ap, uint32*) = td->td_tilewidth; + break; + case TIFFTAG_TILELENGTH: + *va_arg(ap, uint32*) = td->td_tilelength; + break; + case TIFFTAG_TILEDEPTH: + *va_arg(ap, uint32*) = td->td_tiledepth; + break; + case TIFFTAG_DATATYPE: + switch (td->td_sampleformat) { + case SAMPLEFORMAT_UINT: + *va_arg(ap, uint16*) = DATATYPE_UINT; + break; + case SAMPLEFORMAT_INT: + *va_arg(ap, uint16*) = DATATYPE_INT; + break; + case SAMPLEFORMAT_IEEEFP: + *va_arg(ap, uint16*) = DATATYPE_IEEEFP; + break; + case SAMPLEFORMAT_VOID: + *va_arg(ap, uint16*) = DATATYPE_VOID; + break; + } + break; + case TIFFTAG_SAMPLEFORMAT: + *va_arg(ap, uint16*) = td->td_sampleformat; + break; + case TIFFTAG_IMAGEDEPTH: + *va_arg(ap, uint32*) = td->td_imagedepth; + break; + case TIFFTAG_STONITS: + *va_arg(ap, double*) = td->td_stonits; + break; +#if SUBIFD_SUPPORT + case TIFFTAG_SUBIFD: + *va_arg(ap, uint16*) = td->td_nsubifd; + *va_arg(ap, uint32**) = td->td_subifd; + break; +#endif +#ifdef YCBCR_SUPPORT + case TIFFTAG_YCBCRCOEFFICIENTS: + *va_arg(ap, float**) = td->td_ycbcrcoeffs; + break; + case TIFFTAG_YCBCRPOSITIONING: + *va_arg(ap, uint16*) = td->td_ycbcrpositioning; + break; + case TIFFTAG_YCBCRSUBSAMPLING: + *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0]; + *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1]; + break; +#endif +#ifdef COLORIMETRY_SUPPORT + case TIFFTAG_WHITEPOINT: + *va_arg(ap, float**) = td->td_whitepoint; + break; + case TIFFTAG_PRIMARYCHROMATICITIES: + *va_arg(ap, float**) = td->td_primarychromas; + break; + case TIFFTAG_TRANSFERFUNCTION: + *va_arg(ap, uint16**) = td->td_transferfunction[0]; + if (td->td_samplesperpixel - td->td_extrasamples > 1) { + *va_arg(ap, uint16**) = td->td_transferfunction[1]; + *va_arg(ap, uint16**) = td->td_transferfunction[2]; + } + break; + case TIFFTAG_REFERENCEBLACKWHITE: + *va_arg(ap, float**) = td->td_refblackwhite; + break; +#endif +#ifdef CMYK_SUPPORT + case TIFFTAG_INKSET: + *va_arg(ap, uint16*) = td->td_inkset; + break; + case TIFFTAG_DOTRANGE: + *va_arg(ap, uint16*) = td->td_dotrange[0]; + *va_arg(ap, uint16*) = td->td_dotrange[1]; + break; + case TIFFTAG_INKNAMES: + *va_arg(ap, char**) = td->td_inknames; + break; + case TIFFTAG_NUMBEROFINKS: + *va_arg(ap, uint16*) = td->td_ninks; + break; + case TIFFTAG_TARGETPRINTER: + *va_arg(ap, char**) = td->td_targetprinter; + break; +#endif +#ifdef ICC_SUPPORT + case TIFFTAG_ICCPROFILE: + *va_arg(ap, uint32*) = td->td_profileLength; + *va_arg(ap, void**) = td->td_profileData; + break; +#endif +#ifdef PHOTOSHOP_SUPPORT + case TIFFTAG_PHOTOSHOP: + *va_arg(ap, uint32*) = td->td_photoshopLength; + *va_arg(ap, void**) = td->td_photoshopData; + break; +#endif +#ifdef IPTC_SUPPORT + case TIFFTAG_RICHTIFFIPTC: + *va_arg(ap, uint32*) = td->td_richtiffiptcLength; + *va_arg(ap, void**) = td->td_richtiffiptcData; + break; +#endif + /* Begin Pixar Tags */ + case TIFFTAG_PIXAR_IMAGEFULLWIDTH: + *va_arg(ap, uint32*) = td->td_imagefullwidth; + break; + case TIFFTAG_PIXAR_IMAGEFULLLENGTH: + *va_arg(ap, uint32*) = td->td_imagefulllength; + break; + case TIFFTAG_PIXAR_TEXTUREFORMAT: + *va_arg(ap, char**) = td->td_textureformat; + break; + case TIFFTAG_PIXAR_WRAPMODES: + *va_arg(ap, char**) = td->td_wrapmodes; + break; + case TIFFTAG_PIXAR_FOVCOT: + *va_arg(ap, float*) = td->td_fovcot; + break; + case TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN: + *va_arg(ap, float**) = td->td_matrixWorldToScreen; + break; + case TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA: + *va_arg(ap, float**) = td->td_matrixWorldToCamera; + break; + /* End Pixar Tags */ + + default: + /* + * This can happen if multiple images are open with + * different codecs which have private tags. The + * global tag information table may then have tags + * that are valid for one file but not the other. + * If the client tries to get a tag that is not valid + * for the image's codec then we'll arrive here. + */ + TIFFError("TIFFGetField", + "%s: Invalid %stag \"%s\" (not supported by codec)", + tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", + _TIFFFieldWithTag(tif, tag)->field_name); + break; + } + return (1); +} + +/* + * Return the value of a field in the + * internal directory structure. + */ +int +TIFFGetField(TIFF* tif, ttag_t tag, ...) +{ + int status; + va_list ap; + + va_start(ap, tag); + status = TIFFVGetField(tif, tag, ap); + va_end(ap); + return (status); +} + +/* + * Like TIFFGetField, but taking a varargs + * parameter list. This routine is useful + * for building higher-level interfaces on + * top of the library. + */ +int +TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ? + (*tif->tif_vgetfield)(tif, tag, ap) : 0); +} + +#define CleanupField(member) { \ + if (td->member) { \ + _TIFFfree(td->member); \ + td->member = 0; \ + } \ +} + +/* + * Release storage associated with a directory. + */ +void +TIFFFreeDirectory(TIFF* tif) +{ + register TIFFDirectory *td = &tif->tif_dir; + + CleanupField(td_colormap[0]); + CleanupField(td_colormap[1]); + CleanupField(td_colormap[2]); + CleanupField(td_documentname); + CleanupField(td_artist); + CleanupField(td_datetime); + CleanupField(td_hostcomputer); + CleanupField(td_imagedescription); + CleanupField(td_make); + CleanupField(td_model); + CleanupField(td_software); + CleanupField(td_pagename); + CleanupField(td_sampleinfo); +#if SUBIFD_SUPPORT + CleanupField(td_subifd); +#endif +#ifdef YCBCR_SUPPORT + CleanupField(td_ycbcrcoeffs); +#endif +#ifdef CMYK_SUPPORT + CleanupField(td_inknames); + CleanupField(td_targetprinter); +#endif +#ifdef COLORIMETRY_SUPPORT + CleanupField(td_whitepoint); + CleanupField(td_primarychromas); + CleanupField(td_refblackwhite); + CleanupField(td_transferfunction[0]); + CleanupField(td_transferfunction[1]); + CleanupField(td_transferfunction[2]); +#endif +#ifdef ICC_SUPPORT + CleanupField(td_profileData); +#endif +#ifdef PHOTOSHOP_SUPPORT + CleanupField(td_photoshopData); +#endif +#ifdef IPTC_SUPPORT + CleanupField(td_richtiffiptcData); +#endif + CleanupField(td_stripoffset); + CleanupField(td_stripbytecount); + /* Begin Pixar Tags */ + CleanupField(td_textureformat); + CleanupField(td_wrapmodes); + CleanupField(td_matrixWorldToScreen); + CleanupField(td_matrixWorldToCamera); + /* End Pixar Tags */ +} +#undef CleanupField + +/* + * Client Tag extension support (from Niles Ritter). + */ +static TIFFExtendProc _TIFFextender = (TIFFExtendProc) NULL; + +TIFFExtendProc +TIFFSetTagExtender(TIFFExtendProc extender) +{ + TIFFExtendProc prev = _TIFFextender; + _TIFFextender = extender; + return (prev); +} + +/* + * Setup for a new directory. Should we automatically call + * TIFFWriteDirectory() if the current one is dirty? + * + * The newly created directory will not exist on the file till + * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called. + */ +int +TIFFCreateDirectory(TIFF* tif) +{ + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; + tif->tif_nextdiroff = 0; + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (tstrip_t) -1; + + return 0; +} + +/* + * Setup a default directory structure. + */ +int +TIFFDefaultDirectory(TIFF* tif) +{ + register TIFFDirectory* td = &tif->tif_dir; + + _TIFFSetupFieldInfo(tif); + _TIFFmemset(td, 0, sizeof (*td)); + td->td_fillorder = FILLORDER_MSB2LSB; + td->td_bitspersample = 1; + td->td_threshholding = THRESHHOLD_BILEVEL; + td->td_orientation = ORIENTATION_TOPLEFT; + td->td_samplesperpixel = 1; + td->td_rowsperstrip = (uint32) -1; + td->td_tilewidth = (uint32) -1; + td->td_tilelength = (uint32) -1; + td->td_tiledepth = 1; + td->td_resolutionunit = RESUNIT_INCH; + td->td_sampleformat = SAMPLEFORMAT_UINT; + td->td_imagedepth = 1; +#ifdef YCBCR_SUPPORT + td->td_ycbcrsubsampling[0] = 2; + td->td_ycbcrsubsampling[1] = 2; + td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED; +#endif +#ifdef CMYK_SUPPORT + td->td_inkset = INKSET_CMYK; + td->td_ninks = 4; +#endif + tif->tif_postdecode = _TIFFNoPostDecode; + tif->tif_vsetfield = _TIFFVSetField; + tif->tif_vgetfield = _TIFFVGetField; + tif->tif_printdir = NULL; + /* + * Give client code a chance to install their own + * tag extensions & methods, prior to compression overloads. + */ + if (_TIFFextender) + (*_TIFFextender)(tif); + (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + /* + * NB: The directory is marked dirty as a result of setting + * up the default compression scheme. However, this really + * isn't correct -- we want TIFF_DIRTYDIRECT to be set only + * if the user does something. We could just do the setup + * by hand, but it seems better to use the normal mechanism + * (i.e. TIFFSetField). + */ + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + + /* + * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=19 + * we clear the ISTILED flag when setting up a new directory. + * Should we also be clearing stuff like INSUBIFD? + */ + tif->tif_flags &= ~TIFF_ISTILED; + + return (1); +} + +static int +TIFFAdvanceDirectory(TIFF* tif, uint32* nextdir, toff_t* off) +{ + static const char module[] = "TIFFAdvanceDirectory"; + uint16 dircount; + if (isMapped(tif)) + { + toff_t poff=*nextdir; + if (poff+sizeof(uint16) > tif->tif_size) + { + TIFFError(module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + _TIFFmemcpy(&dircount, tif->tif_base+poff, sizeof (uint16)); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + poff+=sizeof (uint16)+dircount*sizeof (TIFFDirEntry); + if (off != NULL) + *off = poff; + if (((toff_t) (poff+sizeof (uint32))) > tif->tif_size) + { + TIFFError(module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + _TIFFmemcpy(nextdir, tif->tif_base+poff, sizeof (uint32)); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(nextdir); + return (1); + } + else + { + if (!SeekOK(tif, *nextdir) || + !ReadOK(tif, &dircount, sizeof (uint16))) { + TIFFError(module, "%s: Error fetching directory count", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + if (off != NULL) + *off = TIFFSeekFile(tif, + dircount*sizeof (TIFFDirEntry), SEEK_CUR); + else + (void) TIFFSeekFile(tif, + dircount*sizeof (TIFFDirEntry), SEEK_CUR); + if (!ReadOK(tif, nextdir, sizeof (uint32))) { + TIFFError(module, "%s: Error fetching directory link", + tif->tif_name); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(nextdir); + return (1); + } +} + +/* + * Count the number of directories in a file. + */ +tdir_t +TIFFNumberOfDirectories(TIFF* tif) +{ + toff_t nextdir = tif->tif_header.tiff_diroff; + tdir_t n = 0; + + while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL)) + n++; + return (n); +} + +/* + * Set the n-th directory as the current directory. + * NB: Directories are numbered starting at 0. + */ +int +TIFFSetDirectory(TIFF* tif, tdir_t dirn) +{ + toff_t nextdir; + tdir_t n; + + nextdir = tif->tif_header.tiff_diroff; + for (n = dirn; n > 0 && nextdir != 0; n--) + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + tif->tif_nextdiroff = nextdir; + /* + * Set curdir to the actual directory index. The + * -1 is because TIFFReadDirectory will increment + * tif_curdir after successfully reading the directory. + */ + tif->tif_curdir = (dirn - n) - 1; + return (TIFFReadDirectory(tif)); +} + +/* + * Set the current directory to be the directory + * located at the specified file offset. This interface + * is used mainly to access directories linked with + * the SubIFD tag (e.g. thumbnail images). + */ +int +TIFFSetSubDirectory(TIFF* tif, uint32 diroff) +{ + tif->tif_nextdiroff = diroff; + return (TIFFReadDirectory(tif)); +} + +/* + * Return file offset of the current directory. + */ +uint32 +TIFFCurrentDirOffset(TIFF* tif) +{ + return (tif->tif_diroff); +} + +/* + * Return an indication of whether or not we are + * at the last directory in the file. + */ +int +TIFFLastDirectory(TIFF* tif) +{ + return (tif->tif_nextdiroff == 0); +} + +/* + * Unlink the specified directory from the directory chain. + */ +int +TIFFUnlinkDirectory(TIFF* tif, tdir_t dirn) +{ + static const char module[] = "TIFFUnlinkDirectory"; + toff_t nextdir; + toff_t off; + tdir_t n; + + if (tif->tif_mode == O_RDONLY) { + TIFFError(module, "Can not unlink directory in read-only file"); + return (0); + } + /* + * Go to the directory before the one we want + * to unlink and nab the offset of the link + * field we'll need to patch. + */ + nextdir = tif->tif_header.tiff_diroff; + off = sizeof (uint16) + sizeof (uint16); + for (n = dirn-1; n > 0; n--) { + if (nextdir == 0) { + TIFFError(module, "Directory %d does not exist", dirn); + return (0); + } + if (!TIFFAdvanceDirectory(tif, &nextdir, &off)) + return (0); + } + /* + * Advance to the directory to be unlinked and fetch + * the offset of the directory that follows. + */ + if (!TIFFAdvanceDirectory(tif, &nextdir, NULL)) + return (0); + /* + * Go back and patch the link field of the preceding + * directory to point to the offset of the directory + * that follows. + */ + (void) TIFFSeekFile(tif, off, SEEK_SET); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir); + if (!WriteOK(tif, &nextdir, sizeof (uint32))) { + TIFFError(module, "Error writing directory link"); + return (0); + } + /* + * Leave directory state setup safely. We don't have + * facilities for doing inserting and removing directories, + * so it's safest to just invalidate everything. This + * means that the caller can only append to the directory + * chain. + */ + (*tif->tif_cleanup)(tif); + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE); + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + tif->tif_diroff = 0; /* force link on next write */ + tif->tif_nextdiroff = 0; /* next write must be at end */ + tif->tif_curoff = 0; + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (tstrip_t) -1; + return (1); +} + +/* [BFC] + * + * Author: Bruce Cameron + * + * Set a table of tags that are to be replaced during directory process by the + * 'IGNORE' state - or return TRUE/FALSE for the requested tag such that + * 'ReadDirectory' can use the stored information. + */ +int +TIFFReassignTagToIgnore (enum TIFFIgnoreSense task, int TIFFtagID) +{ + static int TIFFignoretags [FIELD_LAST]; + static int tagcount = 0 ; + int i; /* Loop index */ + int j; /* Loop index */ + + switch (task) + { + case TIS_STORE: + if ( tagcount < (FIELD_LAST - 1) ) + { + for ( j = 0 ; j < tagcount ; ++j ) + { /* Do not add duplicate tag */ + if ( TIFFignoretags [j] == TIFFtagID ) + return (TRUE) ; + } + TIFFignoretags [tagcount++] = TIFFtagID ; + return (TRUE) ; + } + break ; + + case TIS_EXTRACT: + for ( i = 0 ; i < tagcount ; ++i ) + { + if ( TIFFignoretags [i] == TIFFtagID ) + return (TRUE) ; + } + break; + + case TIS_EMPTY: + tagcount = 0 ; /* Clear the list */ + return (TRUE) ; + + default: + break; + } + + return (FALSE); +} diff --git a/freeimage241/Source/LibTIFF/tif_dir.h b/freeimage241/Source/LibTIFF/tif_dir.h new file mode 100644 index 0000000..e0d08fe --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_dir.h @@ -0,0 +1,268 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_dir.h,v 1.0 2001-04-13 00:42:30+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFDIR_ +#define _TIFFDIR_ +/* + * ``Library-private'' Directory-related Definitions. + */ + +/* + * Internal format of a TIFF directory entry. + */ +typedef struct { +#define FIELD_SETLONGS 3 + /* bit vector of fields that are set */ + u_long td_fieldsset[FIELD_SETLONGS]; + + uint32 td_imagewidth, td_imagelength, td_imagedepth; + uint32 td_tilewidth, td_tilelength, td_tiledepth; + uint32 td_subfiletype; + uint16 td_bitspersample; + uint16 td_sampleformat; + uint16 td_compression; + uint16 td_photometric; + uint16 td_threshholding; + uint16 td_fillorder; + uint16 td_orientation; + uint16 td_samplesperpixel; + uint32 td_rowsperstrip; + uint16 td_minsamplevalue, td_maxsamplevalue; + double td_sminsamplevalue, td_smaxsamplevalue; + float td_xresolution, td_yresolution; + uint16 td_resolutionunit; + uint16 td_planarconfig; + float td_xposition, td_yposition; + uint16 td_pagenumber[2]; + uint16* td_colormap[3]; + uint16 td_halftonehints[2]; + uint16 td_extrasamples; + uint16* td_sampleinfo; + double td_stonits; + char* td_documentname; + char* td_artist; + char* td_datetime; + char* td_hostcomputer; + char* td_imagedescription; + char* td_make; + char* td_model; + char* td_software; + char* td_pagename; + tstrip_t td_stripsperimage; + tstrip_t td_nstrips; /* size of offset & bytecount arrays */ + uint32* td_stripoffset; + uint32* td_stripbytecount; +#if SUBIFD_SUPPORT + uint16 td_nsubifd; + uint32* td_subifd; +#endif +#ifdef YCBCR_SUPPORT + float* td_ycbcrcoeffs; + uint16 td_ycbcrsubsampling[2]; + uint16 td_ycbcrpositioning; +#endif +#ifdef COLORIMETRY_SUPPORT + float* td_whitepoint; + float* td_primarychromas; + float* td_refblackwhite; + uint16* td_transferfunction[3]; +#endif +#ifdef CMYK_SUPPORT + uint16 td_inkset; + uint16 td_ninks; + uint16 td_dotrange[2]; + int td_inknameslen; + char* td_inknames; + char* td_targetprinter; +#endif +#ifdef ICC_SUPPORT + uint32 td_profileLength; + void *td_profileData; +#endif +#ifdef PHOTOSHOP_SUPPORT + uint32 td_photoshopLength; + void *td_photoshopData; +#endif +#ifdef IPTC_SUPPORT + uint32 td_richtiffiptcLength; + void *td_richtiffiptcData; +#endif + /* Begin Pixar Tag values. */ + uint32 td_imagefullwidth, td_imagefulllength; + char* td_textureformat; + char* td_wrapmodes; + float td_fovcot; + float* td_matrixWorldToScreen; + float* td_matrixWorldToCamera; + /* End Pixar Tag Values. */ +} TIFFDirectory; + +/* + * Field flags used to indicate fields that have + * been set in a directory, and to reference fields + * when manipulating a directory. + */ + +/* + * FIELD_IGNORE is used to signify tags that are to + * be processed but otherwise ignored. This permits + * antiquated tags to be quietly read and discarded. + * Note that a bit *is* allocated for ignored tags; + * this is understood by the directory reading logic + * which uses this fact to avoid special-case handling + */ +#define FIELD_IGNORE 0 + +/* multi-item fields */ +#define FIELD_IMAGEDIMENSIONS 1 +#define FIELD_TILEDIMENSIONS 2 +#define FIELD_RESOLUTION 3 +#define FIELD_POSITION 4 + +/* single-item fields */ +#define FIELD_SUBFILETYPE 5 +#define FIELD_BITSPERSAMPLE 6 +#define FIELD_COMPRESSION 7 +#define FIELD_PHOTOMETRIC 8 +#define FIELD_THRESHHOLDING 9 +#define FIELD_FILLORDER 10 +#define FIELD_DOCUMENTNAME 11 +#define FIELD_IMAGEDESCRIPTION 12 +#define FIELD_MAKE 13 +#define FIELD_MODEL 14 +#define FIELD_ORIENTATION 15 +#define FIELD_SAMPLESPERPIXEL 16 +#define FIELD_ROWSPERSTRIP 17 +#define FIELD_MINSAMPLEVALUE 18 +#define FIELD_MAXSAMPLEVALUE 19 +#define FIELD_PLANARCONFIG 20 +#define FIELD_PAGENAME 21 +#define FIELD_RESOLUTIONUNIT 22 +#define FIELD_PAGENUMBER 23 +#define FIELD_STRIPBYTECOUNTS 24 +#define FIELD_STRIPOFFSETS 25 +#define FIELD_COLORMAP 26 +#define FIELD_ARTIST 27 +#define FIELD_DATETIME 28 +#define FIELD_HOSTCOMPUTER 29 +#define FIELD_SOFTWARE 30 +#define FIELD_EXTRASAMPLES 31 +#define FIELD_SAMPLEFORMAT 32 +#define FIELD_SMINSAMPLEVALUE 33 +#define FIELD_SMAXSAMPLEVALUE 34 +#define FIELD_IMAGEDEPTH 35 +#define FIELD_TILEDEPTH 36 +#define FIELD_HALFTONEHINTS 37 +#define FIELD_YCBCRCOEFFICIENTS 38 +#define FIELD_YCBCRSUBSAMPLING 39 +#define FIELD_YCBCRPOSITIONING 40 +#define FIELD_REFBLACKWHITE 41 +#define FIELD_WHITEPOINT 42 +#define FIELD_PRIMARYCHROMAS 43 +#define FIELD_TRANSFERFUNCTION 44 +#define FIELD_INKSET 45 +#define FIELD_INKNAMES 46 +#define FIELD_DOTRANGE 47 +#define FIELD_TARGETPRINTER 48 +#define FIELD_SUBIFD 49 +#define FIELD_NUMBEROFINKS 50 +#define FIELD_ICCPROFILE 51 +#define FIELD_PHOTOSHOP 52 +#define FIELD_RICHTIFFIPTC 53 +#define FIELD_STONITS 54 +/* Begin PIXAR */ +#define FIELD_IMAGEFULLWIDTH 55 +#define FIELD_IMAGEFULLLENGTH 56 +#define FIELD_TEXTUREFORMAT 57 +#define FIELD_WRAPMODES 58 +#define FIELD_FOVCOT 59 +#define FIELD_MATRIX_WORLDTOSCREEN 60 +#define FIELD_MATRIX_WORLDTOCAMERA 61 +/* end of support for well-known tags; codec-private tags follow */ +#define FIELD_CODEC 62 /* base of codec-private tags */ +/* + * Pseudo-tags don't normally need field bits since they + * are not written to an output file (by definition). + * The library also has express logic to always query a + * codec for a pseudo-tag so allocating a field bit for + * one is a waste. If codec wants to promote the notion + * of a pseudo-tag being ``set'' or ``unset'' then it can + * do using internal state flags without polluting the + * field bit space defined for real tags. + */ +#define FIELD_PSEUDO 0 + +#define FIELD_LAST (32*FIELD_SETLONGS-1) + +#define TIFFExtractData(tif, type, v) \ + ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \ + ((v) >> (tif)->tif_typeshift[type]) & (tif)->tif_typemask[type] : \ + (v) & (tif)->tif_typemask[type])) +#define TIFFInsertData(tif, type, v) \ + ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \ + ((v) & (tif)->tif_typemask[type]) << (tif)->tif_typeshift[type] : \ + (v) & (tif)->tif_typemask[type])) + +typedef struct { + ttag_t field_tag; /* field's tag */ + short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */ + short field_writecount; /* write count/TIFF_VARIABLE */ + TIFFDataType field_type; /* type of associated data */ + u_short field_bit; /* bit in fieldsset bit vector */ + u_char field_oktochange; /* if true, can change while writing */ + u_char field_passcount; /* if true, pass dir count on set */ + char *field_name; /* ASCII name */ +} TIFFFieldInfo; + +#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */ +#define TIFF_VARIABLE -1 /* marker for variable length tags */ +#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */ +#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */ + +extern const int tiffDataWidth[]; /* table of tag datatype widths */ + +#define BITn(n) (((u_long)1L)<<((n)&0x1f)) +#define BITFIELDn(tif, n) ((tif)->tif_dir.td_fieldsset[(n)/32]) +#define TIFFFieldSet(tif, field) (BITFIELDn(tif, field) & BITn(field)) +#define TIFFSetFieldBit(tif, field) (BITFIELDn(tif, field) |= BITn(field)) +#define TIFFClrFieldBit(tif, field) (BITFIELDn(tif, field) &= ~BITn(field)) + +#define FieldSet(fields, f) (fields[(f)/32] & BITn(f)) +#define ResetFieldBit(fields, f) (fields[(f)/32] &= ~BITn(f)) + +#if defined(__cplusplus) +extern "C" { +#endif +extern void _TIFFSetupFieldInfo(TIFF*); +extern void _TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int); +extern void _TIFFPrintFieldInfo(TIFF*, FILE*); +extern const TIFFFieldInfo* _TIFFFindFieldInfo(TIFF*, ttag_t, TIFFDataType); +extern const TIFFFieldInfo* _TIFFFieldWithTag(TIFF*, ttag_t); +extern TIFFDataType _TIFFSampleToTagType(TIFF*); +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFDIR_ */ diff --git a/freeimage241/Source/LibTIFF/tif_dirinfo.c b/freeimage241/Source/LibTIFF/tif_dirinfo.c new file mode 100644 index 0000000..557dde6 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_dirinfo.c @@ -0,0 +1,402 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_dirinfo.c,v 1.0 2001-04-13 00:42:30+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Core Directory Tag Support. + */ +#include "tiffiop.h" +#include + +/* + * NB: NB: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG. + * If a tag can have both LONG and SHORT types + * then the LONG must be placed before the SHORT for + * writing to work properly. + */ +static const TIFFFieldInfo tiffFieldInfo[] = { + { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, FIELD_SUBFILETYPE, + TRUE, FALSE, "SubfileType" }, +/* XXX SHORT for compatibility w/ old versions of the library */ + { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE, + TRUE, FALSE, "SubfileType" }, + { TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE, + TRUE, FALSE, "OldSubfileType" }, + { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS, + FALSE, FALSE, "ImageWidth" }, + { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS, + FALSE, FALSE, "ImageWidth" }, + { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS, + TRUE, FALSE, "ImageLength" }, + { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS, + TRUE, FALSE, "ImageLength" }, + { TIFFTAG_BITSPERSAMPLE, -1,-1, TIFF_SHORT, FIELD_BITSPERSAMPLE, + FALSE, FALSE, "BitsPerSample" }, + { TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, FIELD_COMPRESSION, + FALSE, FALSE, "Compression" }, + { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, FIELD_PHOTOMETRIC, + FALSE, FALSE, "PhotometricInterpretation" }, + { TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, FIELD_THRESHHOLDING, + TRUE, FALSE, "Threshholding" }, + { TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, FIELD_IGNORE, + TRUE, FALSE, "CellWidth" }, + { TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, FIELD_IGNORE, + TRUE, FALSE, "CellLength" }, + { TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, FIELD_FILLORDER, + FALSE, FALSE, "FillOrder" }, + { TIFFTAG_DOCUMENTNAME, -1,-1, TIFF_ASCII, FIELD_DOCUMENTNAME, + TRUE, FALSE, "DocumentName" }, + { TIFFTAG_IMAGEDESCRIPTION, -1,-1, TIFF_ASCII, FIELD_IMAGEDESCRIPTION, + TRUE, FALSE, "ImageDescription" }, + { TIFFTAG_MAKE, -1,-1, TIFF_ASCII, FIELD_MAKE, + TRUE, FALSE, "Make" }, + { TIFFTAG_MODEL, -1,-1, TIFF_ASCII, FIELD_MODEL, + TRUE, FALSE, "Model" }, + { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_LONG, FIELD_STRIPOFFSETS, + FALSE, FALSE, "StripOffsets" }, + { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_SHORT, FIELD_STRIPOFFSETS, + FALSE, FALSE, "StripOffsets" }, + { TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, FIELD_ORIENTATION, + FALSE, FALSE, "Orientation" }, + { TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, FIELD_SAMPLESPERPIXEL, + FALSE, FALSE, "SamplesPerPixel" }, + { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, FIELD_ROWSPERSTRIP, + FALSE, FALSE, "RowsPerStrip" }, + { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_SHORT, FIELD_ROWSPERSTRIP, + FALSE, FALSE, "RowsPerStrip" }, + { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_STRIPBYTECOUNTS, + FALSE, FALSE, "StripByteCounts" }, + { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS, + FALSE, FALSE, "StripByteCounts" }, + { TIFFTAG_MINSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MINSAMPLEVALUE, + TRUE, FALSE, "MinSampleValue" }, + { TIFFTAG_MAXSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MAXSAMPLEVALUE, + TRUE, FALSE, "MaxSampleValue" }, + { TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION, + FALSE, FALSE, "XResolution" }, + { TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION, + FALSE, FALSE, "YResolution" }, + { TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, FIELD_PLANARCONFIG, + FALSE, FALSE, "PlanarConfiguration" }, + { TIFFTAG_PAGENAME, -1,-1, TIFF_ASCII, FIELD_PAGENAME, + TRUE, FALSE, "PageName" }, + { TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION, + TRUE, FALSE, "XPosition" }, + { TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION, + TRUE, FALSE, "YPosition" }, + { TIFFTAG_FREEOFFSETS, -1,-1, TIFF_LONG, FIELD_IGNORE, + FALSE, FALSE, "FreeOffsets" }, + { TIFFTAG_FREEBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_IGNORE, + FALSE, FALSE, "FreeByteCounts" }, + { TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE, + TRUE, FALSE, "GrayResponseUnit" }, + { TIFFTAG_GRAYRESPONSECURVE,-1,-1, TIFF_SHORT, FIELD_IGNORE, + TRUE, FALSE, "GrayResponseCurve" }, + { TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, FIELD_RESOLUTIONUNIT, + FALSE, FALSE, "ResolutionUnit" }, + { TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, FIELD_PAGENUMBER, + TRUE, FALSE, "PageNumber" }, + { TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE, + TRUE, FALSE, "ColorResponseUnit" }, +#ifdef COLORIMETRY_SUPPORT + { TIFFTAG_TRANSFERFUNCTION, -1,-1, TIFF_SHORT, FIELD_TRANSFERFUNCTION, + TRUE, FALSE, "TransferFunction" }, +#endif + { TIFFTAG_SOFTWARE, -1,-1, TIFF_ASCII, FIELD_SOFTWARE, + TRUE, FALSE, "Software" }, + { TIFFTAG_DATETIME, 20,20, TIFF_ASCII, FIELD_DATETIME, + TRUE, FALSE, "DateTime" }, + { TIFFTAG_ARTIST, -1,-1, TIFF_ASCII, FIELD_ARTIST, + TRUE, FALSE, "Artist" }, + { TIFFTAG_HOSTCOMPUTER, -1,-1, TIFF_ASCII, FIELD_HOSTCOMPUTER, + TRUE, FALSE, "HostComputer" }, +#ifdef COLORIMETRY_SUPPORT + { TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL,FIELD_WHITEPOINT, + TRUE, FALSE, "WhitePoint" }, + { TIFFTAG_PRIMARYCHROMATICITIES,6,6,TIFF_RATIONAL,FIELD_PRIMARYCHROMAS, + TRUE, FALSE, "PrimaryChromaticities" }, +#endif + { TIFFTAG_COLORMAP, -1,-1, TIFF_SHORT, FIELD_COLORMAP, + TRUE, FALSE, "ColorMap" }, + { TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, FIELD_HALFTONEHINTS, + TRUE, FALSE, "HalftoneHints" }, + { TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS, + FALSE, FALSE, "TileWidth" }, + { TIFFTAG_TILEWIDTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS, + FALSE, FALSE, "TileWidth" }, + { TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS, + FALSE, FALSE, "TileLength" }, + { TIFFTAG_TILELENGTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS, + FALSE, FALSE, "TileLength" }, + { TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG, FIELD_STRIPOFFSETS, + FALSE, FALSE, "TileOffsets" }, + { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG, FIELD_STRIPBYTECOUNTS, + FALSE, FALSE, "TileByteCounts" }, + { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS, + FALSE, FALSE, "TileByteCounts" }, +#ifdef TIFFTAG_SUBIFD + { TIFFTAG_SUBIFD, -1,-1, TIFF_LONG, FIELD_SUBIFD, + TRUE, TRUE, "SubIFD" }, +#endif +#ifdef CMYK_SUPPORT /* 6.0 CMYK tags */ + { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, FIELD_INKSET, + FALSE, FALSE, "InkSet" }, + { TIFFTAG_INKNAMES, -1,-1, TIFF_ASCII, FIELD_INKNAMES, + TRUE, TRUE, "InkNames" }, + { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, FIELD_NUMBEROFINKS, + TRUE, FALSE, "NumberOfInks" }, + { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, FIELD_DOTRANGE, + FALSE, FALSE, "DotRange" }, + { TIFFTAG_DOTRANGE, 2, 2, TIFF_BYTE, FIELD_DOTRANGE, + FALSE, FALSE, "DotRange" }, + { TIFFTAG_TARGETPRINTER, -1,-1, TIFF_ASCII, FIELD_TARGETPRINTER, + TRUE, FALSE, "TargetPrinter" }, +#endif + { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_SHORT, FIELD_EXTRASAMPLES, + FALSE, FALSE, "ExtraSamples" }, +/* XXX for bogus Adobe Photoshop v2.5 files */ + { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_BYTE, FIELD_EXTRASAMPLES, + FALSE, FALSE, "ExtraSamples" }, + { TIFFTAG_SAMPLEFORMAT, -1,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT, + FALSE, FALSE, "SampleFormat" }, + { TIFFTAG_SMINSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMINSAMPLEVALUE, + TRUE, FALSE, "SMinSampleValue" }, + { TIFFTAG_SMAXSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMAXSAMPLEVALUE, + TRUE, FALSE, "SMaxSampleValue" }, +#ifdef YCBCR_SUPPORT /* 6.0 YCbCr tags */ + { TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, FIELD_YCBCRCOEFFICIENTS, + FALSE, FALSE, "YCbCrCoefficients" }, + { TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, FIELD_YCBCRSUBSAMPLING, + FALSE, FALSE, "YCbCrSubsampling" }, + { TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, FIELD_YCBCRPOSITIONING, + FALSE, FALSE, "YCbCrPositioning" }, +#endif +#ifdef COLORIMETRY_SUPPORT + { TIFFTAG_REFERENCEBLACKWHITE,6,6,TIFF_RATIONAL, FIELD_REFBLACKWHITE, + TRUE, FALSE, "ReferenceBlackWhite" }, +/* XXX temporarily accept LONG for backwards compatibility */ + { TIFFTAG_REFERENCEBLACKWHITE,6,6,TIFF_LONG, FIELD_REFBLACKWHITE, + TRUE, FALSE, "ReferenceBlackWhite" }, +#endif +/* begin SGI tags */ + { TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, FIELD_EXTRASAMPLES, + FALSE, FALSE, "Matteing" }, + { TIFFTAG_DATATYPE, -2,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT, + FALSE, FALSE, "DataType" }, + { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, FIELD_IMAGEDEPTH, + FALSE, FALSE, "ImageDepth" }, + { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDEPTH, + FALSE, FALSE, "ImageDepth" }, + { TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, FIELD_TILEDEPTH, + FALSE, FALSE, "TileDepth" }, + { TIFFTAG_TILEDEPTH, 1, 1, TIFF_SHORT, FIELD_TILEDEPTH, + FALSE, FALSE, "TileDepth" }, +/* end SGI tags */ +#ifdef IPTC_SUPPORT +#ifdef PHOTOSHOP_SUPPORT + { TIFFTAG_RICHTIFFIPTC, -1,-1, TIFF_LONG, FIELD_RICHTIFFIPTC, + FALSE, TRUE, "RichTIFFIPTC" }, +#else + { TIFFTAG_RICHTIFFIPTC, -1,-3, TIFF_UNDEFINED, FIELD_RICHTIFFIPTC, + FALSE, TRUE, "RichTIFFIPTC" }, +#endif +#endif +#ifdef PHOTOSHOP_SUPPORT + { TIFFTAG_PHOTOSHOP, -1,-3, TIFF_UNDEFINED, FIELD_PHOTOSHOP, + FALSE, TRUE, "Photoshop" }, + { TIFFTAG_PHOTOSHOP, -1,-1, TIFF_BYTE, FIELD_PHOTOSHOP, + FALSE, TRUE, "Photoshop" }, +#endif +#ifdef ICC_SUPPORT + { TIFFTAG_ICCPROFILE, -1,-3, TIFF_UNDEFINED, FIELD_ICCPROFILE, + FALSE, TRUE, "ICC Profile" }, +#endif + { TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, FIELD_STONITS, + FALSE, FALSE, "StoNits" }, +/* begin Pixar tags */ + { TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, FIELD_IMAGEFULLWIDTH, + TRUE, FALSE, "ImageFullWidth" }, + { TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, FIELD_IMAGEFULLLENGTH, + TRUE, FALSE, "ImageFullLength" }, + { TIFFTAG_PIXAR_TEXTUREFORMAT, -1,-1, TIFF_ASCII, FIELD_TEXTUREFORMAT, + TRUE, FALSE, "TextureFormat" }, + { TIFFTAG_PIXAR_WRAPMODES, -1,-1, TIFF_ASCII, FIELD_WRAPMODES, + TRUE, FALSE, "TextureWrapModes" }, + { TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, FIELD_FOVCOT, + TRUE, FALSE, "FieldOfViewCotan" }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16,16, TIFF_FLOAT, + FIELD_MATRIX_WORLDTOSCREEN, TRUE, FALSE, "MatrixWorldToScreen" }, + { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16,16, TIFF_FLOAT, + FIELD_MATRIX_WORLDTOCAMERA, TRUE, FALSE, "MatrixWorldToCamera" }, +/* end Pixar tags */ +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +void +_TIFFSetupFieldInfo(TIFF* tif) +{ + if (tif->tif_fieldinfo) { + _TIFFfree(tif->tif_fieldinfo); + tif->tif_nfields = 0; + } + _TIFFMergeFieldInfo(tif, tiffFieldInfo, N(tiffFieldInfo)); +} + +static int +tagCompare(const void* a, const void* b) +{ + const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a; + const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) b; + /* NB: be careful of return values for 16-bit platforms */ + if (ta->field_tag != tb->field_tag) + return (ta->field_tag < tb->field_tag ? -1 : 1); + else + return (tb->field_type < ta->field_type ? -1 : 1); +} + +void +_TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n) +{ + TIFFFieldInfo** tp; + int i; + + if (tif->tif_nfields > 0) { + tif->tif_fieldinfo = (TIFFFieldInfo**) + _TIFFrealloc(tif->tif_fieldinfo, + (tif->tif_nfields+n) * sizeof (TIFFFieldInfo*)); + } else { + tif->tif_fieldinfo = (TIFFFieldInfo**) + _TIFFmalloc(n * sizeof (TIFFFieldInfo*)); + } + tp = &tif->tif_fieldinfo[tif->tif_nfields]; + for (i = 0; i < n; i++) + tp[i] = (TIFFFieldInfo*) &info[i]; /* XXX */ + /* + * NB: the core tags are presumed sorted correctly. + */ + if (tif->tif_nfields > 0) + qsort(tif->tif_fieldinfo, (size_t) (tif->tif_nfields += n), + sizeof (TIFFFieldInfo*), tagCompare); + else + tif->tif_nfields += n; +} + +void +_TIFFPrintFieldInfo(TIFF* tif, FILE* fd) +{ + int i; + + fprintf(fd, "%s: \n", tif->tif_name); + for (i = 0; i < tif->tif_nfields; i++) { + const TIFFFieldInfo* fip = tif->tif_fieldinfo[i]; + fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n" + , i + , (unsigned long) fip->field_tag + , fip->field_readcount, fip->field_writecount + , fip->field_type + , fip->field_bit + , fip->field_oktochange ? "TRUE" : "FALSE" + , fip->field_passcount ? "TRUE" : "FALSE" + , fip->field_name + ); + } +} + +const int tiffDataWidth[] = { + 1, /* nothing */ + 1, /* TIFF_BYTE */ + 1, /* TIFF_ASCII */ + 2, /* TIFF_SHORT */ + 4, /* TIFF_LONG */ + 8, /* TIFF_RATIONAL */ + 1, /* TIFF_SBYTE */ + 1, /* TIFF_UNDEFINED */ + 2, /* TIFF_SSHORT */ + 4, /* TIFF_SLONG */ + 8, /* TIFF_SRATIONAL */ + 4, /* TIFF_FLOAT */ + 8, /* TIFF_DOUBLE */ +}; + +/* + * Return nearest TIFFDataType to the sample type of an image. + */ +TIFFDataType +_TIFFSampleToTagType(TIFF* tif) +{ + int bps = (int) TIFFhowmany(tif->tif_dir.td_bitspersample, 8); + + switch (tif->tif_dir.td_sampleformat) { + case SAMPLEFORMAT_IEEEFP: + return (bps == 4 ? TIFF_FLOAT : TIFF_DOUBLE); + case SAMPLEFORMAT_INT: + return (bps <= 1 ? TIFF_SBYTE : + bps <= 2 ? TIFF_SSHORT : TIFF_SLONG); + case SAMPLEFORMAT_UINT: + return (bps <= 1 ? TIFF_BYTE : + bps <= 2 ? TIFF_SHORT : TIFF_LONG); + case SAMPLEFORMAT_VOID: + return (TIFF_UNDEFINED); + } + /*NOTREACHED*/ + return (TIFF_UNDEFINED); +} + +const TIFFFieldInfo* +_TIFFFindFieldInfo(TIFF* tif, ttag_t tag, TIFFDataType dt) +{ + static const TIFFFieldInfo *last = NULL; + int i, n; + + if (last && last->field_tag == tag && + (dt == TIFF_ANY || dt == last->field_type)) + return (last); + /* NB: if table gets big, use sorted search (e.g. binary search) */ + for (i = 0, n = tif->tif_nfields; i < n; i++) { + const TIFFFieldInfo* fip = tif->tif_fieldinfo[i]; + if (fip->field_tag == tag && + (dt == TIFF_ANY || fip->field_type == dt)) + return (last = fip); + } + return ((const TIFFFieldInfo *)0); +} + +#include +#include + +const TIFFFieldInfo* +_TIFFFieldWithTag(TIFF* tif, ttag_t tag) +{ + const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY); + if (!fip) { + TIFFError("TIFFFieldWithTag", + "Internal error, unknown tag 0x%x", (u_int) tag); + assert(fip != NULL); + /*NOTREACHED*/ + } + return (fip); +} diff --git a/freeimage241/Source/LibTIFF/tif_dirread.c b/freeimage241/Source/LibTIFF/tif_dirread.c new file mode 100644 index 0000000..5f53d82 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_dirread.c @@ -0,0 +1,1375 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_dirread.c,v 1.0 2001-04-13 00:42:30+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Read Support Routines. + */ +#include "tiffiop.h" + +#define IGNORE 0 /* tag placeholder used below */ + +#if HAVE_IEEEFP +#define TIFFCvtIEEEFloatToNative(tif, n, fp) +#define TIFFCvtIEEEDoubleToNative(tif, n, dp) +#else +extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*); +extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*); +#endif + +static void EstimateStripByteCounts(TIFF*, TIFFDirEntry*, uint16); +static void MissingRequired(TIFF*, const char*); +static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32); +static tsize_t TIFFFetchData(TIFF*, TIFFDirEntry*, char*); +static tsize_t TIFFFetchString(TIFF*, TIFFDirEntry*, char*); +static float TIFFFetchRational(TIFF*, TIFFDirEntry*); +static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*); +static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, int*); +static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*); +static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*); +static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**); +static int TIFFFetchExtraSamples(TIFF*, TIFFDirEntry*); +static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*); +static float TIFFFetchFloat(TIFF*, TIFFDirEntry*); +static int TIFFFetchFloatArray(TIFF*, TIFFDirEntry*, float*); +static int TIFFFetchDoubleArray(TIFF*, TIFFDirEntry*, double*); +static int TIFFFetchAnyArray(TIFF*, TIFFDirEntry*, double*); +static int TIFFFetchShortPair(TIFF*, TIFFDirEntry*); +static void ChopUpSingleUncompressedStrip(TIFF*); + +static char * +CheckMalloc(TIFF* tif, tsize_t n, const char* what) +{ + char *cp = (char*)_TIFFmalloc(n); + if (cp == NULL) + TIFFError(tif->tif_name, "No space %s", what); + return (cp); +} + +/* + * Read the next TIFF directory from a file + * and convert it to the internal format. + * We read directories sequentially. + */ +int +TIFFReadDirectory(TIFF* tif) +{ + register TIFFDirEntry* dp; + register int n; + register TIFFDirectory* td; + TIFFDirEntry* dir; + int iv; + long v; + double dv; + const TIFFFieldInfo* fip; + int fix; + uint16 dircount; + toff_t nextdiroff; + char* cp; + int diroutoforderwarning = 0; + + tif->tif_diroff = tif->tif_nextdiroff; + if (tif->tif_diroff == 0) /* no more directories */ + return (0); + /* + * Cleanup any previous compression state. + */ + (*tif->tif_cleanup)(tif); + tif->tif_curdir++; + nextdiroff = 0; + if (!isMapped(tif)) { + if (!SeekOK(tif, tif->tif_diroff)) { + TIFFError(tif->tif_name, + "Seek error accessing TIFF directory"); + return (0); + } + if (!ReadOK(tif, &dircount, sizeof (uint16))) { + TIFFError(tif->tif_name, + "Can not read TIFF directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + dir = (TIFFDirEntry *)CheckMalloc(tif, + dircount * sizeof (TIFFDirEntry), "to read TIFF directory"); + if (dir == NULL) + return (0); + if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) { + TIFFError(tif->tif_name, "Can not read TIFF directory"); + goto bad; + } + /* + * Read offset to next directory for sequential scans. + */ + (void) ReadOK(tif, &nextdiroff, sizeof (uint32)); + } else { + toff_t off = tif->tif_diroff; + + if (off + sizeof (uint16) > tif->tif_size) { + TIFFError(tif->tif_name, + "Can not read TIFF directory count"); + return (0); + } else + _TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16)); + off += sizeof (uint16); + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + dir = (TIFFDirEntry *)CheckMalloc(tif, + dircount * sizeof (TIFFDirEntry), "to read TIFF directory"); + if (dir == NULL) + return (0); + if (off + dircount*sizeof (TIFFDirEntry) > tif->tif_size) { + TIFFError(tif->tif_name, "Can not read TIFF directory"); + goto bad; + } else + _TIFFmemcpy(dir, tif->tif_base + off, + dircount*sizeof (TIFFDirEntry)); + off += dircount* sizeof (TIFFDirEntry); + if (off + sizeof (uint32) <= tif->tif_size) + _TIFFmemcpy(&nextdiroff, tif->tif_base+off, sizeof (uint32)); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdiroff); + tif->tif_nextdiroff = nextdiroff; + + tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ + /* + * Setup default value and then make a pass over + * the fields to check type and tag information, + * and to extract info required to size data + * structures. A second pass is made afterwards + * to read in everthing not taken in the first pass. + */ + td = &tif->tif_dir; + /* free any old stuff and reinit */ + TIFFFreeDirectory(tif); + TIFFDefaultDirectory(tif); + /* + * Electronic Arts writes gray-scale TIFF files + * without a PlanarConfiguration directory entry. + * Thus we setup a default value here, even though + * the TIFF spec says there is no default value. + */ + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + + /* + * Sigh, we must make a separate pass through the + * directory for the following reason: + * + * We must process the Compression tag in the first pass + * in order to merge in codec-private tag definitions (otherwise + * we may get complaints about unknown tags). However, the + * Compression tag may be dependent on the SamplesPerPixel + * tag value because older TIFF specs permited Compression + * to be written as a SamplesPerPixel-count tag entry. + * Thus if we don't first figure out the correct SamplesPerPixel + * tag value then we may end up ignoring the Compression tag + * value because it has an incorrect count value (if the + * true value of SamplesPerPixel is not 1). + * + * It sure would have been nice if Aldus had really thought + * this stuff through carefully. + */ + for (dp = dir, n = dircount; n > 0; n--, dp++) { + if (tif->tif_flags & TIFF_SWAB) { + TIFFSwabArrayOfShort(&dp->tdir_tag, 2); + TIFFSwabArrayOfLong(&dp->tdir_count, 2); + } + if (dp->tdir_tag == TIFFTAG_SAMPLESPERPIXEL) { + if (!TIFFFetchNormalTag(tif, dp)) + goto bad; + dp->tdir_tag = IGNORE; + } + } + /* + * First real pass over the directory. + */ + fix = 0; + for (dp = dir, n = dircount; n > 0; n--, dp++) { + + /* + * Find the field information entry for this tag. + * Added check for tags to ignore ... [BFC] + */ + if( TIFFReassignTagToIgnore(TIS_EXTRACT, dp->tdir_tag) ) + dp->tdir_tag = IGNORE; + + if (dp->tdir_tag == IGNORE) + continue; + + /* + * Silicon Beach (at least) writes unordered + * directory tags (violating the spec). Handle + * it here, but be obnoxious (maybe they'll fix it?). + */ + if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) { + if (!diroutoforderwarning) { + TIFFWarning(tif->tif_name, + "invalid TIFF directory; tags are not sorted in ascending order"); + diroutoforderwarning = 1; + } + fix = 0; /* O(n^2) */ + } + while (fix < tif->tif_nfields && + tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) + fix++; + if (fix == tif->tif_nfields || + tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { + TIFFWarning(tif->tif_name, + "unknown field with tag %d (0x%x) ignored", + dp->tdir_tag, dp->tdir_tag); + dp->tdir_tag = IGNORE; + fix = 0; /* restart search */ + continue; + } + /* + * Null out old tags that we ignore. + */ + if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) { + ignore: + dp->tdir_tag = IGNORE; + continue; + } + /* + * Check data type. + */ + fip = tif->tif_fieldinfo[fix]; + while (dp->tdir_type != (u_short) fip->field_type) { + if (fip->field_type == TIFF_ANY) /* wildcard */ + break; + fip++, fix++; + if (fix == tif->tif_nfields || + fip->field_tag != dp->tdir_tag) { + TIFFWarning(tif->tif_name, + "wrong data type %d for \"%s\"; tag ignored", + dp->tdir_type, fip[-1].field_name); + goto ignore; + } + } + /* + * Check count if known in advance. + */ + if (fip->field_readcount != TIFF_VARIABLE) { + uint32 expected = (fip->field_readcount == TIFF_SPP) ? + (uint32) td->td_samplesperpixel : + (uint32) fip->field_readcount; + if (!CheckDirCount(tif, dp, expected)) + goto ignore; + } + + switch (dp->tdir_tag) { + case TIFFTAG_COMPRESSION: + /* + * The 5.0 spec says the Compression tag has + * one value, while earlier specs say it has + * one value per sample. Because of this, we + * accept the tag if one value is supplied. + */ + if (dp->tdir_count == 1) { + v = TIFFExtractData(tif, + dp->tdir_type, dp->tdir_offset); + if (!TIFFSetField(tif, dp->tdir_tag, (int)v)) + goto bad; + break; + } + if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || + !TIFFSetField(tif, dp->tdir_tag, iv)) + goto bad; + dp->tdir_tag = IGNORE; + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEOFFSETS: + case TIFFTAG_TILEBYTECOUNTS: + TIFFSetFieldBit(tif, fip->field_bit); + break; + case TIFFTAG_IMAGEWIDTH: + case TIFFTAG_IMAGELENGTH: + case TIFFTAG_IMAGEDEPTH: + case TIFFTAG_TILELENGTH: + case TIFFTAG_TILEWIDTH: + case TIFFTAG_TILEDEPTH: + case TIFFTAG_PLANARCONFIG: + case TIFFTAG_ROWSPERSTRIP: + if (!TIFFFetchNormalTag(tif, dp)) + goto bad; + dp->tdir_tag = IGNORE; + break; + case TIFFTAG_EXTRASAMPLES: + (void) TIFFFetchExtraSamples(tif, dp); + dp->tdir_tag = IGNORE; + break; + } + } + + /* + * Allocate directory structure and setup defaults. + */ + if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { + MissingRequired(tif, "ImageLength"); + goto bad; + } + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { + MissingRequired(tif, "PlanarConfiguration"); + goto bad; + } + /* + * Setup appropriate structures (by strip or by tile) + */ + if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { + td->td_nstrips = TIFFNumberOfStrips(tif); + td->td_tilewidth = td->td_imagewidth; + td->td_tilelength = td->td_rowsperstrip; + td->td_tiledepth = td->td_imagedepth; + tif->tif_flags &= ~TIFF_ISTILED; + } else { + td->td_nstrips = TIFFNumberOfTiles(tif); + tif->tif_flags |= TIFF_ISTILED; + } + td->td_stripsperimage = td->td_nstrips; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + td->td_stripsperimage /= td->td_samplesperpixel; + if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { + MissingRequired(tif, + isTiled(tif) ? "TileOffsets" : "StripOffsets"); + goto bad; + } + + /* + * Second pass: extract other information. + */ + for (dp = dir, n = dircount; n > 0; n--, dp++) { + if (dp->tdir_tag == IGNORE) + continue; + switch (dp->tdir_tag) { + case TIFFTAG_MINSAMPLEVALUE: + case TIFFTAG_MAXSAMPLEVALUE: + case TIFFTAG_BITSPERSAMPLE: + /* + * The 5.0 spec says the Compression tag has + * one value, while earlier specs say it has + * one value per sample. Because of this, we + * accept the tag if one value is supplied. + * + * The MinSampleValue, MaxSampleValue and + * BitsPerSample tags are supposed to be written + * as one value/sample, but some vendors incorrectly + * write one value only -- so we accept that + * as well (yech). + */ + if (dp->tdir_count == 1) { + v = TIFFExtractData(tif, + dp->tdir_type, dp->tdir_offset); + if (!TIFFSetField(tif, dp->tdir_tag, (int)v)) + goto bad; + break; + } + /* fall thru... */ + case TIFFTAG_DATATYPE: + case TIFFTAG_SAMPLEFORMAT: + if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || + !TIFFSetField(tif, dp->tdir_tag, iv)) + goto bad; + break; + case TIFFTAG_SMINSAMPLEVALUE: + case TIFFTAG_SMAXSAMPLEVALUE: + if (!TIFFFetchPerSampleAnys(tif, dp, &dv) || + !TIFFSetField(tif, dp->tdir_tag, dv)) + goto bad; + break; + case TIFFTAG_STRIPOFFSETS: + case TIFFTAG_TILEOFFSETS: + if (!TIFFFetchStripThing(tif, dp, + td->td_nstrips, &td->td_stripoffset)) + goto bad; + break; + case TIFFTAG_STRIPBYTECOUNTS: + case TIFFTAG_TILEBYTECOUNTS: + if (!TIFFFetchStripThing(tif, dp, + td->td_nstrips, &td->td_stripbytecount)) + goto bad; + break; + case TIFFTAG_COLORMAP: + case TIFFTAG_TRANSFERFUNCTION: + /* + * TransferFunction can have either 1x or 3x data + * values; Colormap can have only 3x items. + */ + v = 1L<td_bitspersample; + if (dp->tdir_tag == TIFFTAG_COLORMAP || + dp->tdir_count != (uint32) v) { + if (!CheckDirCount(tif, dp, (uint32)(3*v))) + break; + } + v *= sizeof (uint16); + cp = CheckMalloc(tif, dp->tdir_count * sizeof (uint16), + "to read \"TransferFunction\" tag"); + if (cp != NULL) { + if (TIFFFetchData(tif, dp, cp)) { + /* + * This deals with there being only + * one array to apply to all samples. + */ + uint32 c = + (uint32)1 << td->td_bitspersample; + if (dp->tdir_count == c) + v = 0; + TIFFSetField(tif, dp->tdir_tag, + cp, cp+v, cp+2*v); + } + _TIFFfree(cp); + } + break; + case TIFFTAG_PAGENUMBER: + case TIFFTAG_HALFTONEHINTS: + case TIFFTAG_YCBCRSUBSAMPLING: + case TIFFTAG_DOTRANGE: + (void) TIFFFetchShortPair(tif, dp); + break; +#ifdef COLORIMETRY_SUPPORT + case TIFFTAG_REFERENCEBLACKWHITE: + (void) TIFFFetchRefBlackWhite(tif, dp); + break; +#endif +/* BEGIN REV 4.0 COMPATIBILITY */ + case TIFFTAG_OSUBFILETYPE: + v = 0; + switch (TIFFExtractData(tif, dp->tdir_type, + dp->tdir_offset)) { + case OFILETYPE_REDUCEDIMAGE: + v = FILETYPE_REDUCEDIMAGE; + break; + case OFILETYPE_PAGE: + v = FILETYPE_PAGE; + break; + } + if (v) + (void) TIFFSetField(tif, + TIFFTAG_SUBFILETYPE, (int)v); + break; +/* END REV 4.0 COMPATIBILITY */ + default: + (void) TIFFFetchNormalTag(tif, dp); + break; + } + } + /* + * Verify Palette image has a Colormap. + */ + if (td->td_photometric == PHOTOMETRIC_PALETTE && + !TIFFFieldSet(tif, FIELD_COLORMAP)) { + MissingRequired(tif, "Colormap"); + goto bad; + } + /* + * Attempt to deal with a missing StripByteCounts tag. + */ + if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) { + /* + * Some manufacturers violate the spec by not giving + * the size of the strips. In this case, assume there + * is one uncompressed strip of data. + */ + if ((td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_nstrips > 1) || + (td->td_planarconfig == PLANARCONFIG_SEPARATE && + td->td_nstrips != td->td_samplesperpixel)) { + MissingRequired(tif, "StripByteCounts"); + goto bad; + } + TIFFWarning(tif->tif_name, +"TIFF directory is missing required \"%s\" field, calculating from imagelength", + _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); + EstimateStripByteCounts(tif, dir, dircount); +#define BYTECOUNTLOOKSBAD \ + ((td->td_stripbytecount[0] == 0 && td->td_stripoffset[0] != 0) || \ + (td->td_compression == COMPRESSION_NONE && \ + td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0])) + } else if (td->td_nstrips == 1 && BYTECOUNTLOOKSBAD) { + /* + * Plexus (and others) sometimes give a value + * of zero for a tag when they don't know what + * the correct value is! Try and handle the + * simple case of estimating the size of a one + * strip image. + */ + TIFFWarning(tif->tif_name, + "Bogus \"%s\" field, ignoring and calculating from imagelength", + _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); + EstimateStripByteCounts(tif, dir, dircount); + } + if (dir) + _TIFFfree((char *)dir); + if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) + td->td_maxsamplevalue = (uint16)((1L<td_bitspersample)-1); + /* + * Setup default compression scheme. + */ + if (!TIFFFieldSet(tif, FIELD_COMPRESSION)) + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + /* + * Some manufacturers make life difficult by writing + * large amounts of uncompressed data as a single strip. + * This is contrary to the recommendations of the spec. + * The following makes an attempt at breaking such images + * into strips closer to the recommended 8k bytes. A + * side effect, however, is that the RowsPerStrip tag + * value may be changed. + */ + if (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE && + (tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP) + ChopUpSingleUncompressedStrip(tif); + /* + * Reinitialize i/o since we are starting on a new directory. + */ + tif->tif_row = (uint32) -1; + tif->tif_curstrip = (tstrip_t) -1; + tif->tif_col = (uint32) -1; + tif->tif_curtile = (ttile_t) -1; + tif->tif_tilesize = TIFFTileSize(tif); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + return (1); +bad: + if (dir) + _TIFFfree(dir); + return (0); +} + +static void +EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount) +{ + register TIFFDirEntry *dp; + register TIFFDirectory *td = &tif->tif_dir; + uint16 i; + + if (td->td_stripbytecount) + _TIFFfree(td->td_stripbytecount); + td->td_stripbytecount = (uint32*) + CheckMalloc(tif, td->td_nstrips * sizeof (uint32), + "for \"StripByteCounts\" array"); + if (td->td_compression != COMPRESSION_NONE) { + uint32 space = (uint32)(sizeof (TIFFHeader) + + sizeof (uint16) + + (dircount * sizeof (TIFFDirEntry)) + + sizeof (uint32)); + toff_t filesize = TIFFGetFileSize(tif); + uint16 n; + + /* calculate amount of space used by indirect values */ + for (dp = dir, n = dircount; n > 0; n--, dp++) { + uint32 cc = dp->tdir_count*tiffDataWidth[dp->tdir_type]; + if (cc > sizeof (uint32)) + space += cc; + } + space = filesize - space; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + space /= td->td_samplesperpixel; + for (i = 0; i < td->td_nstrips; i++) + td->td_stripbytecount[i] = space; + /* + * This gross hack handles the case were the offset to + * the last strip is past the place where we think the strip + * should begin. Since a strip of data must be contiguous, + * it's safe to assume that we've overestimated the amount + * of data in the strip and trim this number back accordingly. + */ + i--; + if (((toff_t)(td->td_stripoffset[i]+td->td_stripbytecount[i])) + > filesize) + td->td_stripbytecount[i] = + filesize - td->td_stripoffset[i]; + } else { + uint32 rowbytes = TIFFScanlineSize(tif); + uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage; + for (i = 0; i < td->td_nstrips; i++) + td->td_stripbytecount[i] = rowbytes*rowsperstrip; + } + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP)) + td->td_rowsperstrip = td->td_imagelength; +} + +static void +MissingRequired(TIFF* tif, const char* tagname) +{ + TIFFError(tif->tif_name, + "TIFF directory is missing required \"%s\" field", tagname); +} + +/* + * Check the count field of a directory + * entry against a known value. The caller + * is expected to skip/ignore the tag if + * there is a mismatch. + */ +static int +CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count) +{ + if (count != dir->tdir_count) { + TIFFWarning(tif->tif_name, + "incorrect count for field \"%s\" (%lu, expecting %lu); tag ignored", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, + dir->tdir_count, count); + return (0); + } + return (1); +} + +/* + * Fetch a contiguous directory item. + */ +static tsize_t +TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + int w = tiffDataWidth[dir->tdir_type]; + tsize_t cc = dir->tdir_count * w; + + if (!isMapped(tif)) { + if (!SeekOK(tif, dir->tdir_offset)) + goto bad; + if (!ReadOK(tif, cp, cc)) + goto bad; + } else { + if (dir->tdir_offset + cc > tif->tif_size) + goto bad; + _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc); + } + if (tif->tif_flags & TIFF_SWAB) { + switch (dir->tdir_type) { + case TIFF_SHORT: + case TIFF_SSHORT: + TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); + break; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); + break; + case TIFF_DOUBLE: + TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); + break; + } + } + return (cc); +bad: + TIFFError(tif->tif_name, "Error fetching data for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + return ((tsize_t) 0); +} + +/* + * Fetch an ASCII item from the file. + */ +static tsize_t +TIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + if (dir->tdir_count <= 4) { + uint32 l = dir->tdir_offset; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&l); + _TIFFmemcpy(cp, &l, dir->tdir_count); + return (1); + } + return (TIFFFetchData(tif, dir, cp)); +} + +/* + * Convert numerator+denominator to float. + */ +static int +cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv) +{ + if (denom == 0) { + TIFFError(tif->tif_name, + "%s: Rational with zero denominator (num = %lu)", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num); + return (0); + } else { + if (dir->tdir_type == TIFF_RATIONAL) + *rv = ((float)num / (float)denom); + else + *rv = ((float)(int32)num / (float)(int32)denom); + return (1); + } +} + +/* + * Fetch a rational item from the file + * at offset off and return the value + * as a floating point number. + */ +static float +TIFFFetchRational(TIFF* tif, TIFFDirEntry* dir) +{ + uint32 l[2]; + float v; + + return (!TIFFFetchData(tif, dir, (char *)l) || + !cvtRational(tif, dir, l[0], l[1], &v) ? 1.0f : v); +} + +/* + * Fetch a single floating point value + * from the offset field and return it + * as a native float. + */ +static float +TIFFFetchFloat(TIFF* tif, TIFFDirEntry* dir) +{ + long l = TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset); + float v = *(float*) &l; + TIFFCvtIEEEFloatToNative(tif, 1, &v); + return (v); +} + +/* + * Fetch an array of BYTE or SBYTE values. + */ +static int +TIFFFetchByteArray(TIFF* tif, TIFFDirEntry* dir, uint16* v) +{ + if (dir->tdir_count <= 4) { + /* + * Extract data from offset field. + */ + if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { + switch (dir->tdir_count) { + case 4: v[3] = (uint16)(dir->tdir_offset & 0xff); + case 3: v[2] = (uint16)((dir->tdir_offset >> 8) & 0xff); + case 2: v[1] = (uint16)((dir->tdir_offset >> 16) & 0xff); + case 1: v[0] = (uint16)(dir->tdir_offset >> 24); + } + } else { + switch (dir->tdir_count) { + case 4: v[3] = (uint16)(dir->tdir_offset >> 24); + case 3: v[2] = (uint16)((dir->tdir_offset >> 16) & 0xff); + case 2: v[1] = (uint16)((dir->tdir_offset >> 8) & 0xff); + case 1: v[0] = (uint16)(dir->tdir_offset & 0xff); + } + } + return (1); + } else + return (TIFFFetchData(tif, dir, (char*) v) != 0); /* XXX */ +} + +/* + * Fetch an array of SHORT or SSHORT values. + */ +static int +TIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v) +{ + if (dir->tdir_count <= 2) { + if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { + switch (dir->tdir_count) { + case 2: v[1] = (uint16) (dir->tdir_offset & 0xffff); + case 1: v[0] = (uint16) (dir->tdir_offset >> 16); + } + } else { + switch (dir->tdir_count) { + case 2: v[1] = (uint16) (dir->tdir_offset >> 16); + case 1: v[0] = (uint16) (dir->tdir_offset & 0xffff); + } + } + return (1); + } else + return (TIFFFetchData(tif, dir, (char *)v) != 0); +} + +/* + * Fetch a pair of SHORT or BYTE values. + */ +static int +TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir) +{ + uint16 v[2]; + int ok = 0; + + switch (dir->tdir_type) { + case TIFF_SHORT: + case TIFF_SSHORT: + ok = TIFFFetchShortArray(tif, dir, v); + break; + case TIFF_BYTE: + case TIFF_SBYTE: + ok = TIFFFetchByteArray(tif, dir, v); + break; + } + if (ok) + TIFFSetField(tif, dir->tdir_tag, v[0], v[1]); + return (ok); +} + +/* + * Fetch an array of LONG or SLONG values. + */ +static int +TIFFFetchLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v) +{ + if (dir->tdir_count == 1) { + v[0] = dir->tdir_offset; + return (1); + } else + return (TIFFFetchData(tif, dir, (char*) v) != 0); +} + +/* + * Fetch an array of RATIONAL or SRATIONAL values. + */ +static int +TIFFFetchRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v) +{ + int ok = 0; + uint32* l; + + l = (uint32*)CheckMalloc(tif, + dir->tdir_count*tiffDataWidth[dir->tdir_type], + "to fetch array of rationals"); + if (l) { + if (TIFFFetchData(tif, dir, (char *)l)) { + uint32 i; + for (i = 0; i < dir->tdir_count; i++) { + ok = cvtRational(tif, dir, + l[2*i+0], l[2*i+1], &v[i]); + if (!ok) + break; + } + } + _TIFFfree((char *)l); + } + return (ok); +} + +/* + * Fetch an array of FLOAT values. + */ +static int +TIFFFetchFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v) +{ + + if (dir->tdir_count == 1) { + v[0] = *(float*) &dir->tdir_offset; + TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v); + return (1); + } else if (TIFFFetchData(tif, dir, (char*) v)) { + TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v); + return (1); + } else + return (0); +} + +/* + * Fetch an array of DOUBLE values. + */ +static int +TIFFFetchDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v) +{ + if (TIFFFetchData(tif, dir, (char*) v)) { + TIFFCvtIEEEDoubleToNative(tif, dir->tdir_count, v); + return (1); + } else + return (0); +} + +/* + * Fetch an array of ANY values. The actual values are + * returned as doubles which should be able hold all the + * types. Yes, there really should be an tany_t to avoid + * this potential non-portability ... Note in particular + * that we assume that the double return value vector is + * large enough to read in any fundamental type. We use + * that vector as a buffer to read in the base type vector + * and then convert it in place to double (from end + * to front of course). + */ +static int +TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v) +{ + int i; + + switch (dir->tdir_type) { + case TIFF_BYTE: + case TIFF_SBYTE: + if (!TIFFFetchByteArray(tif, dir, (uint16*) v)) + return (0); + if (dir->tdir_type == TIFF_BYTE) { + uint16* vp = (uint16*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } else { + int16* vp = (int16*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_SHORT: + case TIFF_SSHORT: + if (!TIFFFetchShortArray(tif, dir, (uint16*) v)) + return (0); + if (dir->tdir_type == TIFF_SHORT) { + uint16* vp = (uint16*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } else { + int16* vp = (int16*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_LONG: + case TIFF_SLONG: + if (!TIFFFetchLongArray(tif, dir, (uint32*) v)) + return (0); + if (dir->tdir_type == TIFF_LONG) { + uint32* vp = (uint32*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } else { + int32* vp = (int32*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + if (!TIFFFetchRationalArray(tif, dir, (float*) v)) + return (0); + { float* vp = (float*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_FLOAT: + if (!TIFFFetchFloatArray(tif, dir, (float*) v)) + return (0); + { float* vp = (float*) v; + for (i = dir->tdir_count-1; i >= 0; i--) + v[i] = vp[i]; + } + break; + case TIFF_DOUBLE: + return (TIFFFetchDoubleArray(tif, dir, (double*) v)); + default: + /* TIFF_NOTYPE */ + /* TIFF_ASCII */ + /* TIFF_UNDEFINED */ + TIFFError(tif->tif_name, + "Cannot read TIFF_ANY type %d for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + return (0); + } + return (1); +} + +/* + * Fetch a tag that is not handled by special case code. + */ +static int +TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp) +{ + static const char mesg[] = "to fetch tag value"; + int ok = 0; + const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dp->tdir_tag); + + if (dp->tdir_count > 1) { /* array of values */ + char* cp = NULL; + + switch (dp->tdir_type) { + case TIFF_BYTE: + case TIFF_SBYTE: + /* NB: always expand BYTE values to shorts */ + cp = CheckMalloc(tif, + dp->tdir_count * sizeof (uint16), mesg); + ok = cp && TIFFFetchByteArray(tif, dp, (uint16*) cp); + break; + case TIFF_SHORT: + case TIFF_SSHORT: + cp = CheckMalloc(tif, + dp->tdir_count * sizeof (uint16), mesg); + ok = cp && TIFFFetchShortArray(tif, dp, (uint16*) cp); + break; + case TIFF_LONG: + case TIFF_SLONG: + cp = CheckMalloc(tif, + dp->tdir_count * sizeof (uint32), mesg); + ok = cp && TIFFFetchLongArray(tif, dp, (uint32*) cp); + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + cp = CheckMalloc(tif, + dp->tdir_count * sizeof (float), mesg); + ok = cp && TIFFFetchRationalArray(tif, dp, (float*) cp); + break; + case TIFF_FLOAT: + cp = CheckMalloc(tif, + dp->tdir_count * sizeof (float), mesg); + ok = cp && TIFFFetchFloatArray(tif, dp, (float*) cp); + break; + case TIFF_DOUBLE: + cp = CheckMalloc(tif, + dp->tdir_count * sizeof (double), mesg); + ok = cp && TIFFFetchDoubleArray(tif, dp, (double*) cp); + break; + case TIFF_ASCII: + case TIFF_UNDEFINED: /* bit of a cheat... */ + /* + * Some vendors write strings w/o the trailing + * NULL byte, so always append one just in case. + */ + cp = CheckMalloc(tif, dp->tdir_count+1, mesg); + if( (ok = (cp && TIFFFetchString(tif, dp, cp))) != 0 ) + cp[dp->tdir_count] = '\0'; /* XXX */ + break; + } + if (ok) { + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, dp->tdir_count, cp) + : TIFFSetField(tif, dp->tdir_tag, cp)); + } + if (cp != NULL) + _TIFFfree(cp); + } else if (CheckDirCount(tif, dp, 1)) { /* singleton value */ + switch (dp->tdir_type) { + case TIFF_BYTE: + case TIFF_SBYTE: + case TIFF_SHORT: + case TIFF_SSHORT: + /* + * If the tag is also acceptable as a LONG or SLONG + * then TIFFSetField will expect an uint32 parameter + * passed to it (through varargs). Thus, for machines + * where sizeof (int) != sizeof (uint32) we must do + * a careful check here. It's hard to say if this + * is worth optimizing. + * + * NB: We use TIFFFieldWithTag here knowing that + * it returns us the first entry in the table + * for the tag and that that entry is for the + * widest potential data type the tag may have. + */ + { TIFFDataType type = fip->field_type; + if (type != TIFF_LONG && type != TIFF_SLONG) { + uint16 v = (uint16) + TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v) + : TIFFSetField(tif, dp->tdir_tag, v)); + break; + } + } + /* fall thru... */ + case TIFF_LONG: + case TIFF_SLONG: + { uint32 v32 = + TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v32) + : TIFFSetField(tif, dp->tdir_tag, v32)); + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + case TIFF_FLOAT: + { float v = (dp->tdir_type == TIFF_FLOAT ? + TIFFFetchFloat(tif, dp) + : TIFFFetchRational(tif, dp)); + ok = (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v) + : TIFFSetField(tif, dp->tdir_tag, v)); + } + break; + case TIFF_DOUBLE: + { double v; + ok = (TIFFFetchDoubleArray(tif, dp, &v) && + (fip->field_passcount ? + TIFFSetField(tif, dp->tdir_tag, 1, &v) + : TIFFSetField(tif, dp->tdir_tag, v)) + ); + } + break; + case TIFF_ASCII: + case TIFF_UNDEFINED: /* bit of a cheat... */ + { char c[2]; + if( (ok = (TIFFFetchString(tif, dp, c) != 0)) != 0 ){ + c[1] = '\0'; /* XXX paranoid */ + ok = TIFFSetField(tif, dp->tdir_tag, c); + } + } + break; + } + } + return (ok); +} + +#define NITEMS(x) (sizeof (x) / sizeof (x[0])) +/* + * Fetch samples/pixel short values for + * the specified tag and verify that + * all values are the same. + */ +static int +TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, int* pl) +{ + int samples = tif->tif_dir.td_samplesperpixel; + int status = 0; + + if (CheckDirCount(tif, dir, (uint32) samples)) { + uint16 buf[10]; + uint16* v = buf; + + if (samples > NITEMS(buf)) + v = (uint16*) _TIFFmalloc(samples * sizeof (uint16)); + if (TIFFFetchShortArray(tif, dir, v)) { + int i; + for (i = 1; i < samples; i++) + if (v[i] != v[0]) { + TIFFError(tif->tif_name, + "Cannot handle different per-sample values for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + goto bad; + } + *pl = v[0]; + status = 1; + } + bad: + if (v != buf) + _TIFFfree((char*) v); + } + return (status); +} + +/* + * Fetch samples/pixel ANY values for + * the specified tag and verify that + * all values are the same. + */ +static int +TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl) +{ + int samples = (int) tif->tif_dir.td_samplesperpixel; + int status = 0; + + if (CheckDirCount(tif, dir, (uint32) samples)) { + double buf[10]; + double* v = buf; + + if (samples > NITEMS(buf)) + v = (double*) _TIFFmalloc(samples * sizeof (double)); + if (TIFFFetchAnyArray(tif, dir, v)) { + int i; + for (i = 1; i < samples; i++) + if (v[i] != v[0]) { + TIFFError(tif->tif_name, + "Cannot handle different per-sample values for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + goto bad; + } + *pl = v[0]; + status = 1; + } + bad: + if (v != buf) + _TIFFfree(v); + } + return (status); +} +#undef NITEMS + +/* + * Fetch a set of offsets or lengths. + * While this routine says "strips", + * in fact it's also used for tiles. + */ +static int +TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, long nstrips, uint32** lpp) +{ + register uint32* lp; + int status; + + if (!CheckDirCount(tif, dir, (uint32) nstrips)) + return (0); + /* + * Allocate space for strip information. + */ + if (*lpp == NULL && + (*lpp = (uint32 *)CheckMalloc(tif, + nstrips * sizeof (uint32), "for strip array")) == NULL) + return (0); + lp = *lpp; + if (dir->tdir_type == (int)TIFF_SHORT) { + /* + * Handle uint16->uint32 expansion. + */ + uint16* dp = (uint16*) CheckMalloc(tif, + dir->tdir_count* sizeof (uint16), "to fetch strip tag"); + if (dp == NULL) + return (0); + if( (status = TIFFFetchShortArray(tif, dir, dp)) != 0 ) { + register uint16* wp = dp; + while (nstrips-- > 0) + *lp++ = *wp++; + } + _TIFFfree((char*) dp); + } else + status = TIFFFetchLongArray(tif, dir, lp); + return (status); +} + +#define NITEMS(x) (sizeof (x) / sizeof (x[0])) +/* + * Fetch and set the ExtraSamples tag. + */ +static int +TIFFFetchExtraSamples(TIFF* tif, TIFFDirEntry* dir) +{ + uint16 buf[10]; + uint16* v = buf; + int status; + + if (dir->tdir_count > NITEMS(buf)) + v = (uint16*) _TIFFmalloc(dir->tdir_count * sizeof (uint16)); + if (dir->tdir_type == TIFF_BYTE) + status = TIFFFetchByteArray(tif, dir, v); + else + status = TIFFFetchShortArray(tif, dir, v); + if (status) + status = TIFFSetField(tif, dir->tdir_tag, dir->tdir_count, v); + if (v != buf) + _TIFFfree((char*) v); + return (status); +} +#undef NITEMS + +#ifdef COLORIMETRY_SUPPORT +/* + * Fetch and set the RefBlackWhite tag. + */ +static int +TIFFFetchRefBlackWhite(TIFF* tif, TIFFDirEntry* dir) +{ + static const char mesg[] = "for \"ReferenceBlackWhite\" array"; + char* cp; + int ok; + + if (dir->tdir_type == TIFF_RATIONAL) + return (TIFFFetchNormalTag(tif, dir)); + /* + * Handle LONG's for backward compatibility. + */ + cp = CheckMalloc(tif, dir->tdir_count * sizeof (uint32), mesg); + if( (ok = (cp && TIFFFetchLongArray(tif, dir, (uint32*) cp))) != 0) { + float* fp = (float*) + CheckMalloc(tif, dir->tdir_count * sizeof (float), mesg); + if( (ok = (fp != NULL)) != 0 ) { + uint32 i; + for (i = 0; i < dir->tdir_count; i++) + fp[i] = (float)((uint32*) cp)[i]; + ok = TIFFSetField(tif, dir->tdir_tag, fp); + _TIFFfree((char*) fp); + } + } + if (cp) + _TIFFfree(cp); + return (ok); +} +#endif + +/* + * Replace a single strip (tile) of uncompressed data by + * multiple strips (tiles), each approximately 8Kbytes. + * This is useful for dealing with large images or + * for dealing with machines with a limited amount + * memory. + */ +static void +ChopUpSingleUncompressedStrip(TIFF* tif) +{ + register TIFFDirectory *td = &tif->tif_dir; + uint32 bytecount = td->td_stripbytecount[0]; + uint32 offset = td->td_stripoffset[0]; + tsize_t rowbytes = TIFFVTileSize(tif, 1), stripbytes; + tstrip_t strip, nstrips, rowsperstrip; + uint32* newcounts; + uint32* newoffsets; + + /* + * Make the rows hold at least one + * scanline, but fill 8k if possible. + */ + if (rowbytes > 8192) { + stripbytes = rowbytes; + rowsperstrip = 1; + } else { + rowsperstrip = 8192 / rowbytes; + stripbytes = rowbytes * rowsperstrip; + } + /* never increase the number of strips in an image */ + if (rowsperstrip >= td->td_rowsperstrip) + return; + nstrips = (tstrip_t) TIFFhowmany(bytecount, stripbytes); + newcounts = (uint32*) CheckMalloc(tif, nstrips * sizeof (uint32), + "for chopped \"StripByteCounts\" array"); + newoffsets = (uint32*) CheckMalloc(tif, nstrips * sizeof (uint32), + "for chopped \"StripOffsets\" array"); + if (newcounts == NULL || newoffsets == NULL) { + /* + * Unable to allocate new strip information, give + * up and use the original one strip information. + */ + if (newcounts != NULL) + _TIFFfree(newcounts); + if (newoffsets != NULL) + _TIFFfree(newoffsets); + return; + } + /* + * Fill the strip information arrays with + * new bytecounts and offsets that reflect + * the broken-up format. + */ + for (strip = 0; strip < nstrips; strip++) { + if (stripbytes > (tsize_t) bytecount) + stripbytes = bytecount; + newcounts[strip] = stripbytes; + newoffsets[strip] = offset; + offset += stripbytes; + bytecount -= stripbytes; + } + /* + * Replace old single strip info with multi-strip info. + */ + td->td_stripsperimage = td->td_nstrips = nstrips; + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); + + _TIFFfree(td->td_stripbytecount); + _TIFFfree(td->td_stripoffset); + td->td_stripbytecount = newcounts; + td->td_stripoffset = newoffsets; +} diff --git a/freeimage241/Source/LibTIFF/tif_dirwrite.c b/freeimage241/Source/LibTIFF/tif_dirwrite.c new file mode 100644 index 0000000..2cf02ff --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_dirwrite.c @@ -0,0 +1,1021 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_dirwrite.c,v 1.0 2001-04-13 00:42:31+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Write Support Routines. + */ +#include "tiffiop.h" + +#if HAVE_IEEEFP +#define TIFFCvtNativeToIEEEFloat(tif, n, fp) +#define TIFFCvtNativeToIEEEDouble(tif, n, dp) +#else +extern void TIFFCvtNativeToIEEEFloat(TIFF*, uint32, float*); +extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*); +#endif + +static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*); +static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32); +static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*); +static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*); +static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*); +static int TIFFWriteShortTable(TIFF*, ttag_t, TIFFDirEntry*, uint32, uint16**); +static int TIFFWriteShortArray(TIFF*, + TIFFDataType, ttag_t, TIFFDirEntry*, uint32, uint16*); +static int TIFFWriteLongArray(TIFF *, + TIFFDataType, ttag_t, TIFFDirEntry*, uint32, uint32*); +static int TIFFWriteRationalArray(TIFF *, + TIFFDataType, ttag_t, TIFFDirEntry*, uint32, float*); +static int TIFFWriteFloatArray(TIFF *, + TIFFDataType, ttag_t, TIFFDirEntry*, uint32, float*); +static int TIFFWriteDoubleArray(TIFF *, + TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*); +static int TIFFWriteByteArray(TIFF*, TIFFDirEntry*, char*); +static int TIFFWriteAnyArray(TIFF*, + TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*); +#ifdef COLORIMETRY_SUPPORT +static int TIFFWriteTransferFunction(TIFF*, TIFFDirEntry*); +#endif +#ifdef CMYK_SUPPORT +static int TIFFWriteInkNames(TIFF*, TIFFDirEntry*); +#endif +static int TIFFWriteData(TIFF*, TIFFDirEntry*, char*); +static int TIFFLinkDirectory(TIFF*); + +#define WriteRationalPair(type, tag1, v1, tag2, v2) { \ + if (!TIFFWriteRational(tif, type, tag1, dir, v1)) \ + goto bad; \ + if (!TIFFWriteRational(tif, type, tag2, dir+1, v2)) \ + goto bad; \ + dir++; \ +} +#define TIFFWriteRational(tif, type, tag, dir, v) \ + TIFFWriteRationalArray((tif), (type), (tag), (dir), 1, &(v)) +#ifndef TIFFWriteRational +static int TIFFWriteRational(TIFF*, + TIFFDataType, ttag_t, TIFFDirEntry*, float); +#endif + +/* + * Write the contents of the current directory + * to the specified file. This routine doesn't + * handle overwriting a directory with auxiliary + * storage that's been changed. + */ +int +TIFFWriteDirectory(TIFF* tif) +{ + uint16 dircount; + toff_t diroff; + ttag_t tag; + uint32 nfields; + tsize_t dirsize; + char* data; + TIFFDirEntry* dir; + TIFFDirectory* td; + u_long b, fields[FIELD_SETLONGS]; + int fi, nfi; + + if (tif->tif_mode == O_RDONLY) + return (1); + /* + * Clear write state so that subsequent images with + * different characteristics get the right buffers + * setup for them. + */ + if (tif->tif_flags & TIFF_POSTENCODE) { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) { + TIFFError(tif->tif_name, + "Error post-encoding before directory write"); + return (0); + } + } + (*tif->tif_close)(tif); /* shutdown encoder */ + /* + * Flush any data that might have been written + * by the compression close+cleanup routines. + */ + if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) { + TIFFError(tif->tif_name, + "Error flushing data before directory write"); + return (0); + } + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + tif->tif_rawcc = 0; + tif->tif_rawdatasize = 0; + } + tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); + + td = &tif->tif_dir; + /* + * Size the directory so that we can calculate + * offsets for the data items that aren't kept + * in-place in each field. + */ + nfields = 0; + for (b = 0; b <= FIELD_LAST; b++) + if (TIFFFieldSet(tif, b)) + nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); + dirsize = nfields * sizeof (TIFFDirEntry); + data = (char*) _TIFFmalloc(dirsize); + if (data == NULL) { + TIFFError(tif->tif_name, + "Cannot write directory, out of space"); + return (0); + } + /* + * Directory hasn't been placed yet, put + * it at the end of the file and link it + * into the existing directory structure. + */ + if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) + goto bad; + tif->tif_dataoff = (toff_t)( + tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); + if (tif->tif_dataoff & 1) + tif->tif_dataoff++; + (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); + tif->tif_curdir++; + dir = (TIFFDirEntry*) data; + /* + * Setup external form of directory + * entries and write data items. + */ + _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); + /* + * Write out ExtraSamples tag only if + * extra samples are present in the data. + */ + if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { + ResetFieldBit(fields, FIELD_EXTRASAMPLES); + nfields--; + dirsize -= sizeof (TIFFDirEntry); + } /*XXX*/ + for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { + const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; + if (!FieldSet(fields, fip->field_bit)) + continue; + switch (fip->field_bit) { + case FIELD_STRIPOFFSETS: + /* + * We use one field bit for both strip and tile + * offsets, and so must be careful in selecting + * the appropriate field descriptor (so that tags + * are written in sorted order). + */ + tag = isTiled(tif) ? + TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS; + if (tag != fip->field_tag) + continue; + if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir, + (uint32) td->td_nstrips, td->td_stripoffset)) + goto bad; + break; + case FIELD_STRIPBYTECOUNTS: + /* + * We use one field bit for both strip and tile + * byte counts, and so must be careful in selecting + * the appropriate field descriptor (so that tags + * are written in sorted order). + */ + tag = isTiled(tif) ? + TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS; + if (tag != fip->field_tag) + continue; + if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir, + (uint32) td->td_nstrips, td->td_stripbytecount)) + goto bad; + break; + case FIELD_ROWSPERSTRIP: + TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, + dir, td->td_rowsperstrip); + break; + case FIELD_COLORMAP: + if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, + 3, td->td_colormap)) + goto bad; + break; + case FIELD_IMAGEDIMENSIONS: + TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, + dir++, td->td_imagewidth); + TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, + dir, td->td_imagelength); + break; + case FIELD_TILEDIMENSIONS: + TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, + dir++, td->td_tilewidth); + TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, + dir, td->td_tilelength); + break; + case FIELD_POSITION: + WriteRationalPair(TIFF_RATIONAL, + TIFFTAG_XPOSITION, td->td_xposition, + TIFFTAG_YPOSITION, td->td_yposition); + break; + case FIELD_RESOLUTION: + WriteRationalPair(TIFF_RATIONAL, + TIFFTAG_XRESOLUTION, td->td_xresolution, + TIFFTAG_YRESOLUTION, td->td_yresolution); + break; + case FIELD_BITSPERSAMPLE: + case FIELD_MINSAMPLEVALUE: + case FIELD_MAXSAMPLEVALUE: + case FIELD_SAMPLEFORMAT: + if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) + goto bad; + break; + case FIELD_SMINSAMPLEVALUE: + case FIELD_SMAXSAMPLEVALUE: + if (!TIFFWritePerSampleAnys(tif, + _TIFFSampleToTagType(tif), fip->field_tag, dir)) + goto bad; + break; + case FIELD_PAGENUMBER: + case FIELD_HALFTONEHINTS: +#ifdef YCBCR_SUPPORT + case FIELD_YCBCRSUBSAMPLING: +#endif +#ifdef CMYK_SUPPORT + case FIELD_DOTRANGE: +#endif + if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) + goto bad; + break; +#ifdef CMYK_SUPPORT + case FIELD_INKNAMES: + if (!TIFFWriteInkNames(tif, dir)) + goto bad; + break; +#endif +#ifdef COLORIMETRY_SUPPORT + case FIELD_TRANSFERFUNCTION: + if (!TIFFWriteTransferFunction(tif, dir)) + goto bad; + break; +#endif +#if SUBIFD_SUPPORT + case FIELD_SUBIFD: + if (!TIFFWriteNormalTag(tif, dir, fip)) + goto bad; + /* + * Total hack: if this directory includes a SubIFD + * tag then force the next directories to be + * written as ``sub directories'' of this one. This + * is used to write things like thumbnails and + * image masks that one wants to keep out of the + * normal directory linkage access mechanism. + */ + if (dir->tdir_count > 0) { + tif->tif_flags |= TIFF_INSUBIFD; + tif->tif_nsubifd = (uint16) dir->tdir_count; + if (dir->tdir_count > 1) + tif->tif_subifdoff = dir->tdir_offset; + else + tif->tif_subifdoff = (uint32)( + tif->tif_diroff + + sizeof (uint16) + + ((char*)&dir->tdir_offset-data)); + } + break; +#endif + default: + if (!TIFFWriteNormalTag(tif, dir, fip)) + goto bad; + break; + } + dir++; + ResetFieldBit(fields, fip->field_bit); + } + /* + * Write directory. + */ + dircount = (uint16) nfields; + diroff = (uint32) tif->tif_nextdiroff; + if (tif->tif_flags & TIFF_SWAB) { + /* + * The file's byte order is opposite to the + * native machine architecture. We overwrite + * the directory information with impunity + * because it'll be released below after we + * write it to the file. Note that all the + * other tag construction routines assume that + * we do this byte-swapping; i.e. they only + * byte-swap indirect data. + */ + for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { + TIFFSwabArrayOfShort(&dir->tdir_tag, 2); + TIFFSwabArrayOfLong(&dir->tdir_count, 2); + } + dircount = (uint16) nfields; + TIFFSwabShort(&dircount); + TIFFSwabLong(&diroff); + } + (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); + if (!WriteOK(tif, &dircount, sizeof (dircount))) { + TIFFError(tif->tif_name, "Error writing directory count"); + goto bad; + } + if (!WriteOK(tif, data, dirsize)) { + TIFFError(tif->tif_name, "Error writing directory contents"); + goto bad; + } + if (!WriteOK(tif, &diroff, sizeof (diroff))) { + TIFFError(tif->tif_name, "Error writing directory link"); + goto bad; + } + TIFFFreeDirectory(tif); + _TIFFfree(data); + tif->tif_flags &= ~TIFF_DIRTYDIRECT; + (*tif->tif_cleanup)(tif); + + /* + * Reset directory-related state for subsequent + * directories. + */ + TIFFCreateDirectory(tif); + return (1); +bad: + _TIFFfree(data); + return (0); +} +#undef WriteRationalPair + +/* + * Process tags that are not special cased. + */ +static int +TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip) +{ + u_short wc = (u_short) fip->field_writecount; + uint32 wc2; + + dir->tdir_tag = (uint16) fip->field_tag; + dir->tdir_type = (u_short) fip->field_type; + dir->tdir_count = wc; +#define WRITEF(x,y) x(tif, fip->field_type, fip->field_tag, dir, wc, y) + switch (fip->field_type) { + case TIFF_SHORT: + case TIFF_SSHORT: + if (wc > 1) { + uint16* wp; + if (wc == (u_short) TIFF_VARIABLE) + TIFFGetField(tif, fip->field_tag, &wc, &wp); + else + TIFFGetField(tif, fip->field_tag, &wp); + if (!WRITEF(TIFFWriteShortArray, wp)) + return (0); + } else { + uint16 sv; + TIFFGetField(tif, fip->field_tag, &sv); + dir->tdir_offset = + TIFFInsertData(tif, dir->tdir_type, sv); + } + break; + case TIFF_LONG: + case TIFF_SLONG: + if (wc > 1) { + uint32* lp; + if (wc == (u_short) TIFF_VARIABLE) + TIFFGetField(tif, fip->field_tag, &wc, &lp); + else + TIFFGetField(tif, fip->field_tag, &lp); + if (!WRITEF(TIFFWriteLongArray, lp)) + return (0); + } else { + /* XXX handle LONG->SHORT conversion */ + TIFFGetField(tif, fip->field_tag, &dir->tdir_offset); + } + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + if (wc > 1) { + float* fp; + if (wc == (u_short) TIFF_VARIABLE) + TIFFGetField(tif, fip->field_tag, &wc, &fp); + else + TIFFGetField(tif, fip->field_tag, &fp); + if (!WRITEF(TIFFWriteRationalArray, fp)) + return (0); + } else { + float fv; + TIFFGetField(tif, fip->field_tag, &fv); + if (!WRITEF(TIFFWriteRationalArray, &fv)) + return (0); + } + break; + case TIFF_FLOAT: + if (wc > 1) { + float* fp; + if (wc == (u_short) TIFF_VARIABLE) + TIFFGetField(tif, fip->field_tag, &wc, &fp); + else + TIFFGetField(tif, fip->field_tag, &fp); + if (!WRITEF(TIFFWriteFloatArray, fp)) + return (0); + } else { + float fv; + TIFFGetField(tif, fip->field_tag, &fv); + if (!WRITEF(TIFFWriteFloatArray, &fv)) + return (0); + } + break; + case TIFF_DOUBLE: + if (wc > 1) { + double* dp; + if (wc == (u_short) TIFF_VARIABLE) + TIFFGetField(tif, fip->field_tag, &wc, &dp); + else + TIFFGetField(tif, fip->field_tag, &dp); + if (!WRITEF(TIFFWriteDoubleArray, dp)) + return (0); + } else { + double dv; + TIFFGetField(tif, fip->field_tag, &dv); + if (!WRITEF(TIFFWriteDoubleArray, &dv)) + return (0); + } + break; + case TIFF_ASCII: + { char* cp; + TIFFGetField(tif, fip->field_tag, &cp); + dir->tdir_count = (uint32) (strlen(cp) + 1); + if (!TIFFWriteByteArray(tif, dir, cp)) + return (0); + } + break; + + /* added based on patch request from MARTIN.MCBRIDE.MM@agfa.co.uk, + correctness not verified (FW, 99/08) */ + case TIFF_BYTE: + case TIFF_SBYTE: + if (wc > 1) { + char* cp; + if (wc == (u_short) TIFF_VARIABLE) { + TIFFGetField(tif, fip->field_tag, &wc, &cp); + dir->tdir_count = wc; + } else + TIFFGetField(tif, fip->field_tag, &cp); + if (!TIFFWriteByteArray(tif, dir, cp)) + return (0); + } else { + char cv; + TIFFGetField(tif, fip->field_tag, &cv); + if (!TIFFWriteByteArray(tif, dir, &cv)) + return (0); + } + break; + + case TIFF_UNDEFINED: + { char* cp; + if (wc == (u_short) TIFF_VARIABLE) { + TIFFGetField(tif, fip->field_tag, &wc, &cp); + dir->tdir_count = wc; + } else if (wc == (u_short) TIFF_VARIABLE2) { + TIFFGetField(tif, fip->field_tag, &wc2, &cp); + dir->tdir_count = wc2; + } else + TIFFGetField(tif, fip->field_tag, &cp); + if (!TIFFWriteByteArray(tif, dir, cp)) + return (0); + } + break; + + case TIFF_NOTYPE: + break; + } + return (1); +} +#undef WRITEF + +/* + * Setup a directory entry with either a SHORT + * or LONG type according to the value. + */ +static void +TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v) +{ + dir->tdir_tag = (uint16) tag; + dir->tdir_count = 1; + if (v > 0xffffL) { + dir->tdir_type = (short) TIFF_LONG; + dir->tdir_offset = v; + } else { + dir->tdir_type = (short) TIFF_SHORT; + dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v); + } +} +#undef MakeShortDirent + +#ifndef TIFFWriteRational +/* + * Setup a RATIONAL directory entry and + * write the associated indirect value. + */ +static int +TIFFWriteRational(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, float v) +{ + return (TIFFWriteRationalArray(tif, type, tag, dir, 1, &v)); +} +#endif + +#define NITEMS(x) (sizeof (x) / sizeof (x[0])) +/* + * Setup a directory entry that references a + * samples/pixel array of SHORT values and + * (potentially) write the associated indirect + * values. + */ +static int +TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir) +{ + uint16 buf[10], v; + uint16* w = buf; + int i, status, samples = tif->tif_dir.td_samplesperpixel; + + if (samples > NITEMS(buf)) + w = (uint16*) _TIFFmalloc(samples * sizeof (uint16)); + TIFFGetField(tif, tag, &v); + for (i = 0; i < samples; i++) + w[i] = v; + status = TIFFWriteShortArray(tif, TIFF_SHORT, tag, dir, samples, w); + if (w != buf) + _TIFFfree((char*) w); + return (status); +} + +/* + * Setup a directory entry that references a samples/pixel array of ``type'' + * values and (potentially) write the associated indirect values. The source + * data from TIFFGetField() for the specified tag must be returned as double. + */ +static int +TIFFWritePerSampleAnys(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir) +{ + double buf[10], v; + double* w = buf; + int i, status; + int samples = (int) tif->tif_dir.td_samplesperpixel; + + if (samples > NITEMS(buf)) + w = (double*) _TIFFmalloc(samples * sizeof (double)); + TIFFGetField(tif, tag, &v); + for (i = 0; i < samples; i++) + w[i] = v; + status = TIFFWriteAnyArray(tif, type, tag, dir, samples, w); + if (w != buf) + _TIFFfree(w); + return (status); +} +#undef NITEMS + +/* + * Setup a pair of shorts that are returned by + * value, rather than as a reference to an array. + */ +static int +TIFFSetupShortPair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir) +{ + uint16 v[2]; + + TIFFGetField(tif, tag, &v[0], &v[1]); + return (TIFFWriteShortArray(tif, TIFF_SHORT, tag, dir, 2, v)); +} + +/* + * Setup a directory entry for an NxM table of shorts, + * where M is known to be 2**bitspersample, and write + * the associated indirect data. + */ +static int +TIFFWriteShortTable(TIFF* tif, + ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16** table) +{ + uint32 i, off; + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) TIFF_SHORT; + /* XXX -- yech, fool TIFFWriteData */ + dir->tdir_count = (uint32) (1L<tif_dir.td_bitspersample); + off = tif->tif_dataoff; + for (i = 0; i < n; i++) + if (!TIFFWriteData(tif, dir, (char *)table[i])) + return (0); + dir->tdir_count *= n; + dir->tdir_offset = off; + return (1); +} + +/* + * Write/copy data associated with an ASCII or opaque tag value. + */ +static int +TIFFWriteByteArray(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + if (dir->tdir_count > 4) { + if (!TIFFWriteData(tif, dir, cp)) + return (0); + } else + _TIFFmemcpy(&dir->tdir_offset, cp, dir->tdir_count); + return (1); +} + +/* + * Setup a directory entry of an array of SHORT + * or SSHORT and write the associated indirect values. + */ +static int +TIFFWriteShortArray(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16* v) +{ + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) type; + dir->tdir_count = n; + if (n <= 2) { + if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) { + dir->tdir_offset = (uint32) ((long) v[0] << 16); + if (n == 2) + dir->tdir_offset |= v[1] & 0xffff; + } else { + dir->tdir_offset = v[0] & 0xffff; + if (n == 2) + dir->tdir_offset |= (long) v[1] << 16; + } + return (1); + } else + return (TIFFWriteData(tif, dir, (char*) v)); +} + +/* + * Setup a directory entry of an array of LONG + * or SLONG and write the associated indirect values. + */ +static int +TIFFWriteLongArray(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint32* v) +{ + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) type; + dir->tdir_count = n; + if (n == 1) { + dir->tdir_offset = v[0]; + return (1); + } else + return (TIFFWriteData(tif, dir, (char*) v)); +} + +/* + * Setup a directory entry of an array of RATIONAL + * or SRATIONAL and write the associated indirect values. + */ +static int +TIFFWriteRationalArray(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, float* v) +{ + uint32 i; + uint32* t; + int status; + + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) type; + dir->tdir_count = n; + t = (uint32*) _TIFFmalloc(2*n * sizeof (uint32)); + for (i = 0; i < n; i++) { + float fv = v[i]; + int sign = 1; + uint32 den; + + if (fv < 0) { + if (type == TIFF_RATIONAL) { + TIFFWarning(tif->tif_name, + "\"%s\": Information lost writing value (%g) as (unsigned) RATIONAL", + _TIFFFieldWithTag(tif,tag)->field_name, fv); + fv = 0; + } else + fv = -fv, sign = -1; + } + den = 1L; + if (fv > 0) { + while (fv < 1L<<(31-3) && den < 1L<<(31-3)) + fv *= 1<<3, den *= 1L<<3; + } + t[2*i+0] = (uint32) (sign * (fv + 0.5)); + t[2*i+1] = den; + } + status = TIFFWriteData(tif, dir, (char *)t); + _TIFFfree((char*) t); + return (status); +} + +static int +TIFFWriteFloatArray(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, float* v) +{ + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) type; + dir->tdir_count = n; + TIFFCvtNativeToIEEEFloat(tif, n, v); + if (n == 1) { + dir->tdir_offset = *(uint32*) &v[0]; + return (1); + } else + return (TIFFWriteData(tif, dir, (char*) v)); +} + +static int +TIFFWriteDoubleArray(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v) +{ + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) type; + dir->tdir_count = n; + TIFFCvtNativeToIEEEDouble(tif, n, v); + return (TIFFWriteData(tif, dir, (char*) v)); +} + +/* + * Write an array of ``type'' values for a specified tag (i.e. this is a tag + * which is allowed to have different types, e.g. SMaxSampleType). + * Internally the data values are represented as double since a double can + * hold any of the TIFF tag types (yes, this should really be an abstract + * type tany_t for portability). The data is converted into the specified + * type in a temporary buffer and then handed off to the appropriate array + * writer. + */ +static int +TIFFWriteAnyArray(TIFF* tif, + TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v) +{ + char buf[10 * sizeof(double)]; + char* w = buf; + int i, status = 0; + + if (n * tiffDataWidth[type] > sizeof buf) + w = (char*) _TIFFmalloc(n * tiffDataWidth[type]); + switch (type) { + case TIFF_BYTE: + { uint8* bp = (uint8*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (uint8) v[i]; + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) type; + dir->tdir_count = n; + if (!TIFFWriteByteArray(tif, dir, (char*) bp)) + goto out; + } + break; + case TIFF_SBYTE: + { int8* bp = (int8*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (int8) v[i]; + dir->tdir_tag = (uint16) tag; + dir->tdir_type = (short) type; + dir->tdir_count = n; + if (!TIFFWriteByteArray(tif, dir, (char*) bp)) + goto out; + } + break; + case TIFF_SHORT: + { uint16* bp = (uint16*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (uint16) v[i]; + if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp)) + goto out; + } + break; + case TIFF_SSHORT: + { int16* bp = (int16*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (int16) v[i]; + if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp)) + goto out; + } + break; + case TIFF_LONG: + { uint32* bp = (uint32*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (uint32) v[i]; + if (!TIFFWriteLongArray(tif, type, tag, dir, n, bp)) + goto out; + } + break; + case TIFF_SLONG: + { int32* bp = (int32*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (int32) v[i]; + if (!TIFFWriteLongArray(tif, type, tag, dir, n, (uint32*) bp)) + goto out; + } + break; + case TIFF_FLOAT: + { float* bp = (float*) w; + for (i = 0; i < (int) n; i++) + bp[i] = (float) v[i]; + if (!TIFFWriteFloatArray(tif, type, tag, dir, n, bp)) + goto out; + } + break; + case TIFF_DOUBLE: + return (TIFFWriteDoubleArray(tif, type, tag, dir, n, v)); + default: + /* TIFF_NOTYPE */ + /* TIFF_ASCII */ + /* TIFF_UNDEFINED */ + /* TIFF_RATIONAL */ + /* TIFF_SRATIONAL */ + goto out; + } + status = 1; + out: + if (w != buf) + _TIFFfree(w); + return (status); +} + +#ifdef COLORIMETRY_SUPPORT +static int +TIFFWriteTransferFunction(TIFF* tif, TIFFDirEntry* dir) +{ + TIFFDirectory* td = &tif->tif_dir; + tsize_t n = (1L<td_bitspersample) * sizeof (uint16); + uint16** tf = td->td_transferfunction; + int ncols; + + /* + * Check if the table can be written as a single column, + * or if it must be written as 3 columns. Note that we + * write a 3-column tag if there are 2 samples/pixel and + * a single column of data won't suffice--hmm. + */ + switch (td->td_samplesperpixel - td->td_extrasamples) { + default: if (_TIFFmemcmp(tf[0], tf[2], n)) { ncols = 3; break; } + case 2: if (_TIFFmemcmp(tf[0], tf[1], n)) { ncols = 3; break; } + case 1: case 0: ncols = 1; + } + return (TIFFWriteShortTable(tif, + TIFFTAG_TRANSFERFUNCTION, dir, ncols, tf)); +} +#endif + +#ifdef CMYK_SUPPORT +static int +TIFFWriteInkNames(TIFF* tif, TIFFDirEntry* dir) +{ + TIFFDirectory* td = &tif->tif_dir; + + dir->tdir_tag = TIFFTAG_INKNAMES; + dir->tdir_type = (short) TIFF_ASCII; + dir->tdir_count = td->td_inknameslen; + return (TIFFWriteByteArray(tif, dir, td->td_inknames)); +} +#endif + +/* + * Write a contiguous directory item. + */ +static int +TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp) +{ + tsize_t cc; + + if (tif->tif_flags & TIFF_SWAB) { + switch (dir->tdir_type) { + case TIFF_SHORT: + case TIFF_SSHORT: + TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count); + break; + case TIFF_LONG: + case TIFF_SLONG: + case TIFF_FLOAT: + TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count); + break; + case TIFF_RATIONAL: + case TIFF_SRATIONAL: + TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count); + break; + case TIFF_DOUBLE: + TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count); + break; + } + } + dir->tdir_offset = tif->tif_dataoff; + cc = dir->tdir_count * tiffDataWidth[dir->tdir_type]; + if (SeekOK(tif, dir->tdir_offset) && + WriteOK(tif, cp, cc)) { + tif->tif_dataoff += (cc + 1) & ~1; + return (1); + } + TIFFError(tif->tif_name, "Error writing data for field \"%s\"", + _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name); + return (0); +} + +/* + * Link the current directory into the + * directory chain for the file. + */ +static int +TIFFLinkDirectory(TIFF* tif) +{ + static const char module[] = "TIFFLinkDirectory"; + toff_t nextdir; + toff_t diroff, off; + + tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1; + diroff = tif->tif_diroff; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&diroff); +#if SUBIFD_SUPPORT + if (tif->tif_flags & TIFF_INSUBIFD) { + (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET); + if (!WriteOK(tif, &diroff, sizeof (diroff))) { + TIFFError(module, + "%s: Error writing SubIFD directory link", + tif->tif_name); + return (0); + } + /* + * Advance to the next SubIFD or, if this is + * the last one configured, revert back to the + * normal directory linkage. + */ + if (--tif->tif_nsubifd) + tif->tif_subifdoff += sizeof (diroff); + else + tif->tif_flags &= ~TIFF_INSUBIFD; + return (1); + } +#endif + if (tif->tif_header.tiff_diroff == 0) { + /* + * First directory, overwrite offset in header. + */ + tif->tif_header.tiff_diroff = tif->tif_diroff; +#define HDROFF(f) ((toff_t) &(((TIFFHeader*) 0)->f)) + (void) TIFFSeekFile(tif, HDROFF(tiff_diroff), SEEK_SET); + if (!WriteOK(tif, &diroff, sizeof (diroff))) { + TIFFError(tif->tif_name, "Error writing TIFF header"); + return (0); + } + return (1); + } + /* + * Not the first directory, search to the last and append. + */ + nextdir = tif->tif_header.tiff_diroff; + do { + uint16 dircount; + + if (!SeekOK(tif, nextdir) || + !ReadOK(tif, &dircount, sizeof (dircount))) { + TIFFError(module, "Error fetching directory count"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&dircount); + (void) TIFFSeekFile(tif, + dircount * sizeof (TIFFDirEntry), SEEK_CUR); + if (!ReadOK(tif, &nextdir, sizeof (nextdir))) { + TIFFError(module, "Error fetching directory link"); + return (0); + } + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabLong(&nextdir); + } while (nextdir != 0); + off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */ + (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET); + if (!WriteOK(tif, &diroff, sizeof (diroff))) { + TIFFError(module, "Error writing directory link"); + return (0); + } + return (1); +} diff --git a/freeimage241/Source/LibTIFF/tif_dumpmode.c b/freeimage241/Source/LibTIFF/tif_dumpmode.c new file mode 100644 index 0000000..b3d1de7 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_dumpmode.c @@ -0,0 +1,118 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_dumpmode.c,v 1.0 2001-04-13 00:42:31+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * "Null" Compression Algorithm Support. + */ +#include "tiffiop.h" +#include + +/* + * Encode a hunk of pixels. + */ +static int +DumpModeEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s) +{ + (void) s; + while (cc > 0) { + tsize_t n; + + n = cc; + if (tif->tif_rawcc + n > tif->tif_rawdatasize) + n = tif->tif_rawdatasize - tif->tif_rawcc; + + assert( n > 0 ); + + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != pp) + _TIFFmemcpy(tif->tif_rawcp, pp, n); + tif->tif_rawcp += n; + tif->tif_rawcc += n; + pp += n; + cc -= n; + if (tif->tif_rawcc >= tif->tif_rawdatasize && + !TIFFFlushData1(tif)) + return (-1); + } + return (1); +} + +/* + * Decode a hunk of pixels. + */ +static int +DumpModeDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + (void) s; + if (tif->tif_rawcc < cc) { + TIFFError(tif->tif_name, + "DumpModeDecode: Not enough data for scanline %d", + tif->tif_row); + return (0); + } + /* + * Avoid copy if client has setup raw + * data buffer to avoid extra copy. + */ + if (tif->tif_rawcp != buf) + _TIFFmemcpy(buf, tif->tif_rawcp, cc); + tif->tif_rawcp += cc; + tif->tif_rawcc -= cc; + return (1); +} + +/* + * Seek forwards nrows in the current strip. + */ +static int +DumpModeSeek(TIFF* tif, uint32 nrows) +{ + tif->tif_rawcp += nrows * tif->tif_scanlinesize; + tif->tif_rawcc -= nrows * tif->tif_scanlinesize; + return (1); +} + +/* + * Initialize dump mode. + */ +int +TIFFInitDumpMode(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = DumpModeDecode; + tif->tif_decodestrip = DumpModeDecode; + tif->tif_decodetile = DumpModeDecode; + tif->tif_encoderow = DumpModeEncode; + tif->tif_encodestrip = DumpModeEncode; + tif->tif_encodetile = DumpModeEncode; + tif->tif_seek = DumpModeSeek; + return (1); +} diff --git a/freeimage241/Source/LibTIFF/tif_error.c b/freeimage241/Source/LibTIFF/tif_error.c new file mode 100644 index 0000000..12e977e --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_error.c @@ -0,0 +1,49 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_error.c,v 1.0 2001-04-13 00:42:31+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +TIFFErrorHandler +TIFFSetErrorHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFerrorHandler; + _TIFFerrorHandler = handler; + return (prev); +} + +void +TIFFError(const char* module, const char* fmt, ...) +{ + if (_TIFFerrorHandler) { + va_list ap; + va_start(ap, fmt); + (*_TIFFerrorHandler)(module, fmt, ap); + va_end(ap); + } +} diff --git a/freeimage241/Source/LibTIFF/tif_fax3.c b/freeimage241/Source/LibTIFF/tif_fax3.c new file mode 100644 index 0000000..d0cc302 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_fax3.c @@ -0,0 +1,1552 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_fax3.c,v 1.0 2001-04-13 00:42:31+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef CCITT_SUPPORT +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Compression Support. + * + * This file contains support for decoding and encoding TIFF + * compression algorithms 2, 3, 4, and 32771. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tif_fax3.h" +#define G3CODES +#include "t4.h" +#include +#include + +/* + * NB: define PURIFY if you're using purify and you want + * to avoid some harmless array bounds complaints that + * can happen in the _TIFFFax3fillruns routine. + */ + +/* + * Compression+decompression state blocks are + * derived from this ``base state'' block. + */ +typedef struct { + int rw_mode; /* O_RDONLY for decode, else encode */ + int mode; /* operating mode */ + uint32 rowbytes; /* bytes in a decoded scanline */ + uint32 rowpixels; /* pixels in a scanline */ + + uint16 cleanfaxdata; /* CleanFaxData tag */ + uint32 badfaxrun; /* BadFaxRun tag */ + uint32 badfaxlines; /* BadFaxLines tag */ + uint32 groupoptions; /* Group 3/4 options tag */ + uint32 recvparams; /* encoded Class 2 session params */ + char* subaddress; /* subaddress string */ + uint32 recvtime; /* time spent receiving (secs) */ + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} Fax3BaseState; +#define Fax3State(tif) ((Fax3BaseState*) (tif)->tif_data) + +typedef struct { + Fax3BaseState b; + const u_char* bitmap; /* bit reversal table */ + uint32 data; /* current i/o byte/word */ + int bit; /* current i/o bit in byte */ + int EOLcnt; /* count of EOL codes recognized */ + TIFFFaxFillFunc fill; /* fill routine */ + uint32* runs; /* b&w runs for current/previous row */ + uint32* refruns; /* runs for reference line */ + uint32* curruns; /* runs for current line */ +} Fax3DecodeState; +#define DecoderState(tif) ((Fax3DecodeState*) Fax3State(tif)) + +typedef enum { G3_1D, G3_2D } Ttag; +typedef struct { + Fax3BaseState b; + int data; /* current i/o byte */ + int bit; /* current i/o bit in byte */ + Ttag tag; /* encoding state */ + u_char* refline; /* reference line for 2d decoding */ + int k; /* #rows left that can be 2d encoded */ + int maxk; /* max #rows that can be 2d encoded */ +} Fax3EncodeState; +#define EncoderState(tif) ((Fax3EncodeState*) Fax3State(tif)) + +#define is2DEncoding(sp) \ + (sp->b.groupoptions & GROUP3OPT_2DENCODING) +#define isAligned(p,t) ((((u_long)(p)) & (sizeof (t)-1)) == 0) + +/* + * Group 3 and Group 4 Decoding. + */ + +/* + * These macros glue the TIFF library state to + * the state expected by Frank's decoder. + */ +#define DECLARE_STATE(tif, sp, mod) \ + static const char module[] = mod; \ + Fax3DecodeState* sp = DecoderState(tif); \ + int a0; /* reference element */ \ + int lastx = sp->b.rowpixels; /* last element in row */ \ + uint32 BitAcc; /* bit accumulator */ \ + int BitsAvail; /* # valid bits in BitAcc */ \ + int RunLength; /* length of current run */ \ + u_char* cp; /* next byte of input data */ \ + u_char* ep; /* end of input data */ \ + uint32* pa; /* place to stuff next run */ \ + uint32* thisrun; /* current row's run array */ \ + int EOLcnt; /* # EOL codes recognized */ \ + const u_char* bitmap = sp->bitmap; /* input data bit reverser */ \ + const TIFFFaxTabEnt* TabEnt +#define DECLARE_STATE_2D(tif, sp, mod) \ + DECLARE_STATE(tif, sp, mod); \ + int b1; /* next change on prev line */ \ + uint32* pb /* next run in reference line */\ +/* + * Load any state that may be changed during decoding. + */ +#define CACHE_STATE(tif, sp) do { \ + BitAcc = sp->data; \ + BitsAvail = sp->bit; \ + EOLcnt = sp->EOLcnt; \ + cp = (unsigned char*) tif->tif_rawcp; \ + ep = cp + tif->tif_rawcc; \ +} while (0) +/* + * Save state possibly changed during decoding. + */ +#define UNCACHE_STATE(tif, sp) do { \ + sp->bit = BitsAvail; \ + sp->data = BitAcc; \ + sp->EOLcnt = EOLcnt; \ + tif->tif_rawcc -= (tidata_t) cp - tif->tif_rawcp; \ + tif->tif_rawcp = (tidata_t) cp; \ +} while (0) + +/* + * Setup state for decoding a strip. + */ +static int +Fax3PreDecode(TIFF* tif, tsample_t s) +{ + Fax3DecodeState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 0; /* force initial read */ + sp->data = 0; + sp->EOLcnt = 0; /* force initial scan for EOL */ + /* + * Decoder assumes lsb-to-msb bit order. Note that we select + * this here rather than in Fax3SetupState so that viewers can + * hold the image open, fiddle with the FillOrder tag value, + * and then re-decode the image. Otherwise they'd need to close + * and open the image to get the state reset. + */ + sp->bitmap = + TIFFGetBitRevTable(tif->tif_dir.td_fillorder != FILLORDER_LSB2MSB); + if (sp->refruns) { /* init reference line to white */ + sp->refruns[0] = (uint32) sp->b.rowpixels; + sp->refruns[1] = 0; + } + return (1); +} + +/* + * Routine for handling various errors/conditions. + * Note how they are "glued into the decoder" by + * overriding the definitions used by the decoder. + */ + +static void +Fax3Unexpected(const char* module, TIFF* tif, uint32 a0) +{ + TIFFError(module, "%s: Bad code word at scanline %d (x %lu)", + tif->tif_name, tif->tif_row, (u_long) a0); +} +#define unexpected(table, a0) Fax3Unexpected(module, tif, a0) + +static void +Fax3Extension(const char* module, TIFF* tif, uint32 a0) +{ + TIFFError(module, + "%s: Uncompressed data (not supported) at scanline %d (x %lu)", + tif->tif_name, tif->tif_row, (u_long) a0); +} +#define extension(a0) Fax3Extension(module, tif, a0) + +static void +Fax3BadLength(const char* module, TIFF* tif, uint32 a0, uint32 lastx) +{ + TIFFWarning(module, "%s: %s at scanline %d (got %lu, expected %lu)", + tif->tif_name, + a0 < lastx ? "Premature EOL" : "Line length mismatch", + tif->tif_row, (u_long) a0, (u_long) lastx); +} +#define badlength(a0,lastx) Fax3BadLength(module, tif, a0, lastx) + +static void +Fax3PrematureEOF(const char* module, TIFF* tif, uint32 a0) +{ + TIFFWarning(module, "%s: Premature EOF at scanline %d (x %lu)", + tif->tif_name, tif->tif_row, (u_long) a0); +} +#define prematureEOF(a0) Fax3PrematureEOF(module, tif, a0) + +#define Nop + +/* + * Decode the requested amount of G3 1D-encoded data. + */ +static int +Fax3Decode1D(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE(tif, sp, "Fax3Decode1D"); + + (void) s; + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + SYNC_EOL(EOF1D); + EXPAND1D(EOF1Da); + (*sp->fill)(buf, thisrun, pa, lastx); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + if (occ != 0) + tif->tif_row++; + continue; + EOF1D: /* premature EOF */ + CLEANUP_RUNS(); + EOF1Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G3 2D-encoded data. + */ +static int +Fax3Decode2D(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE_2D(tif, sp, "Fax3Decode2D"); + int is1D; /* current line is 1d/2d-encoded */ + + (void) s; + CACHE_STATE(tif, sp); + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d EOLcnt = %d", + BitAcc, BitsAvail, EOLcnt); +#endif + SYNC_EOL(EOF2D); + NeedBits8(1, EOF2D); + is1D = GetBits(1); /* 1D/2D-encoding tag bit */ + ClrBits(1); +#ifdef FAX3_DEBUG + printf(" %s\n-------------------- %d\n", + is1D ? "1D" : "2D", tif->tif_row); + fflush(stdout); +#endif + pb = sp->refruns; + b1 = *pb++; + if (is1D) + EXPAND1D(EOF2Da); + else + EXPAND2D(EOF2Da); + (*sp->fill)(buf, thisrun, pa, lastx); + SETVAL(0); /* imaginary change for reference */ + SWAP(uint32*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + if (occ != 0) + tif->tif_row++; + continue; + EOF2D: /* premature EOF */ + CLEANUP_RUNS(); + EOF2Da: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * The ZERO & FILL macros must handle spans < 2*sizeof(long) bytes. + * For machines with 64-bit longs this is <16 bytes; otherwise + * this is <8 bytes. We optimize the code here to reflect the + * machine characteristics. + */ +#if defined(__alpha) || _MIPS_SZLONG == 64 +#define FILL(n, cp) \ + switch (n) { \ + case 15:(cp)[14] = 0xff; case 14:(cp)[13] = 0xff; case 13: (cp)[12] = 0xff;\ + case 12:(cp)[11] = 0xff; case 11:(cp)[10] = 0xff; case 10: (cp)[9] = 0xff;\ + case 9: (cp)[8] = 0xff; case 8: (cp)[7] = 0xff; case 7: (cp)[6] = 0xff;\ + case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; case 4: (cp)[3] = 0xff;\ + case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ + case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ + } +#define ZERO(n, cp) \ + switch (n) { \ + case 15:(cp)[14] = 0; case 14:(cp)[13] = 0; case 13: (cp)[12] = 0; \ + case 12:(cp)[11] = 0; case 11:(cp)[10] = 0; case 10: (cp)[9] = 0; \ + case 9: (cp)[8] = 0; case 8: (cp)[7] = 0; case 7: (cp)[6] = 0; \ + case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; case 4: (cp)[3] = 0; \ + case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ + case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ + } +#else +#define FILL(n, cp) \ + switch (n) { \ + case 7: (cp)[6] = 0xff; case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; \ + case 4: (cp)[3] = 0xff; case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \ + case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \ + } +#define ZERO(n, cp) \ + switch (n) { \ + case 7: (cp)[6] = 0; case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; \ + case 4: (cp)[3] = 0; case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \ + case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \ + } +#endif + +/* + * Bit-fill a row according to the white/black + * runs generated during G3/G4 decoding. + */ +void +_TIFFFax3fillruns(u_char* buf, uint32* runs, uint32* erun, uint32 lastx) +{ + static const unsigned char _fillmasks[] = + { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + u_char* cp; + uint32 x, bx, run; + int32 n, nw; + long* lp; + + if ((erun-runs)&1) + *erun++ = 0; + x = 0; + for (; runs < erun; runs += 2) { + run = runs[0]; + if (x+run > lastx || run > lastx ) + run = runs[0] = (uint32) (lastx - x); + if (run) { + cp = buf + (x>>3); + bx = x&7; + if (run > 8-bx) { + if (bx) { /* align to byte boundary */ + *cp++ &= 0xff << (8-bx); + run -= 8-bx; + } + if( (n = run >> 3) != 0 ) { /* multiple bytes to fill */ + if ((n/sizeof (long)) > 1) { + /* + * Align to longword boundary and fill. + */ + for (; n && !isAligned(cp, long); n--) + *cp++ = 0x00; + lp = (long*) cp; + nw = (int32)(n / sizeof (long)); + n -= nw * sizeof (long); + do { + *lp++ = 0L; + } while (--nw); + cp = (u_char*) lp; + } + ZERO(n, cp); + run &= 7; + } +#ifdef PURIFY + if (run) + cp[0] &= 0xff >> run; +#else + cp[0] &= 0xff >> run; +#endif + } else + cp[0] &= ~(_fillmasks[run]>>bx); + x += runs[0]; + } + run = runs[1]; + if (x+run > lastx || run > lastx ) + run = runs[1] = lastx - x; + if (run) { + cp = buf + (x>>3); + bx = x&7; + if (run > 8-bx) { + if (bx) { /* align to byte boundary */ + *cp++ |= 0xff >> bx; + run -= 8-bx; + } + if( (n = run>>3) != 0 ) { /* multiple bytes to fill */ + if ((n/sizeof (long)) > 1) { + /* + * Align to longword boundary and fill. + */ + for (; n && !isAligned(cp, long); n--) + *cp++ = 0xff; + lp = (long*) cp; + nw = (int32)(n / sizeof (long)); + n -= nw * sizeof (long); + do { + *lp++ = -1L; + } while (--nw); + cp = (u_char*) lp; + } + FILL(n, cp); + run &= 7; + } +#ifdef PURIFY + if (run) + cp[0] |= 0xff00 >> run; +#else + cp[0] |= 0xff00 >> run; +#endif + } else + cp[0] |= _fillmasks[run]>>bx; + x += runs[1]; + } + } + assert(x == lastx); +} +#undef ZERO +#undef FILL + +/* + * Setup G3/G4-related compression/decompression state + * before data is processed. This routine is called once + * per image -- it sets up different state based on whether + * or not decoding or encoding is being done and whether + * 1D- or 2D-encoded data is involved. + */ +static int +Fax3SetupState(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + Fax3BaseState* sp = Fax3State(tif); + long rowbytes, rowpixels; + int needsRefLine; + + if (td->td_bitspersample != 1) { + TIFFError(tif->tif_name, + "Bits/sample must be 1 for Group 3/4 encoding/decoding"); + return (0); + } + /* + * Calculate the scanline/tile widths. + */ + if (isTiled(tif)) { + rowbytes = TIFFTileRowSize(tif); + rowpixels = td->td_tilewidth; + } else { + rowbytes = TIFFScanlineSize(tif); + rowpixels = td->td_imagewidth; + } + sp->rowbytes = (uint32) rowbytes; + sp->rowpixels = (uint32) rowpixels; + /* + * Allocate any additional space required for decoding/encoding. + */ + needsRefLine = ( + (sp->groupoptions & GROUP3OPT_2DENCODING) || + td->td_compression == COMPRESSION_CCITTFAX4 + ); + if (sp->rw_mode == O_RDONLY) { /* 1d/2d decoding */ + Fax3DecodeState* dsp = DecoderState(tif); + uint32 nruns = needsRefLine ? + 2*TIFFroundup(rowpixels,32) : rowpixels; + + dsp->runs = (uint32*) _TIFFmalloc((2*nruns+3)*sizeof (uint32)); + if (dsp->runs == NULL) { + TIFFError("Fax3SetupState", + "%s: No space for Group 3/4 run arrays", + tif->tif_name); + return (0); + } + dsp->curruns = dsp->runs; + if (needsRefLine) + dsp->refruns = dsp->runs + (nruns>>1); + else + dsp->refruns = NULL; + if (is2DEncoding(dsp)) { /* NB: default is 1D routine */ + tif->tif_decoderow = Fax3Decode2D; + tif->tif_decodestrip = Fax3Decode2D; + tif->tif_decodetile = Fax3Decode2D; + } + } else if (needsRefLine) { /* 2d encoding */ + Fax3EncodeState* esp = EncoderState(tif); + /* + * 2d encoding requires a scanline + * buffer for the ``reference line''; the + * scanline against which delta encoding + * is referenced. The reference line must + * be initialized to be ``white'' (done elsewhere). + */ + esp->refline = (u_char*) _TIFFmalloc(rowbytes); + if (esp->refline == NULL) { + TIFFError("Fax3SetupState", + "%s: No space for Group 3/4 reference line", + tif->tif_name); + return (0); + } + } else /* 1d encoding */ + EncoderState(tif)->refline = NULL; + return (1); +} + +/* + * CCITT Group 3 FAX Encoding. + */ + +#define Fax3FlushBits(tif, sp) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \ + (void) TIFFFlushData1(tif); \ + *(tif)->tif_rawcp++ = (sp)->data; \ + (tif)->tif_rawcc++; \ + (sp)->data = 0, (sp)->bit = 8; \ +} +#define _FlushBits(tif) { \ + if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \ + (void) TIFFFlushData1(tif); \ + *(tif)->tif_rawcp++ = data; \ + (tif)->tif_rawcc++; \ + data = 0, bit = 8; \ +} +static const int _msbmask[9] = + { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; +#define _PutBits(tif, bits, length) { \ + while (length > bit) { \ + data |= bits >> (length - bit); \ + length -= bit; \ + _FlushBits(tif); \ + } \ + data |= (bits & _msbmask[length]) << (bit - length); \ + bit -= length; \ + if (bit == 0) \ + _FlushBits(tif); \ +} + +/* + * Write a variable-length bit-value to + * the output stream. Values are + * assumed to be at most 16 bits. + */ +static void +Fax3PutBits(TIFF* tif, u_int bits, u_int length) +{ + Fax3EncodeState* sp = EncoderState(tif); + u_int bit = sp->bit; + int data = sp->data; + + _PutBits(tif, bits, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Write a code to the output stream. + */ +#define putcode(tif, te) Fax3PutBits(tif, (te)->code, (te)->length) + +#ifdef FAX3_DEBUG +#define DEBUG_COLOR(w) (tab == TIFFFaxWhiteCodes ? w "W" : w "B") +#define DEBUG_PRINT(what,len) { \ + int t; \ + printf("%08X/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len); \ + for (t = length-1; t >= 0; t--) \ + putchar(code & (1<bit; + int data = sp->data; + u_int code, length; + + while (span >= 2624) { + const tableentry* te = &tab[63 + (2560>>6)]; + code = te->code, length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + if (span >= 64) { + const tableentry* te = &tab[63 + (span>>6)]; + assert(te->runlen == 64*(span>>6)); + code = te->code, length = te->length; +#ifdef FAX3_DEBUG + DEBUG_PRINT("MakeUp", te->runlen); +#endif + _PutBits(tif, code, length); + span -= te->runlen; + } + code = tab[span].code, length = tab[span].length; +#ifdef FAX3_DEBUG + DEBUG_PRINT(" Term", tab[span].runlen); +#endif + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Write an EOL code to the output stream. The zero-fill + * logic for byte-aligning encoded scanlines is handled + * here. We also handle writing the tag bit for the next + * scanline when doing 2d encoding. + */ +static void +Fax3PutEOL(TIFF* tif) +{ + Fax3EncodeState* sp = EncoderState(tif); + u_int bit = sp->bit; + int data = sp->data; + u_int code, length, tparm; + + if (sp->b.groupoptions & GROUP3OPT_FILLBITS) { + /* + * Force bit alignment so EOL will terminate on + * a byte boundary. That is, force the bit alignment + * to 16-12 = 4 before putting out the EOL code. + */ + int align = 8 - 4; + if (align != sp->bit) { + if (align > sp->bit) + align = sp->bit + (8 - align); + else + align = sp->bit - align; + code = 0; + tparm=align; + _PutBits(tif, 0, tparm); + } + } + code = EOL, length = 12; + if (is2DEncoding(sp)) + code = (code<<1) | (sp->tag == G3_1D), length++; + _PutBits(tif, code, length); + + sp->data = data; + sp->bit = bit; +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +Fax3PreEncode(TIFF* tif, tsample_t s) +{ + Fax3EncodeState* sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->bit = 8; + sp->data = 0; + sp->tag = G3_1D; + /* + * This is necessary for Group 4; otherwise it isn't + * needed because the first scanline of each strip ends + * up being copied into the refline. + */ + if (sp->refline) + _TIFFmemset(sp->refline, 0x00, sp->b.rowbytes); + if (is2DEncoding(sp)) { + float res = tif->tif_dir.td_yresolution; + /* + * The CCITT spec says that when doing 2d encoding, you + * should only do it on K consecutive scanlines, where K + * depends on the resolution of the image being encoded + * (2 for <= 200 lpi, 4 for > 200 lpi). Since the directory + * code initializes td_yresolution to 0, this code will + * select a K of 2 unless the YResolution tag is set + * appropriately. (Note also that we fudge a little here + * and use 150 lpi to avoid problems with units conversion.) + */ + if (tif->tif_dir.td_resolutionunit == RESUNIT_CENTIMETER) + res *= 2.54f; /* convert to inches */ + sp->maxk = (res > 150 ? 4 : 2); + sp->k = sp->maxk-1; + } else + sp->k = sp->maxk = 0; + return (1); +} + +static const u_char zeroruns[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */ +}; +static const u_char oneruns[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */ +}; + +/* + * On certain systems it pays to inline + * the routines that find pixel spans. + */ +#ifdef VAXC +static int32 find0span(u_char*, int32, int32); +static int32 find1span(u_char*, int32, int32); +#pragma inline(find0span,find1span) +#endif + +/* + * Find a span of ones or zeros using the supplied + * table. The ``base'' of the bit string is supplied + * along with the start+end bit indices. + */ +INLINE static int32 +find0span(u_char* bp, int32 bs, int32 be) +{ + int32 bits = be - bs; + int32 n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7))) { + span = zeroruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= 2*8*sizeof (long)) { + long* lp; + /* + * Align to longword boundary and check longwords. + */ + while (!isAligned(bp, long)) { + if (*bp != 0x00) + return (span + zeroruns[*bp]); + span += 8, bits -= 8; + bp++; + } + lp = (long*) bp; + while (bits >= 8*sizeof (long) && *lp == 0) { + span += 8*sizeof (long), bits -= 8*sizeof (long); + lp++; + } + bp = (u_char*) lp; + } + /* + * Scan full bytes for all 0's. + */ + while (bits >= 8) { + if (*bp != 0x00) /* end of run */ + return (span + zeroruns[*bp]); + span += 8, bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = zeroruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +INLINE static int32 +find1span(u_char* bp, int32 bs, int32 be) +{ + int32 bits = be - bs; + int32 n, span; + + bp += bs>>3; + /* + * Check partial byte on lhs. + */ + if (bits > 0 && (n = (bs & 7))) { + span = oneruns[(*bp << n) & 0xff]; + if (span > 8-n) /* table value too generous */ + span = 8-n; + if (span > bits) /* constrain span to bit range */ + span = bits; + if (n+span < 8) /* doesn't extend to edge of byte */ + return (span); + bits -= span; + bp++; + } else + span = 0; + if (bits >= 2*8*sizeof (long)) { + long* lp; + /* + * Align to longword boundary and check longwords. + */ + while (!isAligned(bp, long)) { + if (*bp != 0xff) + return (span + oneruns[*bp]); + span += 8, bits -= 8; + bp++; + } + lp = (long*) bp; + while (bits >= 8*sizeof (long) && *lp == ~0) { + span += 8*sizeof (long), bits -= 8*sizeof (long); + lp++; + } + bp = (u_char*) lp; + } + /* + * Scan full bytes for all 1's. + */ + while (bits >= 8) { + if (*bp != 0xff) /* end of run */ + return (span + oneruns[*bp]); + span += 8, bits -= 8; + bp++; + } + /* + * Check partial byte on rhs. + */ + if (bits > 0) { + n = oneruns[*bp]; + span += (n > bits ? bits : n); + } + return (span); +} + +/* + * Return the offset of the next bit in the range + * [bs..be] that is different from the specified + * color. The end, be, is returned if no such bit + * exists. + */ +#define finddiff(_cp, _bs, _be, _color) \ + (_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be))) +/* + * Like finddiff, but also check the starting bit + * against the end in case start > end. + */ +#define finddiff2(_cp, _bs, _be, _color) \ + (_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be) + +/* + * 1d-encode a row of pixels. The encoding is + * a sequence of all-white or all-black spans + * of pixels encoded with Huffman codes. + */ +static int +Fax3Encode1DRow(TIFF* tif, u_char* bp, uint32 bits) +{ + Fax3EncodeState* sp = EncoderState(tif); + int32 span; + uint32 bs = 0; + + for (;;) { + span = find0span(bp, bs, bits); /* white span */ + putspan(tif, span, TIFFFaxWhiteCodes); + bs += span; + if (bs >= bits) + break; + span = find1span(bp, bs, bits); /* black span */ + putspan(tif, span, TIFFFaxBlackCodes); + bs += span; + if (bs >= bits) + break; + } + if (sp->b.mode & (FAXMODE_BYTEALIGN|FAXMODE_WORDALIGN)) { + if (sp->bit != 8) /* byte-align */ + Fax3FlushBits(tif, sp); + if ((sp->b.mode&FAXMODE_WORDALIGN) && + !isAligned(tif->tif_rawcp, uint16)) + Fax3FlushBits(tif, sp); + } + return (1); +} + +static const tableentry horizcode = + { 3, 0x1 }; /* 001 */ +static const tableentry passcode = + { 4, 0x1 }; /* 0001 */ +static const tableentry vcodes[7] = { + { 7, 0x03 }, /* 0000 011 */ + { 6, 0x03 }, /* 0000 11 */ + { 3, 0x03 }, /* 011 */ + { 1, 0x1 }, /* 1 */ + { 3, 0x2 }, /* 010 */ + { 6, 0x02 }, /* 0000 10 */ + { 7, 0x02 } /* 0000 010 */ +}; + +/* + * 2d-encode a row of pixels. Consult the CCITT + * documentation for the algorithm. + */ +static int +Fax3Encode2DRow(TIFF* tif, u_char* bp, u_char* rp, uint32 bits) +{ +#define PIXEL(buf,ix) ((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1) + uint32 a0 = 0; + uint32 a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0)); + uint32 b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0)); + uint32 a2, b2; + + for (;;) { + b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1)); + if (b2 >= a1) { + int32 d = b1 - a1; + if (!(-3 <= d && d <= 3)) { /* horizontal mode */ + a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1)); + putcode(tif, &horizcode); + if (a0+a1 == 0 || PIXEL(bp, a0) == 0) { + putspan(tif, a1-a0, TIFFFaxWhiteCodes); + putspan(tif, a2-a1, TIFFFaxBlackCodes); + } else { + putspan(tif, a1-a0, TIFFFaxBlackCodes); + putspan(tif, a2-a1, TIFFFaxWhiteCodes); + } + a0 = a2; + } else { /* vertical mode */ + putcode(tif, &vcodes[d+3]); + a0 = a1; + } + } else { /* pass mode */ + putcode(tif, &passcode); + a0 = b2; + } + if (a0 >= bits) + break; + a1 = finddiff(bp, a0, bits, PIXEL(bp,a0)); + b1 = finddiff(rp, a0, bits, !PIXEL(bp,a0)); + b1 = finddiff(rp, b1, bits, PIXEL(bp,a0)); + } + return (1); +#undef PIXEL +} + +/* + * Encode a buffer of pixels. + */ +static int +Fax3Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + Fax3EncodeState* sp = EncoderState(tif); + + (void) s; + while ((long)cc > 0) { + if ((sp->b.mode & FAXMODE_NOEOL) == 0) + Fax3PutEOL(tif); + if (is2DEncoding(sp)) { + if (sp->tag == G3_1D) { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + sp->tag = G3_2D; + } else { + if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels)) + return (0); + sp->k--; + } + if (sp->k == 0) { + sp->tag = G3_1D; + sp->k = sp->maxk-1; + } else + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + } else { + if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels)) + return (0); + } + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + if (cc != 0) + tif->tif_row++; + } + return (1); +} + +static int +Fax3PostEncode(TIFF* tif) +{ + Fax3EncodeState* sp = EncoderState(tif); + + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +static void +Fax3Close(TIFF* tif) +{ + if ((Fax3State(tif)->mode & FAXMODE_NORTC) == 0) { + Fax3EncodeState* sp = EncoderState(tif); + u_int code = EOL; + u_int length = 12; + int i; + + if (is2DEncoding(sp)) + code = (code<<1) | (sp->tag == G3_1D), length++; + for (i = 0; i < 6; i++) + Fax3PutBits(tif, code, length); + Fax3FlushBits(tif, sp); + } +} + +static void +Fax3Cleanup(TIFF* tif) +{ + if (tif->tif_data) { + if (Fax3State(tif)->rw_mode == O_RDONLY) { + Fax3DecodeState* sp = DecoderState(tif); + if (sp->runs) + _TIFFfree(sp->runs); + } else { + Fax3EncodeState* sp = EncoderState(tif); + if (sp->refline) + _TIFFfree(sp->refline); + } + if (Fax3State(tif)->subaddress) + _TIFFfree(Fax3State(tif)->subaddress); + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + } +} + +#define FIELD_BADFAXLINES (FIELD_CODEC+0) +#define FIELD_CLEANFAXDATA (FIELD_CODEC+1) +#define FIELD_BADFAXRUN (FIELD_CODEC+2) +#define FIELD_RECVPARAMS (FIELD_CODEC+3) +#define FIELD_SUBADDRESS (FIELD_CODEC+4) +#define FIELD_RECVTIME (FIELD_CODEC+5) + +#define FIELD_OPTIONS (FIELD_CODEC+6) + +static const TIFFFieldInfo faxFieldInfo[] = { + { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "FaxMode" }, + { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "FaxFillFunc" }, + { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, FIELD_BADFAXLINES, + TRUE, FALSE, "BadFaxLines" }, + { TIFFTAG_BADFAXLINES, 1, 1, TIFF_SHORT, FIELD_BADFAXLINES, + TRUE, FALSE, "BadFaxLines" }, + { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, FIELD_CLEANFAXDATA, + TRUE, FALSE, "CleanFaxData" }, + { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_LONG, FIELD_BADFAXRUN, + TRUE, FALSE, "ConsecutiveBadFaxLines" }, + { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_SHORT, FIELD_BADFAXRUN, + TRUE, FALSE, "ConsecutiveBadFaxLines" }, + { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, + TRUE, FALSE, "FaxRecvParams" }, + { TIFFTAG_FAXSUBADDRESS, -1,-1, TIFF_ASCII, FIELD_SUBADDRESS, + TRUE, FALSE, "FaxSubAddress" }, + { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, + TRUE, FALSE, "FaxRecvTime" }, +}; +static const TIFFFieldInfo fax3FieldInfo[] = { + { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS, + FALSE, FALSE, "Group3Options" }, +}; +static const TIFFFieldInfo fax4FieldInfo[] = { + { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS, + FALSE, FALSE, "Group4Options" }, +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +static int +Fax3VSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + + switch (tag) { + case TIFFTAG_FAXMODE: + sp->mode = va_arg(ap, int); + return (1); /* NB: pseudo tag */ + case TIFFTAG_FAXFILLFUNC: + if (sp->rw_mode == O_RDONLY) + DecoderState(tif)->fill = va_arg(ap, TIFFFaxFillFunc); + return (1); /* NB: pseudo tag */ + case TIFFTAG_GROUP3OPTIONS: + case TIFFTAG_GROUP4OPTIONS: + sp->groupoptions = va_arg(ap, uint32); + break; + case TIFFTAG_BADFAXLINES: + sp->badfaxlines = va_arg(ap, uint32); + break; + case TIFFTAG_CLEANFAXDATA: + sp->cleanfaxdata = (uint16) va_arg(ap, int); + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + sp->badfaxrun = va_arg(ap, uint32); + break; + case TIFFTAG_FAXRECVPARAMS: + sp->recvparams = va_arg(ap, uint32); + break; + case TIFFTAG_FAXSUBADDRESS: + _TIFFsetString(&sp->subaddress, va_arg(ap, char*)); + break; + case TIFFTAG_FAXRECVTIME: + sp->recvtime = va_arg(ap, uint32); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit); + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} + +static int +Fax3VGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + Fax3BaseState* sp = Fax3State(tif); + + switch (tag) { + case TIFFTAG_FAXMODE: + *va_arg(ap, int*) = sp->mode; + break; + case TIFFTAG_FAXFILLFUNC: + if (sp->rw_mode == O_RDONLY) + *va_arg(ap, TIFFFaxFillFunc*) = DecoderState(tif)->fill; + break; + case TIFFTAG_GROUP3OPTIONS: + case TIFFTAG_GROUP4OPTIONS: + *va_arg(ap, uint32*) = sp->groupoptions; + break; + case TIFFTAG_BADFAXLINES: + *va_arg(ap, uint32*) = sp->badfaxlines; + break; + case TIFFTAG_CLEANFAXDATA: + *va_arg(ap, uint16*) = sp->cleanfaxdata; + break; + case TIFFTAG_CONSECUTIVEBADFAXLINES: + *va_arg(ap, uint32*) = sp->badfaxrun; + break; + case TIFFTAG_FAXRECVPARAMS: + *va_arg(ap, uint32*) = sp->recvparams; + break; + case TIFFTAG_FAXSUBADDRESS: + *va_arg(ap, char**) = sp->subaddress; + break; + case TIFFTAG_FAXRECVTIME: + *va_arg(ap, uint32*) = sp->recvtime; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +Fax3PrintDir(TIFF* tif, FILE* fd, long flags) +{ + Fax3BaseState* sp = Fax3State(tif); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_OPTIONS)) { + const char* sep = " "; + if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) { + fprintf(fd, " Group 4 Options:"); + if (sp->groupoptions & GROUP4OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } else { + + fprintf(fd, " Group 3 Options:"); + if (sp->groupoptions & GROUP3OPT_2DENCODING) + fprintf(fd, "%s2-d encoding", sep), sep = "+"; + if (sp->groupoptions & GROUP3OPT_FILLBITS) + fprintf(fd, "%sEOL padding", sep), sep = "+"; + if (sp->groupoptions & GROUP3OPT_UNCOMPRESSED) + fprintf(fd, "%suncompressed data", sep); + } + fprintf(fd, " (%lu = 0x%lx)\n", + (u_long) sp->groupoptions, (u_long) sp->groupoptions); + } + if (TIFFFieldSet(tif,FIELD_CLEANFAXDATA)) { + fprintf(fd, " Fax Data:"); + switch (sp->cleanfaxdata) { + case CLEANFAXDATA_CLEAN: + fprintf(fd, " clean"); + break; + case CLEANFAXDATA_REGENERATED: + fprintf(fd, " receiver regenerated"); + break; + case CLEANFAXDATA_UNCLEAN: + fprintf(fd, " uncorrected errors"); + break; + } + fprintf(fd, " (%u = 0x%x)\n", + sp->cleanfaxdata, sp->cleanfaxdata); + } + if (TIFFFieldSet(tif,FIELD_BADFAXLINES)) + fprintf(fd, " Bad Fax Lines: %lu\n", (u_long) sp->badfaxlines); + if (TIFFFieldSet(tif,FIELD_BADFAXRUN)) + fprintf(fd, " Consecutive Bad Fax Lines: %lu\n", + (u_long) sp->badfaxrun); + if (TIFFFieldSet(tif,FIELD_RECVPARAMS)) + fprintf(fd, " Fax Receive Parameters: %08lx\n", + (u_long) sp->recvparams); + if (TIFFFieldSet(tif,FIELD_SUBADDRESS)) + fprintf(fd, " Fax SubAddress: %s\n", sp->subaddress); + if (TIFFFieldSet(tif,FIELD_RECVTIME)) + fprintf(fd, " Fax Receive Time: %lu secs\n", + (u_long) sp->recvtime); +} + +static int +InitCCITTFax3(TIFF* tif) +{ + Fax3BaseState* sp; + + /* + * Allocate state block so tag methods have storage to record values. + */ + if (tif->tif_mode == O_RDONLY) + tif->tif_data = (tidata_t) + _TIFFmalloc(sizeof (Fax3DecodeState)); + else + tif->tif_data = (tidata_t) + _TIFFmalloc(sizeof (Fax3EncodeState)); + + if (tif->tif_data == NULL) { + TIFFError("TIFFInitCCITTFax3", + "%s: No space for state block", tif->tif_name); + return (0); + } + + sp = Fax3State(tif); + sp->rw_mode = tif->tif_mode; + + /* + * Merge codec-specific tag information and + * override parent get/set field methods. + */ + _TIFFMergeFieldInfo(tif, faxFieldInfo, N(faxFieldInfo)); + sp->vgetparent = tif->tif_vgetfield; + tif->tif_vgetfield = Fax3VGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_vsetfield; + tif->tif_vsetfield = Fax3VSetField; /* hook for codec tags */ + tif->tif_printdir = Fax3PrintDir; /* hook for codec tags */ + sp->groupoptions = 0; + sp->recvparams = 0; + sp->subaddress = NULL; + + if (sp->rw_mode == O_RDONLY) { + tif->tif_flags |= TIFF_NOBITREV;/* decoder does bit reversal */ + DecoderState(tif)->runs = NULL; + TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, _TIFFFax3fillruns); + } else + EncoderState(tif)->refline = NULL; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = Fax3SetupState; + tif->tif_predecode = Fax3PreDecode; + tif->tif_decoderow = Fax3Decode1D; + tif->tif_decodestrip = Fax3Decode1D; + tif->tif_decodetile = Fax3Decode1D; + tif->tif_setupencode = Fax3SetupState; + tif->tif_preencode = Fax3PreEncode; + tif->tif_postencode = Fax3PostEncode; + tif->tif_encoderow = Fax3Encode; + tif->tif_encodestrip = Fax3Encode; + tif->tif_encodetile = Fax3Encode; + tif->tif_close = Fax3Close; + tif->tif_cleanup = Fax3Cleanup; + + return (1); +} + +int +TIFFInitCCITTFax3(TIFF* tif, int scheme) +{ + if (InitCCITTFax3(tif)) { + _TIFFMergeFieldInfo(tif, fax3FieldInfo, N(fax3FieldInfo)); + + /* + * The default format is Class/F-style w/o RTC. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_CLASSF); + } else + return (0); +} + +/* + * CCITT Group 4 (T.6) Facsimile-compatible + * Compression Scheme Support. + */ + +#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; } +/* + * Decode the requested amount of G4-encoded data. + */ +static int +Fax4Decode(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE_2D(tif, sp, "Fax4Decode"); + + (void) s; + CACHE_STATE(tif, sp); + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun = sp->curruns; + pb = sp->refruns; + b1 = *pb++; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND2D(EOFG4); + if (EOLcnt) + goto EOFG4; + (*sp->fill)(buf, thisrun, pa, lastx); + SETVAL(0); /* imaginary change for reference */ + SWAP(uint32*, sp->curruns, sp->refruns); + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + if (occ != 0) + tif->tif_row++; + continue; + EOFG4: + NeedBits16( 13, BADG4 ); + BADG4: +#ifdef FAX3_DEBUG + if( GetBits(13) != 0x1001 ) + fputs( "Bad RTC\n", stderr ); +#endif + ClrBits( 13 ); + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} +#undef SWAP + +/* + * Encode the requested amount of data. + */ +static int +Fax4Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + Fax3EncodeState *sp = EncoderState(tif); + + (void) s; + while ((long)cc > 0) { + if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels)) + return (0); + _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes); + bp += sp->b.rowbytes; + cc -= sp->b.rowbytes; + if (cc != 0) + tif->tif_row++; + } + return (1); +} + +static int +Fax4PostEncode(TIFF* tif) +{ + Fax3EncodeState *sp = EncoderState(tif); + + /* terminate strip w/ EOFB */ + Fax3PutBits(tif, EOL, 12); + Fax3PutBits(tif, EOL, 12); + if (sp->bit != 8) + Fax3FlushBits(tif, sp); + return (1); +} + +int +TIFFInitCCITTFax4(TIFF* tif, int scheme) +{ + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + _TIFFMergeFieldInfo(tif, fax4FieldInfo, N(fax4FieldInfo)); + + tif->tif_decoderow = Fax4Decode; + tif->tif_decodestrip = Fax4Decode; + tif->tif_decodetile = Fax4Decode; + tif->tif_encoderow = Fax4Encode; + tif->tif_encodestrip = Fax4Encode; + tif->tif_encodetile = Fax4Encode; + tif->tif_postencode = Fax4PostEncode; + /* + * Suppress RTC at the end of each strip. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_NORTC); + } else + return (0); +} + +/* + * CCITT Group 3 1-D Modified Huffman RLE Compression Support. + * (Compression algorithms 2 and 32771) + */ + +/* + * Decode the requested amount of RLE-encoded data. + */ +static int +Fax3DecodeRLE(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + DECLARE_STATE(tif, sp, "Fax3DecodeRLE"); + int mode = sp->b.mode; + + (void) s; + CACHE_STATE(tif, sp); + thisrun = sp->curruns; + while ((long)occ > 0) { + a0 = 0; + RunLength = 0; + pa = thisrun; +#ifdef FAX3_DEBUG + printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail); + printf("-------------------- %d\n", tif->tif_row); + fflush(stdout); +#endif + EXPAND1D(EOFRLE); + (*sp->fill)(buf, thisrun, pa, lastx); + /* + * Cleanup at the end of the row. + */ + if (mode & FAXMODE_BYTEALIGN) { + int n = BitsAvail - (BitsAvail &~ 7); + ClrBits(n); + } else if (mode & FAXMODE_WORDALIGN) { + int n = BitsAvail - (BitsAvail &~ 15); + ClrBits(n); + if (BitsAvail == 0 && !isAligned(cp, uint16)) + cp++; + } + buf += sp->b.rowbytes; + occ -= sp->b.rowbytes; + if (occ != 0) + tif->tif_row++; + continue; + EOFRLE: /* premature EOF */ + (*sp->fill)(buf, thisrun, pa, lastx); + UNCACHE_STATE(tif, sp); + return (-1); + } + UNCACHE_STATE(tif, sp); + return (1); +} + +int +TIFFInitCCITTRLE(TIFF* tif, int scheme) +{ + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and byte-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_BYTEALIGN); + } else + return (0); +} + +int +TIFFInitCCITTRLEW(TIFF* tif, int scheme) +{ + if (InitCCITTFax3(tif)) { /* reuse G3 support */ + tif->tif_decoderow = Fax3DecodeRLE; + tif->tif_decodestrip = Fax3DecodeRLE; + tif->tif_decodetile = Fax3DecodeRLE; + /* + * Suppress RTC+EOLs when encoding and word-align data. + */ + return TIFFSetField(tif, TIFFTAG_FAXMODE, + FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_WORDALIGN); + } else + return (0); +} +#endif /* CCITT_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_fax3.h b/freeimage241/Source/LibTIFF/tif_fax3.h new file mode 100644 index 0000000..bd942c3 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_fax3.h @@ -0,0 +1,525 @@ +/* $Id: tif_fax3.h,v 1.0 2001-04-13 00:42:32+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _FAX3_ +#define _FAX3_ +/* + * TIFF Library. + * + * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support. + * + * Decoder support is derived, with permission, from the code + * in Frank Cringle's viewfax program; + * Copyright (C) 1990, 1995 Frank D. Cringle. + */ +#include "tiff.h" + +/* + * To override the default routine used to image decoded + * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC. + * The routine must have the type signature given below; + * for example: + * + * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) + * + * where buf is place to set the bits, runs is the array of b&w run + * lengths (white then black), erun is the last run in the array, and + * lastx is the width of the row in pixels. Fill routines can assume + * the run array has room for at least lastx runs and can overwrite + * data in the run array as needed (e.g. to append zero runs to bring + * the count up to a nice multiple). + */ +typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32); + +/* + * The default run filler; made external for other decoders. + */ +#if defined(__cplusplus) +extern "C" { +#endif +extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32); +#if defined(__cplusplus) +} +#endif + + +/* finite state machine codes */ +#define S_Null 0 +#define S_Pass 1 +#define S_Horiz 2 +#define S_V0 3 +#define S_VR 4 +#define S_VL 5 +#define S_Ext 6 +#define S_TermW 7 +#define S_TermB 8 +#define S_MakeUpW 9 +#define S_MakeUpB 10 +#define S_MakeUp 11 +#define S_EOL 12 + +typedef struct { /* state table entry */ + unsigned char State; /* see above */ + unsigned char Width; /* width of code in bits */ + uint32 Param; /* unsigned 32-bit run length in bits */ +} TIFFFaxTabEnt; + +extern const TIFFFaxTabEnt TIFFFaxMainTable[]; +extern const TIFFFaxTabEnt TIFFFaxWhiteTable[]; +extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; + +/* + * The following macros define the majority of the G3/G4 decoder + * algorithm using the state tables defined elsewhere. To build + * a decoder you need some setup code and some glue code. Note + * that you may also need/want to change the way the NeedBits* + * macros get input data if, for example, you know the data to be + * decoded is properly aligned and oriented (doing so before running + * the decoder can be a big performance win). + * + * Consult the decoder in the TIFF library for an idea of what you + * need to define and setup to make use of these definitions. + * + * NB: to enable a debugging version of these macros define FAX3_DEBUG + * before including this file. Trace output goes to stdout. + */ + +#ifndef EndOfData +#define EndOfData() (cp >= ep) +#endif +/* + * Need <=8 or <=16 bits of input data. Unlike viewfax we + * cannot use/assume a word-aligned, properly bit swizzled + * input data set because data may come from an arbitrarily + * aligned, read-only source such as a memory-mapped file. + * Note also that the viewfax decoder does not check for + * running off the end of the input data buffer. This is + * possible for G3-encoded data because it prescans the input + * data to count EOL markers, but can cause problems for G4 + * data. In any event, we don't prescan and must watch for + * running out of data since we can't permit the library to + * scan past the end of the input data buffer. + * + * Finally, note that we must handle remaindered data at the end + * of a strip specially. The coder asks for a fixed number of + * bits when scanning for the next code. This may be more bits + * than are actually present in the data stream. If we appear + * to run out of data but still have some number of valid bits + * remaining then we makeup the requested amount with zeros and + * return successfully. If the returned data is incorrect then + * we should be called again and get a premature EOF error; + * otherwise we should get the right answer. + */ +#ifndef NeedBits8 +#define NeedBits8(n,eoflab) do { \ + if (BitsAvail < (n)) { \ + if (EndOfData()) { \ + if (BitsAvail == 0) /* no valid bits */ \ + goto eoflab; \ + BitsAvail = (n); /* pad with zeros */ \ + } else { \ + BitAcc |= ((uint32) bitmap[*cp++])<>= (n); \ +} while (0) + +#ifdef FAX3_DEBUG +static const char* StateNames[] = { + "Null ", + "Pass ", + "Horiz ", + "V0 ", + "VR ", + "VL ", + "Ext ", + "TermW ", + "TermB ", + "MakeUpW", + "MakeUpB", + "MakeUp ", + "EOL ", +}; +#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0') +#define LOOKUP8(wid,tab,eoflab) do { \ + int t; \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + int t; \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ + StateNames[TabEnt->State], TabEnt->Param); \ + for (t = 0; t < TabEnt->Width; t++) \ + DEBUG_SHOW; \ + putchar('\n'); \ + fflush(stdout); \ + ClrBits(TabEnt->Width); \ +} while (0) + +#define SETVAL(x) do { \ + *pa++ = RunLength + (x); \ + printf("SETVAL: %d\t%d\n", RunLength + (x), a0); \ + a0 += x; \ + RunLength = 0; \ +} while (0) +#else +#define LOOKUP8(wid,tab,eoflab) do { \ + NeedBits8(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) +#define LOOKUP16(wid,tab,eoflab) do { \ + NeedBits16(wid,eoflab); \ + TabEnt = tab + GetBits(wid); \ + ClrBits(TabEnt->Width); \ +} while (0) + +/* + * Append a run to the run length array for the + * current row and reset decoding state. + */ +#define SETVAL(x) do { \ + *pa++ = RunLength + (x); \ + a0 += (x); \ + RunLength = 0; \ +} while (0) +#endif + +/* + * Synchronize input decoding at the start of each + * row by scanning for an EOL (if appropriate) and + * skipping any trash data that might be present + * after a decoding error. Note that the decoding + * done elsewhere that recognizes an EOL only consumes + * 11 consecutive zero bits. This means that if EOLcnt + * is non-zero then we still need to scan for the final flag + * bit that is part of the EOL code. + */ +#define SYNC_EOL(eoflab) do { \ + if (EOLcnt == 0) { \ + for (;;) { \ + NeedBits16(11,eoflab); \ + if (GetBits(11) == 0) \ + break; \ + ClrBits(1); \ + } \ + } \ + for (;;) { \ + NeedBits8(8,eoflab); \ + if (GetBits(8)) \ + break; \ + ClrBits(8); \ + } \ + while (GetBits(1) == 0) \ + ClrBits(1); \ + ClrBits(1); /* EOL bit */ \ + EOLcnt = 0; /* reset EOL counter/flag */ \ +} while (0) + +/* + * Cleanup the array of runs after decoding a row. + * We adjust final runs to insure the user buffer is not + * overwritten and/or undecoded area is white filled. + */ +#define CLEANUP_RUNS() do { \ + if (RunLength) \ + SETVAL(0); \ + if (a0 != lastx) { \ + badlength(a0, lastx); \ + while (a0 > lastx && pa > thisrun) \ + a0 -= *--pa; \ + if (a0 < lastx) { \ + if (a0 < 0) \ + a0 = 0; \ + if ((pa-thisrun)&1) \ + SETVAL(0); \ + SETVAL(lastx - a0); \ + } else if (a0 > lastx) { \ + SETVAL(lastx); \ + SETVAL(0); \ + } \ + } \ +} while (0) + +/* + * Decode a line of 1D-encoded data. + * + * The line expanders are written as macros so that they can be reused + * but still have direct access to the local variables of the "calling" + * function. + * + * Note that unlike the original version we have to explicitly test for + * a0 >= lastx after each black/white run is decoded. This is because + * the original code depended on the input data being zero-padded to + * insure the decoder recognized an EOL before running out of data. + */ +#define EXPAND1D(eoflab) do { \ + for (;;) { \ + for (;;) { \ + LOOKUP16(12, TIFFFaxWhiteTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + goto doneWhite1d; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("WhiteTable", a0); \ + goto done1d; \ + } \ + } \ + doneWhite1d: \ + if (a0 >= lastx) \ + goto done1d; \ + for (;;) { \ + LOOKUP16(13, TIFFFaxBlackTable, eof1d); \ + switch (TabEnt->State) { \ + case S_EOL: \ + EOLcnt = 1; \ + goto done1d; \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + goto doneBlack1d; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + unexpected("BlackTable", a0); \ + goto done1d; \ + } \ + } \ + doneBlack1d: \ + if (a0 >= lastx) \ + goto done1d; \ + if( *(pa-1) == 0 && *(pa-2) == 0 ) \ + pa -= 2; \ + } \ +eof1d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ +done1d: \ + CLEANUP_RUNS(); \ +} while (0) + +/* + * Update the value of b1 using the array + * of runs for the reference line. + */ +#define CHECK_b1 do { \ + if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \ + b1 += pb[0] + pb[1]; \ + pb += 2; \ + } \ +} while (0) + +/* + * Expand a row of 2D-encoded data. + */ +#define EXPAND2D(eoflab) do { \ + while (a0 < lastx) { \ + LOOKUP8(7, TIFFFaxMainTable, eof2d); \ + switch (TabEnt->State) { \ + case S_Pass: \ + CHECK_b1; \ + b1 += *pb++; \ + RunLength += b1 - a0; \ + a0 = b1; \ + b1 += *pb++; \ + break; \ + case S_Horiz: \ + if ((pa-thisrun)&1) { \ + for (;;) { /* black first */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + goto doneWhite2da; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneWhite2da:; \ + for (;;) { /* then white */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + goto doneBlack2da; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneBlack2da:; \ + } else { \ + for (;;) { /* white first */ \ + LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermW: \ + SETVAL(TabEnt->Param); \ + goto doneWhite2db; \ + case S_MakeUpW: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badWhite2d; \ + } \ + } \ + doneWhite2db:; \ + for (;;) { /* then black */ \ + LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ + switch (TabEnt->State) { \ + case S_TermB: \ + SETVAL(TabEnt->Param); \ + goto doneBlack2db; \ + case S_MakeUpB: \ + case S_MakeUp: \ + a0 += TabEnt->Param; \ + RunLength += TabEnt->Param; \ + break; \ + default: \ + goto badBlack2d; \ + } \ + } \ + doneBlack2db:; \ + } \ + CHECK_b1; \ + break; \ + case S_V0: \ + CHECK_b1; \ + SETVAL(b1 - a0); \ + b1 += *pb++; \ + break; \ + case S_VR: \ + CHECK_b1; \ + SETVAL(b1 - a0 + TabEnt->Param); \ + b1 += *pb++; \ + break; \ + case S_VL: \ + CHECK_b1; \ + SETVAL(b1 - a0 - TabEnt->Param); \ + b1 -= *--pb; \ + break; \ + case S_Ext: \ + *pa++ = lastx - a0; \ + extension(a0); \ + goto eol2d; \ + case S_EOL: \ + *pa++ = lastx - a0; \ + NeedBits8(4,eof2d); \ + if (GetBits(4)) \ + unexpected("EOL", a0); \ + ClrBits(4); \ + EOLcnt = 1; \ + goto eol2d; \ + default: \ + badMain2d: \ + unexpected("MainTable", a0); \ + goto eol2d; \ + badBlack2d: \ + unexpected("BlackTable", a0); \ + goto eol2d; \ + badWhite2d: \ + unexpected("WhiteTable", a0); \ + goto eol2d; \ + eof2d: \ + prematureEOF(a0); \ + CLEANUP_RUNS(); \ + goto eoflab; \ + } \ + } \ + if (RunLength) { \ + if (RunLength + a0 < lastx) { \ + /* expect a final V0 */ \ + NeedBits8(1,eof2d); \ + if (!GetBits(1)) \ + goto badMain2d; \ + ClrBits(1); \ + } \ + SETVAL(0); \ + } \ +eol2d: \ + CLEANUP_RUNS(); \ +} while (0) +#endif /* _FAX3_ */ diff --git a/freeimage241/Source/LibTIFF/tif_flush.c b/freeimage241/Source/LibTIFF/tif_flush.c new file mode 100644 index 0000000..f105607 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_flush.c @@ -0,0 +1,67 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_flush.c,v 1.0 2001-04-13 00:42:32+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +int +TIFFFlush(TIFF* tif) +{ + + if (tif->tif_mode != O_RDONLY) { + if (!TIFFFlushData(tif)) + return (0); + if ((tif->tif_flags & TIFF_DIRTYDIRECT) && + !TIFFWriteDirectory(tif)) + return (0); + } + return (1); +} + +/* + * Flush buffered data to the file. + * + * Frank Warmerdam'2000: I modified this to return 1 if TIFF_BEENWRITING + * is not set, so that TIFFFlush() will proceed to write out the directory. + * The documentation says returning 1 is an error indicator, but not having + * been writing isn't exactly a an error. Hopefully this doesn't cause + * problems for other people. + */ +int +TIFFFlushData(TIFF* tif) +{ + if ((tif->tif_flags & TIFF_BEENWRITING) == 0) + return (0); + if (tif->tif_flags & TIFF_POSTENCODE) { + tif->tif_flags &= ~TIFF_POSTENCODE; + if (!(*tif->tif_postencode)(tif)) + return (0); + } + return (TIFFFlushData1(tif)); +} + diff --git a/freeimage241/Source/LibTIFF/tif_getimage.c b/freeimage241/Source/LibTIFF/tif_getimage.c new file mode 100644 index 0000000..6edaed3 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_getimage.c @@ -0,0 +1,2291 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_getimage.c,v 1.0 2001-04-13 00:42:33+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library + * + * Read and return a packed RGBA image. + */ + +#pragma warning (disable : 4550) + +#include "tiffiop.h" +#include +#include + +static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32); +static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); +static int pickTileContigCase(TIFFRGBAImage*); +static int pickTileSeparateCase(TIFFRGBAImage*); + +static const char photoTag[] = "PhotometricInterpretation"; + +/* + * Check the image to see if TIFFReadRGBAImage can deal with it. + * 1/0 is returned according to whether or not the image can + * be handled. If 0 is returned, emsg contains the reason + * why it is being rejected. + */ +int +TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) +{ + TIFFDirectory* td = &tif->tif_dir; + uint16 photometric; + int colorchannels; + + switch (td->td_bitspersample) { + case 1: case 2: case 4: + case 8: case 16: + break; + default: + sprintf(emsg, "Sorry, can not handle images with %d-bit samples", + td->td_bitspersample); + return (0); + } + colorchannels = td->td_samplesperpixel - td->td_extrasamples; + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { + switch (colorchannels) { + case 1: + photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + photometric = PHOTOMETRIC_RGB; + break; + default: + sprintf(emsg, "Missing needed %s tag", photoTag); + return (0); + } + } + switch (photometric) { + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_PALETTE: + if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_samplesperpixel != 1) { + sprintf(emsg, + "Sorry, can not handle contiguous data with %s=%d, and %s=%d", + photoTag, photometric, + "Samples/pixel", td->td_samplesperpixel); + return (0); + } + break; + case PHOTOMETRIC_YCBCR: + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d", + "Planarconfiguration", td->td_planarconfig); + return (0); + } + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) { + sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + return (0); + } + break; +#ifdef CMYK_SUPPORT + case PHOTOMETRIC_SEPARATED: + if (td->td_inkset != INKSET_CMYK) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "InkSet", td->td_inkset); + return (0); + } + if (td->td_samplesperpixel != 4) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "Samples/pixel", td->td_samplesperpixel); + return (0); + } + break; +#endif + case PHOTOMETRIC_LOGL: + if (td->td_compression != COMPRESSION_SGILOG) { + sprintf(emsg, "Sorry, LogL data must have %s=%d", + "Compression", COMPRESSION_SGILOG); + return (0); + } + break; + case PHOTOMETRIC_LOGLUV: + if (td->td_compression != COMPRESSION_SGILOG && + td->td_compression != COMPRESSION_SGILOG24) { + sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); + return (0); + } + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", + "Planarconfiguration", td->td_planarconfig); + return (0); + } + break; + default: + sprintf(emsg, "Sorry, can not handle image with %s=%d", + photoTag, photometric); + return (0); + } + return (1); +} + +void +TIFFRGBAImageEnd(TIFFRGBAImage* img) +{ + if (img->Map) + _TIFFfree(img->Map), img->Map = NULL; + if (img->BWmap) + _TIFFfree(img->BWmap), img->BWmap = NULL; + if (img->PALmap) + _TIFFfree(img->PALmap), img->PALmap = NULL; + if (img->ycbcr) + _TIFFfree(img->ycbcr), img->ycbcr = NULL; + + if( img->redcmap ) { + _TIFFfree( img->redcmap ); + _TIFFfree( img->greencmap ); + _TIFFfree( img->bluecmap ); + } +} + +static int +isCCITTCompression(TIFF* tif) +{ + uint16 compress; + TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress); + return (compress == COMPRESSION_CCITTFAX3 || + compress == COMPRESSION_CCITTFAX4 || + compress == COMPRESSION_CCITTRLE || + compress == COMPRESSION_CCITTRLEW); +} + +int +TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) +{ + uint16* sampleinfo; + uint16 extrasamples; + uint16 planarconfig; + uint16 compress; + int colorchannels; + uint16 *red_orig, *green_orig, *blue_orig; + int n_color; + + /* Initialize to normal values */ + img->row_offset = 0; + img->col_offset = 0; + img->redcmap = NULL; + img->greencmap = NULL; + img->bluecmap = NULL; + + img->tif = tif; + img->stoponerr = stop; + TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); + switch (img->bitspersample) { + case 1: case 2: case 4: + case 8: case 16: + break; + default: + sprintf(emsg, "Sorry, can not image with %d-bit samples", + img->bitspersample); + return (0); + } + img->alpha = 0; + TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, + &extrasamples, &sampleinfo); + if (extrasamples == 1) + switch (sampleinfo[0]) { + case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ + case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ + img->alpha = sampleinfo[0]; + break; + } + colorchannels = img->samplesperpixel - extrasamples; + TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); + TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); + if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) { + switch (colorchannels) { + case 1: + if (isCCITTCompression(tif)) + img->photometric = PHOTOMETRIC_MINISWHITE; + else + img->photometric = PHOTOMETRIC_MINISBLACK; + break; + case 3: + img->photometric = PHOTOMETRIC_RGB; + break; + default: + sprintf(emsg, "Missing needed %s tag", photoTag); + return (0); + } + } + switch (img->photometric) { + case PHOTOMETRIC_PALETTE: + if (!TIFFGetField(tif, TIFFTAG_COLORMAP, + &red_orig, &green_orig, &blue_orig)) { + TIFFError(TIFFFileName(tif), "Missing required \"Colormap\" tag"); + return (0); + } + + /* copy the colormaps so we can modify them */ + n_color = (1L << img->bitspersample); + img->redcmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + img->greencmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + img->bluecmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color); + if( !img->redcmap || !img->greencmap || !img->bluecmap ) { + TIFFError(TIFFFileName(tif), "Out of memory for colormap copy"); + return (0); + } + + memcpy( img->redcmap, red_orig, n_color * 2 ); + memcpy( img->greencmap, green_orig, n_color * 2 ); + memcpy( img->bluecmap, blue_orig, n_color * 2 ); + + /* fall thru... */ + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) { + sprintf(emsg, + "Sorry, can not handle contiguous data with %s=%d, and %s=%d", + photoTag, img->photometric, + "Samples/pixel", img->samplesperpixel); + return (0); + } + break; + case PHOTOMETRIC_YCBCR: + if (planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d", + "Planarconfiguration", planarconfig); + return (0); + } + /* It would probably be nice to have a reality check here. */ + if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { + /* can rely on libjpeg to convert to RGB */ + /* XXX should restore current state on exit */ + TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + img->photometric = PHOTOMETRIC_RGB; + } + break; + case PHOTOMETRIC_RGB: + if (colorchannels < 3) { + sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", + "Color channels", colorchannels); + return (0); + } + break; + case PHOTOMETRIC_SEPARATED: { + uint16 inkset; + TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); + if (inkset != INKSET_CMYK) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "InkSet", inkset); + return (0); + } + if (img->samplesperpixel != 4) { + sprintf(emsg, "Sorry, can not handle separated image with %s=%d", + "Samples/pixel", img->samplesperpixel); + return (0); + } + break; + } + case PHOTOMETRIC_LOGL: + if (compress != COMPRESSION_SGILOG) { + sprintf(emsg, "Sorry, LogL data must have %s=%d", + "Compression", COMPRESSION_SGILOG); + return (0); + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */ + img->bitspersample = 8; + break; + case PHOTOMETRIC_LOGLUV: + if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) { + sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", + "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); + return (0); + } + if (planarconfig != PLANARCONFIG_CONTIG) { + sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", + "Planarconfiguration", planarconfig); + return (0); + } + TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); + img->photometric = PHOTOMETRIC_RGB; /* little white lie */ + img->bitspersample = 8; + break; + default: + sprintf(emsg, "Sorry, can not handle image with %s=%d", + photoTag, img->photometric); + return (0); + } + img->Map = NULL; + img->BWmap = NULL; + img->PALmap = NULL; + img->ycbcr = NULL; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); + TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); + img->isContig = + !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1); + if (img->isContig) { + img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig; + (void) pickTileContigCase(img); + } else { + img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate; + (void) pickTileSeparateCase(img); + } + return (1); +} + +int +TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + if (img->get == NULL) { + TIFFError(TIFFFileName(img->tif), "No \"get\" routine setup"); + return (0); + } + if (img->put.any == NULL) { + TIFFError(TIFFFileName(img->tif), + "No \"put\" routine setupl; probably can not handle image format"); + return (0); + } + return (*img->get)(img, raster, w, h); +} + +/* + * Read the specified image into an ABGR-format raster. + */ +int +TIFFReadRGBAImage(TIFF* tif, + uint32 rwidth, uint32 rheight, uint32* raster, int stop) +{ + char emsg[1024]; + TIFFRGBAImage img; + int ok; + + if (TIFFRGBAImageBegin(&img, tif, stop, emsg)) { + /* XXX verify rwidth and rheight against width and height */ + ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth, + rwidth, img.height); + TIFFRGBAImageEnd(&img); + } else { + TIFFError(TIFFFileName(tif), emsg); + ok = 0; + } + return (ok); +} + +static uint32 +setorientation(TIFFRGBAImage* img, uint32 h) +{ + TIFF* tif = img->tif; + uint32 y; + + switch (img->orientation) { + case ORIENTATION_BOTRIGHT: + case ORIENTATION_RIGHTBOT: /* XXX */ + case ORIENTATION_LEFTBOT: /* XXX */ + TIFFWarning(TIFFFileName(tif), "using bottom-left orientation"); + img->orientation = ORIENTATION_BOTLEFT; + /* fall thru... */ + case ORIENTATION_BOTLEFT: + y = 0; + break; + case ORIENTATION_TOPRIGHT: + case ORIENTATION_RIGHTTOP: /* XXX */ + case ORIENTATION_LEFTTOP: /* XXX */ + default: + TIFFWarning(TIFFFileName(tif), "using top-left orientation"); + img->orientation = ORIENTATION_TOPLEFT; + /* fall thru... */ + case ORIENTATION_TOPLEFT: + y = h-1; + break; + } + return (y); +} + +/* + * Get an tile-organized image that has + * PlanarConfiguration contiguous if SamplesPerPixel > 1 + * or + * SamplesPerPixel == 1 + */ +static int +gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileContigRoutine put = img->put.contig; + uint16 orientation; + uint32 col, row, y; + uint32 tw, th; + u_char* buf; + int32 fromskew, toskew; + uint32 nrow; + + buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif)); + if (buf == 0) { + TIFFError(TIFFFileName(tif), "No space for tile buffer"); + return (0); + } + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); + y = setorientation(img, h); + orientation = img->orientation; + toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? tw+w : tw-w); + for (row = 0; row < h; row += th) { + nrow = (row + th > h ? h - row : th); + for (col = 0; col < w; col += tw) { + if (TIFFReadTile(tif, buf, col+img->col_offset, + row+img->row_offset, 0, 0) < 0 && img->stoponerr) + break; + if (col + tw > w) { + /* + * Tile is clipped horizontally. Calculate + * visible portion and skewing factors. + */ + uint32 npix = w - col; + fromskew = tw - npix; + (*put)(img, raster+y*w+col, col, y, + npix, nrow, fromskew, toskew + fromskew, buf); + } else { + (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf); + } + } + y += (orientation == ORIENTATION_TOPLEFT ? + -(int32) nrow : (int32) nrow); + } + _TIFFfree(buf); + return (1); +} + +/* + * Get an tile-organized image that has + * SamplesPerPixel > 1 + * PlanarConfiguration separated + * We assume that all such images are RGB. + */ +static int +gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileSeparateRoutine put = img->put.separate; + uint16 orientation; + uint32 col, row, y; + uint32 tw, th; + u_char* buf; + u_char* r; + u_char* g; + u_char* b; + u_char* a; + tsize_t tilesize; + int32 fromskew, toskew; + int alpha = img->alpha; + uint32 nrow; + + tilesize = TIFFTileSize(tif); + buf = (u_char*) _TIFFmalloc(4*tilesize); + if (buf == 0) { + TIFFError(TIFFFileName(tif), "No space for tile buffer"); + return (0); + } + r = buf; + g = r + tilesize; + b = g + tilesize; + a = b + tilesize; + if (!alpha) + memset(a, 0xff, tilesize); + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); + TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); + y = setorientation(img, h); + orientation = img->orientation; + toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? tw+w : tw-w); + for (row = 0; row < h; row += th) { + nrow = (row + th > h ? h - row : th); + for (col = 0; col < w; col += tw) { + if (TIFFReadTile(tif, r, col+img->col_offset, + row+img->row_offset,0,0) < 0 && img->stoponerr) + break; + if (TIFFReadTile(tif, g, col+img->col_offset, + row+img->row_offset,0,1) < 0 && img->stoponerr) + break; + if (TIFFReadTile(tif, b, col+img->col_offset, + row+img->row_offset,0,2) < 0 && img->stoponerr) + break; + if (alpha && TIFFReadTile(tif,a,col+img->col_offset, + row+img->row_offset,0,3) < 0 && img->stoponerr) + break; + if (col + tw > w) { + /* + * Tile is clipped horizontally. Calculate + * visible portion and skewing factors. + */ + uint32 npix = w - col; + fromskew = tw - npix; + (*put)(img, raster+y*w+col, col, y, + npix, nrow, fromskew, toskew + fromskew, r, g, b, a); + } else { + (*put)(img, raster+y*w+col, col, y, + tw, nrow, 0, toskew, r, g, b, a); + } + } + y += (orientation == ORIENTATION_TOPLEFT ? + -(int32) nrow : (int32) nrow); + } + _TIFFfree(buf); + return (1); +} + +/* + * Get a strip-organized image that has + * PlanarConfiguration contiguous if SamplesPerPixel > 1 + * or + * SamplesPerPixel == 1 + */ +static int +gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileContigRoutine put = img->put.contig; + uint16 orientation; + uint32 row, y, nrow; + u_char* buf; + uint32 rowsperstrip; + uint32 imagewidth = img->width; + tsize_t scanline; + int32 fromskew, toskew; + + buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif)); + if (buf == 0) { + TIFFError(TIFFFileName(tif), "No space for strip buffer"); + return (0); + } + y = setorientation(img, h); + orientation = img->orientation; + toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? w+w : w-w); + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + scanline = TIFFScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += rowsperstrip) { + nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); + if (TIFFReadEncodedStrip(tif, + TIFFComputeStrip(tif,row+img->row_offset, 0), + buf, nrow*scanline) < 0 + && img->stoponerr) + break; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf); + y += (orientation == ORIENTATION_TOPLEFT ? + -(int32) nrow : (int32) nrow); + } + _TIFFfree(buf); + return (1); +} + +/* + * Get a strip-organized image with + * SamplesPerPixel > 1 + * PlanarConfiguration separated + * We assume that all such images are RGB. + */ +static int +gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) +{ + TIFF* tif = img->tif; + tileSeparateRoutine put = img->put.separate; + uint16 orientation; + u_char *buf; + u_char *r, *g, *b, *a; + uint32 row, y, nrow; + tsize_t scanline; + uint32 rowsperstrip, offset_row; + uint32 imagewidth = img->width; + tsize_t stripsize; + int32 fromskew, toskew; + int alpha = img->alpha; + + stripsize = TIFFStripSize(tif); + r = buf = (u_char *)_TIFFmalloc(4*stripsize); + if (buf == 0) { + TIFFError(TIFFFileName(tif), "No space for tile buffer"); + return (0); + } + g = r + stripsize; + b = g + stripsize; + a = b + stripsize; + if (!alpha) + memset(a, 0xff, stripsize); + y = setorientation(img, h); + orientation = img->orientation; + toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? w+w : w-w); + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + scanline = TIFFScanlineSize(tif); + fromskew = (w < imagewidth ? imagewidth - w : 0); + for (row = 0; row < h; row += rowsperstrip) { + nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); + offset_row = row + img->row_offset; + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), + r, nrow*scanline) < 0 && img->stoponerr) + break; + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), + g, nrow*scanline) < 0 && img->stoponerr) + break; + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), + b, nrow*scanline) < 0 && img->stoponerr) + break; + if (alpha && + (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 3), + a, nrow*scanline) < 0 && img->stoponerr)) + break; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, r, g, b, a); + y += (orientation == ORIENTATION_TOPLEFT ? + -(int32) nrow : (int32) nrow); + } + _TIFFfree(buf); + return (1); +} + +/* + * The following routines move decoded data returned + * from the TIFF library into rasters filled with packed + * ABGR pixels (i.e. suitable for passing to lrecwrite.) + * + * The routines have been created according to the most + * important cases and optimized. pickTileContigCase and + * pickTileSeparateCase analyze the parameters and select + * the appropriate "put" routine to use. + */ +#define REPEAT8(op) REPEAT4(op); REPEAT4(op) +#define REPEAT4(op) REPEAT2(op); REPEAT2(op) +#define REPEAT2(op) op; op +#define CASE8(x,op) \ + switch (x) { \ + case 7: op; case 6: op; case 5: op; \ + case 4: op; case 3: op; case 2: op; \ + case 1: op; \ + } +#define CASE4(x,op) switch (x) { case 3: op; case 2: op; case 1: op; } +#define NOP + +#define UNROLL8(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 8; _x -= 8) { \ + op1; \ + REPEAT8(op2); \ + } \ + if (_x > 0) { \ + op1; \ + CASE8(_x,op2); \ + } \ +} +#define UNROLL4(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 4; _x -= 4) { \ + op1; \ + REPEAT4(op2); \ + } \ + if (_x > 0) { \ + op1; \ + CASE4(_x,op2); \ + } \ +} +#define UNROLL2(w, op1, op2) { \ + uint32 _x; \ + for (_x = w; _x >= 2; _x -= 2) { \ + op1; \ + REPEAT2(op2); \ + } \ + if (_x) { \ + op1; \ + op2; \ + } \ +} + +#define SKEW(r,g,b,skew) { r += skew; g += skew; b += skew; } +#define SKEW4(r,g,b,a,skew) { r += skew; g += skew; b += skew; a+= skew; } + +#define A1 ((uint32)(0xffL<<24)) +#define PACK(r,g,b) \ + ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1) +#define PACK4(r,g,b,a) \ + ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24)) +#define W2B(v) (((v)>>8)&0xff) +#define PACKW(r,g,b) \ + ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1) +#define PACKW4(r,g,b,a) \ + ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24)) + +#define DECLAREContigPutFunc(name) \ +static void name(\ + TIFFRGBAImage* img, \ + uint32* cp, \ + uint32 x, uint32 y, \ + uint32 w, uint32 h, \ + int32 fromskew, int32 toskew, \ + u_char* pp \ +) + +/* + * 8-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put8bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + while (h-- > 0) { + UNROLL8(w, NOP, *cp++ = PALmap[*pp++][0]); + cp += toskew; + pp += fromskew; + } +} + +/* + * 4-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put4bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 2; + while (h-- > 0) { + uint32* bw; + UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 2-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put2bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 4; + while (h-- > 0) { + uint32* bw; + UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 1-bit palette => colormap/RGB + */ +DECLAREContigPutFunc(put1bitcmaptile) +{ + uint32** PALmap = img->PALmap; + + (void) x; (void) y; + fromskew /= 8; + while (h-- > 0) { + uint32* bw; + UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(putgreytile) +{ + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + for (x = w; x-- > 0;) + *cp++ = BWmap[*pp++][0]; + cp += toskew; + pp += fromskew; + } +} + +/* + * 1-bit bilevel => colormap/RGB + */ +DECLAREContigPutFunc(put1bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 8; + while (h-- > 0) { + uint32* bw; + UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 2-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put2bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 4; + while (h-- > 0) { + uint32* bw; + UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 4-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put4bitbwtile) +{ + uint32** BWmap = img->BWmap; + + (void) x; (void) y; + fromskew /= 2; + while (h-- > 0) { + uint32* bw; + UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples, no Map => RGB + */ +DECLAREContigPutFunc(putRGBcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + *cp++ = PACK(pp[0], pp[1], pp[2]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples, w/ Map => RGB + */ +DECLAREContigPutFunc(putRGBcontig8bitMaptile) +{ + TIFFRGBValue* Map = img->Map; + int samplesperpixel = img->samplesperpixel; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + *cp++ = PACK(Map[pp[0]], Map[pp[1]], Map[pp[2]]); + pp += samplesperpixel; + } + pp += fromskew; + cp += toskew; + } +} + +/* + * 8-bit packed samples => RGBA w/ associated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBAAcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed samples => RGBA w/ unassociated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBUAcontig8bittile) +{ + int samplesperpixel = img->samplesperpixel; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + uint32 r, g, b, a; + for (x = w; x-- > 0;) { + a = pp[3]; + r = (pp[0] * a) / 255; + g = (pp[1] * a) / 255; + b = (pp[2] * a) / 255; + *cp++ = PACK4(r,g,b,a); + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 16-bit packed samples => RGB + */ +DECLAREContigPutFunc(putRGBcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + *cp++ = PACKW(wp[0], wp[1], wp[2]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 16-bit packed samples => RGBA w/ associated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBAAcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + *cp++ = PACKW4(wp[0], wp[1], wp[2], wp[3]); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 16-bit packed samples => RGBA w/ unassociated alpha + * (known to have Map == NULL) + */ +DECLAREContigPutFunc(putRGBUAcontig16bittile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 *wp = (uint16 *)pp; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + uint32 r,g,b,a; + /* + * We shift alpha down four bits just in case unsigned + * arithmetic doesn't handle the full range. + * We still have plenty of accuracy, since the output is 8 bits. + * So we have (r * 0xffff) * (a * 0xfff)) = r*a * (0xffff*0xfff) + * Since we want r*a * 0xff for eight bit output, + * we divide by (0xffff * 0xfff) / 0xff == 0x10eff. + */ + for (x = w; x-- > 0;) { + a = wp[3] >> 4; + r = (wp[0] * a) / 0x10eff; + g = (wp[1] * a) / 0x10eff; + b = (wp[2] * a) / 0x10eff; + *cp++ = PACK4(r,g,b,a); + wp += samplesperpixel; + } + cp += toskew; + wp += fromskew; + } +} + +/* + * 8-bit packed CMYK samples w/o Map => RGB + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) +{ + int samplesperpixel = img->samplesperpixel; + uint16 r, g, b, k; + + (void) x; (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + UNROLL8(w, NOP, + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + *cp++ = PACK(r, g, b); + pp += samplesperpixel); + cp += toskew; + pp += fromskew; + } +} + +/* + * 8-bit packed CMYK samples w/Map => RGB + * + * NB: The conversion of CMYK->RGB is *very* crude. + */ +DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) +{ + int samplesperpixel = img->samplesperpixel; + TIFFRGBValue* Map = img->Map; + uint16 r, g, b, k; + + (void) y; + fromskew *= samplesperpixel; + while (h-- > 0) { + for (x = w; x-- > 0;) { + k = 255 - pp[3]; + r = (k*(255-pp[0]))/255; + g = (k*(255-pp[1]))/255; + b = (k*(255-pp[2]))/255; + *cp++ = PACK(Map[r], Map[g], Map[b]); + pp += samplesperpixel; + } + pp += fromskew; + cp += toskew; + } +} + +#define DECLARESepPutFunc(name) \ +static void name(\ + TIFFRGBAImage* img,\ + uint32* cp,\ + uint32 x, uint32 y, \ + uint32 w, uint32 h,\ + int32 fromskew, int32 toskew,\ + u_char* r, u_char* g, u_char* b, u_char* a\ +) + +/* + * 8-bit unpacked samples => RGB + */ +DECLARESepPutFunc(putRGBseparate8bittile) +{ + (void) img; (void) x; (void) y; (void) a; + while (h-- > 0) { + UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++)); + SKEW(r, g, b, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGB + */ +DECLARESepPutFunc(putRGBseparate8bitMaptile) +{ + TIFFRGBValue* Map = img->Map; + + (void) y; (void) a; + while (h-- > 0) { + for (x = w; x > 0; x--) + *cp++ = PACK(Map[*r++], Map[*g++], Map[*b++]); + SKEW(r, g, b, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGBA w/ associated alpha + */ +DECLARESepPutFunc(putRGBAAseparate8bittile) +{ + (void) img; (void) x; (void) y; + while (h-- > 0) { + UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++)); + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + +/* + * 8-bit unpacked samples => RGBA w/ unassociated alpha + */ +DECLARESepPutFunc(putRGBUAseparate8bittile) +{ + (void) img; (void) y; + while (h-- > 0) { + uint32 rv, gv, bv, av; + for (x = w; x-- > 0;) { + av = *a++; + rv = (*r++ * av) / 255; + gv = (*g++ * av) / 255; + bv = (*b++ * av) / 255; + *cp++ = PACK4(rv,gv,bv,av); + } + SKEW4(r, g, b, a, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGB + */ +DECLARESepPutFunc(putRGBseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + + (void) img; (void) y; (void) a; + while (h-- > 0) { + for (x = 0; x < w; x++) + *cp++ = PACKW(*wr++, *wg++, *wb++); + SKEW(wr, wg, wb, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGBA w/ associated alpha + */ +DECLARESepPutFunc(putRGBAAseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + uint16 *wa = (uint16*) a; + + (void) img; (void) y; + while (h-- > 0) { + for (x = 0; x < w; x++) + *cp++ = PACKW4(*wr++, *wg++, *wb++, *wa++); + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } +} + +/* + * 16-bit unpacked samples => RGBA w/ unassociated alpha + */ +DECLARESepPutFunc(putRGBUAseparate16bittile) +{ + uint16 *wr = (uint16*) r; + uint16 *wg = (uint16*) g; + uint16 *wb = (uint16*) b; + uint16 *wa = (uint16*) a; + + (void) img; (void) y; + while (h-- > 0) { + uint32 r,g,b,a; + /* + * We shift alpha down four bits just in case unsigned + * arithmetic doesn't handle the full range. + * We still have plenty of accuracy, since the output is 8 bits. + * So we have (r * 0xffff) * (a * 0xfff)) = r*a * (0xffff*0xfff) + * Since we want r*a * 0xff for eight bit output, + * we divide by (0xffff * 0xfff) / 0xff == 0x10eff. + */ + for (x = w; x-- > 0;) { + a = *wa++ >> 4; + r = (*wr++ * a) / 0x10eff; + g = (*wg++ * a) / 0x10eff; + b = (*wb++ * a) / 0x10eff; + *cp++ = PACK4(r,g,b,a); + } + SKEW4(wr, wg, wb, wa, fromskew); + cp += toskew; + } +} + +/* + * YCbCr -> RGB conversion and packing routines. The colorspace + * conversion algorithm comes from the IJG v5a code; see below + * for more information on how it works. + */ + +#define YCbCrtoRGB(dst, yc) { \ + int Y = (yc); \ + dst = PACK( \ + clamptab[Y+Crrtab[Cr]], \ + clamptab[Y + (int)((Cbgtab[Cb]+Crgtab[Cr])>>16)], \ + clamptab[Y+Cbbtab[Cb]]); \ +} +#define YCbCrSetup \ + TIFFYCbCrToRGB* ycbcr = img->ycbcr; \ + int* Crrtab = ycbcr->Cr_r_tab; \ + int* Cbbtab = ycbcr->Cb_b_tab; \ + int32* Crgtab = ycbcr->Cr_g_tab; \ + int32* Cbgtab = ycbcr->Cb_g_tab; \ + TIFFRGBValue* clamptab = ycbcr->clamptab + +/* + * 8-bit packed YCbCr samples => RGB + * This function is generic for different sampling sizes, + * and can handle blocks sizes that aren't multiples of the + * sampling size. However, it is substantially less optimized + * than the specific sampling cases. It is used as a fallback + * for difficult blocks. + */ +#ifdef notdef +static void putcontig8bitYCbCrGenericTile( + TIFFRGBAImage* img, + uint32* cp, + uint32 x, uint32 y, + uint32 w, uint32 h, + int32 fromskew, int32 toskew, + u_char* pp, + int h_group, + int v_group ) + +{ + YCbCrSetup; + + uint32* cp1 = cp+w+toskew; + uint32* cp2 = cp1+w+toskew; + uint32* cp3 = cp2+w+toskew; + int32 incr = 3*w+4*toskew; + int Cb, Cr; + int group_size = v_group * h_group + 2; + + (void) y; + fromskew = (fromskew * group_size) / h_group; + + for( yy = 0; yy < h; yy++ ) + { + u_char *pp_line; + int y_line_group = yy / v_group; + int y_remainder = yy - y_line_group * v_group; + + pp_line = pp + v_line_group * + + + for( xx = 0; xx < w; xx++ ) + { + Cb = pp + } + } + for (; h >= 4; h -= 4) { + x = w>>2; + do { + Cb = pp[16]; + Cr = pp[17]; + + YCbCrtoRGB(cp [0], pp[ 0]); + YCbCrtoRGB(cp [1], pp[ 1]); + YCbCrtoRGB(cp [2], pp[ 2]); + YCbCrtoRGB(cp [3], pp[ 3]); + YCbCrtoRGB(cp1[0], pp[ 4]); + YCbCrtoRGB(cp1[1], pp[ 5]); + YCbCrtoRGB(cp1[2], pp[ 6]); + YCbCrtoRGB(cp1[3], pp[ 7]); + YCbCrtoRGB(cp2[0], pp[ 8]); + YCbCrtoRGB(cp2[1], pp[ 9]); + YCbCrtoRGB(cp2[2], pp[10]); + YCbCrtoRGB(cp2[3], pp[11]); + YCbCrtoRGB(cp3[0], pp[12]); + YCbCrtoRGB(cp3[1], pp[13]); + YCbCrtoRGB(cp3[2], pp[14]); + YCbCrtoRGB(cp3[3], pp[15]); + + cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; + pp += 18; + } while (--x); + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } +} +#endif + +/* + * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr44tile) +{ + YCbCrSetup; + uint32* cp1 = cp+w+toskew; + uint32* cp2 = cp1+w+toskew; + uint32* cp3 = cp2+w+toskew; + int32 incr = 3*w+4*toskew; + + (void) y; + /* adjust fromskew */ + fromskew = (fromskew * 18) / 4; + if ((h & 3) == 0 && (w & 3) == 0) { + for (; h >= 4; h -= 4) { + x = w>>2; + do { + int Cb = pp[16]; + int Cr = pp[17]; + + YCbCrtoRGB(cp [0], pp[ 0]); + YCbCrtoRGB(cp [1], pp[ 1]); + YCbCrtoRGB(cp [2], pp[ 2]); + YCbCrtoRGB(cp [3], pp[ 3]); + YCbCrtoRGB(cp1[0], pp[ 4]); + YCbCrtoRGB(cp1[1], pp[ 5]); + YCbCrtoRGB(cp1[2], pp[ 6]); + YCbCrtoRGB(cp1[3], pp[ 7]); + YCbCrtoRGB(cp2[0], pp[ 8]); + YCbCrtoRGB(cp2[1], pp[ 9]); + YCbCrtoRGB(cp2[2], pp[10]); + YCbCrtoRGB(cp2[3], pp[11]); + YCbCrtoRGB(cp3[0], pp[12]); + YCbCrtoRGB(cp3[1], pp[13]); + YCbCrtoRGB(cp3[2], pp[14]); + YCbCrtoRGB(cp3[3], pp[15]); + + cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; + pp += 18; + } while (--x); + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int Cb = pp[16]; + int Cr = pp[17]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; cp2 += x; cp3 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; cp2 += 4; cp3 += 4; + x -= 4; + } + pp += 18; + } + if (h <= 4) + break; + h -= 4; + cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; + pp += fromskew; + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr42tile) +{ + YCbCrSetup; + uint32* cp1 = cp+w+toskew; + int32 incr = 2*toskew+w; + + (void) y; + fromskew = (fromskew * 10) / 4; + if ((h & 3) == 0 && (w & 1) == 0) { + for (; h >= 2; h -= 2) { + x = w>>2; + do { + int Cb = pp[8]; + int Cr = pp[9]; + + YCbCrtoRGB(cp [0], pp[0]); + YCbCrtoRGB(cp [1], pp[1]); + YCbCrtoRGB(cp [2], pp[2]); + YCbCrtoRGB(cp [3], pp[3]); + YCbCrtoRGB(cp1[0], pp[4]); + YCbCrtoRGB(cp1[1], pp[5]); + YCbCrtoRGB(cp1[2], pp[6]); + YCbCrtoRGB(cp1[3], pp[7]); + + cp += 4, cp1 += 4; + pp += 10; + } while (--x); + cp += incr, cp1 += incr; + pp += fromskew; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int Cb = pp[8]; + int Cr = pp[9]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; + x -= 4; + } + pp += 10; + } + if (h <= 2) + break; + h -= 2; + cp += incr, cp1 += incr; + pp += fromskew; + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr41tile) +{ + YCbCrSetup; + + (void) y; + /* XXX adjust fromskew */ + do { + x = w>>2; + do { + int Cb = pp[4]; + int Cr = pp[5]; + + YCbCrtoRGB(cp [0], pp[0]); + YCbCrtoRGB(cp [1], pp[1]); + YCbCrtoRGB(cp [2], pp[2]); + YCbCrtoRGB(cp [3], pp[3]); + + cp += 4; + pp += 6; + } while (--x); + + if( (w&3) != 0 ) + { + int Cb = pp[4]; + int Cr = pp[5]; + + switch( (w&3) ) { + case 3: YCbCrtoRGB(cp [2], pp[2]); + case 2: YCbCrtoRGB(cp [1], pp[1]); + case 1: YCbCrtoRGB(cp [0], pp[0]); + case 0: break; + } + + cp += (w&3); + pp += 6; + } + + cp += toskew; + pp += fromskew; + } while (--h); + +} + +/* + * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr22tile) +{ + YCbCrSetup; + uint32* cp1 = cp+w+toskew; + int32 incr = 2*toskew+w; + + (void) y; + fromskew = (fromskew * 6) / 2; + if ((h & 1) == 0 && (w & 1) == 0) { + for (; h >= 2; h -= 2) { + x = w>>1; + do { + int Cb = pp[4]; + int Cr = pp[5]; + + YCbCrtoRGB(cp [0], pp[0]); + YCbCrtoRGB(cp [1], pp[1]); + YCbCrtoRGB(cp1[0], pp[2]); + YCbCrtoRGB(cp1[1], pp[3]); + + cp += 2, cp1 += 2; + pp += 6; + } while (--x); + cp += incr, cp1 += incr; + pp += fromskew; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int Cb = pp[4]; + int Cr = pp[5]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp1[1], pp[ 3]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp1[0], pp[ 2]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 2) { + cp += x; cp1 += x; + x = 0; + } + else { + cp += 2; cp1 += 2; + x -= 2; + } + pp += 6; + } + if (h <= 2) + break; + h -= 2; + cp += incr, cp1 += incr; + pp += fromskew; + } + } +} + +/* + * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr21tile) +{ + YCbCrSetup; + + (void) y; + fromskew = (fromskew * 4) / 2; + do { + x = w>>1; + do { + int Cb = pp[2]; + int Cr = pp[3]; + + YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[1], pp[1]); + + cp += 2; + pp += 4; + } while (--x); + + if( (w&1) != 0 ) + { + int Cb = pp[2]; + int Cr = pp[3]; + + YCbCrtoRGB(cp [0], pp[0]); + + cp += 1; + pp += 4; + } + + cp += toskew; + pp += fromskew; + } while (--h); +} + +/* + * 8-bit packed YCbCr samples w/ no subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr11tile) +{ + YCbCrSetup; + + (void) y; + fromskew *= 3; + do { + x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */ + do { + int Cb = pp[1]; + int Cr = pp[2]; + + YCbCrtoRGB(*cp++, pp[0]); + + pp += 3; + } while (--x); + cp += toskew; + pp += fromskew; + } while (--h); +} +#undef YCbCrSetup +#undef YCbCrtoRGB + +#define LumaRed coeffs[0] +#define LumaGreen coeffs[1] +#define LumaBlue coeffs[2] +#define SHIFT 16 +#define FIX(x) ((int32)((x) * (1L<RGB conversion tables. The conversion + * is done according to the 6.0 spec: + * + * R = Y + Cr*(2 - 2*LumaRed) + * B = Y + Cb*(2 - 2*LumaBlue) + * G = Y + * - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen + * - LumaRed*Cr*(2-2*LumaRed)/LumaGreen + * + * To avoid floating point arithmetic the fractional constants that + * come out of the equations are represented as fixed point values + * in the range 0...2^16. We also eliminate multiplications by + * pre-calculating possible values indexed by Cb and Cr (this code + * assumes conversion is being done for 8-bit samples). + */ +static void +TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, TIFF* tif) +{ + TIFFRGBValue* clamptab; + float* coeffs; + int i; + + clamptab = (TIFFRGBValue*)( + (tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long))); + _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */ + ycbcr->clamptab = (clamptab += 256); + for (i = 0; i < 256; i++) + clamptab[i] = i; + _TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */ + TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs); + _TIFFmemcpy(ycbcr->coeffs, coeffs, 3*sizeof (float)); + { float f1 = 2-2*LumaRed; int32 D1 = FIX(f1); + float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2); + float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3); + float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4); + int x; + + ycbcr->Cr_r_tab = (int*) (clamptab + 3*256); + ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256; + ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256); + ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256; + /* + * i is the actual input pixel value in the range 0..255 + * Cb and Cr values are in the range -128..127 (actually + * they are in a range defined by the ReferenceBlackWhite + * tag) so there is some range shifting to do here when + * constructing tables indexed by the raw pixel data. + * + * XXX handle ReferenceBlackWhite correctly to calculate + * Cb/Cr values to use in constructing the tables. + */ + for (i = 0, x = -128; i < 256; i++, x++) { + ycbcr->Cr_r_tab[i] = (int)((D1*x + ONE_HALF)>>SHIFT); + ycbcr->Cb_b_tab[i] = (int)((D3*x + ONE_HALF)>>SHIFT); + ycbcr->Cr_g_tab[i] = D2*x; + ycbcr->Cb_g_tab[i] = D4*x + ONE_HALF; + } + } +} +#undef SHIFT +#undef ONE_HALF +#undef FIX +#undef LumaBlue +#undef LumaGreen +#undef LumaRed + +static tileContigRoutine +initYCbCrConversion(TIFFRGBAImage* img) +{ + uint16 hs, vs; + + if (img->ycbcr == NULL) { + img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc( + TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)) + + 4*256*sizeof (TIFFRGBValue) + + 2*256*sizeof (int) + + 2*256*sizeof (int32) + ); + if (img->ycbcr == NULL) { + TIFFError(TIFFFileName(img->tif), + "No space for YCbCr->RGB conversion state"); + return (NULL); + } + TIFFYCbCrToRGBInit(img->ycbcr, img->tif); + } else { + float* coeffs; + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs); + if (_TIFFmemcmp(coeffs, img->ycbcr->coeffs, 3*sizeof (float)) != 0) + TIFFYCbCrToRGBInit(img->ycbcr, img->tif); + } + /* + * The 6.0 spec says that subsampling must be + * one of 1, 2, or 4, and that vertical subsampling + * must always be <= horizontal subsampling; so + * there are only a few possibilities and we just + * enumerate the cases. + */ + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); + switch ((hs<<4)|vs) { + case 0x44: return (putcontig8bitYCbCr44tile); + case 0x42: return (putcontig8bitYCbCr42tile); + case 0x41: return (putcontig8bitYCbCr41tile); + case 0x22: return (putcontig8bitYCbCr22tile); + case 0x21: return (putcontig8bitYCbCr21tile); + case 0x11: return (putcontig8bitYCbCr11tile); + } + return (NULL); +} + +/* + * Greyscale images with less than 8 bits/sample are handled + * with a table to avoid lots of shifts and masks. The table + * is setup so that put*bwtile (below) can retrieve 8/bitspersample + * pixel values simply by indexing into the table with one + * number. + */ +static int +makebwmap(TIFFRGBAImage* img) +{ + TIFFRGBValue* Map = img->Map; + int bitspersample = img->bitspersample; + int nsamples = 8 / bitspersample; + int i; + uint32* p; + + img->BWmap = (uint32**) _TIFFmalloc( + 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); + if (img->BWmap == NULL) { + TIFFError(TIFFFileName(img->tif), "No space for B&W mapping table"); + return (0); + } + p = (uint32*)(img->BWmap + 256); + for (i = 0; i < 256; i++) { + TIFFRGBValue c; + img->BWmap[i] = p; + switch (bitspersample) { +#define GREY(x) c = Map[x]; *p++ = PACK(c,c,c); + case 1: + GREY(i>>7); + GREY((i>>6)&1); + GREY((i>>5)&1); + GREY((i>>4)&1); + GREY((i>>3)&1); + GREY((i>>2)&1); + GREY((i>>1)&1); + GREY(i&1); + break; + case 2: + GREY(i>>6); + GREY((i>>4)&3); + GREY((i>>2)&3); + GREY(i&3); + break; + case 4: + GREY(i>>4); + GREY(i&0xf); + break; + case 8: + GREY(i); + break; + } +#undef GREY + } + return (1); +} + +/* + * Construct a mapping table to convert from the range + * of the data samples to [0,255] --for display. This + * process also handles inverting B&W images when needed. + */ +static int +setupMap(TIFFRGBAImage* img) +{ + int32 x, range; + + range = (int32)((1L<bitspersample)-1); + img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue)); + if (img->Map == NULL) { + TIFFError(TIFFFileName(img->tif), + "No space for photometric conversion table"); + return (0); + } + if (img->photometric == PHOTOMETRIC_MINISWHITE) { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range); + } else { + for (x = 0; x <= range; x++) + img->Map[x] = (TIFFRGBValue) ((x * 255) / range); + } + if (img->bitspersample <= 8 && + (img->photometric == PHOTOMETRIC_MINISBLACK || + img->photometric == PHOTOMETRIC_MINISWHITE)) { + /* + * Use photometric mapping table to construct + * unpacking tables for samples <= 8 bits. + */ + if (!makebwmap(img)) + return (0); + /* no longer need Map, free it */ + _TIFFfree(img->Map), img->Map = NULL; + } + return (1); +} + +static int +checkcmap(TIFFRGBAImage* img) +{ + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + long n = 1L<bitspersample; + + while (n-- > 0) + if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) + return (16); + return (8); +} + +static void +cvtcmap(TIFFRGBAImage* img) +{ + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + long i; + + for (i = (1L<bitspersample)-1; i >= 0; i--) { +#define CVT(x) ((uint16)((x)>>8)) + r[i] = CVT(r[i]); + g[i] = CVT(g[i]); + b[i] = CVT(b[i]); +#undef CVT + } +} + +/* + * Palette images with <= 8 bits/sample are handled + * with a table to avoid lots of shifts and masks. The table + * is setup so that put*cmaptile (below) can retrieve 8/bitspersample + * pixel values simply by indexing into the table with one + * number. + */ +static int +makecmap(TIFFRGBAImage* img) +{ + int bitspersample = img->bitspersample; + int nsamples = 8 / bitspersample; + uint16* r = img->redcmap; + uint16* g = img->greencmap; + uint16* b = img->bluecmap; + uint32 *p; + int i; + + img->PALmap = (uint32**) _TIFFmalloc( + 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); + if (img->PALmap == NULL) { + TIFFError(TIFFFileName(img->tif), "No space for Palette mapping table"); + return (0); + } + p = (uint32*)(img->PALmap + 256); + for (i = 0; i < 256; i++) { + TIFFRGBValue c; + img->PALmap[i] = p; +#define CMAP(x) c = x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff); + switch (bitspersample) { + case 1: + CMAP(i>>7); + CMAP((i>>6)&1); + CMAP((i>>5)&1); + CMAP((i>>4)&1); + CMAP((i>>3)&1); + CMAP((i>>2)&1); + CMAP((i>>1)&1); + CMAP(i&1); + break; + case 2: + CMAP(i>>6); + CMAP((i>>4)&3); + CMAP((i>>2)&3); + CMAP(i&3); + break; + case 4: + CMAP(i>>4); + CMAP(i&0xf); + break; + case 8: + CMAP(i); + break; + } +#undef CMAP + } + return (1); +} + +/* + * Construct any mapping table used + * by the associated put routine. + */ +static int +buildMap(TIFFRGBAImage* img) +{ + switch (img->photometric) { + case PHOTOMETRIC_RGB: + case PHOTOMETRIC_YCBCR: + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8) + break; + /* fall thru... */ + case PHOTOMETRIC_MINISBLACK: + case PHOTOMETRIC_MINISWHITE: + if (!setupMap(img)) + return (0); + break; + case PHOTOMETRIC_PALETTE: + /* + * Convert 16-bit colormap to 8-bit (unless it looks + * like an old-style 8-bit colormap). + */ + if (checkcmap(img) == 16) + cvtcmap(img); + else + TIFFWarning(TIFFFileName(img->tif), "Assuming 8-bit colormap"); + /* + * Use mapping table and colormap to construct + * unpacking tables for samples < 8 bits. + */ + if (img->bitspersample <= 8 && !makecmap(img)) + return (0); + break; + } + return (1); +} + +/* + * Select the appropriate conversion routine for packed data. + */ +static int +pickTileContigCase(TIFFRGBAImage* img) +{ + tileContigRoutine put = 0; + + if (buildMap(img)) { + switch (img->photometric) { + case PHOTOMETRIC_RGB: + switch (img->bitspersample) { + case 8: + if (!img->Map) { + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + put = putRGBAAcontig8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + put = putRGBUAcontig8bittile; + else + put = putRGBcontig8bittile; + } else + put = putRGBcontig8bitMaptile; + break; + case 16: + put = putRGBcontig16bittile; + if (!img->Map) { + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + put = putRGBAAcontig16bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + put = putRGBUAcontig16bittile; + } + break; + } + break; + case PHOTOMETRIC_SEPARATED: + if (img->bitspersample == 8) { + if (!img->Map) + put = putRGBcontig8bitCMYKtile; + else + put = putRGBcontig8bitCMYKMaptile; + } + break; + case PHOTOMETRIC_PALETTE: + switch (img->bitspersample) { + case 8: put = put8bitcmaptile; break; + case 4: put = put4bitcmaptile; break; + case 2: put = put2bitcmaptile; break; + case 1: put = put1bitcmaptile; break; + } + break; + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + switch (img->bitspersample) { + case 8: put = putgreytile; break; + case 4: put = put4bitbwtile; break; + case 2: put = put2bitbwtile; break; + case 1: put = put1bitbwtile; break; + } + break; + case PHOTOMETRIC_YCBCR: + if (img->bitspersample == 8) + put = initYCbCrConversion(img); + break; + } + } + return ((img->put.contig = put) != 0); +} + +/* + * Select the appropriate conversion routine for unpacked data. + * + * NB: we assume that unpacked single channel data is directed + * to the "packed routines. + */ +static int +pickTileSeparateCase(TIFFRGBAImage* img) +{ + tileSeparateRoutine put = 0; + + if (buildMap(img)) { + switch (img->photometric) { + case PHOTOMETRIC_RGB: + switch (img->bitspersample) { + case 8: + if (!img->Map) { + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + put = putRGBAAseparate8bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + put = putRGBUAseparate8bittile; + else + put = putRGBseparate8bittile; + } else + put = putRGBseparate8bitMaptile; + break; + case 16: + put = putRGBseparate16bittile; + if (!img->Map) { + if (img->alpha == EXTRASAMPLE_ASSOCALPHA) + put = putRGBAAseparate16bittile; + else if (img->alpha == EXTRASAMPLE_UNASSALPHA) + put = putRGBUAseparate16bittile; + } + break; + } + break; + } + } + return ((img->put.separate = put) != 0); +} + +/* + * Read a whole strip off data from the file, and convert to RGBA form. + * If this is the last strip, then it will only contain the portion of + * the strip that is actually within the image space. The result is + * organized in bottom to top form. + */ + + +int +TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) + +{ + char emsg[1024]; + TIFFRGBAImage img; + int ok; + uint32 rowsperstrip, rows_to_read; + + if( TIFFIsTiled( tif ) ) + { + TIFFError(TIFFFileName(tif), + "Can't use TIFFReadRGBAStrip() with tiled file."); + return (0); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); + if( (row % rowsperstrip) != 0 ) + { + TIFFError(TIFFFileName(tif), + "Row passed to TIFFReadRGBAStrip() must be first in a strip."); + return (0); + } + + if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + + img.row_offset = row; + img.col_offset = 0; + + if( row + rowsperstrip > img.height ) + rows_to_read = img.height - row; + else + rows_to_read = rowsperstrip; + + ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read ); + + TIFFRGBAImageEnd(&img); + } else { + TIFFError(TIFFFileName(tif), emsg); + ok = 0; + } + + return (ok); +} + +/* + * Read a whole tile off data from the file, and convert to RGBA form. + * The returned RGBA data is organized from bottom to top of tile, + * and may include zeroed areas if the tile extends off the image. + */ + +int +TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) + +{ + char emsg[1024]; + TIFFRGBAImage img; + int ok; + uint32 tile_xsize, tile_ysize; + uint32 read_xsize, read_ysize; + uint32 i_row; + + /* + * Verify that our request is legal - on a tile file, and on a + * tile boundary. + */ + + if( !TIFFIsTiled( tif ) ) + { + TIFFError(TIFFFileName(tif), + "Can't use TIFFReadRGBATile() with stripped file."); + return (0); + } + + TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); + TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); + if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 ) + { + TIFFError(TIFFFileName(tif), + "Row/col passed to TIFFReadRGBATile() must be top" + "left corner of a tile."); + return (0); + } + + /* + * Setup the RGBA reader. + */ + + if ( !TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + TIFFError(TIFFFileName(tif), emsg); + return( 0 ); + } + + /* + * The TIFFRGBAImageGet() function doesn't allow us to get off the + * edge of the image, even to fill an otherwise valid tile. So we + * figure out how much we can read, and fix up the tile buffer to + * a full tile configuration afterwards. + */ + + if( row + tile_ysize > img.height ) + read_ysize = img.height - row; + else + read_ysize = tile_ysize; + + if( col + tile_xsize > img.width ) + read_xsize = img.width - col; + else + read_xsize = tile_xsize; + + /* + * Read the chunk of imagery. + */ + + img.row_offset = row; + img.col_offset = col; + + ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize ); + + TIFFRGBAImageEnd(&img); + + /* + * If our read was incomplete we will need to fix up the tile by + * shifting the data around as if a full tile of data is being returned. + * + * This is all the more complicated because the image is organized in + * bottom to top format. + */ + + if( read_xsize == tile_xsize && read_ysize == tile_ysize ) + return( ok ); + + for( i_row = 0; i_row < read_ysize; i_row++ ) + { + _TIFFmemcpy( raster + (tile_ysize - i_row - 1) * tile_xsize, + raster + (read_ysize - i_row - 1) * read_xsize, + read_xsize * sizeof(uint32) ); + _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize, + 0, sizeof(uint32) * (tile_xsize - read_xsize) ); + } + + for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) + { + _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize, + 0, sizeof(uint32) * tile_xsize ); + } + + return (ok); +} diff --git a/freeimage241/Source/LibTIFF/tif_jpeg.c b/freeimage241/Source/LibTIFF/tif_jpeg.c new file mode 100644 index 0000000..912f278 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_jpeg.c @@ -0,0 +1,1485 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_jpeg.c,v 1.0 2001-04-13 00:42:33+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1994-1997 Sam Leffler + * Copyright (c) 1994-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef JPEG_SUPPORT +/* + * TIFF Library + * + * JPEG Compression support per TIFF Technical Note #2 + * (*not* per the original TIFF 6.0 spec). + * + * This file is simply an interface to the libjpeg library written by + * the Independent JPEG Group. You need release 5 or later of the IJG + * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/. + * + * Contributed by Tom Lane . + */ +#include +#include +#include + +/* We undefine FAR to avoid conflict with JPEG definition */ + +#ifdef FAR +#undef FAR +#endif + +#include "jpeglib.h" +#include "jerror.h" + +/* + * On some machines it may be worthwhile to use _setjmp or sigsetjmp + * in place of plain setjmp. These macros will make it easier. + */ +#define SETJMP(jbuf) setjmp(jbuf) +#define LONGJMP(jbuf,code) longjmp(jbuf,code) +#define JMP_BUF jmp_buf + +typedef struct jpeg_destination_mgr jpeg_destination_mgr; +typedef struct jpeg_source_mgr jpeg_source_mgr; +typedef struct jpeg_error_mgr jpeg_error_mgr; + +/* + * State block for each open TIFF file using + * libjpeg to do JPEG compression/decompression. + * + * libjpeg's visible state is either a jpeg_compress_struct + * or jpeg_decompress_struct depending on which way we + * are going. comm can be used to refer to the fields + * which are common to both. + * + * NB: cinfo is required to be the first member of JPEGState, + * so we can safely cast JPEGState* -> jpeg_xxx_struct* + * and vice versa! + */ +typedef struct { + union { + struct jpeg_compress_struct c; + struct jpeg_decompress_struct d; + struct jpeg_common_struct comm; + } cinfo; /* NB: must be first */ + jpeg_error_mgr err; /* libjpeg error manager */ + JMP_BUF exit_jmpbuf; /* for catching libjpeg failures */ + /* + * The following two members could be a union, but + * they're small enough that it's not worth the effort. + */ + jpeg_destination_mgr dest; /* data dest for compression */ + jpeg_source_mgr src; /* data source for decompression */ + /* private state */ + TIFF* tif; /* back link needed by some code */ + uint16 photometric; /* copy of PhotometricInterpretation */ + uint16 h_sampling; /* luminance sampling factors */ + uint16 v_sampling; + tsize_t bytesperline; /* decompressed bytes per scanline */ + /* pointers to intermediate buffers when processing downsampled data */ + JSAMPARRAY ds_buffer[MAX_COMPONENTS]; + int scancount; /* number of "scanlines" accumulated */ + int samplesperclump; + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFStripMethod defsparent; /* super-class method */ + TIFFTileMethod deftparent; /* super-class method */ + /* pseudo-tag fields */ + void* jpegtables; /* JPEGTables tag value, or NULL */ + uint32 jpegtables_length; /* number of bytes in same */ + int jpegquality; /* Compression quality level */ + int jpegcolormode; /* Auto RGB<=>YCbCr convert? */ + int jpegtablesmode; /* What to put in JPEGTables */ +} JPEGState; + +#define JState(tif) ((JPEGState*)(tif)->tif_data) + +static int JPEGDecode(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGDecodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGEncode(TIFF*, tidata_t, tsize_t, tsample_t); +static int JPEGEncodeRaw(TIFF*, tidata_t, tsize_t, tsample_t); + +#define FIELD_JPEGTABLES (FIELD_CODEC+0) + +static const TIFFFieldInfo jpegFieldInfo[] = { + { TIFFTAG_JPEGTABLES, -1,-1, TIFF_UNDEFINED, FIELD_JPEGTABLES, + FALSE, TRUE, "JPEGTables" }, + { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO, + TRUE, FALSE, "" }, + { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "" }, + { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO, + FALSE, FALSE, "" }, +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +/* + * libjpeg interface layer. + * + * We use setjmp/longjmp to return control to libtiff + * when a fatal error is encountered within the JPEG + * library. We also direct libjpeg error and warning + * messages through the appropriate libtiff handlers. + */ + +/* + * Error handling routines (these replace corresponding + * IJG routines from jerror.c). These are used for both + * compression and decompression. + */ +static void +TIFFjpeg_error_exit(j_common_ptr cinfo) +{ + JPEGState *sp = (JPEGState *) cinfo; /* NB: cinfo assumed first */ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFError("JPEGLib", buffer); /* display the error message */ + jpeg_abort(cinfo); /* clean up libjpeg state */ + LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ +} + +/* + * This routine is invoked only for warning messages, + * since error_exit does its own thing and trace_level + * is never set > 0. + */ +static void +TIFFjpeg_output_message(j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + (*cinfo->err->format_message) (cinfo, buffer); + TIFFWarning("JPEGLib", buffer); +} + +/* + * Interface routines. This layer of routines exists + * primarily to limit side-effects from using setjmp. + * Also, normal/error returns are converted into return + * values per libtiff practice. + */ +#define CALLJPEG(sp, fail, op) (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op)) +#define CALLVJPEG(sp, op) CALLJPEG(sp, 0, ((op),1)) + +static int +TIFFjpeg_create_compress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.c.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_create_decompress(JPEGState* sp) +{ + /* initialize JPEG error handling */ + sp->cinfo.d.err = jpeg_std_error(&sp->err); + sp->err.error_exit = TIFFjpeg_error_exit; + sp->err.output_message = TIFFjpeg_output_message; + + return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_set_defaults(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c)); +} + +static int +TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace) +{ + return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace)); +} + +static int +TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline) +{ + return CALLVJPEG(sp, + jpeg_set_quality(&sp->cinfo.c, quality, force_baseline)); +} + +static int +TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress) +{ + return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress)); +} + +static int +TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables) +{ + return CALLVJPEG(sp, + jpeg_start_compress(&sp->cinfo.c, write_all_tables)); +} + +static int +TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c, + scanlines, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c, + data, (JDIMENSION) num_lines)); +} + +static int +TIFFjpeg_finish_compress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c)); +} + +static int +TIFFjpeg_write_tables(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c)); +} + +static int +TIFFjpeg_read_header(JPEGState* sp, boolean require_image) +{ + return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image)); +} + +static int +TIFFjpeg_start_decompress(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d, + scanlines, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines) +{ + return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d, + data, (JDIMENSION) max_lines)); +} + +static int +TIFFjpeg_finish_decompress(JPEGState* sp) +{ + return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d)); +} + +static int +TIFFjpeg_abort(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm)); +} + +static int +TIFFjpeg_destroy(JPEGState* sp) +{ + return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm)); +} + +static JSAMPARRAY +TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id, + JDIMENSION samplesperrow, JDIMENSION numrows) +{ + return CALLJPEG(sp, (JSAMPARRAY) NULL, + (*sp->cinfo.comm.mem->alloc_sarray) + (&sp->cinfo.comm, pool_id, samplesperrow, numrows)); +} + +/* + * JPEG library destination data manager. + * These routines direct compressed data from libjpeg into the + * libtiff output buffer. + */ + +static void +std_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; +} + +static boolean +std_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + /* the entire buffer has been filled */ + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata; + sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize; + + return (TRUE); +} + +static void +std_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + tif->tif_rawcp = (tidata_t) sp->dest.next_output_byte; + tif->tif_rawcc = + tif->tif_rawdatasize - (tsize_t) sp->dest.free_in_buffer; + /* NB: libtiff does the final buffer flush */ +} + +static void +TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = std_init_destination; + sp->dest.empty_output_buffer = std_empty_output_buffer; + sp->dest.term_destination = std_term_destination; +} + +/* + * Alternate destination manager for outputting to JPEGTables field. + */ + +static void +tables_init_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* while building, jpegtables_length is allocated buffer size */ + sp->dest.next_output_byte = (JOCTET*) sp->jpegtables; + sp->dest.free_in_buffer = (size_t) sp->jpegtables_length; +} + +static boolean +tables_empty_output_buffer(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + void* newbuf; + + /* the entire buffer has been filled; enlarge it by 1000 bytes */ + newbuf = _TIFFrealloc((tdata_t) sp->jpegtables, + (tsize_t) (sp->jpegtables_length + 1000)); + if (newbuf == NULL) + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100); + sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length; + sp->dest.free_in_buffer = (size_t) 1000; + sp->jpegtables = newbuf; + sp->jpegtables_length += 1000; + return (TRUE); +} + +static void +tables_term_destination(j_compress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + /* set tables length to number of bytes actually emitted */ + sp->jpegtables_length -= sp->dest.free_in_buffer; +} + +static int +TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif) +{ + (void) tif; + /* + * Allocate a working buffer for building tables. + * Initial size is 1000 bytes, which is usually adequate. + */ + if (sp->jpegtables) + _TIFFfree(sp->jpegtables); + sp->jpegtables_length = 1000; + sp->jpegtables = (void*) _TIFFmalloc((tsize_t) sp->jpegtables_length); + if (sp->jpegtables == NULL) { + sp->jpegtables_length = 0; + TIFFError("TIFFjpeg_tables_dest", "No space for JPEGTables"); + return (0); + } + sp->cinfo.c.dest = &sp->dest; + sp->dest.init_destination = tables_init_destination; + sp->dest.empty_output_buffer = tables_empty_output_buffer; + sp->dest.term_destination = tables_term_destination; + return (1); +} + +/* + * JPEG library source data manager. + * These routines supply compressed data to libjpeg. + */ + +static void +std_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + TIFF* tif = sp->tif; + + sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata; + sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc; +} + +static boolean +std_fill_input_buffer(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState* ) cinfo; + static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI }; + + /* + * Should never get here since entire strip/tile is + * read into memory before the decompressor is called, + * and thus was supplied by init_source. + */ + WARNMS(cinfo, JWRN_JPEG_EOF); + /* insert a fake EOI marker */ + sp->src.next_input_byte = dummy_EOI; + sp->src.bytes_in_buffer = 2; + return (TRUE); +} + +static void +std_skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + JPEGState* sp = (JPEGState*) cinfo; + + if (num_bytes > 0) { + if (num_bytes > (long) sp->src.bytes_in_buffer) { + /* oops, buffer overrun */ + (void) std_fill_input_buffer(cinfo); + } else { + sp->src.next_input_byte += (size_t) num_bytes; + sp->src.bytes_in_buffer -= (size_t) num_bytes; + } + } +} + +static void +std_term_source(j_decompress_ptr cinfo) +{ + /* No work necessary here */ + /* Or must we update tif->tif_rawcp, tif->tif_rawcc ??? */ + /* (if so, need empty tables_term_source!) */ + (void) cinfo; +} + +static void +TIFFjpeg_data_src(JPEGState* sp, TIFF* tif) +{ + (void) tif; + sp->cinfo.d.src = &sp->src; + sp->src.init_source = std_init_source; + sp->src.fill_input_buffer = std_fill_input_buffer; + sp->src.skip_input_data = std_skip_input_data; + sp->src.resync_to_restart = jpeg_resync_to_restart; + sp->src.term_source = std_term_source; + sp->src.bytes_in_buffer = 0; /* for safety */ + sp->src.next_input_byte = NULL; +} + +/* + * Alternate source manager for reading from JPEGTables. + * We can share all the code except for the init routine. + */ + +static void +tables_init_source(j_decompress_ptr cinfo) +{ + JPEGState* sp = (JPEGState*) cinfo; + + sp->src.next_input_byte = (const JOCTET*) sp->jpegtables; + sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length; +} + +static void +TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif) +{ + TIFFjpeg_data_src(sp, tif); + sp->src.init_source = tables_init_source; +} + +/* + * Allocate downsampled-data buffers needed for downsampled I/O. + * We use values computed in jpeg_start_compress or jpeg_start_decompress. + * We use libjpeg's allocator so that buffers will be released automatically + * when done with strip/tile. + * This is also a handy place to compute samplesperclump, bytesperline. + */ +static int +alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info, + int num_components) +{ + JPEGState* sp = JState(tif); + int ci; + jpeg_component_info* compptr; + JSAMPARRAY buf; + int samples_per_clump = 0; + + for (ci = 0, compptr = comp_info; ci < num_components; + ci++, compptr++) { + samples_per_clump += compptr->h_samp_factor * + compptr->v_samp_factor; + buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE, + compptr->width_in_blocks * DCTSIZE, + (JDIMENSION) (compptr->v_samp_factor*DCTSIZE)); + if (buf == NULL) + return (0); + sp->ds_buffer[ci] = buf; + } + sp->samplesperclump = samples_per_clump; + /* Cb,Cr both have sampling factors 1 */ + /* so downsampled width of Cb is # of clumps per line */ + sp->bytesperline = sizeof(JSAMPLE) * samples_per_clump * + comp_info[1].downsampled_width; + return (1); +} + + +/* + * JPEG Decoding. + */ + +static int +JPEGSetupDecode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + + /* Read JPEGTables if it is present */ + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) { + TIFFjpeg_tables_src(sp, tif); + if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) { + TIFFError("JPEGSetupDecode", "Bogus JPEGTables field"); + return (0); + } + } + + /* Grab parameters that are same for all strips/tiles */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + break; + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Set up for reading normal data */ + TIFFjpeg_data_src(sp, tif); + tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */ + return (1); +} + +/* + * Set up for decoding a strip or tile. + */ +static int +JPEGPreDecode(TIFF* tif, tsample_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreDecode"; + uint32 segment_width, segment_height; + int downsampled_output; + int ci; + + assert(sp != NULL); + assert(sp->cinfo.comm.is_decompressor); + /* + * Reset decoder state from any previous strip/tile, + * in case application didn't read the whole strip. + */ + if (!TIFFjpeg_abort(sp)) + return (0); + /* + * Read the header for this strip/tile. + */ + if (TIFFjpeg_read_header(sp, TRUE) != JPEG_HEADER_OK) + return (0); + /* + * Check image parameters and set decompression parameters. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* + * For PC 2, scale down the expected strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany(segment_width, sp->h_sampling); + segment_height = TIFFhowmany(segment_height, sp->v_sampling); + } + if (sp->cinfo.d.image_width != segment_width || + sp->cinfo.d.image_height != segment_height) { + TIFFError(module, "Improper JPEG strip/tile size"); + return (0); + } + if (sp->cinfo.d.num_components != + (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1)) { + TIFFError(module, "Improper JPEG component count"); + return (0); + } + if (sp->cinfo.d.data_precision != td->td_bitspersample) { + TIFFError(module, "Improper JPEG data precision"); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + /* Component 0 should have expected sampling factors */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling || + sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling) { + TIFFError(module, "Improper JPEG sampling factors"); + return (0); + } + /* Rest should have sampling factors 1,1 */ + for (ci = 1; ci < sp->cinfo.d.num_components; ci++) { + if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 || + sp->cinfo.d.comp_info[ci].v_samp_factor != 1) { + TIFFError(module, "Improper JPEG sampling factors"); + return (0); + } + } + } else { + /* PC 2's single component should have sampling factors 1,1 */ + if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 || + sp->cinfo.d.comp_info[0].v_samp_factor != 1) { + TIFFError(module, "Improper JPEG sampling factors"); + return (0); + } + } + downsampled_output = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + sp->photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + /* Convert YCbCr to RGB */ + sp->cinfo.d.jpeg_color_space = JCS_YCbCr; + sp->cinfo.d.out_color_space = JCS_RGB; + } else { + /* Suppress colorspace handling */ + sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN; + sp->cinfo.d.out_color_space = JCS_UNKNOWN; + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + (sp->h_sampling != 1 || sp->v_sampling != 1)) + downsampled_output = TRUE; + /* XXX what about up-sampling? */ + } + if (downsampled_output) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.d.raw_data_out = TRUE; + tif->tif_decoderow = JPEGDecodeRaw; + tif->tif_decodestrip = JPEGDecodeRaw; + tif->tif_decodetile = JPEGDecodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.d.raw_data_out = FALSE; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + } + /* Start JPEG decompressor */ + if (!TIFFjpeg_start_decompress(sp)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_output) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info, + sp->cinfo.d.num_components)) + return (0); + sp->scancount = DCTSIZE; /* mark buffer empty */ + } + return (1); +} + +/* + * Decode a chunk of pixels. + * "Standard" case: returned data is not downsampled. + */ +static int +JPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + tsize_t nrows; + JSAMPROW bufptr[1]; + + (void) s; + assert(sp != NULL); + /* data is expected to be read in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline not read"); + + while (nrows-- > 0) { + bufptr[0] = (JSAMPROW) buf; + if (TIFFjpeg_read_scanlines(sp, bufptr, 1) != 1) + return (0); + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + /* Close down the decompressor if we've finished the strip or tile. */ + if (sp->cinfo.d.output_scanline == sp->cinfo.d.output_height) { + if (TIFFjpeg_finish_decompress(sp) != TRUE) + return (0); + } + return (1); +} + +/* + * Decode a chunk of pixels. + * Returned data is downsampled per sampling factors. + */ +static int +JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + JSAMPLE* inptr; + JSAMPLE* outptr; + tsize_t nrows; + JDIMENSION clumps_per_line, nclump; + int clumpoffset, ci, xpos, ypos; + jpeg_component_info* compptr; + int samples_per_clump = sp->samplesperclump; + + (void) s; + assert(sp != NULL); + /* data is expected to be read in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline not read"); + + /* Cb,Cr both have sampling factors 1, so this is correct */ + clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width; + + while (nrows-- > 0) { + /* Reload downsampled-data buffer if needed */ + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + /* + * Fastest way to unseparate the data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.d.comp_info; + ci < sp->cinfo.d.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + for (ypos = 0; ypos < vsamp; ypos++) { + inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + outptr = ((JSAMPLE*) buf) + clumpoffset; + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + outptr[0] = *inptr++; + outptr += samples_per_clump; + } + } else { + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + outptr[xpos] = *inptr++; + outptr += samples_per_clump; + } + } + clumpoffset += hsamp; + } + } + sp->scancount++; + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + + /* Close down the decompressor if done. */ + if (sp->cinfo.d.output_scanline >= sp->cinfo.d.output_height) { + if (TIFFjpeg_finish_decompress(sp) != TRUE) + return (0); + } + + return (1); +} + + +/* + * JPEG Encoding. + */ + +static void +unsuppress_quant_table (JPEGState* sp, int tblno) +{ + JQUANT_TBL* qtbl; + + if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL) + qtbl->sent_table = FALSE; +} + +static void +unsuppress_huff_table (JPEGState* sp, int tblno) +{ + JHUFF_TBL* htbl; + + if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; + if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL) + htbl->sent_table = FALSE; +} + +static int +prepare_JPEGTables(TIFF* tif) +{ + JPEGState* sp = JState(tif); + + /* Initialize quant tables for current quality setting */ + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + /* Mark only the tables we want for output */ + /* NB: chrominance tables are currently used only with YCbCr */ + if (!TIFFjpeg_suppress_tables(sp, TRUE)) + return (0); + if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) { + unsuppress_quant_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) { + unsuppress_huff_table(sp, 0); + if (sp->photometric == PHOTOMETRIC_YCBCR) + unsuppress_huff_table(sp, 1); + } + /* Direct libjpeg output into jpegtables */ + if (!TIFFjpeg_tables_dest(sp, tif)) + return (0); + /* Emit tables-only datastream */ + if (!TIFFjpeg_write_tables(sp)) + return (0); + + return (1); +} + +static int +JPEGSetupEncode(TIFF* tif) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGSetupEncode"; + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + + /* + * Initialize all JPEG parameters to default values. + * Note that jpeg_set_defaults needs legal values for + * in_color_space and input_components. + */ + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + sp->cinfo.c.input_components = 1; + if (!TIFFjpeg_set_defaults(sp)) + return (0); + /* Set per-file parameters */ + sp->photometric = td->td_photometric; + switch (sp->photometric) { + case PHOTOMETRIC_YCBCR: + sp->h_sampling = td->td_ycbcrsubsampling[0]; + sp->v_sampling = td->td_ycbcrsubsampling[1]; + /* + * A ReferenceBlackWhite field *must* be present since the + * default value is inappropriate for YCbCr. Fill in the + * proper value if application didn't set it. + */ +#ifdef COLORIMETRY_SUPPORT + if (!TIFFFieldSet(tif, FIELD_REFBLACKWHITE)) { + float refbw[6]; + long top = 1L << td->td_bitspersample; + refbw[0] = 0; + refbw[1] = (float)(top-1L); + refbw[2] = (float)(top>>1); + refbw[3] = refbw[1]; + refbw[4] = refbw[2]; + refbw[5] = refbw[1]; + TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE, refbw); + } +#endif + break; + case PHOTOMETRIC_PALETTE: /* disallowed by Tech Note */ + case PHOTOMETRIC_MASK: + TIFFError(module, + "PhotometricInterpretation %d not allowed for JPEG", + (int) sp->photometric); + return (0); + default: + /* TIFF 6.0 forbids subsampling of all other color spaces */ + sp->h_sampling = 1; + sp->v_sampling = 1; + break; + } + + /* Verify miscellaneous parameters */ + + /* + * This would need work if libtiff ever supports different + * depths for different components, or if libjpeg ever supports + * run-time selection of depth. Neither is imminent. + */ + if (td->td_bitspersample != BITS_IN_JSAMPLE) { + TIFFError(module, "BitsPerSample %d not allowed for JPEG", + (int) td->td_bitspersample); + return (0); + } + sp->cinfo.c.data_precision = td->td_bitspersample; + if (isTiled(tif)) { + if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFError(module, + "JPEG tile height must be multiple of %d", + sp->v_sampling * DCTSIZE); + return (0); + } + if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) { + TIFFError(module, + "JPEG tile width must be multiple of %d", + sp->h_sampling * DCTSIZE); + return (0); + } + } else { + if (td->td_rowsperstrip < td->td_imagelength && + (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) { + TIFFError(module, + "RowsPerStrip must be multiple of %d for JPEG", + sp->v_sampling * DCTSIZE); + return (0); + } + } + + /* Create a JPEGTables field if appropriate */ + if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) { + if (!prepare_JPEGTables(tif)) + return (0); + /* Mark the field present */ + /* Can't use TIFFSetField since BEENWRITING is already set! */ + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + tif->tif_flags |= TIFF_DIRTYDIRECT; + } else { + /* We do not support application-supplied JPEGTables, */ + /* so mark the field not present */ + TIFFClrFieldBit(tif, FIELD_JPEGTABLES); + } + + /* Direct libjpeg output to libtiff's output buffer */ + TIFFjpeg_data_dest(sp, tif); + + return (1); +} + +/* + * Set encoding state at the start of a strip or tile. + */ +static int +JPEGPreEncode(TIFF* tif, tsample_t s) +{ + JPEGState *sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "JPEGPreEncode"; + uint32 segment_width, segment_height; + int downsampled_input; + + assert(sp != NULL); + assert(!sp->cinfo.comm.is_decompressor); + /* + * Set encoding parameters for this strip/tile. + */ + if (isTiled(tif)) { + segment_width = td->td_tilewidth; + segment_height = td->td_tilelength; + sp->bytesperline = TIFFTileRowSize(tif); + } else { + segment_width = td->td_imagewidth; + segment_height = td->td_imagelength - tif->tif_row; + if (segment_height > td->td_rowsperstrip) + segment_height = td->td_rowsperstrip; + sp->bytesperline = TIFFScanlineSize(tif); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) { + /* for PC 2, scale down the strip/tile size + * to match a downsampled component + */ + segment_width = TIFFhowmany(segment_width, sp->h_sampling); + segment_height = TIFFhowmany(segment_height, sp->v_sampling); + } + if (segment_width > 65535 || segment_height > 65535) { + TIFFError(module, "Strip/tile too large for JPEG"); + return (0); + } + sp->cinfo.c.image_width = segment_width; + sp->cinfo.c.image_height = segment_height; + downsampled_input = FALSE; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + sp->cinfo.c.input_components = td->td_samplesperpixel; + if (sp->photometric == PHOTOMETRIC_YCBCR) { + if (sp->jpegcolormode == JPEGCOLORMODE_RGB) { + sp->cinfo.c.in_color_space = JCS_RGB; + } else { + sp->cinfo.c.in_color_space = JCS_YCbCr; + if (sp->h_sampling != 1 || sp->v_sampling != 1) + downsampled_input = TRUE; + } + if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr)) + return (0); + /* + * Set Y sampling factors; + * we assume jpeg_set_colorspace() set the rest to 1 + */ + sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling; + sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling; + } else { + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + /* jpeg_set_colorspace set all sampling factors to 1 */ + } + } else { + sp->cinfo.c.input_components = 1; + sp->cinfo.c.in_color_space = JCS_UNKNOWN; + if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN)) + return (0); + sp->cinfo.c.comp_info[0].component_id = s; + /* jpeg_set_colorspace() set sampling factors to 1 */ + if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) { + sp->cinfo.c.comp_info[0].quant_tbl_no = 1; + sp->cinfo.c.comp_info[0].dc_tbl_no = 1; + sp->cinfo.c.comp_info[0].ac_tbl_no = 1; + } + } + /* ensure libjpeg won't write any extraneous markers */ + sp->cinfo.c.write_JFIF_header = FALSE; + sp->cinfo.c.write_Adobe_marker = FALSE; + /* set up table handling correctly */ + if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) { + if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE)) + return (0); + unsuppress_quant_table(sp, 0); + unsuppress_quant_table(sp, 1); + } + if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) + sp->cinfo.c.optimize_coding = FALSE; + else + sp->cinfo.c.optimize_coding = TRUE; + if (downsampled_input) { + /* Need to use raw-data interface to libjpeg */ + sp->cinfo.c.raw_data_in = TRUE; + tif->tif_encoderow = JPEGEncodeRaw; + tif->tif_encodestrip = JPEGEncodeRaw; + tif->tif_encodetile = JPEGEncodeRaw; + } else { + /* Use normal interface to libjpeg */ + sp->cinfo.c.raw_data_in = FALSE; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + } + /* Start JPEG compressor */ + if (!TIFFjpeg_start_compress(sp, FALSE)) + return (0); + /* Allocate downsampled-data buffers if needed */ + if (downsampled_input) { + if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info, + sp->cinfo.c.num_components)) + return (0); + } + sp->scancount = 0; + + return (1); +} + +/* + * Encode a chunk of pixels. + * "Standard" case: incoming data is not downsampled. + */ +static int +JPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + tsize_t nrows; + JSAMPROW bufptr[1]; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline discarded"); + + while (nrows-- > 0) { + bufptr[0] = (JSAMPROW) buf; + if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1) + return (0); + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + return (1); +} + +/* + * Encode a chunk of pixels. + * Incoming data is expected to be downsampled per sampling factors. + */ +static int +JPEGEncodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + JPEGState *sp = JState(tif); + JSAMPLE* inptr; + JSAMPLE* outptr; + tsize_t nrows; + JDIMENSION clumps_per_line, nclump; + int clumpoffset, ci, xpos, ypos; + jpeg_component_info* compptr; + int samples_per_clump = sp->samplesperclump; + + (void) s; + assert(sp != NULL); + /* data is expected to be supplied in multiples of a scanline */ + nrows = cc / sp->bytesperline; + if (cc % sp->bytesperline) + TIFFWarning(tif->tif_name, "fractional scanline discarded"); + + /* Cb,Cr both have sampling factors 1, so this is correct */ + clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width; + + while (nrows-- > 0) { + /* + * Fastest way to separate the data is to make one pass + * over the scanline for each row of each component. + */ + clumpoffset = 0; /* first sample in clump */ + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int hsamp = compptr->h_samp_factor; + int vsamp = compptr->v_samp_factor; + int padding = (int) (compptr->width_in_blocks * DCTSIZE - + clumps_per_line * hsamp); + for (ypos = 0; ypos < vsamp; ypos++) { + inptr = ((JSAMPLE*) buf) + clumpoffset; + outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos]; + if (hsamp == 1) { + /* fast path for at least Cb and Cr */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + *outptr++ = inptr[0]; + inptr += samples_per_clump; + } + } else { + /* general case */ + for (nclump = clumps_per_line; nclump-- > 0; ) { + for (xpos = 0; xpos < hsamp; xpos++) + *outptr++ = inptr[xpos]; + inptr += samples_per_clump; + } + } + /* pad each scanline as needed */ + for (xpos = 0; xpos < padding; xpos++) { + *outptr = outptr[-1]; + outptr++; + } + clumpoffset += hsamp; + } + } + sp->scancount++; + if (sp->scancount >= DCTSIZE) { + int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + sp->scancount = 0; + } + if (nrows > 0) + tif->tif_row++; + buf += sp->bytesperline; + } + return (1); +} + +/* + * Finish up at the end of a strip or tile. + */ +static int +JPEGPostEncode(TIFF* tif) +{ + JPEGState *sp = JState(tif); + + if (sp->scancount > 0) { + /* + * Need to emit a partial bufferload of downsampled data. + * Pad the data vertically. + */ + int ci, ypos, n; + jpeg_component_info* compptr; + + for (ci = 0, compptr = sp->cinfo.c.comp_info; + ci < sp->cinfo.c.num_components; + ci++, compptr++) { + int vsamp = compptr->v_samp_factor; + tsize_t row_width = compptr->width_in_blocks * DCTSIZE + * sizeof(JSAMPLE); + for (ypos = sp->scancount * vsamp; + ypos < DCTSIZE * vsamp; ypos++) { + _TIFFmemcpy((tdata_t)sp->ds_buffer[ci][ypos], + (tdata_t)sp->ds_buffer[ci][ypos-1], + row_width); + + } + } + n = sp->cinfo.c.max_v_samp_factor * DCTSIZE; + if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n) + return (0); + } + + return (TIFFjpeg_finish_compress(JState(tif))); +} + +static void +JPEGCleanup(TIFF* tif) +{ + if (tif->tif_data) { + JPEGState *sp = JState(tif); + TIFFjpeg_destroy(sp); /* release libjpeg resources */ + if (sp->jpegtables) /* tag value */ + _TIFFfree(sp->jpegtables); + _TIFFfree(tif->tif_data); /* release local state */ + tif->tif_data = NULL; + } +} + +static int +JPEGVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + TIFFDirectory* td = &tif->tif_dir; + uint32 v32; + + switch (tag) { + case TIFFTAG_JPEGTABLES: + v32 = va_arg(ap, uint32); + if (v32 == 0) { + /* XXX */ + return (0); + } + _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*), + (long) v32); + sp->jpegtables_length = v32; + TIFFSetFieldBit(tif, FIELD_JPEGTABLES); + break; + case TIFFTAG_JPEGQUALITY: + sp->jpegquality = va_arg(ap, int); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGCOLORMODE: + sp->jpegcolormode = va_arg(ap, int); + /* + * Mark whether returned data is up-sampled or not + * so TIFFStripSize and TIFFTileSize return values + * that reflect the true amount of data. + */ + tif->tif_flags &= ~TIFF_UPSAMPLED; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + if (td->td_photometric == PHOTOMETRIC_YCBCR && + sp->jpegcolormode == JPEGCOLORMODE_RGB) { + tif->tif_flags |= TIFF_UPSAMPLED; + } else { + if (td->td_ycbcrsubsampling[0] != 1 || + td->td_ycbcrsubsampling[1] != 1) + ; /* XXX what about up-sampling? */ + } + } + /* + * Must recalculate cached tile size + * in case sampling state changed. + */ + tif->tif_tilesize = TIFFTileSize(tif); + return (1); /* pseudo tag */ + case TIFFTAG_JPEGTABLESMODE: + sp->jpegtablesmode = va_arg(ap, int); + return (1); /* pseudo tag */ + default: + return (*sp->vsetparent)(tif, tag, ap); + } + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} + +static int +JPEGVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + JPEGState* sp = JState(tif); + + switch (tag) { + case TIFFTAG_JPEGTABLES: + /* u_short is bogus --- should be uint32 ??? */ + /* TIFFWriteNormalTag needs fixed XXX */ + *va_arg(ap, u_short*) = (u_short) sp->jpegtables_length; + *va_arg(ap, void**) = sp->jpegtables; + break; + case TIFFTAG_JPEGQUALITY: + *va_arg(ap, int*) = sp->jpegquality; + break; + case TIFFTAG_JPEGCOLORMODE: + *va_arg(ap, int*) = sp->jpegcolormode; + break; + case TIFFTAG_JPEGTABLESMODE: + *va_arg(ap, int*) = sp->jpegtablesmode; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +JPEGPrintDir(TIFF* tif, FILE* fd, long flags) +{ + JPEGState* sp = JState(tif); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) + fprintf(fd, " JPEG Tables: (%lu bytes)\n", + (u_long) sp->jpegtables_length); +} + +static uint32 +JPEGDefaultStripSize(TIFF* tif, uint32 s) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + s = (*sp->defsparent)(tif, s); + if (s < td->td_imagelength) + s = TIFFroundup(s, td->td_ycbcrsubsampling[1] * DCTSIZE); + return (s); +} + +static void +JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + JPEGState* sp = JState(tif); + TIFFDirectory *td = &tif->tif_dir; + + (*sp->deftparent)(tif, tw, th); + *tw = TIFFroundup(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE); + *th = TIFFroundup(*th, td->td_ycbcrsubsampling[1] * DCTSIZE); +} + +int +TIFFInitJPEG(TIFF* tif, int scheme) +{ + JPEGState* sp; + + assert(scheme == COMPRESSION_JPEG); + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (JPEGState)); + if (tif->tif_data == NULL) { + TIFFError("TIFFInitJPEG", "No space for JPEG state block"); + return (0); + } + sp = JState(tif); + sp->tif = tif; /* back link */ + + /* + * Merge codec-specific tag information and + * override parent get/set field methods. + */ + _TIFFMergeFieldInfo(tif, jpegFieldInfo, N(jpegFieldInfo)); + sp->vgetparent = tif->tif_vgetfield; + tif->tif_vgetfield = JPEGVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_vsetfield; + tif->tif_vsetfield = JPEGVSetField; /* hook for codec tags */ + tif->tif_printdir = JPEGPrintDir; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->jpegtables = NULL; + sp->jpegtables_length = 0; + sp->jpegquality = 75; /* Default IJG quality */ + sp->jpegcolormode = JPEGCOLORMODE_RAW; + sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = JPEGSetupDecode; + tif->tif_predecode = JPEGPreDecode; + tif->tif_decoderow = JPEGDecode; + tif->tif_decodestrip = JPEGDecode; + tif->tif_decodetile = JPEGDecode; + tif->tif_setupencode = JPEGSetupEncode; + tif->tif_preencode = JPEGPreEncode; + tif->tif_postencode = JPEGPostEncode; + tif->tif_encoderow = JPEGEncode; + tif->tif_encodestrip = JPEGEncode; + tif->tif_encodetile = JPEGEncode; + tif->tif_cleanup = JPEGCleanup; + sp->defsparent = tif->tif_defstripsize; + tif->tif_defstripsize = JPEGDefaultStripSize; + sp->deftparent = tif->tif_deftilesize; + tif->tif_deftilesize = JPEGDefaultTileSize; + tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */ + + /* + * Initialize libjpeg. + */ + if (tif->tif_mode == O_RDONLY) { + if (!TIFFjpeg_create_decompress(sp)) + return (0); + } else { + if (!TIFFjpeg_create_compress(sp)) + return (0); + } + + return (1); +} +#endif /* JPEG_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_luv.c b/freeimage241/Source/LibTIFF/tif_luv.c new file mode 100644 index 0000000..fc900ec --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_luv.c @@ -0,0 +1,1425 @@ +/* + * Copyright (c) 1997 Greg Ward Larson + * Copyright (c) 1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any + * advertising or publicity relating to the software without the specific, + * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE + * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef LOGLUV_SUPPORT + +/* + * TIFF Library. + * LogLuv compression support for high dynamic range images. + * + * Contributed by Greg Larson. + * + * LogLuv image support uses the TIFF library to store 16 or 10-bit + * log luminance values with 8 bits each of u and v or a 14-bit index. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit integer values. A 16-bit luminance is interpreted + * as a sign bit followed by a 15-bit integer that is converted + * to and from a linear magnitude using the transformation: + * + * L = 2^( (Le+.5)/256 - 64 ) # real from 15-bit + * + * Le = floor( 256*(log2(L) + 64) ) # 15-bit from real + * + * The actual conversion to world luminance units in candelas per sq. meter + * requires an additional multiplier, which is stored in the TIFFTAG_STONITS. + * This value is usually set such that a reasonable exposure comes from + * clamping decoded luminances above 1 to 1 in the displayed image. + * + * The 16-bit values for u and v may be converted to real values by dividing + * each by 32768. (This allows for negative values, which aren't useful as + * far as we know, but are left in case of future improvements in human + * color vision.) + * + * Conversion from (u,v), which is actually the CIE (u',v') system for + * you color scientists, is accomplished by the following transformation: + * + * u = 4*x / (-2*x + 12*y + 3) + * v = 9*y / (-2*x + 12*y + 3) + * + * x = 9*u / (6*u - 16*v + 12) + * y = 4*v / (6*u - 16*v + 12) + * + * This process is greatly simplified by passing 32-bit IEEE floats + * for each of three CIE XYZ coordinates. The codec then takes care + * of conversion to and from LogLuv, though the application is still + * responsible for interpreting the TIFFTAG_STONITS calibration factor. + * + * The information is compressed into one of two basic encodings, depending on + * the setting of the compression tag, which is one of COMPRESSION_SGILOG + * or COMPRESSION_SGILOG24. For COMPRESSION_SGILOG, greyscale data is + * stored as: + * + * 1 15 + * |-+---------------| + * + * COMPRESSION_SGILOG color data is stored as: + * + * 1 15 8 8 + * |-+---------------|--------+--------| + * S Le ue ve + * + * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as: + * + * 10 14 + * |----------|--------------| + * Le' Ce + * + * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is + * encoded as an index for optimal color resolution. The 10 log bits are + * defined by the following conversions: + * + * L = 2^((Le'+.5)/64 - 12) # real from 10-bit + * + * Le' = floor( 64*(log2(L) + 12) ) # 10-bit from real + * + * The 10 bits of the smaller format may be converted into the 15 bits of + * the larger format by multiplying by 4 and adding 13314. Obviously, + * a smaller range of magnitudes is covered (about 5 orders of magnitude + * instead of 38), and the lack of a sign bit means that negative luminances + * are not allowed. (Well, they aren't allowed in the real world, either, + * but they are useful for certain types of image processing.) + * + * The desired user format is controlled by the setting the internal + * pseudo tag TIFFTAG_SGILOGDATAFMT to one of: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float XYZ values + * SGILOGDATAFMT_16BIT = 16-bit integer encodings of logL, u and v + * Raw data i/o is also possible using: + * SGILOGDATAFMT_RAW = 32-bit unsigned integer with encoded pixel + * In addition, the following decoding is provided for ease of display: + * SGILOGDATAFMT_8BIT = 8-bit default RGB gamma-corrected values + * + * For grayscale images, we provide the following data formats: + * SGILOGDATAFMT_FLOAT = IEEE 32-bit float Y values + * SGILOGDATAFMT_16BIT = 16-bit integer w/ encoded luminance + * SGILOGDATAFMT_8BIT = 8-bit gray monitor values + * + * Note that the COMPRESSION_SGILOG applies a simple run-length encoding + * scheme by separating the logL, u and v bytes for each row and applying + * a PackBits type of compression. Since the 24-bit encoding is not + * adaptive, the 32-bit color format takes less space in many cases. + */ + +#include +#include +#include +#include + +/* + * State block for each open TIFF + * file using LogLuv compression/decompression. + */ +typedef struct logLuvState LogLuvState; + +struct logLuvState { + int user_datafmt; /* user data format */ + int pixel_size; /* bytes per pixel */ + + tidata_t* tbuf; /* translation buffer */ + short tbuflen; /* buffer length */ + void (*tfunc)(LogLuvState*, tidata_t, int); + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +}; + +#define DecoderState(tif) ((LogLuvState*) (tif)->tif_data) +#define EncoderState(tif) ((LogLuvState*) (tif)->tif_data) + +#define N(a) (sizeof(a)/sizeof(a[0])) +#define SGILOGDATAFMT_UNKNOWN -1 + +#define MINRUN 4 /* minimum run length */ + +/* + * Decode a string of 16-bit gray pixels. + */ +static int +LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + LogLuvState* sp = DecoderState(tif); + int shft, i, npixels; + u_char* bp; + int16* tp; + int16 b; + int cc, rc; + + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16*) op; + else { + assert(sp->tbuflen >= npixels); + tp = (int16*) sp->tbuf; + } + _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); + + bp = (u_char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 2*8; (shft -= 8) >= 0; ) { + for (i = 0; i < npixels && cc > 0; ) + if (*bp >= 128) { /* run */ + rc = *bp++ + (2-128); + b = (int16)*bp++ << shft; + cc -= 2; + while (rc--) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc--) + tp[i++] |= (int16)*bp++ << shft; + } + if (i != npixels) { + TIFFError(tif->tif_name, + "LogL16Decode: Not enough data at row %d (short %d pixels)", + tif->tif_row, npixels - i); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a string of 24-bit pixels. + */ +static int +LogLuvDecode24(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + LogLuvState* sp = DecoderState(tif); + int cc, i, npixels; + u_char* bp; + uint32* tp; + + assert(s == 0); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32 *)op; + else { + assert(sp->tbuflen >= npixels); + tp = (uint32 *) sp->tbuf; + } + _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); + /* copy to array of uint32 */ + bp = (u_char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + for (i = 0; i < npixels && cc > 0; i++) { + tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2]; + bp += 3; + cc -= 3; + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + if (i != npixels) { + TIFFError(tif->tif_name, + "LogLuvDecode24: Not enough data at row %d (short %d pixels)", + tif->tif_row, npixels - i); + return (0); + } + (*sp->tfunc)(sp, op, npixels); + return (1); +} + +/* + * Decode a string of 32-bit pixels. + */ +static int +LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + LogLuvState* sp; + int shft, i, npixels; + u_char* bp; + uint32* tp; + uint32 b; + int cc, rc; + + assert(s == 0); + sp = DecoderState(tif); + assert(sp != NULL); + + npixels = occ / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) op; + else { + assert(sp->tbuflen >= npixels); + tp = (uint32*) sp->tbuf; + } + _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0])); + + bp = (u_char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + /* get each byte string */ + for (shft = 4*8; (shft -= 8) >= 0; ) { + for (i = 0; i < npixels && cc > 0; ) + if (*bp >= 128) { /* run */ + rc = *bp++ + (2-128); + b = (uint32)*bp++ << shft; + cc -= 2; + while (rc--) + tp[i++] |= b; + } else { /* non-run */ + rc = *bp++; /* nul is noop */ + while (--cc && rc--) + tp[i++] |= (uint32)*bp++ << shft; + } + if (i != npixels) { + TIFFError(tif->tif_name, + "LogLuvDecode32: Not enough data at row %d (short %d pixels)", + tif->tif_row, npixels - i); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (0); + } + } + (*sp->tfunc)(sp, op, npixels); + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (1); +} + +/* + * Decode a strip of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFScanlineSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Decode a tile of pixels. We break it into rows to + * maintain synchrony with the encode algorithm, which + * is row by row. + */ +static int +LogLuvDecodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFTileRowSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s)) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode a row of 16-bit pixels. + */ +static int +LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + LogLuvState* sp = EncoderState(tif); + int shft, i, j, npixels; + tidata_t op; + int16* tp; + int16 b; + int occ, rc=0, mask, beg; + + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_16BIT) + tp = (int16*) bp; + else { + tp = (int16*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 2*8; (shft -= 8) >= 0; ) + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = tp[beg] & mask; + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = tp[i] & mask; /* check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = 128-2+j-i; + *op++ = b >> shft; + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = j; occ--; + while (j--) { + *op++ = tp[i++] >> shft & 0xff; + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = 128-2+rc; + *op++ = tp[beg] >> shft & 0xff; + occ -= 2; + } else + rc = 0; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (0); +} + +/* + * Encode a row of 24-bit pixels. + */ +static int +LogLuvEncode24(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + LogLuvState* sp = EncoderState(tif); + int i, npixels, occ; + tidata_t op; + uint32* tp; + + assert(s == 0); + assert(sp != NULL); + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) bp; + else { + tp = (uint32*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* write out encoded pixels */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (i = npixels; i--; ) { + if (occ < 3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = (tidataval_t)(*tp >> 16); + *op++ = (tidataval_t)(*tp >> 8 & 0xff); + *op++ = (tidataval_t)(*tp++ & 0xff); + occ -= 3; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (0); +} + +/* + * Encode a row of 32-bit pixels. + */ +static int +LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + LogLuvState* sp = EncoderState(tif); + int shft, i, j, npixels; + tidata_t op; + uint32* tp; + uint32 b; + int occ, rc=0, mask, beg; + + assert(s == 0); + assert(sp != NULL); + + npixels = cc / sp->pixel_size; + + if (sp->user_datafmt == SGILOGDATAFMT_RAW) + tp = (uint32*) bp; + else { + tp = (uint32*) sp->tbuf; + assert(sp->tbuflen >= npixels); + (*sp->tfunc)(sp, bp, npixels); + } + /* compress each byte string */ + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + for (shft = 4*8; (shft -= 8) >= 0; ) + for (i = 0; i < npixels; i += rc) { + if (occ < 4) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + mask = 0xff << shft; /* find next run */ + for (beg = i; beg < npixels; beg += rc) { + b = tp[beg] & mask; + rc = 1; + while (rc < 127+2 && beg+rc < npixels && + (tp[beg+rc] & mask) == b) + rc++; + if (rc >= MINRUN) + break; /* long enough */ + } + if (beg-i > 1 && beg-i < MINRUN) { + b = tp[i] & mask; /* check short run */ + j = i+1; + while ((tp[j++] & mask) == b) + if (j == beg) { + *op++ = (tidataval_t)(128-2+j-i); + *op++ = (tidataval_t)(b >> shft); + occ -= 2; + i = beg; + break; + } + } + while (i < beg) { /* write out non-run */ + if ((j = beg-i) > 127) j = 127; + if (occ < j+3) { + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + occ = tif->tif_rawdatasize - tif->tif_rawcc; + } + *op++ = j; occ--; + while (j--) { + *op++ = (tidataval_t)(tp[i++] >> shft & 0xff); + occ--; + } + } + if (rc >= MINRUN) { /* write out run */ + *op++ = 128-2+rc; + *op++ = (tidataval_t)(tp[beg] >> shft & 0xff); + occ -= 2; + } else + rc = 0; + } + tif->tif_rawcp = op; + tif->tif_rawcc = tif->tif_rawdatasize - occ; + + return (0); +} + +/* + * Encode a strip of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFScanlineSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 0) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode a tile of pixels. We break it into rows to + * avoid encoding runs across row boundaries. + */ +static int +LogLuvEncodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowlen = TIFFTileRowSize(tif); + + assert(cc%rowlen == 0); + while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 0) + bp += rowlen, cc -= rowlen; + return (cc == 0); +} + +/* + * Encode/Decode functions for converting to and from user formats. + */ +#include "uvcode.h" + +#define U_NEU 0.210526316 +#define V_NEU 0.473684211 + +#ifdef M_LN2 +#define LOGOF2 M_LN2 +#else +#define LOGOF2 0.69314718055994530942 +#endif +#define log2(x) ((1./LOGOF2)*log(x)) +#define exp2(x) exp(LOGOF2*(x)) + +#define UVSCALE 410. + +static double +pix16toY(int p16) +{ + int Le = p16 & 0x7fff; + double Y; + + if (!Le) + return (0.); + Y = exp(LOGOF2/256.*(Le+.5) - LOGOF2*64.); + if (p16 & 0x8000) + return (-Y); + return (Y); +} + +static int +pix16fromY(double Y) +{ + if (Y >= 1.84467e19) + return (0x7fff); + if (Y <= -1.84467e19) + return (0xffff); + if (Y > 5.43571e-20) + return (int)(256.*(log2(Y) + 64.)); + if (Y < -5.43571e-20) + return (~0x7fff | (int)(256.*(log2(-Y) + 64.))); + return (0); +} + +static void +L16toY(LogLuvState* sp, tidata_t op, int n) +{ + int16* l16 = (int16*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *yp++ = (float)pix16toY(*l16++); +} + +static void +L16toGry(LogLuvState* sp, tidata_t op, int n) +{ + int16* l16 = (int16*) sp->tbuf; + uint8* gp = (uint8*) op; + + while (n-- > 0) { + double Y = pix16toY(*l16++); + *gp++ = (Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y)); + } +} + +static void +L16fromY(LogLuvState* sp, tidata_t op, int n) +{ + int16* l16 = (int16*) sp->tbuf; + float* yp = (float*) op; + + while (n-- > 0) + *l16++ = pix16fromY(*yp++); +} + +static void +XYZtoRGB24(float xyz[3], uint8 rgb[3]) +{ + double r, g, b; + /* assume CCIR-709 primaries */ + r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2]; + g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2]; + b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2]; + /* assume 2.0 gamma for speed */ + /* could use integer sqrt approx., but this is probably faster */ + rgb[0] = (r <= 0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r)); + rgb[1] = (g <= 0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g)); + rgb[2] = (b <= 0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b)); +} + +static int +uv_encode(double u, double v) /* encode (u',v') coordinates */ +{ + register int vi, ui; + + if (v < UV_VSTART) + return(-1); + vi = (int)((v - UV_VSTART)*(1./UV_SQSIZ)); + if (vi >= UV_NVS) + return(-1); + if (u < uv_row[vi].ustart) + return(-1); + ui = (int)((u - uv_row[vi].ustart)*(1./UV_SQSIZ)); + if (ui >= uv_row[vi].nus) + return(-1); + return(uv_row[vi].ncum + ui); +} + +static int +uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ +{ + int upper, lower; + register int ui, vi; + + if (c < 0 || c >= UV_NDIVS) + return(-1); + lower = 0; /* binary search */ + upper = UV_NVS; + do { + vi = (lower + upper) >> 1; + ui = c - uv_row[vi].ncum; + if (ui > 0) + lower = vi; + else if (ui < 0) + upper = vi; + else + break; + } while (upper - lower > 1); + vi = lower; + ui = c - uv_row[vi].ncum; + *up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ; + *vp = UV_VSTART + (vi+.5)*UV_SQSIZ; + return(0); +} + +static void +pix24toXYZ(uint32 p, float XYZ[3]) +{ + int Le, Ce; + double L, u, v, s, x, y; + /* decode luminance */ + Le = p >> 14 & 0x3ff; + if (Le == 0) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + L = exp(LOGOF2/64.*(Le+.5) - LOGOF2*12.); + /* decode color */ + Ce = p & 0x3fff; + if (uv_decode(&u, &v, Ce) < 0) { + u = U_NEU; v = V_NEU; + } + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +static uint32 +pix24fromXYZ(float XYZ[3]) +{ + int Le, Ce; + double L, u, v, s; + /* encode luminance */ + L = XYZ[1]; + if (L >= 16.) + Le = 0x3ff; + else if (L <= 1./4096.) + Le = 0; + else + Le = (int)(64.*(log2(L) + 12.)); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (s == 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + Ce = uv_encode(u, v); + if (Ce < 0) + Ce = uv_encode(U_NEU, V_NEU); + /* combine encodings */ + return (Le << 14 | Ce); +} + +static void +Luv24toXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + pix24toXYZ(*luv, xyz); + xyz += 3; + luv++; + } +} + +static void +Luv24toLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314); + if (uv_decode(&u, &v, *luv&0x3fff) < 0) { + u = U_NEU; + v = V_NEU; + } + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); + luv++; + } +} + +static void +Luv24toRGB(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + uint8* rgb = (uint8*) op; + + while (n-- > 0) { + float xyz[3]; + + pix24toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv24fromXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = pix24fromXYZ(xyz); + xyz += 3; + } +} + +static void +Luv24fromLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + int Le, Ce; + + if (luv3[0] <= 0) + Le = 0; + else if (luv3[0] >= (1<<12)+3314) + Le = (1<<10) - 1; + else + Le = (luv3[0]-3314) >> 2; + Ce = uv_encode((luv[1]+.5)/(1<<15), (luv[2]+.5)/(1<<15)); + if (Ce < 0) + Ce = uv_encode(U_NEU, V_NEU); + *luv++ = (uint32)Le << 14 | Ce; + luv3 += 3; + } +} + +static void +pix32toXYZ(uint32 p, float XYZ[3]) +{ + double L, u, v, s, x, y; + /* decode luminance */ + L = pix16toY((int)p >> 16); + if (L == 0.) { + XYZ[0] = XYZ[1] = XYZ[2] = 0.; + return; + } + /* decode color */ + u = 1./UVSCALE * ((p>>8 & 0xff) + .5); + v = 1./UVSCALE * ((p & 0xff) + .5); + s = 1./(6.*u - 16.*v + 12.); + x = 9.*u * s; + y = 4.*v * s; + /* convert to XYZ */ + XYZ[0] = (float)(x/y * L); + XYZ[1] = (float)L; + XYZ[2] = (float)((1.-x-y)/y * L); +} + +static uint32 +pix32fromXYZ(float XYZ[3]) +{ + unsigned int Le, ue, ve; + double u, v, s; + /* encode luminance */ + Le = (unsigned int)pix16fromY(XYZ[1]); + /* encode color */ + s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2]; + if (s == 0.) { + u = U_NEU; + v = V_NEU; + } else { + u = 4.*XYZ[0] / s; + v = 9.*XYZ[1] / s; + } + if (u <= 0.) ue = 0; + else ue = (unsigned int)(UVSCALE * u); + if (ue > 255) ue = 255; + if (v <= 0.) ve = 0; + else ve = (unsigned int)(UVSCALE * v); + if (ve > 255) ve = 255; + /* combine encodings */ + return (Le << 16 | ue << 8 | ve); +} + +static void +Luv32toXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + pix32toXYZ(*luv++, xyz); + xyz += 3; + } +} + +static void +Luv32toLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + double u, v; + + *luv3++ = (int16)(*luv >> 16); + u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5); + v = 1./UVSCALE * ((*luv & 0xff) + .5); + *luv3++ = (int16)(u * (1L<<15)); + *luv3++ = (int16)(v * (1L<<15)); + luv++; + } +} + +static void +Luv32toRGB(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + uint8* rgb = (uint8*) op; + + while (n-- > 0) { + float xyz[3]; + + pix32toXYZ(*luv++, xyz); + XYZtoRGB24(xyz, rgb); + rgb += 3; + } +} + +static void +Luv32fromXYZ(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + float* xyz = (float*) op; + + while (n-- > 0) { + *luv++ = pix32fromXYZ(xyz); + xyz += 3; + } +} + +static void +Luv32fromLuv48(LogLuvState* sp, tidata_t op, int n) +{ + uint32* luv = (uint32*) sp->tbuf; + int16* luv3 = (int16*) op; + + while (n-- > 0) { + *luv++ = (uint32)luv3[0] << 16 | + (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) | + (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff); + luv3 += 3; + } +} + +static void +_logLuvNop(LogLuvState* sp, tidata_t op, int n) +{ + (void) sp; (void) op; (void) n; +} + +static int +LogL16GuessDataFmt(TIFFDirectory *td) +{ +#define PACK(s,b,f) (((b)<<6)|((s)<<3)|(f)) + switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) { + case PACK(1, 32, SAMPLEFORMAT_IEEEFP): + return (SGILOGDATAFMT_FLOAT); + case PACK(1, 16, SAMPLEFORMAT_VOID): + case PACK(1, 16, SAMPLEFORMAT_INT): + case PACK(1, 16, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_16BIT); + case PACK(1, 8, SAMPLEFORMAT_VOID): + case PACK(1, 8, SAMPLEFORMAT_UINT): + return (SGILOGDATAFMT_8BIT); + } +#undef PACK + return (SGILOGDATAFMT_UNKNOWN); +} + +static int +LogL16InitState(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + static const char module[] = "LogL16InitState"; + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGL); + + /* for some reason, we can't do this in TIFFInitLogL16 */ + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogL16GuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = sizeof (int16); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = sizeof (uint8); + break; + default: + TIFFError(tif->tif_name, + "No support for converting user data format to LogL"); + return (0); + } + sp->tbuflen = (short)(td->td_imagewidth * td->td_rowsperstrip); + sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16)); + if (sp->tbuf == NULL) { + TIFFError(module, "%s: No space for SGILog translation buffer", + tif->tif_name); + return (0); + } + return (1); +} + +static int +LogLuvGuessDataFmt(TIFFDirectory *td) +{ + int guess; + + /* + * If the user didn't tell us their datafmt, + * take our best guess from the bitspersample. + */ +#define PACK(a,b) (((a)<<3)|(b)) + switch (PACK(td->td_bitspersample, td->td_sampleformat)) { + case PACK(32, SAMPLEFORMAT_IEEEFP): + guess = SGILOGDATAFMT_FLOAT; + break; + case PACK(32, SAMPLEFORMAT_VOID): + case PACK(32, SAMPLEFORMAT_UINT): + case PACK(32, SAMPLEFORMAT_INT): + guess = SGILOGDATAFMT_RAW; + break; + case PACK(16, SAMPLEFORMAT_VOID): + case PACK(16, SAMPLEFORMAT_INT): + case PACK(16, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_16BIT; + break; + case PACK( 8, SAMPLEFORMAT_VOID): + case PACK( 8, SAMPLEFORMAT_UINT): + guess = SGILOGDATAFMT_8BIT; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; +#undef PACK + } + /* + * Double-check samples per pixel. + */ + switch (td->td_samplesperpixel) { + case 1: + if (guess != SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + case 3: + if (guess == SGILOGDATAFMT_RAW) + guess = SGILOGDATAFMT_UNKNOWN; + break; + default: + guess = SGILOGDATAFMT_UNKNOWN; + break; + } + return (guess); +} + +static int +LogLuvInitState(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + LogLuvState* sp = DecoderState(tif); + static const char module[] = "LogLuvInitState"; + + assert(sp != NULL); + assert(td->td_photometric == PHOTOMETRIC_LOGLUV); + + /* for some reason, we can't do this in TIFFInitLogLuv */ + if (td->td_planarconfig != PLANARCONFIG_CONTIG) { + TIFFError(module, + "SGILog compression cannot handle non-contiguous data"); + return (0); + } + if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN) + sp->user_datafmt = LogLuvGuessDataFmt(td); + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->pixel_size = 3*sizeof (float); + break; + case SGILOGDATAFMT_16BIT: + sp->pixel_size = 3*sizeof (int16); + break; + case SGILOGDATAFMT_RAW: + sp->pixel_size = sizeof (uint32); + break; + case SGILOGDATAFMT_8BIT: + sp->pixel_size = 3*sizeof (uint8); + break; + default: + TIFFError(tif->tif_name, + "No support for converting user data format to LogLuv"); + return (0); + } + sp->tbuflen = (short)(td->td_imagewidth * td->td_rowsperstrip); + sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32)); + if (sp->tbuf == NULL) { + TIFFError(module, "%s: No space for SGILog translation buffer", + tif->tif_name); + return (0); + } + return (1); +} + +static int +LogLuvSetupDecode(TIFF* tif) +{ + LogLuvState* sp = DecoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + tif->tif_postdecode = _TIFFNoPostDecode; + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + break; + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_decoderow = LogLuvDecode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv24toRGB; + break; + } + } else { + tif->tif_decoderow = LogLuvDecode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32toXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32toLuv48; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = Luv32toRGB; + break; + } + } + return (1); + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + break; + tif->tif_decoderow = LogL16Decode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16toY; + break; + case SGILOGDATAFMT_8BIT: + sp->tfunc = L16toGry; + break; + } + return (1); + default: + TIFFError(tif->tif_name, + "Inappropriate photometric interpretation %d for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + break; + } + return (0); +} + +static int +LogLuvSetupEncode(TIFF* tif) +{ + LogLuvState* sp = EncoderState(tif); + TIFFDirectory* td = &tif->tif_dir; + + switch (td->td_photometric) { + case PHOTOMETRIC_LOGLUV: + if (!LogLuvInitState(tif)) + break; + if (td->td_compression == COMPRESSION_SGILOG24) { + tif->tif_encoderow = LogLuvEncode24; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv24fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv24fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } else { + tif->tif_encoderow = LogLuvEncode32; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = Luv32fromXYZ; + break; + case SGILOGDATAFMT_16BIT: + sp->tfunc = Luv32fromLuv48; + break; + case SGILOGDATAFMT_RAW: + break; + default: + goto notsupported; + } + } + break; + case PHOTOMETRIC_LOGL: + if (!LogL16InitState(tif)) + break; + tif->tif_encoderow = LogL16Encode; + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + sp->tfunc = L16fromY; + break; + case SGILOGDATAFMT_16BIT: + break; + default: + goto notsupported; + } + break; + default: + TIFFError(tif->tif_name, + "Inappropriate photometric interpretation %d for SGILog compression; %s", + td->td_photometric, "must be either LogLUV or LogL"); + break; + } + return (1); +notsupported: + TIFFError(tif->tif_name, + "SGILog compression supported only for %s, or raw data", + td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv"); + return (0); +} + +static void +LogLuvClose(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + + /* + * For consistency, we always want to write out the same + * bitspersample and sampleformat for our TIFF file, + * regardless of the data format being used by the application. + * Since this routine is called after tags have been set but + * before they have been recorded in the file, we reset them here. + */ + td->td_samplesperpixel = + (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3; + td->td_bitspersample = 16; + td->td_sampleformat = SAMPLEFORMAT_INT; +} + +static void +LogLuvCleanup(TIFF* tif) +{ + LogLuvState* sp = (LogLuvState *)tif->tif_data; + + if (sp) { + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + } +} + +static int +LogLuvVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + LogLuvState* sp = DecoderState(tif); + int bps, fmt; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + sp->user_datafmt = va_arg(ap, int); + /* + * Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case SGILOGDATAFMT_FLOAT: + bps = 32, fmt = SAMPLEFORMAT_IEEEFP; + break; + case SGILOGDATAFMT_16BIT: + bps = 16, fmt = SAMPLEFORMAT_INT; + break; + case SGILOGDATAFMT_RAW: + bps = 32, fmt = SAMPLEFORMAT_UINT; + break; + case SGILOGDATAFMT_8BIT: + bps = 8, fmt = SAMPLEFORMAT_UINT; + break; + default: + TIFFError(tif->tif_name, + "Unknown data format %d for LogLuv compression", + sp->user_datafmt); + return (0); + } + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt); + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = TIFFTileSize(tif); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + return (1); + default: + return (*sp->vsetparent)(tif, tag, ap); + } +} + +static int +LogLuvVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + LogLuvState *sp = (LogLuvState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_SGILOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + return (1); + default: + return (*sp->vgetparent)(tif, tag, ap); + } +} + +static const TIFFFieldInfo LogLuvFieldInfo[] = { + { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, FIELD_PSEUDO, + TRUE, FALSE, "SGILogDataFmt"} +}; + +int +TIFFInitSGILog(TIFF* tif, int scheme) +{ + static const char module[] = "TIFFInitSGILog"; + LogLuvState* sp; + + assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG); + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (LogLuvState)); + if (tif->tif_data == NULL) + goto bad; + sp = (LogLuvState*) tif->tif_data; + memset(sp, 0, sizeof (*sp)); + sp->user_datafmt = SGILOGDATAFMT_UNKNOWN; + sp->tfunc = _logLuvNop; + + /* + * Install codec methods. + * NB: tif_decoderow & tif_encoderow are filled + * in at setup time. + */ + tif->tif_setupdecode = LogLuvSetupDecode; + tif->tif_decodestrip = LogLuvDecodeStrip; + tif->tif_decodetile = LogLuvDecodeTile; + tif->tif_setupencode = LogLuvSetupEncode; + tif->tif_encodestrip = LogLuvEncodeStrip; + tif->tif_encodetile = LogLuvEncodeTile; + tif->tif_close = LogLuvClose; + tif->tif_cleanup = LogLuvCleanup; + + /* override SetField so we can handle our private pseudo-tag */ + _TIFFMergeFieldInfo(tif, LogLuvFieldInfo, N(LogLuvFieldInfo)); + sp->vgetparent = tif->tif_vgetfield; + tif->tif_vgetfield = LogLuvVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_vsetfield; + tif->tif_vsetfield = LogLuvVSetField; /* hook for codec tags */ + + return (1); +bad: + TIFFError(module, "%s: No space for LogLuv state block", tif->tif_name); + return (0); +} +#endif /* LOGLUV_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_lzw.c b/freeimage241/Source/LibTIFF/tif_lzw.c new file mode 100644 index 0000000..1e27e6b --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_lzw.c @@ -0,0 +1,708 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_lzw.c,v 1.0 2001-04-13 00:42:33+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef LZW_SUPPORT +/* + * TIFF Library. + * Rev 5.0 Lempel-Ziv & Welch Compression Support + * + * This code is derived from the compress program whose code is + * derived from software contributed to Berkeley by James A. Woods, + * derived from original work by Spencer Thomas and Joseph Orost. + * + * The original Berkeley copyright notice appears below in its entirety. + */ +#include "tif_predict.h" + +#include +#include + +/* + * NB: The 5.0 spec describes a different algorithm than Aldus + * implements. Specifically, Aldus does code length transitions + * one code earlier than should be done (for real LZW). + * Earlier versions of this library implemented the correct + * LZW algorithm, but emitted codes in a bit order opposite + * to the TIFF spec. Thus, to maintain compatibility w/ Aldus + * we interpret MSB-LSB ordered codes to be images written w/ + * old versions of this library, but otherwise adhere to the + * Aldus "off by one" algorithm. + * + * Future revisions to the TIFF spec are expected to "clarify this issue". + */ +#define LZW_COMPAT /* include backwards compatibility code */ +/* + * Each strip of data is supposed to be terminated by a CODE_EOI. + * If the following #define is included, the decoder will also + * check for end-of-strip w/o seeing this code. This makes the + * library more robust, but also slower. + */ +#define LZW_CHECKEOS /* include checks for strips w/o EOI code */ + +#define MAXCODE(n) ((1L<<(n))-1) +/* + * The TIFF spec specifies that encoded bit + * strings range from 9 to 12 bits. + */ +#define BITS_MIN 9 /* start with 9 bits */ +#define BITS_MAX 12 /* max of 12 bit strings */ +/* predefined codes */ +#define CODE_CLEAR 256 /* code to clear string table */ +#define CODE_EOI 257 /* end-of-information code */ +#define CODE_FIRST 258 /* first free code entry */ +#define CODE_MAX MAXCODE(BITS_MAX) +#define HSIZE 9001L /* 91% occupancy */ +#define HSHIFT (13-8) +#ifdef LZW_COMPAT +/* NB: +1024 is for compatibility with old files */ +#define CSIZE (MAXCODE(BITS_MAX)+1024L) +#else +#define CSIZE (MAXCODE(BITS_MAX)+1L) +#endif + +/* + * State block for each open TIFF file using LZW + * compression/decompression. Note that the predictor + * state block must be first in this data structure. + */ +typedef struct { + TIFFPredictorState predict; /* predictor super class */ + + u_short nbits; /* # of bits/code */ + u_short maxcode; /* maximum code for lzw_nbits */ + u_short free_ent; /* next free entry in hash table */ + long nextdata; /* next bits of i/o */ + long nextbits; /* # of valid bits in lzw_nextdata */ +} LZWBaseState; + +#define lzw_nbits base.nbits +#define lzw_maxcode base.maxcode +#define lzw_free_ent base.free_ent +#define lzw_nextdata base.nextdata +#define lzw_nextbits base.nextbits + +/* + * Decoding-specific state. + */ +typedef struct code_ent { + struct code_ent *next; + u_short length; /* string len, including this token */ + u_char value; /* data value */ + u_char firstchar; /* first token of string */ +} code_t; + +typedef int (*decodeFunc)(TIFF*, tidata_t, tsize_t, tsample_t); + +typedef struct { + LZWBaseState base; + long dec_nbitsmask; /* lzw_nbits 1 bits, right adjusted */ + long dec_restart; /* restart count */ +#ifdef LZW_CHECKEOS + long dec_bitsleft; /* available bits in raw data */ +#endif + decodeFunc dec_decode; /* regular or backwards compatible */ + code_t* dec_codep; /* current recognized code */ + code_t* dec_oldcodep; /* previously recognized code */ + code_t* dec_free_entp; /* next free entry */ + code_t* dec_maxcodep; /* max available entry */ + code_t* dec_codetab; /* kept separate for small machines */ +} LZWDecodeState; + +/* + * Encoding-specific state. + */ +typedef uint16 hcode_t; /* codes fit in 16 bits */ +typedef struct { + long hash; + hcode_t code; +} hash_t; + +typedef struct { + LZWBaseState base; + int enc_oldcode; /* last code encountered */ + long enc_checkpoint; /* point at which to clear table */ +#define CHECK_GAP 10000 /* enc_ratio check interval */ + long enc_ratio; /* current compression ratio */ + long enc_incount; /* (input) data bytes encoded */ + long enc_outcount; /* encoded (output) bytes */ + tidata_t enc_rawlimit; /* bound on tif_rawdata buffer */ + hash_t* enc_hashtab; /* kept separate for small machines */ +} LZWEncodeState; + +#define LZWState(tif) ((LZWBaseState*) (tif)->tif_data) +#define DecoderState(tif) ((LZWDecodeState*) LZWState(tif)) +#define EncoderState(tif) ((LZWEncodeState*) LZWState(tif)) + +static int LZWDecode(TIFF*, tidata_t, tsize_t, tsample_t); +#ifdef LZW_COMPAT +static int LZWDecodeCompat(TIFF*, tidata_t, tsize_t, tsample_t); +#endif +static void cl_hash(LZWEncodeState*); + +/* + * LZW Decoder. + */ + +#ifdef LZW_CHECKEOS +/* + * This check shouldn't be necessary because each + * strip is suppose to be terminated with CODE_EOI. + */ +#define NextCode(_tif, _sp, _bp, _code, _get) { \ + if ((_sp)->dec_bitsleft < nbits) { \ + TIFFWarning(_tif->tif_name, \ + "LZWDecode: Strip %d not terminated with EOI code", \ + _tif->tif_curstrip); \ + _code = CODE_EOI; \ + } else { \ + _get(_sp,_bp,_code); \ + (_sp)->dec_bitsleft -= nbits; \ + } \ +} +#else +#define NextCode(tif, sp, bp, code, get) get(sp, bp, code) +#endif + +static int +LZWSetupDecode(TIFF* tif) +{ + LZWDecodeState* sp = DecoderState(tif); + static const char module[] = " LZWSetupDecode"; + int code; + + assert(sp != NULL); + if (sp->dec_codetab == NULL) { + sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof (code_t)); + if (sp->dec_codetab == NULL) { + TIFFError(module, "No space for LZW code table"); + return (0); + } + /* + * Pre-load the table. + */ + for (code = 255; code >= 0; code--) { + sp->dec_codetab[code].value = code; + sp->dec_codetab[code].firstchar = code; + sp->dec_codetab[code].length = 1; + sp->dec_codetab[code].next = NULL; + } + } + return (1); +} + +/* + * Setup state for decoding a strip. + */ +static int +LZWPreDecode(TIFF* tif, tsample_t s) +{ + LZWDecodeState *sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + /* + * Check for old bit-reversed codes. + */ + if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) { +#ifdef LZW_COMPAT + if (!sp->dec_decode) { + TIFFWarning(tif->tif_name, + "Old-style LZW codes, convert file"); + /* + * Override default decoding methods with + * ones that deal with the old coding. + * Otherwise the predictor versions set + * above will call the compatibility routines + * through the dec_decode method. + */ + tif->tif_decoderow = LZWDecodeCompat; + tif->tif_decodestrip = LZWDecodeCompat; + tif->tif_decodetile = LZWDecodeCompat; + /* + * If doing horizontal differencing, must + * re-setup the predictor logic since we + * switched the basic decoder methods... + */ + (*tif->tif_setupdecode)(tif); + sp->dec_decode = LZWDecodeCompat; + } + sp->lzw_maxcode = MAXCODE(BITS_MIN); +#else /* !LZW_COMPAT */ + if (!sp->dec_decode) { + TIFFError(tif->tif_name, + "Old-style LZW codes not supported"); + sp->dec_decode = LZWDecode; + } + return (0); +#endif/* !LZW_COMPAT */ + } else { + sp->lzw_maxcode = MAXCODE(BITS_MIN)-1; + sp->dec_decode = LZWDecode; + } + sp->lzw_nbits = BITS_MIN; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + + sp->dec_restart = 0; + sp->dec_nbitsmask = MAXCODE(BITS_MIN); +#ifdef LZW_CHECKEOS + sp->dec_bitsleft = tif->tif_rawcc << 3; +#endif + sp->dec_free_entp = sp->dec_codetab + CODE_FIRST; + /* + * Zero entries that are not yet filled in. We do + * this to guard against bogus input data that causes + * us to index into undefined entries. If you can + * come up with a way to safely bounds-check input codes + * while decoding then you can remove this operation. + */ + _TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t)); + sp->dec_oldcodep = &sp->dec_codetab[-1]; + sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1]; + return (1); +} + +/* + * Decode a "hunk of data". + */ +#define GetNextCode(sp, bp, code) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + } \ + code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask); \ + nextbits -= nbits; \ +} + +static void +codeLoop(TIFF* tif) +{ + TIFFError(tif->tif_name, + "LZWDecode: Bogus encoding, loop in the code table; scanline %d", + tif->tif_row); +} + +static int +LZWDecode(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + LZWDecodeState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + u_char *bp; + hcode_t code; + int len; + long nbits, nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ && codep); + if (codep) { + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + } + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (--residue && codep); + sp->dec_restart = 0; + } + + bp = (u_char *)tif->tif_rawcp; + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask-1; + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + *op++ = (char)code, occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + assert(&sp->dec_codetab[0] <= free_entp && free_entp < &sp->dec_codetab[CSIZE]); + free_entp->next = oldcodep; + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask-1; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep && codep->length > occ); + if (codep) { + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + if (codep) + codeLoop(tif); + } + break; + } + len = codep->length; + tp = op + len; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (codep && tp > op); + if (codep) { + codeLoop(tif); + break; + } + op += len, occ -= len; + } else + *op++ = (char)code, occ--; + } + + tif->tif_rawcp = (tidata_t) bp; + sp->lzw_nbits = (u_short) nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { + TIFFError(tif->tif_name, + "LZWDecode: Not enough data at scanline %d (short %d bytes)", + tif->tif_row, occ); + return (0); + } + return (1); +} + +#ifdef LZW_COMPAT +/* + * Decode a "hunk of data" for old images. + */ +#define GetNextCodeCompat(sp, bp, code) { \ + nextdata |= (u_long) *(bp)++ << nextbits; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata |= (u_long) *(bp)++ << nextbits; \ + nextbits += 8; \ + } \ + code = (hcode_t)(nextdata & nbitsmask); \ + nextdata >>= nbits; \ + nextbits -= nbits; \ +} + +static int +LZWDecodeCompat(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + LZWDecodeState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + u_char *bp; + int code, nbits; + long nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + (void) s; + assert(sp != NULL); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ); + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + return (1); + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + *--tp = codep->value; + codep = codep->next; + } while (--residue); + sp->dec_restart = 0; + } + + bp = (u_char *)tif->tif_rawcp; + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0) { + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask; + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + *op++ = code, occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + assert(&sp->dec_codetab[0] <= free_entp && free_entp < &sp->dec_codetab[CSIZE]); + free_entp->next = oldcodep; + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep->length > occ); + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + break; + } + op += codep->length, occ -= codep->length; + tp = op; + do { + *--tp = codep->value; + } while( (codep = codep->next) != NULL); + } else + *op++ = code, occ--; + } + + tif->tif_rawcp = (tidata_t) bp; + sp->lzw_nbits = nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + + if (occ > 0) { + TIFFError(tif->tif_name, + "LZWDecodeCompat: Not enough data at scanline %d (short %d bytes)", + tif->tif_row, occ); + return (0); + } + return (1); +} +#endif /* LZW_COMPAT */ + + + +static void +LZWCleanup(TIFF* tif) +{ + if (tif->tif_data) { + if (tif->tif_mode == O_RDONLY) { + if (DecoderState(tif)->dec_codetab) + _TIFFfree(DecoderState(tif)->dec_codetab); + } + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + } +} + +int +TIFFInitLZW(TIFF* tif, int scheme) +{ + assert(scheme == COMPRESSION_LZW); + /* + * Allocate state block so tag methods have storage to record values. + */ + if (tif->tif_mode == O_RDONLY) { + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (LZWDecodeState)); + if (tif->tif_data == NULL) + goto bad; + DecoderState(tif)->dec_codetab = NULL; + DecoderState(tif)->dec_decode = NULL; + } + + /* + * Install codec methods. + */ + tif->tif_setupdecode = LZWSetupDecode; + tif->tif_predecode = LZWPreDecode; + tif->tif_decoderow = LZWDecode; + tif->tif_decodestrip = LZWDecode; + tif->tif_decodetile = LZWDecode; + tif->tif_cleanup = LZWCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFError("TIFFInitLZW", "No space for LZW state block"); + return (0); +} + +/* + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#endif /* LZW_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_msdos.c b/freeimage241/Source/LibTIFF/tif_msdos.c new file mode 100644 index 0000000..4cc0927 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_msdos.c @@ -0,0 +1,179 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_msdos.c,v 1.0 2001-04-13 00:42:34+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library MSDOS-specific Routines. + */ +#if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_MSC_VER) +#include /* for open, close, etc. function prototypes */ +#include +#endif +#include "tiffiop.h" + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (read((int) fd, buf, size)); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (write((int) fd, buf, size)); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + return (lseek((int) fd, (off_t) off, whence)); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (close((int) fd)); +} + +#include + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + struct stat sb; + return (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size); +} + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (void*) fd, + _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, + _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + int m, fd; + + m = _TIFFgetMode(mode, module); + if (m == -1) + return ((TIFF*)0); + fd = open(name, m|O_BINARY, 0666); + if (fd < 0) { + TIFFError(module, "%s: Cannot open", name); + return ((TIFF*)0); + } + return (TIFFFdOpen(fd, name, mode)); +} + +#ifdef __GNUC__ +extern char* malloc(); +extern char* realloc(); +#else +#include +#endif + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return (malloc((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + free(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +static void +msdosWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = msdosWarningHandler; + +static void +msdosErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = msdosErrorHandler; diff --git a/freeimage241/Source/LibTIFF/tif_next.c b/freeimage241/Source/LibTIFF/tif_next.c new file mode 100644 index 0000000..22a1e4b --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_next.c @@ -0,0 +1,142 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_next.c,v 1.0 2001-04-13 00:42:34+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef NEXT_SUPPORT +/* + * TIFF Library. + * + * NeXT 2-bit Grey Scale Compression Algorithm Support + */ + +#define SETPIXEL(op, v) { \ + switch (npixels++ & 3) { \ + case 0: op[0] = (v) << 6; break; \ + case 1: op[0] |= (v) << 4; break; \ + case 2: op[0] |= (v) << 2; break; \ + case 3: *op++ |= (v); break; \ + } \ +} + +#define LITERALROW 0x00 +#define LITERALSPAN 0x40 +#define WHITE ((1<<2)-1) + +static int +NeXTDecode(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + register u_char *bp, *op; + register tsize_t cc; + register int n; + tidata_t row; + tsize_t scanline; + + (void) s; + /* + * Each scanline is assumed to start off as all + * white (we assume a PhotometricInterpretation + * of ``min-is-black''). + */ + for (op = buf, cc = occ; cc-- > 0;) + *op++ = 0xff; + + bp = (u_char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + scanline = tif->tif_scanlinesize; + for (row = buf; (long)occ > 0; occ -= scanline, row += scanline) { + n = *bp++, cc--; + switch (n) { + case LITERALROW: + /* + * The entire scanline is given as literal values. + */ + if (cc < scanline) + goto bad; + _TIFFmemcpy(row, bp, scanline); + bp += scanline; + cc -= scanline; + break; + case LITERALSPAN: { + int off; + /* + * The scanline has a literal span + * that begins at some offset. + */ + off = (bp[0] * 256) + bp[1]; + n = (bp[2] * 256) + bp[3]; + if (cc < 4+n) + goto bad; + _TIFFmemcpy(row+off, bp+4, n); + bp += 4+n; + cc -= 4+n; + break; + } + default: { + register int npixels = 0, grey; + u_long imagewidth = tif->tif_dir.td_imagewidth; + + /* + * The scanline is composed of a sequence + * of constant color ``runs''. We shift + * into ``run mode'' and interpret bytes + * as codes of the form + * until we've filled the scanline. + */ + op = row; + for (;;) { + grey = (n>>6) & 0x3; + n &= 0x3f; + while (n-- > 0) + SETPIXEL(op, grey); + if (npixels >= (int) imagewidth) + break; + if (cc == 0) + goto bad; + n = *bp++, cc--; + } + break; + } + } + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + return (1); +bad: + TIFFError(tif->tif_name, "NeXTDecode: Not enough data for scanline %ld", + (long) tif->tif_row); + return (0); +} + +int +TIFFInitNeXT(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = NeXTDecode; + tif->tif_decodestrip = NeXTDecode; + tif->tif_decodetile = NeXTDecode; + return (1); +} +#endif /* NEXT_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_open.c b/freeimage241/Source/LibTIFF/tif_open.c new file mode 100644 index 0000000..2b68247 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_open.c @@ -0,0 +1,486 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_open.c,v 1.0 2001-04-13 00:42:34+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +void _TIFFSetDefaultCompressionState(TIFF* tif); + +static const long typemask[13] = { + 0L, /* TIFF_NOTYPE */ + 0x000000ffL, /* TIFF_BYTE */ + 0xffffffffL, /* TIFF_ASCII */ + 0x0000ffffL, /* TIFF_SHORT */ + 0xffffffffL, /* TIFF_LONG */ + 0xffffffffL, /* TIFF_RATIONAL */ + 0x000000ffL, /* TIFF_SBYTE */ + 0x000000ffL, /* TIFF_UNDEFINED */ + 0x0000ffffL, /* TIFF_SSHORT */ + 0xffffffffL, /* TIFF_SLONG */ + 0xffffffffL, /* TIFF_SRATIONAL */ + 0xffffffffL, /* TIFF_FLOAT */ + 0xffffffffL, /* TIFF_DOUBLE */ +}; +static const int bigTypeshift[13] = { + 0, /* TIFF_NOTYPE */ + 24, /* TIFF_BYTE */ + 0, /* TIFF_ASCII */ + 16, /* TIFF_SHORT */ + 0, /* TIFF_LONG */ + 0, /* TIFF_RATIONAL */ + 24, /* TIFF_SBYTE */ + 24, /* TIFF_UNDEFINED */ + 16, /* TIFF_SSHORT */ + 0, /* TIFF_SLONG */ + 0, /* TIFF_SRATIONAL */ + 0, /* TIFF_FLOAT */ + 0, /* TIFF_DOUBLE */ +}; +static const int litTypeshift[13] = { + 0, /* TIFF_NOTYPE */ + 0, /* TIFF_BYTE */ + 0, /* TIFF_ASCII */ + 0, /* TIFF_SHORT */ + 0, /* TIFF_LONG */ + 0, /* TIFF_RATIONAL */ + 0, /* TIFF_SBYTE */ + 0, /* TIFF_UNDEFINED */ + 0, /* TIFF_SSHORT */ + 0, /* TIFF_SLONG */ + 0, /* TIFF_SRATIONAL */ + 0, /* TIFF_FLOAT */ + 0, /* TIFF_DOUBLE */ +}; + +/* + * Initialize the shift & mask tables, and the + * byte swapping state according to the file + * contents and the machine architecture. + */ +static void +TIFFInitOrder(TIFF* tif, int magic, int bigendian) +{ + tif->tif_typemask = typemask; + if (magic == TIFF_BIGENDIAN) { + tif->tif_typeshift = bigTypeshift; + if (!bigendian) + tif->tif_flags |= TIFF_SWAB; + } else { + tif->tif_typeshift = litTypeshift; + if (bigendian) + tif->tif_flags |= TIFF_SWAB; + } +} + +int +_TIFFgetMode(const char* mode, const char* module) +{ + int m = -1; + + switch (mode[0]) { + case 'r': + m = O_RDONLY; + if (mode[1] == '+') + m = O_RDWR; + break; + case 'w': + case 'a': + m = O_RDWR|O_CREAT; + if (mode[0] == 'w') + m |= O_TRUNC; + break; + default: + TIFFError(module, "\"%s\": Bad mode", mode); + break; + } + return (m); +} + +TIFF* +TIFFClientOpen( + const char* name, const char* mode, + thandle_t clientdata, + TIFFReadWriteProc readproc, + TIFFReadWriteProc writeproc, + TIFFSeekProc seekproc, + TIFFCloseProc closeproc, + TIFFSizeProc sizeproc, + TIFFMapFileProc mapproc, + TIFFUnmapFileProc unmapproc +) +{ + static const char module[] = "TIFFClientOpen"; + TIFF *tif; + int m, bigendian; + const char* cp; + + m = _TIFFgetMode(mode, module); + if (m == -1) + goto bad2; + tif = (TIFF *)_TIFFmalloc(sizeof (TIFF) + strlen(name) + 1); + if (tif == NULL) { + TIFFError(module, "%s: Out of memory (TIFF structure)", name); + goto bad2; + } + _TIFFmemset(tif, 0, sizeof (*tif)); + tif->tif_name = (char *)tif + sizeof (TIFF); + strcpy(tif->tif_name, name); + tif->tif_mode = m &~ (O_CREAT|O_TRUNC); + tif->tif_curdir = (tdir_t) -1; /* non-existent directory */ + tif->tif_curoff = 0; + tif->tif_curstrip = (tstrip_t) -1; /* invalid strip */ + tif->tif_row = (uint32) -1; /* read/write pre-increment */ + tif->tif_clientdata = clientdata; + tif->tif_readproc = readproc; + tif->tif_writeproc = writeproc; + tif->tif_seekproc = seekproc; + tif->tif_closeproc = closeproc; + tif->tif_sizeproc = sizeproc; + tif->tif_mapproc = mapproc; + tif->tif_unmapproc = unmapproc; + _TIFFSetDefaultCompressionState(tif); /* setup default state */ + /* + * Default is to return data MSB2LSB and enable the + * use of memory-mapped files and strip chopping when + * a file is opened read-only. + */ + tif->tif_flags = FILLORDER_MSB2LSB; + if (m == O_RDONLY ) + tif->tif_flags |= TIFF_MAPPED; + +#ifdef STRIPCHOP_DEFAULT + if (m == O_RDONLY || m == O_RDWR) + tif->tif_flags |= STRIPCHOP_DEFAULT; +#endif + + { union { int32 i; char c[4]; } u; u.i = 1; bigendian = u.c[0] == 0; } + /* + * Process library-specific flags in the open mode string. + * The following flags may be used to control intrinsic library + * behaviour that may or may not be desirable (usually for + * compatibility with some application that claims to support + * TIFF but only supports some braindead idea of what the + * vendor thinks TIFF is): + * + * 'l' use little-endian byte order for creating a file + * 'b' use big-endian byte order for creating a file + * 'L' read/write information using LSB2MSB bit order + * 'B' read/write information using MSB2LSB bit order + * 'H' read/write information using host bit order + * 'M' enable use of memory-mapped files when supported + * 'm' disable use of memory-mapped files + * 'C' enable strip chopping support when reading + * 'c' disable strip chopping support + * + * The use of the 'l' and 'b' flags is strongly discouraged. + * These flags are provided solely because numerous vendors, + * typically on the PC, do not correctly support TIFF; they + * only support the Intel little-endian byte order. This + * support is not configured by default because it supports + * the violation of the TIFF spec that says that readers *MUST* + * support both byte orders. It is strongly recommended that + * you not use this feature except to deal with busted apps + * that write invalid TIFF. And even in those cases you should + * bang on the vendors to fix their software. + * + * The 'L', 'B', and 'H' flags are intended for applications + * that can optimize operations on data by using a particular + * bit order. By default the library returns data in MSB2LSB + * bit order for compatibiltiy with older versions of this + * library. Returning data in the bit order of the native cpu + * makes the most sense but also requires applications to check + * the value of the FillOrder tag; something they probabyl do + * not do right now. + * + * The 'M' and 'm' flags are provided because some virtual memory + * systems exhibit poor behaviour when large images are mapped. + * These options permit clients to control the use of memory-mapped + * files on a per-file basis. + * + * The 'C' and 'c' flags are provided because the library support + * for chopping up large strips into multiple smaller strips is not + * application-transparent and as such can cause problems. The 'c' + * option permits applications that only want to look at the tags, + * for example, to get the unadulterated TIFF tag information. + */ + for (cp = mode; *cp; cp++) + switch (*cp) { + case 'b': + if ((m&O_CREAT) && !bigendian) + tif->tif_flags |= TIFF_SWAB; + break; + case 'l': + if ((m&O_CREAT) && bigendian) + tif->tif_flags |= TIFF_SWAB; + break; + case 'B': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_MSB2LSB; + break; + case 'L': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + FILLORDER_LSB2MSB; + break; + case 'H': + tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) | + HOST_FILLORDER; + break; + case 'M': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_MAPPED; + break; + case 'm': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_MAPPED; + break; + case 'C': + if (m == O_RDONLY) + tif->tif_flags |= TIFF_STRIPCHOP; + break; + case 'c': + if (m == O_RDONLY) + tif->tif_flags &= ~TIFF_STRIPCHOP; + break; + } + /* + * Read in TIFF header. + */ + if (!ReadOK(tif, &tif->tif_header, sizeof (TIFFHeader))) { + if (tif->tif_mode == O_RDONLY) { + TIFFError(name, "Cannot read TIFF header"); + goto bad; + } + /* + * Setup header and write. + */ + tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB + ? (bigendian ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN) + : (bigendian ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN); + tif->tif_header.tiff_version = TIFF_VERSION; + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabShort(&tif->tif_header.tiff_version); + tif->tif_header.tiff_diroff = 0; /* filled in later */ + if (!WriteOK(tif, &tif->tif_header, sizeof (TIFFHeader))) { + TIFFError(name, "Error writing TIFF header"); + goto bad; + } + /* + * Setup the byte order handling. + */ + TIFFInitOrder(tif, tif->tif_header.tiff_magic, bigendian); + /* + * Setup default directory. + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + tif->tif_diroff = 0; + return (tif); + } + /* + * Setup the byte order handling. + */ + if (tif->tif_header.tiff_magic != TIFF_BIGENDIAN && + tif->tif_header.tiff_magic != TIFF_LITTLEENDIAN) { + TIFFError(name, "Not a TIFF file, bad magic number %d (0x%x)", + tif->tif_header.tiff_magic, + tif->tif_header.tiff_magic); + goto bad; + } + TIFFInitOrder(tif, tif->tif_header.tiff_magic, bigendian); + /* + * Swap header if required. + */ + if (tif->tif_flags & TIFF_SWAB) { + TIFFSwabShort(&tif->tif_header.tiff_version); + TIFFSwabLong(&tif->tif_header.tiff_diroff); + } + /* + * Now check version (if needed, it's been byte-swapped). + * Note that this isn't actually a version number, it's a + * magic number that doesn't change (stupid). + */ + if (tif->tif_header.tiff_version != TIFF_VERSION) { + TIFFError(name, + "Not a TIFF file, bad version number %d (0x%x)", + tif->tif_header.tiff_version, + tif->tif_header.tiff_version); + goto bad; + } + tif->tif_flags |= TIFF_MYBUFFER; + tif->tif_rawcp = tif->tif_rawdata = 0; + tif->tif_rawdatasize = 0; + /* + * Setup initial directory. + */ + switch (mode[0]) { + case 'r': + tif->tif_nextdiroff = tif->tif_header.tiff_diroff; + /* + * Try to use a memory-mapped file if the client + * has not explicitly suppressed usage with the + * 'm' flag in the open mode (see above). + */ + if ((tif->tif_flags & TIFF_MAPPED) && + !TIFFMapFileContents(tif, (tdata_t*) &tif->tif_base, &tif->tif_size)) + tif->tif_flags &= ~TIFF_MAPPED; + if (TIFFReadDirectory(tif)) { + if( m != O_RDONLY + && tif->tif_dir.td_compression != COMPRESSION_NONE ) + { + TIFFError( name, + "Can't open a compressed TIFF file" + " with compression for update." ); + goto bad; + } + tif->tif_rawcc = -1; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (tif); + } + break; + case 'a': + /* + * New directories are automatically append + * to the end of the directory chain when they + * are written out (see TIFFWriteDirectory). + */ + if (!TIFFDefaultDirectory(tif)) + goto bad; + return (tif); + } +bad: + tif->tif_mode = O_RDONLY; /* XXX avoid flush */ + TIFFClose(tif); + return ((TIFF*)0); +bad2: + (void) (*closeproc)(clientdata); + return ((TIFF*)0); +} + +/* + * Query functions to access private data. + */ + +/* + * Return open file's name. + */ +const char * +TIFFFileName(TIFF* tif) +{ + return (tif->tif_name); +} + +/* + * Return open file's I/O descriptor. + */ +int +TIFFFileno(TIFF* tif) +{ + return (tif->tif_fd); +} + +/* + * Return read/write mode. + */ +int +TIFFGetMode(TIFF* tif) +{ + return (tif->tif_mode); +} + +/* + * Return nonzero if file is organized in + * tiles; zero if organized as strips. + */ +int +TIFFIsTiled(TIFF* tif) +{ + return (isTiled(tif)); +} + +/* + * Return current row being read/written. + */ +uint32 +TIFFCurrentRow(TIFF* tif) +{ + return (tif->tif_row); +} + +/* + * Return index of the current directory. + */ +tdir_t +TIFFCurrentDirectory(TIFF* tif) +{ + return (tif->tif_curdir); +} + +/* + * Return current strip. + */ +tstrip_t +TIFFCurrentStrip(TIFF* tif) +{ + return (tif->tif_curstrip); +} + +/* + * Return current tile. + */ +ttile_t +TIFFCurrentTile(TIFF* tif) +{ + return (tif->tif_curtile); +} + +/* + * Return nonzero if the file has byte-swapped data. + */ +int +TIFFIsByteSwapped(TIFF* tif) +{ + return ((tif->tif_flags & TIFF_SWAB) != 0); +} + +/* + * Return nonzero if the data is returned up-sampled. + */ +int +TIFFIsUpSampled(TIFF* tif) +{ + return (isUpSampled(tif)); +} + +/* + * Return nonzero if the data is returned in MSB-to-LSB bit order. + */ +int +TIFFIsMSB2LSB(TIFF* tif) +{ + return (isFillOrder(tif, FILLORDER_MSB2LSB)); +} diff --git a/freeimage241/Source/LibTIFF/tif_packbits.c b/freeimage241/Source/LibTIFF/tif_packbits.c new file mode 100644 index 0000000..75cd86a --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_packbits.c @@ -0,0 +1,290 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_packbits.c,v 1.0 2001-04-13 00:42:35+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef PACKBITS_SUPPORT +/* + * TIFF Library. + * + * PackBits Compression Algorithm Support + */ +#include +#include + +static int +PackBitsPreEncode(TIFF* tif, tsample_t s) +{ + (void) s; + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + tif->tif_data = (tidata_t) TIFFTileRowSize(tif); + else + tif->tif_data = (tidata_t) TIFFScanlineSize(tif); + return (1); +} + +/* + * NB: tidata is the type representing *(tidata_t); + * if tidata_t is made signed then this type must + * be adjusted accordingly. + */ +typedef unsigned char tidata; + +/* + * Encode a run of pixels. + */ +static int +PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) +{ + u_char* bp = (u_char*) buf; + tidata_t op, ep, lastliteral; + long n, slop; + int b; + enum { BASE, LITERAL, RUN, LITERAL_RUN } state; + + (void) s; + op = tif->tif_rawcp; + ep = tif->tif_rawdata + tif->tif_rawdatasize; + state = BASE; + lastliteral = 0; + while (cc > 0) { + /* + * Find the longest string of identical bytes. + */ + b = *bp++, cc--, n = 1; + for (; cc > 0 && b == *bp; cc--, bp++) + n++; + again: + if (op + 2 >= ep) { /* insure space for new data */ + /* + * Be careful about writing the last + * literal. Must write up to that point + * and then copy the remainder to the + * front of the buffer. + */ + if (state == LITERAL || state == LITERAL_RUN) { + slop = op - lastliteral; + tif->tif_rawcc += lastliteral - tif->tif_rawcp; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + while (slop-- > 0) + *op++ = *lastliteral++; + lastliteral = tif->tif_rawcp; + } else { + tif->tif_rawcc += op - tif->tif_rawcp; + if (!TIFFFlushData1(tif)) + return (-1); + op = tif->tif_rawcp; + } + } + switch (state) { + case BASE: /* initial state, set run/literal */ + if (n > 1) { + state = RUN; + if (n > 128) { + *op++ = (tidata) -127; + *op++ = b; + n -= 128; + goto again; + } + *op++ = (tidataval_t)(-(n-1)); + *op++ = b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = b; + state = LITERAL; + } + break; + case LITERAL: /* last object was literal string */ + if (n > 1) { + state = LITERAL_RUN; + if (n > 128) { + *op++ = (tidata) -127; + *op++ = b; + n -= 128; + goto again; + } + *op++ = (tidataval_t)(-(n-1)); /* encode run */ + *op++ = b; + } else { /* extend literal */ + if (++(*lastliteral) == 127) + state = BASE; + *op++ = b; + } + break; + case RUN: /* last object was run */ + if (n > 1) { + if (n > 128) { + *op++ = (tidata) -127; + *op++ = b; + n -= 128; + goto again; + } + *op++ = (tidataval_t)(-(n-1)); + *op++ = b; + } else { + lastliteral = op; + *op++ = 0; + *op++ = b; + state = LITERAL; + } + break; + case LITERAL_RUN: /* literal followed by a run */ + /* + * Check to see if previous run should + * be converted to a literal, in which + * case we convert literal-run-literal + * to a single literal. + */ + if (n == 1 && op[-2] == (tidata) -1 && + *lastliteral < 126) { + state = (((*lastliteral) += 2) == 127 ? + BASE : LITERAL); + op[-2] = op[-1]; /* replicate */ + } else + state = RUN; + goto again; + } + } + tif->tif_rawcc += op - tif->tif_rawcp; + tif->tif_rawcp = op; + return (1); +} + +/* + * Encode a rectangular chunk of pixels. We break it up + * into row-sized pieces to insure that encoded runs do + * not span rows. Otherwise, there can be problems with + * the decoder if data is read, for example, by scanlines + * when it was encoded by strips. + */ +static int +PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + tsize_t rowsize = (tsize_t) tif->tif_data; + + assert(rowsize > 0); + +#ifdef YCBCR_SUPPORT + /* + * YCBCR data isn't really separable into rows, so we + * might as well encode the whole tile/strip as one chunk. + */ + if( tif->tif_dir.td_photometric == PHOTOMETRIC_YCBCR ) + rowsize = (tsize_t) tif->tif_data; +#endif + + while ((long)cc > 0) { + int chunk = rowsize; + + if( cc < chunk ) + chunk = cc; + + if (PackBitsEncode(tif, bp, chunk, s) < 0) + return (-1); + bp += chunk; + cc -= chunk; + } + return (1); +} + +static int +PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + char *bp; + tsize_t cc; + long n; + int b; + + (void) s; + bp = (char*) tif->tif_rawcp; + cc = tif->tif_rawcc; + while (cc > 0 && (long)occ > 0) { + n = (long) *bp++, cc--; + /* + * Watch out for compilers that + * don't sign extend chars... + */ + if (n >= 128) + n -= 256; + if (n < 0) { /* replicate next byte -n+1 times */ + if (n == -128) /* nop */ + continue; + n = -n + 1; + if( occ < n ) + { + TIFFWarning(tif->tif_name, + "PackBitsDecode: discarding %d bytes " + "to avoid buffer overrun", + n - occ); + } + occ -= n; + b = *bp++, cc--; + while (n-- > 0) + *op++ = b; + } else { /* copy next n+1 bytes literally */ + if (occ < n + 1) + { + TIFFWarning(tif->tif_name, + "PackBitsDecode: discarding %d bytes " + "to avoid buffer overrun", + n - occ + 1); + n = occ - 1; + } + _TIFFmemcpy(op, bp, ++n); + op += n; occ -= n; + bp += n; cc -= n; + } + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + if (occ > 0) { + TIFFError(tif->tif_name, + "PackBitsDecode: Not enough data for scanline %ld", + (long) tif->tif_row); + return (0); + } + return (1); +} + +int +TIFFInitPackBits(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = PackBitsDecode; + tif->tif_decodestrip = PackBitsDecode; + tif->tif_decodetile = PackBitsDecode; + tif->tif_preencode = PackBitsPreEncode; + tif->tif_encoderow = PackBitsEncode; + tif->tif_encodestrip = PackBitsEncodeChunk; + tif->tif_encodetile = PackBitsEncodeChunk; + return (1); +} +#endif /* PACKBITS_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_pixarlog.c b/freeimage241/Source/LibTIFF/tif_pixarlog.c new file mode 100644 index 0000000..27f2a9d --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_pixarlog.c @@ -0,0 +1,1309 @@ +/* + * Copyright (c) 1996-1997 Sam Leffler + * Copyright (c) 1996 Pixar + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Pixar, Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef PIXARLOG_SUPPORT + +/* + * TIFF Library. + * PixarLog Compression Support + * + * Contributed by Dan McCoy. + * + * PixarLog film support uses the TIFF library to store companded + * 11 bit values into a tiff file, which are compressed using the + * zip compressor. + * + * The codec can take as input and produce as output 32-bit IEEE float values + * as well as 16-bit or 8-bit unsigned integer values. + * + * On writing any of the above are converted into the internal + * 11-bit log format. In the case of 8 and 16 bit values, the + * input is assumed to be unsigned linear color values that represent + * the range 0-1. In the case of IEEE values, the 0-1 range is assumed to + * be the normal linear color range, in addition over 1 values are + * accepted up to a value of about 25.0 to encode "hot" hightlights and such. + * The encoding is lossless for 8-bit values, slightly lossy for the + * other bit depths. The actual color precision should be better + * than the human eye can perceive with extra room to allow for + * error introduced by further image computation. As with any quantized + * color format, it is possible to perform image calculations which + * expose the quantization error. This format should certainly be less + * susceptable to such errors than standard 8-bit encodings, but more + * susceptable than straight 16-bit or 32-bit encodings. + * + * On reading the internal format is converted to the desired output format. + * The program can request which format it desires by setting the internal + * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values: + * PIXARLOGDATAFMT_FLOAT = provide IEEE float values. + * PIXARLOGDATAFMT_16BIT = provide unsigned 16-bit integer values + * PIXARLOGDATAFMT_8BIT = provide unsigned 8-bit integer values + * + * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer + * values with the difference that if there are exactly three or four channels + * (rgb or rgba) it swaps the channel order (bgr or abgr). + * + * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly + * packed in 16-bit values. However no tools are supplied for interpreting + * these values. + * + * "hot" (over 1.0) areas written in floating point get clamped to + * 1.0 in the integer data types. + * + * When the file is closed after writing, the bit depth and sample format + * are set always to appear as if 8-bit data has been written into it. + * That way a naive program unaware of the particulars of the encoding + * gets the format it is most likely able to handle. + * + * The codec does it's own horizontal differencing step on the coded + * values so the libraries predictor stuff should be turned off. + * The codec also handle byte swapping the encoded values as necessary + * since the library does not have the information necessary + * to know the bit depth of the raw unencoded buffer. + * + */ + +#include "tif_predict.h" +#include "zlib.h" +#include "zutil.h" + +#include +#include +#include +#include + +/* Tables for converting to/from 11 bit coded values */ + +#define TSIZE 2048 /* decode table size (11-bit tokens) */ +#define TSIZEP1 2049 /* Plus one for slop */ +#define ONE 1250 /* token value of 1.0 exactly */ +#define RATIO 1.004 /* nominal ratio for log part */ + +#define CODE_MASK 0x7ff /* 11 bits. */ + +static float Fltsize; +static float LogK1, LogK2; + +#define REPEAT(n, op) { int i; i=n; do { i--; op; } while (i>0); } + +static void +horizontalAccumulateF(uint16 *wp, int n, int stride, float *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = wp[0]]; + t1 = ToLinearF[cg = wp[1]]; + t2 = ToLinearF[cb = wp[2]]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + } + } else if (stride == 4) { + t0 = ToLinearF[cr = wp[0]]; + t1 = ToLinearF[cg = wp[1]]; + t2 = ToLinearF[cb = wp[2]]; + t3 = ToLinearF[ca = wp[3]]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask]; + t1 = ToLinearF[(cg += wp[1]) & mask]; + t2 = ToLinearF[(cb += wp[2]) & mask]; + t3 = ToLinearF[(ca += wp[3]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinearF[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op, + float *ToLinearF) +{ + register unsigned int cr, cg, cb, ca, mask; + register float t0, t1, t2, t3; + +#define SCALE12 2048.0 +#define CLAMP12(t) (((t) < 3071) ? (uint16) (t) : 3071) + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + t0 = ToLinearF[cr = wp[0]] * SCALE12; + t1 = ToLinearF[cg = wp[1]] * SCALE12; + t2 = ToLinearF[cb = wp[2]] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + } + } else if (stride == 4) { + t0 = ToLinearF[cr = wp[0]] * SCALE12; + t1 = ToLinearF[cg = wp[1]] * SCALE12; + t2 = ToLinearF[cb = wp[2]] * SCALE12; + t3 = ToLinearF[ca = wp[3]] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12; + t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12; + t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12; + t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12; + op[0] = CLAMP12(t0); + op[1] = CLAMP12(t1); + op[2] = CLAMP12(t2); + op[3] = CLAMP12(t3); + } + } else { + REPEAT(stride, t0 = ToLinearF[*wp&mask] * SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; t0 = ToLinearF[wp[stride]&mask]*SCALE12; + *op = CLAMP12(t0); wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate16(uint16 *wp, int n, int stride, uint16 *op, + uint16 *ToLinear16) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear16[cr = wp[0]]; + op[1] = ToLinear16[cg = wp[1]]; + op[2] = ToLinear16[cb = wp[2]]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear16[cr = wp[0]]; + op[1] = ToLinear16[cg = wp[1]]; + op[2] = ToLinear16[cb = wp[2]]; + op[3] = ToLinear16[ca = wp[3]]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = ToLinear16[(cr += wp[0]) & mask]; + op[1] = ToLinear16[(cg += wp[1]) & mask]; + op[2] = ToLinear16[(cb += wp[2]) & mask]; + op[3] = ToLinear16[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear16[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * Returns the log encoded 11-bit values with the horizontal + * differencing undone. + */ +static void +horizontalAccumulate11(uint16 *wp, int n, int stride, uint16 *op) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = cr = wp[0]; op[1] = cg = wp[1]; op[2] = cb = wp[2]; + n -= 3; + while (n > 0) { + wp += 3; + op += 3; + n -= 3; + op[0] = (cr += wp[0]) & mask; + op[1] = (cg += wp[1]) & mask; + op[2] = (cb += wp[2]) & mask; + } + } else if (stride == 4) { + op[0] = cr = wp[0]; op[1] = cg = wp[1]; + op[2] = cb = wp[2]; op[3] = ca = wp[3]; + n -= 4; + while (n > 0) { + wp += 4; + op += 4; + n -= 4; + op[0] = (cr += wp[0]) & mask; + op[1] = (cg += wp[1]) & mask; + op[2] = (cb += wp[2]) & mask; + op[3] = (ca += wp[3]) & mask; + } + } else { + REPEAT(stride, *op = *wp&mask; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = *wp&mask; wp++; op++) + n -= stride; + } + } + } +} + +static void +horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = ToLinear8[cr = wp[0]]; + op[1] = ToLinear8[cg = wp[1]]; + op[2] = ToLinear8[cb = wp[2]]; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 3; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + } + } else if (stride == 4) { + op[0] = ToLinear8[cr = wp[0]]; + op[1] = ToLinear8[cg = wp[1]]; + op[2] = ToLinear8[cb = wp[2]]; + op[3] = ToLinear8[ca = wp[3]]; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + op[0] = ToLinear8[(cr += wp[0]) & mask]; + op[1] = ToLinear8[(cg += wp[1]) & mask]; + op[2] = ToLinear8[(cb += wp[2]) & mask]; + op[3] = ToLinear8[(ca += wp[3]) & mask]; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + + +static void +horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op, + unsigned char *ToLinear8) +{ + register unsigned int cr, cg, cb, ca, mask; + register unsigned char t0, t1, t2, t3; + + if (n >= stride) { + mask = CODE_MASK; + if (stride == 3) { + op[0] = 0; + t1 = ToLinear8[cb = wp[2]]; + t2 = ToLinear8[cg = wp[1]]; + t3 = ToLinear8[cr = wp[0]]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + op += 4; + op[0] = 0; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else if (stride == 4) { + t0 = ToLinear8[ca = wp[3]]; + t1 = ToLinear8[cb = wp[2]]; + t2 = ToLinear8[cg = wp[1]]; + t3 = ToLinear8[cr = wp[0]]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + op += 4; + t0 = ToLinear8[(ca += wp[3]) & mask]; + t1 = ToLinear8[(cb += wp[2]) & mask]; + t2 = ToLinear8[(cg += wp[1]) & mask]; + t3 = ToLinear8[(cr += wp[0]) & mask]; + op[0] = t0; + op[1] = t1; + op[2] = t2; + op[3] = t3; + } + } else { + REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + while (n > 0) { + REPEAT(stride, + wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++) + n -= stride; + } + } + } +} + +/* + * State block for each open TIFF + * file using PixarLog compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + uint16 *tbuf; + uint16 stride; + int state; + int user_datafmt; + int quality; +#define PLSTATE_INIT 1 + + TIFFVSetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + + float *ToLinearF; + uint16 *ToLinear16; + unsigned char *ToLinear8; + uint16 *FromLT2; + uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16 *From8; + +} PixarLogState; + +static int +PixarLogMakeTables(PixarLogState *sp) +{ + +/* + * We make several tables here to convert between various external + * representations (float, 16-bit, and 8-bit) and the internal + * 11-bit companded representation. The 11-bit representation has two + * distinct regions. A linear bottom end up through .018316 in steps + * of about .000073, and a region of constant ratio up to about 25. + * These floating point numbers are stored in the main table ToLinearF. + * All other tables are derived from this one. The tables (and the + * ratios) are continuous at the internal seam. + */ + + int nlin, lt2size; + int i, j; + double b, c, linstep, max; + double k, v, dv, r, lr2, r2; + float *ToLinearF; + uint16 *ToLinear16; + unsigned char *ToLinear8; + uint16 *FromLT2; + uint16 *From14; /* Really for 16-bit data, but we shift down 2 */ + uint16 *From8; + + c = log(RATIO); + nlin = 1./c; /* nlin must be an integer */ + c = 1./nlin; + b = exp(-c*ONE); /* multiplicative scale factor [b*exp(c*ONE) = 1] */ + linstep = b*c*exp(1.); + + LogK1 = 1./c; /* if (v >= 2) token = k1*log(v*k2) */ + LogK2 = 1./b; + lt2size = (2./linstep)+1; + FromLT2 = (uint16 *)_TIFFmalloc(lt2size*sizeof(uint16)); + From14 = (uint16 *)_TIFFmalloc(16384*sizeof(uint16)); + From8 = (uint16 *)_TIFFmalloc(256*sizeof(uint16)); + ToLinearF = (float *)_TIFFmalloc(TSIZEP1 * sizeof(float)); + ToLinear16 = (uint16 *)_TIFFmalloc(TSIZEP1 * sizeof(uint16)); + ToLinear8 = (unsigned char *)_TIFFmalloc(TSIZEP1 * sizeof(unsigned char)); + if (FromLT2 == NULL || From14 == NULL || From8 == NULL || + ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL) { + if (FromLT2) _TIFFfree(FromLT2); + if (From14) _TIFFfree(From14); + if (From8) _TIFFfree(From8); + if (ToLinearF) _TIFFfree(ToLinearF); + if (ToLinear16) _TIFFfree(ToLinear16); + if (ToLinear8) _TIFFfree(ToLinear8); + sp->FromLT2 = NULL; + sp->From14 = NULL; + sp->From8 = NULL; + sp->ToLinearF = NULL; + sp->ToLinear16 = NULL; + sp->ToLinear8 = NULL; + return 0; + } + + j = 0; + + for (i = 0; i < nlin; i++) { + v = i * linstep; + ToLinearF[j++] = v; + } + + for (i = nlin; i < TSIZE; i++) + ToLinearF[j++] = b*exp(c*i); + + ToLinearF[2048] = ToLinearF[2047]; + + for (i = 0; i < TSIZEP1; i++) { + v = ToLinearF[i]*65535.0 + 0.5; + ToLinear16[i] = (v > 65535.0) ? 65535 : v; + v = ToLinearF[i]*255.0 + 0.5; + ToLinear8[i] = (v > 255.0) ? 255 : v; + } + + j = 0; + for (i = 0; i < lt2size; i++) { + if ((i*linstep)*(i*linstep) > ToLinearF[j]*ToLinearF[j+1]) + j++; + FromLT2[i] = j; + } + + /* + * Since we lose info anyway on 16-bit data, we set up a 14-bit + * table and shift 16-bit values down two bits on input. + * saves a little table space. + */ + j = 0; + for (i = 0; i < 16384; i++) { + while ((i/16383.)*(i/16383.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From14[i] = j; + } + + j = 0; + for (i = 0; i < 256; i++) { + while ((i/255.)*(i/255.) > ToLinearF[j]*ToLinearF[j+1]) + j++; + From8[i] = j; + } + + Fltsize = lt2size/2; + + sp->ToLinearF = ToLinearF; + sp->ToLinear16 = ToLinear16; + sp->ToLinear8 = ToLinear8; + sp->FromLT2 = FromLT2; + sp->From14 = From14; + sp->From8 = From8; + + return 1; +} + +#define DecoderState(tif) ((PixarLogState*) (tif)->tif_data) +#define EncoderState(tif) ((PixarLogState*) (tif)->tif_data) + +static int PixarLogEncode(TIFF*, tidata_t, tsize_t, tsample_t); +static int PixarLogDecode(TIFF*, tidata_t, tsize_t, tsample_t); + +#define N(a) (sizeof(a)/sizeof(a[0])) +#define PIXARLOGDATAFMT_UNKNOWN -1 + +static int +PixarLogGuessDataFmt(TIFFDirectory *td) +{ + int guess = PIXARLOGDATAFMT_UNKNOWN; + int format = td->td_sampleformat; + + /* If the user didn't tell us his datafmt, + * take our best guess from the bitspersample. + */ + switch (td->td_bitspersample) { + case 32: + if (format == SAMPLEFORMAT_IEEEFP) + guess = PIXARLOGDATAFMT_FLOAT; + break; + case 16: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_16BIT; + break; + case 12: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT) + guess = PIXARLOGDATAFMT_12BITPICIO; + break; + case 11: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_11BITLOG; + break; + case 8: + if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT) + guess = PIXARLOGDATAFMT_8BIT; + break; + } + + return guess; +} + +static int +PixarLogSetupDecode(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + static const char module[] = "PixarLogSetupDecode"; + + assert(sp != NULL); + + /* Make sure no byte swapping happens on the data + * after decompression. */ + tif->tif_postdecode = _TIFFNoPostDecode; + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + sp->tbuf = (uint16 *) _TIFFmalloc(sp->stride * + td->td_imagewidth * td->td_rowsperstrip * sizeof(uint16)); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + TIFFError(module, + "PixarLog compression can't handle bits depth/data format combination (depth: %d)", + td->td_bitspersample); + return (0); + } + + if (inflateInit(&sp->stream) != Z_OK) { + TIFFError(module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +PixarLogPreDecode(TIFF* tif, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_in = tif->tif_rawdata; + sp->stream.avail_in = tif->tif_rawcc; + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +PixarLogDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = DecoderState(tif); + static const char module[] = "PixarLogDecode"; + int i, nsamples, llen; + uint16 *up; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + nsamples = occ / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + nsamples = occ / sizeof(uint16); /* XXX uint16 == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + nsamples = occ; + break; + default: + TIFFError(tif->tif_name, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + + (void) s; + assert(sp != NULL); + sp->stream.next_out = (unsigned char *) sp->tbuf; + sp->stream.avail_out = nsamples * sizeof(uint16); + do { + int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + if (state == Z_STREAM_END) { + break; /* XXX */ + } + if (state == Z_DATA_ERROR) { + TIFFError(module, + "%s: Decoding error at scanline %d, %s", + tif->tif_name, tif->tif_row, sp->stream.msg); + if (inflateSync(&sp->stream) != Z_OK) + return (0); + continue; + } + if (state != Z_OK) { + TIFFError(module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (sp->stream.avail_out > 0); + + /* hopefully, we got all the bytes we needed */ + if (sp->stream.avail_out != 0) { + TIFFError(module, + "%s: Not enough data at scanline %d (short %d bytes)", + tif->tif_name, tif->tif_row, sp->stream.avail_out); + return (0); + } + + up = sp->tbuf; + /* Swap bytes in the data if from a different endian machine. */ + if (tif->tif_flags & TIFF_SWAB) + TIFFSwabArrayOfShort(up, nsamples); + + for (i = 0; i < nsamples; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalAccumulateF(up, llen, sp->stride, + (float *)op, sp->ToLinearF); + op += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalAccumulate16(up, llen, sp->stride, + (uint16 *)op, sp->ToLinear16); + op += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_12BITPICIO: + horizontalAccumulate12(up, llen, sp->stride, + (int16 *)op, sp->ToLinearF); + op += llen * sizeof(int16); + break; + case PIXARLOGDATAFMT_11BITLOG: + horizontalAccumulate11(up, llen, sp->stride, + (uint16 *)op); + op += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalAccumulate8(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + case PIXARLOGDATAFMT_8BITABGR: + horizontalAccumulate8abgr(up, llen, sp->stride, + (unsigned char *)op, sp->ToLinear8); + op += llen * sizeof(unsigned char); + break; + default: + TIFFError(tif->tif_name, + "PixarLogDecode: unsupported bits/sample: %d", + td->td_bitspersample); + return (0); + } + } + + return (1); +} + +static int +PixarLogSetupEncode(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState* sp = EncoderState(tif); + static const char module[] = "PixarLogSetupEncode"; + + assert(sp != NULL); + + /* for some reason, we can't do this in TIFFInitPixarLog */ + + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + sp->tbuf = (uint16 *) _TIFFmalloc(sp->stride * + td->td_imagewidth * td->td_rowsperstrip * sizeof(uint16)); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) + sp->user_datafmt = PixarLogGuessDataFmt(td); + if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) { + TIFFError(module, "PixarLog compression can't handle %d bit linear encodings", td->td_bitspersample); + return (0); + } + + if (deflateInit(&sp->stream, sp->quality) != Z_OK) { + TIFFError(module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= PLSTATE_INIT; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +PixarLogPreEncode(TIFF* tif, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + return (deflateReset(&sp->stream) == Z_OK); +} + +static void +horizontalDifferenceF(float *ip, int n, int stride, uint16 *wp, uint16 *FromLT2) +{ + + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + register float fltsize = Fltsize; + +#define CLAMP(v) ( (v<(float)0.) ? 0 \ + : (v<(float)2.) ? FromLT2[(int)(v*fltsize)] \ + : (v>(float)24.2) ? 2047 \ + : LogK1*log(v*LogK2) + 0.5 ) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; + } + } else { + ip += n - 1; /* point to last one */ + wp += n - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + } + } +} + +static void +horizontalDifference16(unsigned short *ip, int n, int stride, + unsigned short *wp, uint16 *From14) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +/* assumption is unsigned pixel values */ +#undef CLAMP +#define CLAMP(v) From14[(v) >> 2] + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + wp += 3; + ip += 3; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + wp += 4; + ip += 4; + r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1; + a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1; + } + } else { + ip += n - 1; /* point to last one */ + wp += n - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + } + } +} + + +static void +horizontalDifference8(unsigned char *ip, int n, int stride, + unsigned short *wp, uint16 *From8) +{ + register int r1, g1, b1, a1, r2, g2, b2, a2, mask; + +#undef CLAMP +#define CLAMP(v) (From8[(v)]) + + mask = CODE_MASK; + if (n >= stride) { + if (stride == 3) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); + n -= 3; + while (n > 0) { + n -= 3; + r1 = CLAMP(ip[3]); wp[3] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[4]); wp[4] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[5]); wp[5] = (b1-b2) & mask; b2 = b1; + wp += 3; + ip += 3; + } + } else if (stride == 4) { + r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]); + b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]); + n -= 4; + while (n > 0) { + n -= 4; + r1 = CLAMP(ip[4]); wp[4] = (r1-r2) & mask; r2 = r1; + g1 = CLAMP(ip[5]); wp[5] = (g1-g2) & mask; g2 = g1; + b1 = CLAMP(ip[6]); wp[6] = (b1-b2) & mask; b2 = b1; + a1 = CLAMP(ip[7]); wp[7] = (a1-a2) & mask; a2 = a1; + wp += 4; + ip += 4; + } + } else { + wp += n + stride - 1; /* point to last one */ + ip += n + stride - 1; /* point to last one */ + n -= stride; + while (n > 0) { + REPEAT(stride, wp[0] = CLAMP(ip[0]); + wp[stride] -= wp[0]; + wp[stride] &= mask; + wp--; ip--) + n -= stride; + } + REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--) + } + } +} + +/* + * Encode a chunk of pixels. + */ +static int +PixarLogEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + PixarLogState *sp = EncoderState(tif); + static const char module[] = "PixarLogEncode"; + int i, n, llen; + unsigned short * up; + + (void) s; + + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + n = cc / sizeof(float); /* XXX float == 32 bits */ + break; + case PIXARLOGDATAFMT_16BIT: + case PIXARLOGDATAFMT_12BITPICIO: + case PIXARLOGDATAFMT_11BITLOG: + n = cc / sizeof(uint16); /* XXX uint16 == 16 bits */ + break; + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + n = cc; + break; + default: + TIFFError(tif->tif_name, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + + llen = sp->stride * td->td_imagewidth; + + for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen) { + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_FLOAT: + horizontalDifferenceF((float *)bp, llen, + sp->stride, up, sp->FromLT2); + bp += llen * sizeof(float); + break; + case PIXARLOGDATAFMT_16BIT: + horizontalDifference16((uint16 *)bp, llen, + sp->stride, up, sp->From14); + bp += llen * sizeof(uint16); + break; + case PIXARLOGDATAFMT_8BIT: + horizontalDifference8((unsigned char *)bp, llen, + sp->stride, up, sp->From8); + bp += llen * sizeof(unsigned char); + break; + default: + TIFFError(tif->tif_name, + "%d bit input not supported in PixarLog", + td->td_bitspersample); + return 0; + } + } + + sp->stream.next_in = (unsigned char *) sp->tbuf; + sp->stream.avail_in = n * sizeof(uint16); + + do { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFError(module, "%s: Encoder error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + } while (sp->stream.avail_in > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ + +static int +PixarLogPostEncode(TIFF* tif) +{ + PixarLogState *sp = EncoderState(tif); + static const char module[] = "PixarLogPostEncode"; + int state; + + sp->stream.avail_in = 0; + + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if (sp->stream.avail_out != tif->tif_rawdatasize) { + tif->tif_rawcc = + tif->tif_rawdatasize - sp->stream.avail_out; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + break; + default: + TIFFError(module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +PixarLogClose(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + + /* In a really sneaky maneuver, on close, we covertly modify both + * bitspersample and sampleformat in the directory to indicate + * 8-bit linear. This way, the decode "just works" even for + * readers that don't know about PixarLog, or how to set + * the PIXARLOGDATFMT pseudo-tag. + */ + td->td_bitspersample = 8; + td->td_sampleformat = SAMPLEFORMAT_UINT; +} + +static void +PixarLogCleanup(TIFF* tif) +{ + PixarLogState* sp = (PixarLogState*) tif->tif_data; + + if (sp) { + if (sp->FromLT2) _TIFFfree(sp->FromLT2); + if (sp->From14) _TIFFfree(sp->From14); + if (sp->From8) _TIFFfree(sp->From8); + if (sp->ToLinearF) _TIFFfree(sp->ToLinearF); + if (sp->ToLinear16) _TIFFfree(sp->ToLinear16); + if (sp->ToLinear8) _TIFFfree(sp->ToLinear8); + if (sp->state&PLSTATE_INIT) { + if (tif->tif_mode == O_RDONLY) + inflateEnd(&sp->stream); + else + deflateEnd(&sp->stream); + } + if (sp->tbuf) + _TIFFfree(sp->tbuf); + _TIFFfree(sp); + tif->tif_data = NULL; + } +} + +static int +PixarLogVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + PixarLogState *sp = (PixarLogState *)tif->tif_data; + int result; + static const char module[] = "PixarLogVSetField"; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + sp->quality = va_arg(ap, int); + if (tif->tif_mode != O_RDONLY && (sp->state&PLSTATE_INIT)) { + if (deflateParams(&sp->stream, + sp->quality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFError(module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } + return (1); + case TIFFTAG_PIXARLOGDATAFMT: + sp->user_datafmt = va_arg(ap, int); + /* Tweak the TIFF header so that the rest of libtiff knows what + * size of data will be passed between app and library, and + * assume that the app knows what it is doing and is not + * confused by these header manipulations... + */ + switch (sp->user_datafmt) { + case PIXARLOGDATAFMT_8BIT: + case PIXARLOGDATAFMT_8BITABGR: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_11BITLOG: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_12BITPICIO: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + break; + case PIXARLOGDATAFMT_16BIT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + break; + case PIXARLOGDATAFMT_FLOAT: + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + break; + } + /* + * Must recalculate sizes should bits/sample change. + */ + tif->tif_tilesize = TIFFTileSize(tif); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + result = 1; /* NB: pseudo tag */ + break; + default: + result = (*sp->vsetparent)(tif, tag, ap); + } + return (result); +} + +static int +PixarLogVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + PixarLogState *sp = (PixarLogState *)tif->tif_data; + + switch (tag) { + case TIFFTAG_PIXARLOGQUALITY: + *va_arg(ap, int*) = sp->quality; + break; + case TIFFTAG_PIXARLOGDATAFMT: + *va_arg(ap, int*) = sp->user_datafmt; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFFieldInfo pixarlogFieldInfo[] = { + {TIFFTAG_PIXARLOGDATAFMT,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""}, + {TIFFTAG_PIXARLOGQUALITY,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""} +}; + +int +TIFFInitPixarLog(TIFF* tif, int scheme) +{ + PixarLogState* sp; + + assert(scheme == COMPRESSION_PIXARLOG); + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (PixarLogState)); + if (tif->tif_data == NULL) + goto bad; + sp = (PixarLogState*) tif->tif_data; + memset(sp, 0, sizeof (*sp)); + sp->stream.data_type = Z_BINARY; + sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = PixarLogSetupDecode; + tif->tif_predecode = PixarLogPreDecode; + tif->tif_decoderow = PixarLogDecode; + tif->tif_decodestrip = PixarLogDecode; + tif->tif_decodetile = PixarLogDecode; + tif->tif_setupencode = PixarLogSetupEncode; + tif->tif_preencode = PixarLogPreEncode; + tif->tif_postencode = PixarLogPostEncode; + tif->tif_encoderow = PixarLogEncode; + tif->tif_encodestrip = PixarLogEncode; + tif->tif_encodetile = PixarLogEncode; + tif->tif_close = PixarLogClose; + tif->tif_cleanup = PixarLogCleanup; + + /* Override SetField so we can handle our private pseudo-tag */ + _TIFFMergeFieldInfo(tif, pixarlogFieldInfo, N(pixarlogFieldInfo)); + sp->vgetparent = tif->tif_vgetfield; + tif->tif_vgetfield = PixarLogVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_vsetfield; + tif->tif_vsetfield = PixarLogVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + /* we don't wish to use the predictor, + * the default is none, which predictor value 1 + */ + (void) TIFFPredictorInit(tif); + + /* + * build the companding tables + */ + PixarLogMakeTables(sp); + + return (1); +bad: + TIFFError("TIFFInitPixarLog", "No space for PixarLog state block"); + return (0); +} +#endif /* PIXARLOG_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_predict.c b/freeimage241/Source/LibTIFF/tif_predict.c new file mode 100644 index 0000000..c4d0a29 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_predict.c @@ -0,0 +1,461 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_predict.c,v 1.0 2001-04-13 00:42:35+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Predictor Tag Support (used by multiple codecs). + */ +#include "tiffiop.h" +#include "tif_predict.h" + +#include + +#define PredictorState(tif) ((TIFFPredictorState*) (tif)->tif_data) + +static void horAcc8(TIFF*, tidata_t, tsize_t); +static void horAcc16(TIFF*, tidata_t, tsize_t); +static void swabHorAcc16(TIFF*, tidata_t, tsize_t); +static void horDiff8(TIFF*, tidata_t, tsize_t); +static void horDiff16(TIFF*, tidata_t, tsize_t); +static int PredictorDecodeRow(TIFF*, tidata_t, tsize_t, tsample_t); +static int PredictorDecodeTile(TIFF*, tidata_t, tsize_t, tsample_t); +static int PredictorEncodeRow(TIFF*, tidata_t, tsize_t, tsample_t); +static int PredictorEncodeTile(TIFF*, tidata_t, tsize_t, tsample_t); + +static int +PredictorSetup(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (sp->predictor == 1) /* no differencing */ + return (1); + if (sp->predictor != 2) { + TIFFError(tif->tif_name, "\"Predictor\" value %d not supported", + sp->predictor); + return (0); + } + if (td->td_bitspersample != 8 && td->td_bitspersample != 16) { + TIFFError(tif->tif_name, + "Horizontal differencing \"Predictor\" not supported with %d-bit samples", + td->td_bitspersample); + return (0); + } + sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ? + td->td_samplesperpixel : 1); + /* + * Calculate the scanline/tile-width size in bytes. + */ + if (isTiled(tif)) + sp->rowsize = TIFFTileRowSize(tif); + else + sp->rowsize = TIFFScanlineSize(tif); + return (1); +} + +static int +PredictorSetupDecode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif)) + return (0); + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->pfunc = horAcc8; break; + case 16: sp->pfunc = horAcc16; break; + } + /* + * Override default decoding method with + * one that does the predictor stuff. + */ + sp->coderow = tif->tif_decoderow; + tif->tif_decoderow = PredictorDecodeRow; + sp->codestrip = tif->tif_decodestrip; + tif->tif_decodestrip = PredictorDecodeTile; + sp->codetile = tif->tif_decodetile; + tif->tif_decodetile = PredictorDecodeTile; + /* + * If the data is horizontally differenced + * 16-bit data that requires byte-swapping, + * then it must be byte swapped before the + * accumulation step. We do this with a + * special-purpose routine and override the + * normal post decoding logic that the library + * setup when the directory was read. + */ + if (tif->tif_flags&TIFF_SWAB) { + if (sp->pfunc == horAcc16) { + sp->pfunc = swabHorAcc16; + tif->tif_postdecode = _TIFFNoPostDecode; + } /* else handle 32-bit case... */ + } + } + return (1); +} + +static int +PredictorSetupEncode(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + TIFFDirectory* td = &tif->tif_dir; + + if (!(*sp->setupencode)(tif) || !PredictorSetup(tif)) + return (0); + if (sp->predictor == 2) { + switch (td->td_bitspersample) { + case 8: sp->pfunc = horDiff8; break; + case 16: sp->pfunc = horDiff16; break; + } + /* + * Override default encoding method with + * one that does the predictor stuff. + */ + sp->coderow = tif->tif_encoderow; + tif->tif_encoderow = PredictorEncodeRow; + sp->codestrip = tif->tif_encodestrip; + tif->tif_encodestrip = PredictorEncodeTile; + sp->codetile = tif->tif_encodetile; + tif->tif_encodetile = PredictorEncodeTile; + } + return (1); +} + +#define REPEAT4(n, op) \ + switch (n) { \ + default: { int i; for (i = n-4; i > 0; i--) { op; } } \ + case 4: op; \ + case 3: op; \ + case 2: op; \ + case 1: op; \ + case 0: ; \ + } + +static void +horAcc8(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tsize_t stride = sp->stride; + + char* cp = (char*) cp0; + if (cc > stride) { + cc -= stride; + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + u_int cr = cp[0]; + u_int cg = cp[1]; + u_int cb = cp[2]; + do { + cc -= 3, cp += 3; + cp[0] = (cr += cp[0]); + cp[1] = (cg += cp[1]); + cp[2] = (cb += cp[2]); + } while ((int32) cc > 0); + } else if (stride == 4) { + u_int cr = cp[0]; + u_int cg = cp[1]; + u_int cb = cp[2]; + u_int ca = cp[3]; + do { + cc -= 4, cp += 4; + cp[0] = (cr += cp[0]); + cp[1] = (cg += cp[1]); + cp[2] = (cb += cp[2]); + cp[3] = (ca += cp[3]); + } while ((int32) cc > 0); + } else { + do { + REPEAT4(stride, cp[stride] += *cp; cp++) + cc -= stride; + } while ((int32) cc > 0); + } + } +} + +static void +swabHorAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tsize_t stride = sp->stride; + uint16* wp = (uint16*) cp0; + tsize_t wc = cc / 2; + + if (wc > stride) { + TIFFSwabArrayOfShort(wp, wc); + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while ((int32) wc > 0); + } +} + +static void +horAcc16(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + tsize_t stride = PredictorState(tif)->stride; + uint16* wp = (uint16*) cp0; + tsize_t wc = cc / 2; + + if (wc > stride) { + wc -= stride; + do { + REPEAT4(stride, wp[stride] += wp[0]; wp++) + wc -= stride; + } while ((int32) wc > 0); + } +} + +/* + * Decode a scanline and apply the predictor routine. + */ +static int +PredictorDecodeRow(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->coderow != NULL); + assert(sp->pfunc != NULL); + if ((*sp->coderow)(tif, op0, occ0, s)) { + (*sp->pfunc)(tif, op0, occ0); + return (1); + } else + return (0); +} + +/* + * Decode a tile/strip and apply the predictor routine. + * Note that horizontal differencing must be done on a + * row-by-row basis. The width of a "row" has already + * been calculated at pre-decode time according to the + * strip/tile dimensions. + */ +static int +PredictorDecodeTile(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->codetile != NULL); + if ((*sp->codetile)(tif, op0, occ0, s)) { + tsize_t rowsize = sp->rowsize; + assert(rowsize > 0); + assert(sp->pfunc != NULL); + while ((long)occ0 > 0) { + (*sp->pfunc)(tif, op0, (tsize_t) rowsize); + occ0 -= rowsize; + op0 += rowsize; + } + return (1); + } else + return (0); +} + +static void +horDiff8(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tsize_t stride = sp->stride; + char* cp = (char*) cp0; + + if (cc > stride) { + cc -= stride; + /* + * Pipeline the most common cases. + */ + if (stride == 3) { + int r1, g1, b1; + int r2 = cp[0]; + int g2 = cp[1]; + int b2 = cp[2]; + do { + r1 = cp[3]; cp[3] = r1-r2; r2 = r1; + g1 = cp[4]; cp[4] = g1-g2; g2 = g1; + b1 = cp[5]; cp[5] = b1-b2; b2 = b1; + cp += 3; + } while ((int32)(cc -= 3) > 0); + } else if (stride == 4) { + int r1, g1, b1, a1; + int r2 = cp[0]; + int g2 = cp[1]; + int b2 = cp[2]; + int a2 = cp[3]; + do { + r1 = cp[4]; cp[4] = r1-r2; r2 = r1; + g1 = cp[5]; cp[5] = g1-g2; g2 = g1; + b1 = cp[6]; cp[6] = b1-b2; b2 = b1; + a1 = cp[7]; cp[7] = a1-a2; a2 = a1; + cp += 4; + } while ((int32)(cc -= 4) > 0); + } else { + cp += cc - 1; + do { + REPEAT4(stride, cp[stride] -= cp[0]; cp--) + } while ((int32)(cc -= stride) > 0); + } + } +} + +static void +horDiff16(TIFF* tif, tidata_t cp0, tsize_t cc) +{ + TIFFPredictorState* sp = PredictorState(tif); + tsize_t stride = sp->stride; + int16 *wp = (int16*) cp0; + tsize_t wc = cc/2; + + if (wc > stride) { + wc -= stride; + wp += wc - 1; + do { + REPEAT4(stride, wp[stride] -= wp[0]; wp--) + wc -= stride; + } while ((int32) wc > 0); + } +} + +static int +PredictorEncodeRow(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + + assert(sp != NULL); + assert(sp->pfunc != NULL); + assert(sp->coderow != NULL); +/* XXX horizontal differencing alters user's data XXX */ + (*sp->pfunc)(tif, bp, cc); + return ((*sp->coderow)(tif, bp, cc, s)); +} + +static int +PredictorEncodeTile(TIFF* tif, tidata_t bp0, tsize_t cc0, tsample_t s) +{ + TIFFPredictorState *sp = PredictorState(tif); + tsize_t cc = cc0, rowsize; + u_char* bp = bp0; + + assert(sp != NULL); + assert(sp->pfunc != NULL); + assert(sp->codetile != NULL); + rowsize = sp->rowsize; + assert(rowsize > 0); + while ((long)cc > 0) { + (*sp->pfunc)(tif, bp, (tsize_t) rowsize); + cc -= rowsize; + bp += rowsize; + } + return ((*sp->codetile)(tif, bp0, cc0, s)); +} + +#define FIELD_PREDICTOR (FIELD_CODEC+0) /* XXX */ + +static const TIFFFieldInfo predictFieldInfo[] = { + { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, FIELD_PREDICTOR, + FALSE, FALSE, "Predictor" }, +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +static int +PredictorVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + switch (tag) { + case TIFFTAG_PREDICTOR: + sp->predictor = (uint16) va_arg(ap, int); + TIFFSetFieldBit(tif, FIELD_PREDICTOR); + break; + default: + return (*sp->vsetparent)(tif, tag, ap); + } + tif->tif_flags |= TIFF_DIRTYDIRECT; + return (1); +} + +static int +PredictorVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + TIFFPredictorState *sp = PredictorState(tif); + + switch (tag) { + case TIFFTAG_PREDICTOR: + *va_arg(ap, uint16*) = sp->predictor; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static void +PredictorPrintDir(TIFF* tif, FILE* fd, long flags) +{ + TIFFPredictorState* sp = PredictorState(tif); + + (void) flags; + if (TIFFFieldSet(tif,FIELD_PREDICTOR)) { + fprintf(fd, " Predictor: "); + switch (sp->predictor) { + case 1: fprintf(fd, "none "); break; + case 2: fprintf(fd, "horizontal differencing "); break; + } + fprintf(fd, "%u (0x%x)\n", sp->predictor, sp->predictor); + } + if (sp->printdir) + (*sp->printdir)(tif, fd, flags); +} + +int +TIFFPredictorInit(TIFF* tif) +{ + TIFFPredictorState* sp = PredictorState(tif); + + /* + * Merge codec-specific tag information and + * override parent get/set field methods. + */ + _TIFFMergeFieldInfo(tif, predictFieldInfo, N(predictFieldInfo)); + sp->vgetparent = tif->tif_vgetfield; + tif->tif_vgetfield = PredictorVGetField;/* hook for predictor tag */ + sp->vsetparent = tif->tif_vsetfield; + tif->tif_vsetfield = PredictorVSetField;/* hook for predictor tag */ + sp->printdir = tif->tif_printdir; + tif->tif_printdir = PredictorPrintDir; /* hook for predictor tag */ + + sp->setupdecode = tif->tif_setupdecode; + tif->tif_setupdecode = PredictorSetupDecode; + sp->setupencode = tif->tif_setupencode; + tif->tif_setupencode = PredictorSetupEncode; + + sp->predictor = 1; /* default value */ + sp->pfunc = NULL; /* no predictor routine */ + return (1); +} diff --git a/freeimage241/Source/LibTIFF/tif_predict.h b/freeimage241/Source/LibTIFF/tif_predict.h new file mode 100644 index 0000000..475aca1 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_predict.h @@ -0,0 +1,61 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_predict.h,v 1.0 2001-04-13 00:42:35+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFPREDICT_ +#define _TIFFPREDICT_ +/* + * ``Library-private'' Support for the Predictor Tag + */ + +/* + * Codecs that want to support the Predictor tag must place + * this structure first in their private state block so that + * the predictor code can cast tif_data to find its state. + */ +typedef struct { + int predictor; /* predictor tag value */ + int stride; /* sample stride over data */ + tsize_t rowsize; /* tile/strip row size */ + + TIFFPostMethod pfunc; /* horizontal differencer/accumulator */ + TIFFCodeMethod coderow; /* parent codec encode/decode row */ + TIFFCodeMethod codestrip; /* parent codec encode/decode strip */ + TIFFCodeMethod codetile; /* parent codec encode/decode tile */ + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ + TIFFPrintMethod printdir; /* super-class method */ + TIFFBoolMethod setupdecode; /* super-class method */ + TIFFBoolMethod setupencode; /* super-class method */ +} TIFFPredictorState; + +#if defined(__cplusplus) +extern "C" { +#endif +extern int TIFFPredictorInit(TIFF*); +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFPREDICT_ */ diff --git a/freeimage241/Source/LibTIFF/tif_print.c b/freeimage241/Source/LibTIFF/tif_print.c new file mode 100644 index 0000000..be61108 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_print.c @@ -0,0 +1,525 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_print.c,v 1.0 2001-04-13 00:42:36+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Directory Printing Support + */ +#include "tiffiop.h" +#include + +#include + +static const char *photoNames[] = { + "min-is-white", /* PHOTOMETRIC_MINISWHITE */ + "min-is-black", /* PHOTOMETRIC_MINISBLACK */ + "RGB color", /* PHOTOMETRIC_RGB */ + "palette color (RGB from colormap)", /* PHOTOMETRIC_PALETTE */ + "transparency mask", /* PHOTOMETRIC_MASK */ + "separated", /* PHOTOMETRIC_SEPARATED */ + "YCbCr", /* PHOTOMETRIC_YCBCR */ + "7 (0x7)", + "CIE L*a*b*", /* PHOTOMETRIC_CIELAB */ +}; +#define NPHOTONAMES (sizeof (photoNames) / sizeof (photoNames[0])) + +static const char *orientNames[] = { + "0 (0x0)", + "row 0 top, col 0 lhs", /* ORIENTATION_TOPLEFT */ + "row 0 top, col 0 rhs", /* ORIENTATION_TOPRIGHT */ + "row 0 bottom, col 0 rhs", /* ORIENTATION_BOTRIGHT */ + "row 0 bottom, col 0 lhs", /* ORIENTATION_BOTLEFT */ + "row 0 lhs, col 0 top", /* ORIENTATION_LEFTTOP */ + "row 0 rhs, col 0 top", /* ORIENTATION_RIGHTTOP */ + "row 0 rhs, col 0 bottom", /* ORIENTATION_RIGHTBOT */ + "row 0 lhs, col 0 bottom", /* ORIENTATION_LEFTBOT */ +}; +#define NORIENTNAMES (sizeof (orientNames) / sizeof (orientNames[0])) + +/* + * Print the contents of the current directory + * to the specified stdio file stream. + */ +void +TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) +{ + register TIFFDirectory *td; + char *sep; + uint16 i; + long l, n; + + fprintf(fd, "TIFF Directory at offset 0x%lx\n", tif->tif_diroff); + td = &tif->tif_dir; + if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) { + fprintf(fd, " Subfile Type:"); + sep = " "; + if (td->td_subfiletype & FILETYPE_REDUCEDIMAGE) { + fprintf(fd, "%sreduced-resolution image", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_PAGE) { + fprintf(fd, "%smulti-page document", sep); + sep = "/"; + } + if (td->td_subfiletype & FILETYPE_MASK) + fprintf(fd, "%stransparency mask", sep); + fprintf(fd, " (%lu = 0x%lx)\n", + (long) td->td_subfiletype, (long) td->td_subfiletype); + } + if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) { + fprintf(fd, " Image Width: %lu Image Length: %lu", + (u_long) td->td_imagewidth, (u_long) td->td_imagelength); + if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH)) + fprintf(fd, " Image Depth: %lu", + (u_long) td->td_imagedepth); + fprintf(fd, "\n"); + } + + /* Begin Pixar */ + if (TIFFFieldSet(tif,FIELD_IMAGEFULLWIDTH) || + TIFFFieldSet(tif,FIELD_IMAGEFULLLENGTH)) { + fprintf(fd, " Pixar Full Image Width: %lu Full Image Length: %lu\n", + (u_long) td->td_imagefullwidth, + (u_long) td->td_imagefulllength); + } + if (TIFFFieldSet(tif,FIELD_TEXTUREFORMAT)) + _TIFFprintAsciiTag(fd, "Texture Format", td->td_textureformat); + if (TIFFFieldSet(tif,FIELD_WRAPMODES)) + _TIFFprintAsciiTag(fd, "Texture Wrap Modes", td->td_wrapmodes); + if (TIFFFieldSet(tif,FIELD_FOVCOT)) + fprintf(fd, " Field of View Cotangent: %g\n", td->td_fovcot); + if (TIFFFieldSet(tif,FIELD_MATRIX_WORLDTOSCREEN)) { + typedef float Matrix[4][4]; + Matrix* m = (Matrix*)td->td_matrixWorldToScreen; + + fprintf(fd, " Matrix NP:\n\t%g %g %g %g\n\t%g %g %g %g\n\t%g %g %g %g\n\t%g %g %g %g\n", + (*m)[0][0], (*m)[0][1], (*m)[0][2], (*m)[0][3], + (*m)[1][0], (*m)[1][1], (*m)[1][2], (*m)[1][3], + (*m)[2][0], (*m)[2][1], (*m)[2][2], (*m)[2][3], + (*m)[3][0], (*m)[3][1], (*m)[3][2], (*m)[3][3]); + } + if (TIFFFieldSet(tif,FIELD_MATRIX_WORLDTOCAMERA)) { + typedef float Matrix[4][4]; + Matrix* m = (Matrix*)td->td_matrixWorldToCamera; + + fprintf(fd, " Matrix Nl:\n\t%g %g %g %g\n\t%g %g %g %g\n\t%g %g %g %g\n\t%g %g %g %g\n", + (*m)[0][0], (*m)[0][1], (*m)[0][2], (*m)[0][3], + (*m)[1][0], (*m)[1][1], (*m)[1][2], (*m)[1][3], + (*m)[2][0], (*m)[2][1], (*m)[2][2], (*m)[2][3], + (*m)[3][0], (*m)[3][1], (*m)[3][2], (*m)[3][3]); + } + /* End Pixar */ + + if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) { + fprintf(fd, " Tile Width: %lu Tile Length: %lu", + (u_long) td->td_tilewidth, (u_long) td->td_tilelength); + if (TIFFFieldSet(tif,FIELD_TILEDEPTH)) + fprintf(fd, " Tile Depth: %lu", + (u_long) td->td_tiledepth); + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_RESOLUTION)) { + fprintf(fd, " Resolution: %g, %g", + td->td_xresolution, td->td_yresolution); + if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) { + switch (td->td_resolutionunit) { + case RESUNIT_NONE: + fprintf(fd, " (unitless)"); + break; + case RESUNIT_INCH: + fprintf(fd, " pixels/inch"); + break; + case RESUNIT_CENTIMETER: + fprintf(fd, " pixels/cm"); + break; + default: + fprintf(fd, " (unit %u = 0x%x)", + td->td_resolutionunit, + td->td_resolutionunit); + break; + } + } + fprintf(fd, "\n"); + } + if (TIFFFieldSet(tif,FIELD_POSITION)) + fprintf(fd, " Position: %g, %g\n", + td->td_xposition, td->td_yposition); + if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE)) + fprintf(fd, " Bits/Sample: %u\n", td->td_bitspersample); + if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) { + fprintf(fd, " Sample Format: "); + switch (td->td_sampleformat) { + case SAMPLEFORMAT_VOID: + fprintf(fd, "void\n"); + break; + case SAMPLEFORMAT_INT: + fprintf(fd, "signed integer\n"); + break; + case SAMPLEFORMAT_UINT: + fprintf(fd, "unsigned integer\n"); + break; + case SAMPLEFORMAT_IEEEFP: + fprintf(fd, "IEEE floating point\n"); + break; + case SAMPLEFORMAT_COMPLEXINT: + fprintf(fd, "complex signed integer\n"); + break; + case SAMPLEFORMAT_COMPLEXIEEEFP: + fprintf(fd, "complex IEEE floating point\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_sampleformat, td->td_sampleformat); + break; + } + } + if (TIFFFieldSet(tif,FIELD_COMPRESSION)) { + const TIFFCodec* c = TIFFFindCODEC(td->td_compression); + fprintf(fd, " Compression Scheme: "); + if (c) + fprintf(fd, "%s\n", c->name); + else + fprintf(fd, "%u (0x%x)\n", + td->td_compression, td->td_compression); + } + if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) { + fprintf(fd, " Photometric Interpretation: "); + if (td->td_photometric < NPHOTONAMES) + fprintf(fd, "%s\n", photoNames[td->td_photometric]); + else { + switch (td->td_photometric) { + case PHOTOMETRIC_LOGL: + fprintf(fd, "CIE Log2(L)\n"); + break; + case PHOTOMETRIC_LOGLUV: + fprintf(fd, "CIE Log2(L) (u',v')\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_photometric, td->td_photometric); + break; + } + } + } + if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES) && td->td_extrasamples) { + fprintf(fd, " Extra Samples: %u<", td->td_extrasamples); + sep = ""; + for (i = 0; i < td->td_extrasamples; i++) { + switch (td->td_sampleinfo[i]) { + case EXTRASAMPLE_UNSPECIFIED: + fprintf(fd, "%sunspecified", sep); + break; + case EXTRASAMPLE_ASSOCALPHA: + fprintf(fd, "%sassoc-alpha", sep); + break; + case EXTRASAMPLE_UNASSALPHA: + fprintf(fd, "%sunassoc-alpha", sep); + break; + default: + fprintf(fd, "%s%u (0x%x)", sep, + td->td_sampleinfo[i], td->td_sampleinfo[i]); + break; + } + sep = ", "; + } + fprintf(fd, ">\n"); + } + if (TIFFFieldSet(tif,FIELD_STONITS)) { + fprintf(fd, " Sample to Nits conversion factor: %.4e\n", + td->td_stonits); + } +#ifdef CMYK_SUPPORT + if (TIFFFieldSet(tif,FIELD_INKSET)) { + fprintf(fd, " Ink Set: "); + switch (td->td_inkset) { + case INKSET_CMYK: + fprintf(fd, "CMYK\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_inkset, td->td_inkset); + break; + } + } + if (TIFFFieldSet(tif,FIELD_INKNAMES)) { + char* cp; + fprintf(fd, " Ink Names: "); + i = td->td_samplesperpixel; + sep = ""; + for (cp = td->td_inknames; i > 0; cp = strchr(cp,'\0')+1, i--) { + fprintf(fd, "%s", sep); + _TIFFprintAscii(fd, cp); + sep = ", "; + } + } + if (TIFFFieldSet(tif,FIELD_NUMBEROFINKS)) + fprintf(fd, " Number of Inks: %u\n", td->td_ninks); + if (TIFFFieldSet(tif,FIELD_DOTRANGE)) + fprintf(fd, " Dot Range: %u-%u\n", + td->td_dotrange[0], td->td_dotrange[1]); + if (TIFFFieldSet(tif,FIELD_TARGETPRINTER)) + _TIFFprintAsciiTag(fd, "Target Printer", td->td_targetprinter); +#endif + if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) { + fprintf(fd, " Thresholding: "); + switch (td->td_threshholding) { + case THRESHHOLD_BILEVEL: + fprintf(fd, "bilevel art scan\n"); + break; + case THRESHHOLD_HALFTONE: + fprintf(fd, "halftone or dithered scan\n"); + break; + case THRESHHOLD_ERRORDIFFUSE: + fprintf(fd, "error diffused\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_threshholding, td->td_threshholding); + break; + } + } + if (TIFFFieldSet(tif,FIELD_FILLORDER)) { + fprintf(fd, " FillOrder: "); + switch (td->td_fillorder) { + case FILLORDER_MSB2LSB: + fprintf(fd, "msb-to-lsb\n"); + break; + case FILLORDER_LSB2MSB: + fprintf(fd, "lsb-to-msb\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_fillorder, td->td_fillorder); + break; + } + } +#ifdef YCBCR_SUPPORT + if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING)) + fprintf(fd, " YCbCr Subsampling: %u, %u\n", + td->td_ycbcrsubsampling[0], td->td_ycbcrsubsampling[1]); + if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) { + fprintf(fd, " YCbCr Positioning: "); + switch (td->td_ycbcrpositioning) { + case YCBCRPOSITION_CENTERED: + fprintf(fd, "centered\n"); + break; + case YCBCRPOSITION_COSITED: + fprintf(fd, "cosited\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_ycbcrpositioning, td->td_ycbcrpositioning); + break; + } + } + if (TIFFFieldSet(tif,FIELD_YCBCRCOEFFICIENTS)) + fprintf(fd, " YCbCr Coefficients: %g, %g, %g\n", + td->td_ycbcrcoeffs[0], + td->td_ycbcrcoeffs[1], + td->td_ycbcrcoeffs[2]); +#endif + if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS)) + fprintf(fd, " Halftone Hints: light %u dark %u\n", + td->td_halftonehints[0], td->td_halftonehints[1]); + if (TIFFFieldSet(tif,FIELD_ARTIST)) + _TIFFprintAsciiTag(fd, "Artist", td->td_artist); + if (TIFFFieldSet(tif,FIELD_DATETIME)) + _TIFFprintAsciiTag(fd, "Date & Time", td->td_datetime); + if (TIFFFieldSet(tif,FIELD_HOSTCOMPUTER)) + _TIFFprintAsciiTag(fd, "Host Computer", td->td_hostcomputer); + if (TIFFFieldSet(tif,FIELD_SOFTWARE)) + _TIFFprintAsciiTag(fd, "Software", td->td_software); + if (TIFFFieldSet(tif,FIELD_DOCUMENTNAME)) + _TIFFprintAsciiTag(fd, "Document Name", td->td_documentname); + if (TIFFFieldSet(tif,FIELD_IMAGEDESCRIPTION)) + _TIFFprintAsciiTag(fd, "Image Description", td->td_imagedescription); + if (TIFFFieldSet(tif,FIELD_MAKE)) + _TIFFprintAsciiTag(fd, "Make", td->td_make); + if (TIFFFieldSet(tif,FIELD_MODEL)) + _TIFFprintAsciiTag(fd, "Model", td->td_model); + if (TIFFFieldSet(tif,FIELD_ORIENTATION)) { + fprintf(fd, " Orientation: "); + if (td->td_orientation < NORIENTNAMES) + fprintf(fd, "%s\n", orientNames[td->td_orientation]); + else + fprintf(fd, "%u (0x%x)\n", + td->td_orientation, td->td_orientation); + } + if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL)) + fprintf(fd, " Samples/Pixel: %u\n", td->td_samplesperpixel); + if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) { + fprintf(fd, " Rows/Strip: "); + if (td->td_rowsperstrip == (uint32) -1) + fprintf(fd, "(infinite)\n"); + else + fprintf(fd, "%lu\n", (u_long) td->td_rowsperstrip); + } + if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE)) + fprintf(fd, " Min Sample Value: %u\n", td->td_minsamplevalue); + if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE)) + fprintf(fd, " Max Sample Value: %u\n", td->td_maxsamplevalue); + if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE)) + fprintf(fd, " SMin Sample Value: %g\n", + td->td_sminsamplevalue); + if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE)) + fprintf(fd, " SMax Sample Value: %g\n", + td->td_smaxsamplevalue); + if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) { + fprintf(fd, " Planar Configuration: "); + switch (td->td_planarconfig) { + case PLANARCONFIG_CONTIG: + fprintf(fd, "single image plane\n"); + break; + case PLANARCONFIG_SEPARATE: + fprintf(fd, "separate image planes\n"); + break; + default: + fprintf(fd, "%u (0x%x)\n", + td->td_planarconfig, td->td_planarconfig); + break; + } + } + if (TIFFFieldSet(tif,FIELD_PAGENAME)) + _TIFFprintAsciiTag(fd, "Page Name", td->td_pagename); + if (TIFFFieldSet(tif,FIELD_PAGENUMBER)) + fprintf(fd, " Page Number: %u-%u\n", + td->td_pagenumber[0], td->td_pagenumber[1]); + if (TIFFFieldSet(tif,FIELD_COLORMAP)) { + fprintf(fd, " Color Map: "); + if (flags & TIFFPRINT_COLORMAP) { + fprintf(fd, "\n"); + n = 1L<td_bitspersample; + for (l = 0; l < n; l++) + fprintf(fd, " %5lu: %5u %5u %5u\n", + l, + td->td_colormap[0][l], + td->td_colormap[1][l], + td->td_colormap[2][l]); + } else + fprintf(fd, "(present)\n"); + } +#ifdef COLORIMETRY_SUPPORT + if (TIFFFieldSet(tif,FIELD_WHITEPOINT)) + fprintf(fd, " White Point: %g-%g\n", + td->td_whitepoint[0], td->td_whitepoint[1]); + if (TIFFFieldSet(tif,FIELD_PRIMARYCHROMAS)) + fprintf(fd, " Primary Chromaticities: %g,%g %g,%g %g,%g\n", + td->td_primarychromas[0], td->td_primarychromas[1], + td->td_primarychromas[2], td->td_primarychromas[3], + td->td_primarychromas[4], td->td_primarychromas[5]); + if (TIFFFieldSet(tif,FIELD_REFBLACKWHITE)) { + fprintf(fd, " Reference Black/White:\n"); + for (i = 0; i < td->td_samplesperpixel; i++) + fprintf(fd, " %2d: %5g %5g\n", + i, + td->td_refblackwhite[2*i+0], + td->td_refblackwhite[2*i+1]); + } + if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) { + fprintf(fd, " Transfer Function: "); + if (flags & TIFFPRINT_CURVES) { + fprintf(fd, "\n"); + n = 1L<td_bitspersample; + for (l = 0; l < n; l++) { + fprintf(fd, " %2lu: %5u", + l, td->td_transferfunction[0][l]); + for (i = 1; i < td->td_samplesperpixel; i++) + fprintf(fd, " %5u", + td->td_transferfunction[i][l]); + fputc('\n', fd); + } + } else + fprintf(fd, "(present)\n"); + } +#endif +#ifdef ICC_SUPPORT + if (TIFFFieldSet(tif,FIELD_ICCPROFILE)) + fprintf(fd, " ICC Profile: , %lu bytes\n", + (u_long) td->td_profileLength); +#endif +#ifdef PHOTOSHOP_SUPPORT + if (TIFFFieldSet(tif,FIELD_PHOTOSHOP)) + fprintf(fd, " Photoshop Data: , %lu bytes\n", + (u_long) td->td_photoshopLength); +#endif +#ifdef IPTC_SUPPORT + if (TIFFFieldSet(tif,FIELD_RICHTIFFIPTC)) + fprintf(fd, " RichTIFFIPTC Data: , %lu bytes\n", + (u_long) td->td_richtiffiptcLength); +#endif +#if SUBIFD_SUPPORT + if (TIFFFieldSet(tif, FIELD_SUBIFD)) { + fprintf(fd, " SubIFD Offsets:"); + for (i = 0; i < td->td_nsubifd; i++) + fprintf(fd, " %5lu", (long) td->td_subifd[i]); + fputc('\n', fd); + } +#endif + if (tif->tif_printdir) + (*tif->tif_printdir)(tif, fd, flags); + if ((flags & TIFFPRINT_STRIPS) && + TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) { + tstrip_t s; + + fprintf(fd, " %lu %s:\n", + (long) td->td_nstrips, + isTiled(tif) ? "Tiles" : "Strips"); + for (s = 0; s < td->td_nstrips; s++) + fprintf(fd, " %3lu: [%8lu, %8lu]\n", + (u_long) s, + (u_long) td->td_stripoffset[s], + (u_long) td->td_stripbytecount[s]); + } +} + +void +_TIFFprintAscii(FILE* fd, const char* cp) +{ + for (; *cp != '\0'; cp++) { + const char* tp; + + if (isprint(*cp)) { + fputc(*cp, fd); + continue; + } + for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++) + if (*tp++ == *cp) + break; + if (*tp) + fprintf(fd, "\\%c", *tp); + else + fprintf(fd, "\\%03o", *cp & 0xff); + } +} + +void +_TIFFprintAsciiTag(FILE* fd, const char* name, const char* value) +{ + fprintf(fd, " %s: \"", name); + _TIFFprintAscii(fd, value); + fprintf(fd, "\"\n"); +} diff --git a/freeimage241/Source/LibTIFF/tif_read.c b/freeimage241/Source/LibTIFF/tif_read.c new file mode 100644 index 0000000..c662cfa --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_read.c @@ -0,0 +1,633 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_read.c,v 1.0 2001-04-13 00:42:36+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * Scanline-oriented Read Support + */ +#include "tiffiop.h" +#include +#include + +static int TIFFFillStrip(TIFF*, tstrip_t); +static int TIFFFillTile(TIFF*, ttile_t); +static int TIFFStartStrip(TIFF*, tstrip_t); +static int TIFFStartTile(TIFF*, ttile_t); +static int TIFFCheckRead(TIFF*, int); + +#define NOSTRIP ((tstrip_t) -1) /* undefined state */ +#define NOTILE ((ttile_t) -1) /* undefined state */ + +/* + * Seek to a random row+sample in a file. + */ +static int +TIFFSeek(TIFF* tif, uint32 row, tsample_t sample) +{ + register TIFFDirectory *td = &tif->tif_dir; + tstrip_t strip; + + if (row >= td->td_imagelength) { /* out of range */ + TIFFError(tif->tif_name, "%lu: Row out of range, max %lu", + (u_long) row, (u_long) td->td_imagelength); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFError(tif->tif_name, + "%lu: Sample out of range, max %lu", + (u_long) sample, (u_long) td->td_samplesperpixel); + return (0); + } + strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + if (strip != tif->tif_curstrip) { /* different strip, refill */ + if (!TIFFFillStrip(tif, strip)) + return (0); + } else if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: backup + * to the start and then decode forward (below). + * + * NB: If you're planning on lots of random access within a + * strip, it's better to just read and decode the entire + * strip, and then access the decoded data in a random fashion. + */ + if (!TIFFStartStrip(tif, strip)) + return (0); + } + if (row != tif->tif_row) { + /* + * Seek forward to the desired row. + */ + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (0); + tif->tif_row = row; + } + return (1); +} + +int +TIFFReadScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample) +{ + int e; + + if (!TIFFCheckRead(tif, 0)) + return (-1); + if( (e = TIFFSeek(tif, row, sample)) != 0) { + /* + * Decompress desired row into user buffer. + */ + e = (*tif->tif_decoderow) + (tif, (tidata_t) buf, tif->tif_scanlinesize, sample); + tif->tif_row++; + if (e) + (*tif->tif_postdecode)(tif, (tidata_t) buf, + tif->tif_scanlinesize); + } + return (e > 0 ? 1 : -1); +} + +/* + * Read a strip of data and decompress the specified + * amount into the user-supplied buffer. + */ +tsize_t +TIFFReadEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 nrows; + tsize_t stripsize; + tstrip_t sep_strip, strips_per_sep; + + if (!TIFFCheckRead(tif, 0)) + return (-1); + if (strip >= td->td_nstrips) { + TIFFError(tif->tif_name, "%ld: Strip out of range, max %ld", + (long) strip, (long) td->td_nstrips); + return (-1); + } + /* + * Calculate the strip size according to the number of + * rows in the strip (check for truncated last strip on any + * of the separations). + */ + if( td->td_rowsperstrip >= td->td_imagelength ) + strips_per_sep = 1; + else + strips_per_sep = (td->td_imagelength+td->td_rowsperstrip-1) + / td->td_rowsperstrip; + + sep_strip = strip % strips_per_sep; + + if (sep_strip != strips_per_sep-1 || + (nrows = td->td_imagelength % td->td_rowsperstrip) == 0) + nrows = td->td_rowsperstrip; + + stripsize = TIFFVStripSize(tif, nrows); + if (size == (tsize_t) -1) + size = stripsize; + else if (size > stripsize) + size = stripsize; + if (TIFFFillStrip(tif, strip) && (*tif->tif_decodestrip)(tif, + (tidata_t) buf, size, (tsample_t)(strip / td->td_stripsperimage))) { + (*tif->tif_postdecode)(tif, (tidata_t) buf, size); + return (size); + } else + return ((tsize_t) -1); +} + +static tsize_t +TIFFReadRawStrip1(TIFF* tif, + tstrip_t strip, tdata_t buf, tsize_t size, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (!isMapped(tif)) { + tsize_t cc; + + if (!SeekOK(tif, td->td_stripoffset[strip])) { + TIFFError(module, + "%s: Seek error at scanline %lu, strip %lu", + tif->tif_name, + (u_long) tif->tif_row, (u_long) strip); + return (-1); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { + TIFFError(module, + "%s: Read error at scanline %lu; got %lu bytes, expected %lu", + tif->tif_name, + (u_long) tif->tif_row, + (u_long) cc, + (u_long) size); + return (-1); + } + } else { + if (td->td_stripoffset[strip] + size > tif->tif_size) { + TIFFError(module, + "%s: Read error at scanline %lu, strip %lu; got %lu bytes, expected %lu", + tif->tif_name, + (u_long) tif->tif_row, + (u_long) strip, + (u_long) tif->tif_size - td->td_stripoffset[strip], + (u_long) size); + return (-1); + } + _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[strip], size); + } + return (size); +} + +/* + * Read a strip of data from the file. + */ +tsize_t +TIFFReadRawStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size) +{ + static const char module[] = "TIFFReadRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + tsize_t bytecount; + + if (!TIFFCheckRead(tif, 0)) + return ((tsize_t) -1); + if (strip >= td->td_nstrips) { + TIFFError(tif->tif_name, "%lu: Strip out of range, max %lu", + (u_long) strip, (u_long) td->td_nstrips); + return ((tsize_t) -1); + } + bytecount = td->td_stripbytecount[strip]; + if (bytecount <= 0) { + TIFFError(tif->tif_name, + "%lu: Invalid strip byte count, strip %lu", + (u_long) bytecount, (u_long) strip); + return ((tsize_t) -1); + } + if (size != (tsize_t)-1 && size < bytecount) + bytecount = size; + return (TIFFReadRawStrip1(tif, strip, buf, bytecount, module)); +} + +/* + * Read the specified strip and setup for decoding. + * The data buffer is expanded, as necessary, to + * hold the strip's data. + */ +static int +TIFFFillStrip(TIFF* tif, tstrip_t strip) +{ + static const char module[] = "TIFFFillStrip"; + TIFFDirectory *td = &tif->tif_dir; + tsize_t bytecount; + + bytecount = td->td_stripbytecount[strip]; + if (bytecount <= 0) { + TIFFError(tif->tif_name, + "%lu: Invalid strip byte count, strip %lu", + (u_long) bytecount, (u_long) strip); + return (0); + } + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is going + * to handle this operation itself. In this case, avoid + * copying the raw data and instead just reference the + * data from the memory mapped file image. This assumes + * that the decompression routines do not modify the + * contents of the raw data buffer (if they try to, + * the application will get a fault since the file is + * mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + if ( td->td_stripoffset[strip] + bytecount > tif->tif_size) { + /* + * This error message might seem strange, but it's + * what would happen if a read were done instead. + */ + TIFFError(module, + "%s: Read error on strip %lu; got %lu bytes, expected %lu", + tif->tif_name, + (u_long) strip, + (u_long) tif->tif_size - td->td_stripoffset[strip], + (u_long) bytecount); + tif->tif_curstrip = NOSTRIP; + return (0); + } + tif->tif_rawdatasize = bytecount; + tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip]; + } else { + /* + * Expand raw data buffer, if needed, to + * hold data strip coming from file + * (perhaps should set upper bound on + * the size of a buffer we'll use?). + */ + if (bytecount > tif->tif_rawdatasize) { + tif->tif_curstrip = NOSTRIP; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFError(module, + "%s: Data buffer too small to hold strip %lu", + tif->tif_name, (u_long) strip); + return (0); + } + if (!TIFFReadBufferSetup(tif, 0, + TIFFroundup(bytecount, 1024))) + return (0); + } + if (TIFFReadRawStrip1(tif, strip, (u_char *)tif->tif_rawdata, + bytecount, module) != bytecount) + return (0); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, bytecount); + } + return (TIFFStartStrip(tif, strip)); +} + +/* + * Tile-oriented Read Support + * Contributed by Nancy Cam (Silicon Graphics). + */ + +/* + * Read and decompress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tsize_t +TIFFReadTile(TIFF* tif, + tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s)) + return (-1); + return (TIFFReadEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1)); +} + +/* + * Read a tile of data and decompress the specified + * amount into the user-supplied buffer. + */ +tsize_t +TIFFReadEncodedTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t tilesize = tif->tif_tilesize; + + if (!TIFFCheckRead(tif, 1)) + return (-1); + if (tile >= td->td_nstrips) { + TIFFError(tif->tif_name, "%ld: Tile out of range, max %ld", + (long) tile, (u_long) td->td_nstrips); + return (-1); + } + if (size == (tsize_t) -1) + size = tilesize; + else if (size > tilesize) + size = tilesize; + if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif, + (tidata_t) buf, size, (tsample_t)(tile/td->td_stripsperimage))) { + (*tif->tif_postdecode)(tif, (tidata_t) buf, size); + return (size); + } else + return (-1); +} + +static tsize_t +TIFFReadRawTile1(TIFF* tif, + ttile_t tile, tdata_t buf, tsize_t size, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (!isMapped(tif)) { + tsize_t cc; + + if (!SeekOK(tif, td->td_stripoffset[tile])) { + TIFFError(module, + "%s: Seek error at row %ld, col %ld, tile %ld", + tif->tif_name, + (long) tif->tif_row, + (long) tif->tif_col, + (long) tile); + return ((tsize_t) -1); + } + cc = TIFFReadFile(tif, buf, size); + if (cc != size) { + TIFFError(module, + "%s: Read error at row %ld, col %ld; got %lu bytes, expected %lu", + tif->tif_name, + (long) tif->tif_row, + (long) tif->tif_col, + (u_long) cc, + (u_long) size); + return ((tsize_t) -1); + } + } else { + if (td->td_stripoffset[tile] + size > tif->tif_size) { + TIFFError(module, + "%s: Read error at row %ld, col %ld, tile %ld; got %lu bytes, expected %lu", + tif->tif_name, + (long) tif->tif_row, + (long) tif->tif_col, + (long) tile, + (u_long) tif->tif_size - td->td_stripoffset[tile], + (u_long) size); + return ((tsize_t) -1); + } + _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[tile], size); + } + return (size); +} + +/* + * Read a tile of data from the file. + */ +tsize_t +TIFFReadRawTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size) +{ + static const char module[] = "TIFFReadRawTile"; + TIFFDirectory *td = &tif->tif_dir; + tsize_t bytecount; + + if (!TIFFCheckRead(tif, 1)) + return ((tsize_t) -1); + if (tile >= td->td_nstrips) { + TIFFError(tif->tif_name, "%lu: Tile out of range, max %lu", + (u_long) tile, (u_long) td->td_nstrips); + return ((tsize_t) -1); + } + bytecount = td->td_stripbytecount[tile]; + if (size != (tsize_t) -1 && size < bytecount) + bytecount = size; + return (TIFFReadRawTile1(tif, tile, buf, bytecount, module)); +} + +/* + * Read the specified tile and setup for decoding. + * The data buffer is expanded, as necessary, to + * hold the tile's data. + */ +static int +TIFFFillTile(TIFF* tif, ttile_t tile) +{ + static const char module[] = "TIFFFillTile"; + TIFFDirectory *td = &tif->tif_dir; + tsize_t bytecount; + + bytecount = td->td_stripbytecount[tile]; + if (bytecount <= 0) { + TIFFError(tif->tif_name, + "%lu: Invalid tile byte count, tile %lu", + (u_long) bytecount, (u_long) tile); + return (0); + } + if (isMapped(tif) && + (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) { + /* + * The image is mapped into memory and we either don't + * need to flip bits or the compression routine is going + * to handle this operation itself. In this case, avoid + * copying the raw data and instead just reference the + * data from the memory mapped file image. This assumes + * that the decompression routines do not modify the + * contents of the raw data buffer (if they try to, + * the application will get a fault since the file is + * mapped read-only). + */ + if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + if ( td->td_stripoffset[tile] + bytecount > tif->tif_size) { + tif->tif_curtile = NOTILE; + return (0); + } + tif->tif_rawdatasize = bytecount; + tif->tif_rawdata = tif->tif_base + td->td_stripoffset[tile]; + } else { + /* + * Expand raw data buffer, if needed, to + * hold data tile coming from file + * (perhaps should set upper bound on + * the size of a buffer we'll use?). + */ + if (bytecount > tif->tif_rawdatasize) { + tif->tif_curtile = NOTILE; + if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { + TIFFError(module, + "%s: Data buffer too small to hold tile %ld", + tif->tif_name, (long) tile); + return (0); + } + if (!TIFFReadBufferSetup(tif, 0, + TIFFroundup(bytecount, 1024))) + return (0); + } + if (TIFFReadRawTile1(tif, tile, (u_char *)tif->tif_rawdata, + bytecount, module) != bytecount) + return (0); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, bytecount); + } + return (TIFFStartTile(tif, tile)); +} + +/* + * Setup the raw data buffer in preparation for + * reading a strip of raw data. If the buffer + * is specified as zero, then a buffer of appropriate + * size is allocated by the library. Otherwise, + * the client must guarantee that the buffer is + * large enough to hold any individual strip of + * raw data. + */ +int +TIFFReadBufferSetup(TIFF* tif, tdata_t bp, tsize_t size) +{ + static const char module[] = "TIFFReadBufferSetup"; + + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) + _TIFFfree(tif->tif_rawdata); + tif->tif_rawdata = NULL; + } + if (bp) { + tif->tif_rawdatasize = size; + tif->tif_rawdata = (tidata_t) bp; + tif->tif_flags &= ~TIFF_MYBUFFER; + } else { + tif->tif_rawdatasize = TIFFroundup(size, 1024); + tif->tif_rawdata = (tidata_t) _TIFFmalloc(tif->tif_rawdatasize); + tif->tif_flags |= TIFF_MYBUFFER; + } + if (tif->tif_rawdata == NULL) { + TIFFError(module, + "%s: No space for data buffer at scanline %ld", + tif->tif_name, (long) tif->tif_row); + tif->tif_rawdatasize = 0; + return (0); + } + return (1); +} + +/* + * Set state to appear as if a + * strip has just been read in. + */ +static int +TIFFStartStrip(TIFF* tif, tstrip_t strip) +{ + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_rawcc = td->td_stripbytecount[strip]; + return ((*tif->tif_predecode)(tif, + (tsample_t)(strip / td->td_stripsperimage))); +} + +/* + * Set state to appear as if a + * tile has just been read in. + */ +static int +TIFFStartTile(TIFF* tif, ttile_t tile) +{ + TIFFDirectory *td = &tif->tif_dir; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupdecode)(tif)) + return (0); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_curtile = tile; + tif->tif_row = + (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) * + td->td_tilelength; + tif->tif_col = + (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) * + td->td_tilewidth; + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_rawcc = td->td_stripbytecount[tile]; + return ((*tif->tif_predecode)(tif, + (tsample_t)(tile/td->td_stripsperimage))); +} + +static int +TIFFCheckRead(TIFF* tif, int tiles) +{ + if (tif->tif_mode == O_WRONLY) { + TIFFError(tif->tif_name, "File not open for reading"); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFError(tif->tif_name, tiles ? + "Can not read tiles from a stripped image" : + "Can not read scanlines from a tiled image"); + return (0); + } + return (1); +} + +void +_TIFFNoPostDecode(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; (void) buf; (void) cc; +} + +void +_TIFFSwab16BitData(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; + assert((cc & 1) == 0); + TIFFSwabArrayOfShort((uint16*) buf, cc/2); +} + +void +_TIFFSwab32BitData(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; + assert((cc & 3) == 0); + TIFFSwabArrayOfLong((uint32*) buf, cc/4); +} + +void +_TIFFSwab64BitData(TIFF* tif, tidata_t buf, tsize_t cc) +{ + (void) tif; + assert((cc & 7) == 0); + TIFFSwabArrayOfDouble((double*) buf, cc/8); +} diff --git a/freeimage241/Source/LibTIFF/tif_strip.c b/freeimage241/Source/LibTIFF/tif_strip.c new file mode 100644 index 0000000..293f29b --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_strip.c @@ -0,0 +1,192 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_strip.c,v 1.0 2001-04-13 00:42:36+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Strip-organized Image Support Routines. + */ +#include "tiffiop.h" + +/* + * Compute which strip a (row,sample) value is in. + */ +tstrip_t +TIFFComputeStrip(TIFF* tif, uint32 row, tsample_t sample) +{ + TIFFDirectory *td = &tif->tif_dir; + tstrip_t strip; + + strip = row / td->td_rowsperstrip; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFError(tif->tif_name, + "%u: Sample out of range, max %u", + sample, td->td_samplesperpixel); + return ((tstrip_t) 0); + } + strip += sample*td->td_stripsperimage; + } + return (strip); +} + +/* + * Compute how many strips are in an image. + */ +tstrip_t +TIFFNumberOfStrips(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tstrip_t nstrips; + + nstrips = (td->td_rowsperstrip == (uint32) -1 ? + (td->td_imagelength != 0 ? 1 : 0) : + TIFFhowmany(td->td_imagelength, td->td_rowsperstrip)); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + nstrips *= td->td_samplesperpixel; + return (nstrips); +} + +/* + * Compute the # bytes in a variable height, row-aligned strip. + */ +tsize_t +TIFFVStripSize(TIFF* tif, uint32 nrows) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (nrows == (uint32) -1) + nrows = td->td_imagelength; +#ifdef YCBCR_SUPPORT + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_photometric == PHOTOMETRIC_YCBCR && + !isUpSampled(tif)) { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + tsize_t w = + TIFFroundup(td->td_imagewidth, td->td_ycbcrsubsampling[0]); + tsize_t scanline = TIFFhowmany(w*td->td_bitspersample, 8); + tsize_t samplingarea = + td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1]; + nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]); + /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ + return ((tsize_t) + (nrows*scanline + 2*(nrows*scanline / samplingarea))); + } else +#endif + return ((tsize_t)(nrows * TIFFScanlineSize(tif))); +} + +/* + * Compute the # bytes in a (row-aligned) strip. + * + * Note that if RowsPerStrip is larger than the + * recorded ImageLength, then the strip size is + * truncated to reflect the actual space required + * to hold the strip. + */ +tsize_t +TIFFStripSize(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + uint32 rps = td->td_rowsperstrip; + if (rps > td->td_imagelength) + rps = td->td_imagelength; + return (TIFFVStripSize(tif, rps)); +} + +/* + * Compute a default strip size based on the image + * characteristics and a requested value. If the + * request is <1 then we choose a strip size according + * to certain heuristics. + */ +uint32 +TIFFDefaultStripSize(TIFF* tif, uint32 request) +{ + return (*tif->tif_defstripsize)(tif, request); +} + +uint32 +_TIFFDefaultStripSize(TIFF* tif, uint32 s) +{ + if ((int32) s < 1) { + /* + * If RowsPerStrip is unspecified, try to break the + * image up into strips that are approximately 8Kbytes. + */ + tsize_t scanline = TIFFScanlineSize(tif); + s = (uint32)(8*1024) / (scanline == 0 ? 1 : scanline); + if (s == 0) /* very wide images */ + s = 1; + } + return (s); +} + +/* + * Return the number of bytes to read/write in a call to + * one of the scanline-oriented i/o routines. Note that + * this number may be 1/samples-per-pixel if data is + * stored as separate planes. + */ +tsize_t +TIFFScanlineSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t scanline; + + scanline = td->td_bitspersample * td->td_imagewidth; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) + scanline *= td->td_samplesperpixel; + return ((tsize_t) TIFFhowmany(scanline, 8)); +} + +/* + * Return the number of bytes required to store a complete + * decoded and packed raster scanline (as opposed to the + * I/O size returned by TIFFScanlineSize which may be less + * if data is store as separate planes). + */ +tsize_t +TIFFRasterScanlineSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t scanline; + + scanline = td->td_bitspersample * td->td_imagewidth; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) { + scanline *= td->td_samplesperpixel; + return ((tsize_t) TIFFhowmany(scanline, 8)); + } else + return ((tsize_t) + TIFFhowmany(scanline, 8)*td->td_samplesperpixel); +} diff --git a/freeimage241/Source/LibTIFF/tif_swab.c b/freeimage241/Source/LibTIFF/tif_swab.c new file mode 100644 index 0000000..38639f3 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_swab.c @@ -0,0 +1,217 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_swab.c,v 1.0 2001-04-13 00:42:37+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Bit & Byte Swapping Support. + * + * XXX We assume short = 16-bits and long = 32-bits XXX + */ +#include "tiffiop.h" + +#ifndef TIFFSwabShort +void +TIFFSwabShort(uint16* wp) +{ + register u_char* cp = (u_char*) wp; + int t; + + t = cp[1]; cp[1] = cp[0]; cp[0] = t; +} +#endif + +#ifndef TIFFSwabLong +void +TIFFSwabLong(uint32* lp) +{ + register u_char* cp = (u_char*) lp; + int t; + + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; +} +#endif + +#ifndef TIFFSwabArrayOfShort +void +TIFFSwabArrayOfShort(uint16* wp, register u_long n) +{ + register u_char* cp; + register int t; + + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (u_char*) wp; + t = cp[1]; cp[1] = cp[0]; cp[0] = t; + wp++; + } +} +#endif + +#ifndef TIFFSwabArrayOfLong +void +TIFFSwabArrayOfLong(register uint32* lp, register u_long n) +{ + register unsigned char *cp; + register int t; + + /* XXX unroll loop some */ + while (n-- > 0) { + cp = (unsigned char *)lp; + t = cp[3]; cp[3] = cp[0]; cp[0] = t; + t = cp[2]; cp[2] = cp[1]; cp[1] = t; + lp++; + } +} +#endif + +#ifndef TIFFSwabDouble +void +TIFFSwabDouble(double *dp) +{ + register uint32* lp = (uint32*) dp; + uint32 t; + + TIFFSwabArrayOfLong(lp, 2); + t = lp[0]; lp[0] = lp[1]; lp[1] = t; +} +#endif + +#ifndef TIFFSwabArrayOfDouble +void +TIFFSwabArrayOfDouble(double* dp, register u_long n) +{ + register uint32* lp = (uint32*) dp; + register uint32 t; + + TIFFSwabArrayOfLong(lp, n + n); + while (n-- > 0) { + t = lp[0]; lp[0] = lp[1]; lp[1] = t; + lp += 2; + } +} +#endif + +/* + * Bit reversal tables. TIFFBitRevTable[] gives + * the bit reversed value of . Used in various + * places in the library when the FillOrder requires + * bit reversal of byte values (e.g. CCITT Fax 3 + * encoding/decoding). TIFFNoBitRevTable is provided + * for algorithms that want an equivalent table that + * do not reverse bit values. + */ +static const unsigned char TIFFBitRevTable[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; +static const unsigned char TIFFNoBitRevTable[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +const unsigned char* +TIFFGetBitRevTable(int reversed) +{ + return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable); +} + +void +TIFFReverseBits(register u_char* cp, register u_long n) +{ + for (; n > 8; n -= 8) { + cp[0] = TIFFBitRevTable[cp[0]]; + cp[1] = TIFFBitRevTable[cp[1]]; + cp[2] = TIFFBitRevTable[cp[2]]; + cp[3] = TIFFBitRevTable[cp[3]]; + cp[4] = TIFFBitRevTable[cp[4]]; + cp[5] = TIFFBitRevTable[cp[5]]; + cp[6] = TIFFBitRevTable[cp[6]]; + cp[7] = TIFFBitRevTable[cp[7]]; + cp += 8; + } + while (n-- > 0) + *cp = TIFFBitRevTable[*cp], cp++; +} diff --git a/freeimage241/Source/LibTIFF/tif_thunder.c b/freeimage241/Source/LibTIFF/tif_thunder.c new file mode 100644 index 0000000..344d977 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_thunder.c @@ -0,0 +1,154 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_thunder.c,v 1.0 2001-04-13 00:42:37+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef THUNDER_SUPPORT +/* + * TIFF Library. + * + * ThunderScan 4-bit Compression Algorithm Support + */ + +/* + * ThunderScan uses an encoding scheme designed for + * 4-bit pixel values. Data is encoded in bytes, with + * each byte split into a 2-bit code word and a 6-bit + * data value. The encoding gives raw data, runs of + * pixels, or pixel values encoded as a delta from the + * previous pixel value. For the latter, either 2-bit + * or 3-bit delta values are used, with the deltas packed + * into a single byte. + */ +#define THUNDER_DATA 0x3f /* mask for 6-bit data */ +#define THUNDER_CODE 0xc0 /* mask for 2-bit code word */ +/* code values */ +#define THUNDER_RUN 0x00 /* run of pixels w/ encoded count */ +#define THUNDER_2BITDELTAS 0x40 /* 3 pixels w/ encoded 2-bit deltas */ +#define DELTA2_SKIP 2 /* skip code for 2-bit deltas */ +#define THUNDER_3BITDELTAS 0x80 /* 2 pixels w/ encoded 3-bit deltas */ +#define DELTA3_SKIP 4 /* skip code for 3-bit deltas */ +#define THUNDER_RAW 0xc0 /* raw data encoded */ + +static const int twobitdeltas[4] = { 0, 1, 0, -1 }; +static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 }; + +#define SETPIXEL(op, v) { \ + lastpixel = (v) & 0xf; \ + if (npixels++ & 1) \ + *op++ |= lastpixel; \ + else \ + op[0] = lastpixel << 4; \ +} + +static int +ThunderDecode(TIFF* tif, tidata_t op, tsize_t maxpixels) +{ + register u_char *bp; + register tsize_t cc; + u_int lastpixel; + tsize_t npixels; + + bp = (u_char *)tif->tif_rawcp; + cc = tif->tif_rawcc; + lastpixel = 0; + npixels = 0; + while (cc > 0 && npixels < maxpixels) { + int n, delta; + + n = *bp++, cc--; + switch (n & THUNDER_CODE) { + case THUNDER_RUN: /* pixel run */ + /* + * Replicate the last pixel n times, + * where n is the lower-order 6 bits. + */ + if (npixels & 1) { + op[0] |= lastpixel; + lastpixel = *op++; npixels++; n--; + } else + lastpixel |= lastpixel << 4; + npixels += n; + for (; n > 0; n -= 2) + *op++ = lastpixel; + if (n == -1) + *--op &= 0xf0; + lastpixel &= 0xf; + break; + case THUNDER_2BITDELTAS: /* 2-bit deltas */ + if ((delta = ((n >> 4) & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + if ((delta = ((n >> 2) & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + if ((delta = (n & 3)) != DELTA2_SKIP) + SETPIXEL(op, lastpixel + twobitdeltas[delta]); + break; + case THUNDER_3BITDELTAS: /* 3-bit deltas */ + if ((delta = ((n >> 3) & 7)) != DELTA3_SKIP) + SETPIXEL(op, lastpixel + threebitdeltas[delta]); + if ((delta = (n & 7)) != DELTA3_SKIP) + SETPIXEL(op, lastpixel + threebitdeltas[delta]); + break; + case THUNDER_RAW: /* raw data */ + SETPIXEL(op, n); + break; + } + } + tif->tif_rawcp = (tidata_t) bp; + tif->tif_rawcc = cc; + if (npixels != maxpixels) { + TIFFError(tif->tif_name, + "ThunderDecode: %s data at scanline %ld (%lu != %lu)", + npixels < maxpixels ? "Not enough" : "Too much", + (long) tif->tif_row, (long) npixels, (long) maxpixels); + return (0); + } + return (1); +} + +static int +ThunderDecodeRow(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s) +{ + tidata_t row = buf; + + (void) s; + while ((long)occ > 0) { + if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth)) + return (0); + occ -= tif->tif_scanlinesize; + row += tif->tif_scanlinesize; + } + return (1); +} + +int +TIFFInitThunderScan(TIFF* tif, int scheme) +{ + (void) scheme; + tif->tif_decoderow = ThunderDecodeRow; + tif->tif_decodestrip = ThunderDecodeRow; + return (1); +} +#endif /* THUNDER_SUPPORT */ diff --git a/freeimage241/Source/LibTIFF/tif_tile.c b/freeimage241/Source/LibTIFF/tif_tile.c new file mode 100644 index 0000000..00bd3a0 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_tile.c @@ -0,0 +1,219 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_tile.c,v 1.0 2001-04-13 00:42:37+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1991-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Tiled Image Support Routines. + */ +#include "tiffiop.h" + +/* + * Compute which tile an (x,y,z,s) value is in. + */ +ttile_t +TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 dx = td->td_tilewidth; + uint32 dy = td->td_tilelength; + uint32 dz = td->td_tiledepth; + ttile_t tile = 1; + + if (td->td_imagedepth == 1) + z = 0; + if (dx == (uint32) -1) + dx = td->td_imagewidth; + if (dy == (uint32) -1) + dy = td->td_imagelength; + if (dz == (uint32) -1) + dz = td->td_imagedepth; + if (dx != 0 && dy != 0 && dz != 0) { + uint32 xpt = TIFFhowmany(td->td_imagewidth, dx); + uint32 ypt = TIFFhowmany(td->td_imagelength, dy); + uint32 zpt = TIFFhowmany(td->td_imagedepth, dz); + + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + tile = (xpt*ypt*zpt)*s + + (xpt*ypt)*(z/dz) + + xpt*(y/dy) + + x/dx; + else + tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx + s; + } + return (tile); +} + +/* + * Check an (x,y,z,s) coordinate + * against the image bounds. + */ +int +TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + TIFFDirectory *td = &tif->tif_dir; + + if (x >= td->td_imagewidth) { + TIFFError(tif->tif_name, "Col %ld out of range, max %lu", + (long) x, (u_long) td->td_imagewidth); + return (0); + } + if (y >= td->td_imagelength) { + TIFFError(tif->tif_name, "Row %ld out of range, max %lu", + (long) y, (u_long) td->td_imagelength); + return (0); + } + if (z >= td->td_imagedepth) { + TIFFError(tif->tif_name, "Depth %ld out of range, max %lu", + (long) z, (u_long) td->td_imagedepth); + return (0); + } + if (td->td_planarconfig == PLANARCONFIG_SEPARATE && + s >= td->td_samplesperpixel) { + TIFFError(tif->tif_name, "Sample %d out of range, max %u", + (int) s, td->td_samplesperpixel); + return (0); + } + return (1); +} + +/* + * Compute how many tiles are in an image. + */ +ttile_t +TIFFNumberOfTiles(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + uint32 dx = td->td_tilewidth; + uint32 dy = td->td_tilelength; + uint32 dz = td->td_tiledepth; + ttile_t ntiles; + + if (dx == (uint32) -1) + dx = td->td_imagewidth; + if (dy == (uint32) -1) + dy = td->td_imagelength; + if (dz == (uint32) -1) + dz = td->td_imagedepth; + ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 : + (TIFFhowmany(td->td_imagewidth, dx) * + TIFFhowmany(td->td_imagelength, dy) * + TIFFhowmany(td->td_imagedepth, dz)); + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + ntiles *= td->td_samplesperpixel; + return (ntiles); +} + +/* + * Compute the # bytes in each row of a tile. + */ +tsize_t +TIFFTileRowSize(TIFF* tif) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t rowsize; + + if (td->td_tilelength == 0 || td->td_tilewidth == 0) + return ((tsize_t) 0); + rowsize = td->td_bitspersample * td->td_tilewidth; + if (td->td_planarconfig == PLANARCONFIG_CONTIG) + rowsize *= td->td_samplesperpixel; + return ((tsize_t) TIFFhowmany(rowsize, 8)); +} + +/* + * Compute the # bytes in a variable length, row-aligned tile. + */ +tsize_t +TIFFVTileSize(TIFF* tif, uint32 nrows) +{ + TIFFDirectory *td = &tif->tif_dir; + tsize_t tilesize; + + if (td->td_tilelength == 0 || td->td_tilewidth == 0 || + td->td_tiledepth == 0) + return ((tsize_t) 0); +#ifdef YCBCR_SUPPORT + if (td->td_planarconfig == PLANARCONFIG_CONTIG && + td->td_photometric == PHOTOMETRIC_YCBCR && + !isUpSampled(tif)) { + /* + * Packed YCbCr data contain one Cb+Cr for every + * HorizontalSampling*VerticalSampling Y values. + * Must also roundup width and height when calculating + * since images that are not a multiple of the + * horizontal/vertical subsampling area include + * YCbCr data for the extended image. + */ + tsize_t w = + TIFFroundup(td->td_tilewidth, td->td_ycbcrsubsampling[0]); + tsize_t rowsize = TIFFhowmany(w*td->td_bitspersample, 8); + tsize_t samplingarea = + td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1]; + nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]); + /* NB: don't need TIFFhowmany here 'cuz everything is rounded */ + tilesize = nrows*rowsize + 2*(nrows*rowsize / samplingarea); + } else +#endif + tilesize = nrows * TIFFTileRowSize(tif); + return ((tsize_t)(tilesize * td->td_tiledepth)); +} + +/* + * Compute the # bytes in a row-aligned tile. + */ +tsize_t +TIFFTileSize(TIFF* tif) +{ + return (TIFFVTileSize(tif, tif->tif_dir.td_tilelength)); +} + +/* + * Compute a default tile size based on the image + * characteristics and a requested value. If a + * request is <1 then we choose a size according + * to certain heuristics. + */ +void +TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + (*tif->tif_deftilesize)(tif, tw, th); +} + +void +_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th) +{ + (void) tif; + if (*(int32*) tw < 1) + *tw = 256; + if (*(int32*) th < 1) + *th = 256; + /* roundup to a multiple of 16 per the spec */ + if (*tw & 0xf) + *tw = TIFFroundup(*tw, 16); + if (*th & 0xf) + *th = TIFFroundup(*th, 16); +} diff --git a/freeimage241/Source/LibTIFF/tif_unix.c b/freeimage241/Source/LibTIFF/tif_unix.c new file mode 100644 index 0000000..5409516 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_unix.c @@ -0,0 +1,224 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_unix.c,v 1.0 2001-04-13 00:42:38+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library UNIX-specific Routines. + */ +#include "tiffiop.h" +#include +#include +#include + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return ((tsize_t) read((int) fd, buf, (size_t) size)); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return ((tsize_t) write((int) fd, buf, (size_t) size)); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ +#if USE_64BIT_API == 1 + return ((toff_t) lseek64((int) fd, (off64_t) off, whence)); +#else + return ((toff_t) lseek((int) fd, (off_t) off, whence)); +#endif +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (close((int) fd)); +} + +#include + +static toff_t +_tiffSizeProc(thandle_t fd) +{ +#ifdef _AM29K + long fsize; + return ((fsize = lseek((int) fd, 0, SEEK_END)) < 0 ? 0 : fsize); +#else +#if USE_64BIT_API == 1 + struct stat64 sb; + return (toff_t) (fstat64((int) fd, &sb) < 0 ? 0 : sb.st_size); +#else + struct stat sb; + return (toff_t) (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size); +#endif +#endif +} + +#ifdef HAVE_MMAP +#include + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + toff_t size = _tiffSizeProc(fd); + if (size != (toff_t) -1) { + *pbase = (tdata_t) + mmap(0, size, PROT_READ, MAP_SHARED, (int) fd, 0); + if (*pbase != (tdata_t) -1) { + *psize = size; + return (1); + } + } + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + (void) fd; + (void) munmap(base, (off_t) size); +} +#else /* !HAVE_MMAP */ +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + (void) fd; (void) pbase; (void) psize; + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + (void) fd; (void) base; (void) size; +} +#endif /* !HAVE_MMAP */ + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + int m, fd; + + m = _TIFFgetMode(mode, module); + if (m == -1) + return ((TIFF*)0); + +/* for cygwin */ +#ifdef O_BINARY + m |= O_BINARY; +#endif + +#ifdef _AM29K + fd = open(name, m); +#else + fd = open(name, m, 0666); +#endif + if (fd < 0) { + TIFFError(module, "%s: Cannot open", name); + return ((TIFF *)0); + } + return (TIFFFdOpen(fd, name, mode)); +} + +void* +_TIFFmalloc(tsize_t s) +{ + return (malloc((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + free(p); +} + +void* +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +static void +unixWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFwarningHandler = unixWarningHandler; + +static void +unixErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} +TIFFErrorHandler _TIFFerrorHandler = unixErrorHandler; diff --git a/freeimage241/Source/LibTIFF/tif_version.c b/freeimage241/Source/LibTIFF/tif_version.c new file mode 100644 index 0000000..5664c94 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_version.c @@ -0,0 +1,33 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_version.c,v 1.0 2001-04-13 00:42:38+02 floris_van_den_berg Exp floris_van_den_berg $ */ +/* + * Copyright (c) 1992-1997 Sam Leffler + * Copyright (c) 1992-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#include "tiffiop.h" + +static const char TIFFVersion[] = "LibTIFF 3.5.6. Beta"; + +const char* +TIFFGetVersion(void) +{ + return (TIFFVersion); +} diff --git a/freeimage241/Source/LibTIFF/tif_vms.c b/freeimage241/Source/LibTIFF/tif_vms.c new file mode 100644 index 0000000..f48b4b5 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_vms.c @@ -0,0 +1,588 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_vms.c,v 1.0 2001-04-13 00:42:38+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library VMS-specific Routines. + */ + +#include +#include +#include "tiffiop.h" +#if !HAVE_IEEEFP +#include +#endif + +#ifdef VAXC +#define NOSHARE noshare +#else +#define NOSHARE +#endif + +#ifdef __alpha +/* Dummy entry point for backwards compatibility */ +void TIFFModeCCITTFax3(void){} +#endif + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (read((int) fd, buf, size)); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (write((int) fd, buf, size)); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + return ((toff_t) lseek((int) fd, (off_t) off, whence)); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (close((int) fd)); +} + +#include + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + struct stat sb; + return (toff_t) (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size); +} + +#ifdef HAVE_MMAP +#include +#include +#include + +/* + * Table for storing information on current open sections. + * (Should really be a linked list) + */ +#define MAX_MAPPED 100 +static int no_mapped = 0; +static struct { + char *base; + char *top; + unsigned short channel; +} map_table[MAX_MAPPED]; + +/* + * This routine maps a file into a private section. Note that this + * method of accessing a file is by far the fastest under VMS. + * The routine may fail (i.e. return 0) for several reasons, for + * example: + * - There is no more room for storing the info on sections. + * - The process is out of open file quota, channels, ... + * - fd does not describe an opened file. + * - The file is already opened for write access by this process + * or another process + * - There is no free "hole" in virtual memory that fits the + * size of the file + */ +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + char name[256]; + struct FAB fab; + unsigned short channel; + char *inadr[2], *retadr[2]; + unsigned long status; + long size; + + if (no_mapped >= MAX_MAPPED) + return(0); + /* + * We cannot use a file descriptor, we + * must open the file once more. + */ + if (getname((int)fd, name, 1) == NULL) + return(0); + /* prepare the FAB for a user file open */ + fab = cc$rms_fab; + fab.fab$l_fop |= FAB$V_UFO; + fab.fab$b_fac = FAB$M_GET; + fab.fab$b_shr = FAB$M_SHRGET; + fab.fab$l_fna = name; + fab.fab$b_fns = strlen(name); + status = sys$open(&fab); /* open file & get channel number */ + if ((status&1) == 0) + return(0); + channel = (unsigned short)fab.fab$l_stv; + inadr[0] = inadr[1] = (char *)0; /* just an address in P0 space */ + /* + * Map the blocks of the file up to + * the EOF block into virtual memory. + */ + size = _tiffSizeProc(fd); + status = sys$crmpsc(inadr, retadr, 0, SEC$M_EXPREG, 0,0,0, channel, + TIFFhowmany(size,512), 0,0,0); + if ((status&1) == 0){ + sys$dassgn(channel); + return(0); + } + *pbase = (tdata_t) retadr[0]; /* starting virtual address */ + /* + * Use the size of the file up to the + * EOF mark for UNIX compatibility. + */ + *psize = (toff_t) size; + /* Record the section in the table */ + map_table[no_mapped].base = retadr[0]; + map_table[no_mapped].top = retadr[1]; + map_table[no_mapped].channel = channel; + no_mapped++; + + return(1); +} + +/* + * This routine unmaps a section from the virtual address space of + * the process, but only if the base was the one returned from a + * call to TIFFMapFileContents. + */ +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + char *inadr[2]; + int i, j; + + /* Find the section in the table */ + for (i = 0;i < no_mapped; i++) { + if (map_table[i].base == (char *) base) { + /* Unmap the section */ + inadr[0] = (char *) base; + inadr[1] = map_table[i].top; + sys$deltva(inadr, 0, 0); + sys$dassgn(map_table[i].channel); + /* Remove this section from the list */ + for (j = i+1; j < no_mapped; j++) + map_table[j-1] = map_table[j]; + no_mapped--; + return; + } + } +} +#else /* !HAVE_MMAP */ +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} +#endif /* !HAVE_MMAP */ + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, + _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + int m, fd; + + m = _TIFFgetMode(mode, module); + if (m == -1) + return ((TIFF*)0); + if (m&O_TRUNC){ + /* + * There is a bug in open in VAXC. If you use + * open w/ m=O_RDWR|O_CREAT|O_TRUNC the + * wrong thing happens. On the other hand + * creat does the right thing. + */ + fd = creat((char *) /* bug in stdio.h */ name, 0666, + "alq = 128", "deq = 64", "mbc = 32", + "fop = tef"); + } else if (m&O_RDWR) { + fd = open(name, m, 0666, + "deq = 64", "mbc = 32", "fop = tef", "ctx = stm"); + } else + fd = open(name, m, 0666, "mbc = 32", "ctx = stm"); + if (fd < 0) { + TIFFError(module, "%s: Cannot open", name); + return ((TIFF*)0); + } + return (TIFFFdOpen(fd, name, mode)); +} + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return (malloc((size_t) s)); +} + +void +_TIFFfree(tdata_t p) +{ + free(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (realloc(p, (size_t) s)); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + memset(p, v, (size_t) c); +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + return (memcmp(p1, p2, (size_t) c)); +} + +/* + * On the VAX, we need to make those global, writable pointers + * non-shareable, otherwise they would be made shareable by default. + * On the AXP, this brain damage has been corrected. + * + * I (Karsten Spang, krs@kampsax.dk) have dug around in the GCC + * manual and the GAS code and have come up with the following + * construct, but I don't have GCC on my VAX, so it is untested. + * Please tell me if it does not work. + */ + +static void +vmsWarningHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} + +NOSHARE TIFFErrorHandler _TIFFwarningHandler = vmsWarningHandler +#if defined(VAX) && defined(__GNUC__) +asm("_$$PsectAttributes_NOSHR$$_TIFFwarningHandler") +#endif +; + +static void +vmsErrorHandler(const char* module, const char* fmt, va_list ap) +{ + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +} + +NOSHARE TIFFErrorHandler _TIFFerrorHandler = vmsErrorHandler +#if defined(VAX) && defined(__GNUC__) +asm("_$$PsectAttributes_NOSHR$$_TIFFerrorHandler") +#endif +; + + +#if !HAVE_IEEEFP +/* IEEE floting point handling */ + +typedef struct ieeedouble { + u_long mant2; /* fix NDR: full 8-byte swap */ + u_long mant : 20, + exp : 11, + sign : 1; +} ieeedouble; +typedef struct ieeefloat { + u_long mant : 23, + exp : 8, + sign : 1; +} ieeefloat; + +/* + * NB: These are D_FLOAT's, not G_FLOAT's. A G_FLOAT is + * simply a reverse-IEEE float/double. + */ + +typedef struct { + u_long mant1 : 7, + exp : 8, + sign : 1, + mant2 : 16, + mant3 : 16, + mant4 : 16; +} nativedouble; +typedef struct { + u_long mant1 : 7, + exp : 8, + sign : 1, + mant2 : 16; +} nativefloat; + +typedef union { + ieeedouble ieee; + nativedouble native; + char b[8]; + uint32 l[2]; + double d; +} double_t; + +typedef union { + ieeefloat ieee; + nativefloat native; + char b[4]; + uint32 l; + float f; +} float_t; + +#if defined(VAXC) || defined(DECC) +#pragma inline(ieeetod,dtoieee) +#endif + +/* + * Convert an IEEE double precision number to native double precision. + * The source is contained in two longwords, the second holding the sign, + * exponent and the higher order bits of the mantissa, and the first + * holding the rest of the mantissa as follows: + * (Note: It is assumed that the number has been eight-byte swapped to + * LSB first.) + * + * First longword: + * 32 least significant bits of mantissa + * Second longword: + * 0-19: 20 most significant bits of mantissa + * 20-30: exponent + * 31: sign + * The exponent is stored as excess 1023. + * The most significant bit of the mantissa is implied 1, and not stored. + * If the exponent and mantissa are zero, the number is zero. + * If the exponent is 0 (i.e. -1023) and the mantissa is non-zero, it is an + * unnormalized number with the most significant bit NOT implied. + * If the exponent is 2047, the number is invalid, in case the mantissa is zero, + * this means overflow (+/- depending of the sign bit), otherwise + * it simply means invalid number. + * + * If the number is too large for the machine or was specified as overflow, + * +/-HUGE_VAL is returned. + */ +INLINE static void +ieeetod(double *dp) +{ + double_t source; + long sign,exp,mant; + double dmant; + + source.ieee = ((double_t*)dp)->ieee; + sign = source.ieee.sign; + exp = source.ieee.exp; + mant = source.ieee.mant; + + if (exp == 2047) { + if (mant) /* Not a Number (NAN) */ + *dp = HUGE_VAL; + else /* +/- infinity */ + *dp = (sign ? -HUGE_VAL : HUGE_VAL); + return; + } + if (!exp) { + if (!(mant || source.ieee.mant2)) { /* zero */ + *dp=0; + return; + } else { /* Unnormalized number */ + /* NB: not -1023, the 1 bit is not implied */ + exp= -1022; + } + } else { + mant |= 1<<20; + exp -= 1023; + } + dmant = (((double) mant) + + ((double) source.ieee.mant2) / (((double) (1<<16)) * + ((double) (1<<16)))) / (double) (1<<20); + dmant = ldexp(dmant, exp); + if (sign) + dmant= -dmant; + *dp = dmant; +} + +INLINE static void +dtoieee(double *dp) +{ + double_t num; + double x; + int exp; + + num.d = *dp; + if (!num.d) { /* Zero is just binary all zeros */ + num.l[0] = num.l[1] = 0; + return; + } + + if (num.d < 0) { /* Sign is encoded separately */ + num.d = -num.d; + num.ieee.sign = 1; + } else { + num.ieee.sign = 0; + } + + /* Now separate the absolute value into mantissa and exponent */ + x = frexp(num.d, &exp); + + /* + * Handle cases where the value is outside the + * range for IEEE floating point numbers. + * (Overflow cannot happen on a VAX, but underflow + * can happen for G float.) + */ + if (exp < -1022) { /* Unnormalized number */ + x = ldexp(x, -1023-exp); + exp = 0; + } else if (exp > 1023) { /* +/- infinity */ + x = 0; + exp = 2047; + } else { /* Get rid of most significant bit */ + x *= 2; + x -= 1; + exp += 1022; /* fix NDR: 1.0 -> x=0.5, exp=1 -> ieee.exp = 1023 */ + } + num.ieee.exp = exp; + + x *= (double) (1<<20); + num.ieee.mant = (long) x; + x -= (double) num.ieee.mant; + num.ieee.mant2 = (long) (x*((double) (1<<16)*(double) (1<<16))); + + if (!(num.ieee.mant || num.ieee.exp || num.ieee.mant2)) { + /* Avoid negative zero */ + num.ieee.sign = 0; + } + ((double_t*)dp)->ieee = num.ieee; +} + +/* + * Beware, these do not handle over/under-flow + * during conversion from ieee to native format. + */ +#define NATIVE2IEEEFLOAT(fp) { \ + float_t t; \ + if (t.ieee.exp = (fp)->native.exp) \ + t.ieee.exp += -129 + 127; \ + t.ieee.sign = (fp)->native.sign; \ + t.ieee.mant = ((fp)->native.mant1<<16)|(fp)->native.mant2; \ + *(fp) = t; \ +} +#define IEEEFLOAT2NATIVE(fp) { \ + float_t t; int v = (fp)->ieee.exp; \ + if (v) v += -127 + 129; /* alter bias of exponent */\ + t.native.exp = v; /* implicit truncation of exponent */\ + t.native.sign = (fp)->ieee.sign; \ + v = (fp)->ieee.mant; \ + t.native.mant1 = v >> 16; \ + t.native.mant2 = v;\ + *(fp) = t; \ +} + +#define IEEEDOUBLE2NATIVE(dp) ieeetod(dp) + +#define NATIVE2IEEEDOUBLE(dp) dtoieee(dp) + + +/* + * These unions are used during floating point + * conversions. The above macros define the + * conversion operations. + */ +void +TIFFCvtIEEEFloatToNative(TIFF* tif, u_int n, float* f) +{ + float_t* fp = (float_t*) f; + + while (n-- > 0) { + IEEEFLOAT2NATIVE(fp); + fp++; + } +} + +void +TIFFCvtNativeToIEEEFloat(TIFF* tif, u_int n, float* f) +{ + float_t* fp = (float_t*) f; + + while (n-- > 0) { + NATIVE2IEEEFLOAT(fp); + fp++; + } +} +void +TIFFCvtIEEEDoubleToNative(TIFF* tif, u_int n, double* f) +{ + double_t* fp = (double_t*) f; + + while (n-- > 0) { + IEEEDOUBLE2NATIVE(fp); + fp++; + } +} + +void +TIFFCvtNativeToIEEEDouble(TIFF* tif, u_int n, double* f) +{ + double_t* fp = (double_t*) f; + + while (n-- > 0) { + NATIVE2IEEEDOUBLE(fp); + fp++; + } +} +#endif diff --git a/freeimage241/Source/LibTIFF/tif_warning.c b/freeimage241/Source/LibTIFF/tif_warning.c new file mode 100644 index 0000000..0eb08b1 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_warning.c @@ -0,0 +1,49 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_warning.c,v 1.0 2001-04-13 00:42:38+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + */ +#include "tiffiop.h" + +TIFFErrorHandler +TIFFSetWarningHandler(TIFFErrorHandler handler) +{ + TIFFErrorHandler prev = _TIFFwarningHandler; + _TIFFwarningHandler = handler; + return (prev); +} + +void +TIFFWarning(const char* module, const char* fmt, ...) +{ + if (_TIFFwarningHandler) { + va_list ap; + va_start(ap, fmt); + (*_TIFFwarningHandler)(module, fmt, ap); + va_end(ap); + } +} diff --git a/freeimage241/Source/LibTIFF/tif_win3.c b/freeimage241/Source/LibTIFF/tif_win3.c new file mode 100644 index 0000000..58b0463 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_win3.c @@ -0,0 +1,225 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_win3.c,v 1.0 2001-04-13 00:42:39+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Windows 3.x-specific Routines. + */ +#include "tiffiop.h" +#if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_MSC_VER) +#include /* for open, close, etc. function prototypes */ +#endif + +#include +#include +#include + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (_hread(fd, buf, size)); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + return (_hwrite(fd, buf, size)); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + return (_llseek(fd, (off_t) off, whence)); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (_lclose(fd)); +} + +#include + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + struct stat sb; + return (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size); +} + +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +/* + * Open a TIFF file descriptor for read/writing. + */ +TIFF* +TIFFFdOpen(int fd, const char* name, const char* mode) +{ + TIFF* tif; + + tif = TIFFClientOpen(name, mode, + (thandle_t) fd, + _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, + _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); + if (tif) + tif->tif_fd = fd; + return (tif); +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + int m, fd; + OFSTRUCT of; + int mm = 0; + + m = _TIFFgetMode(mode, module); + if (m == -1) + return ((TIFF*)0); + if (m & O_CREAT) { + if ((m & O_TRUNC) || OpenFile(name, &of, OF_EXIST) != HFILE_ERROR) + mm |= OF_CREATE; + } + if (m & O_WRONLY) + mm |= OF_WRITE; + if (m & O_RDWR) + mm |= OF_READWRITE; + fd = OpenFile(name, &of, mm); + if (fd < 0) { + TIFFError(module, "%s: Cannot open", name); + return ((TIFF*)0); + } + return (TIFFFdOpen(fd, name, mode)); +} + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return (tdata_t) GlobalAllocPtr(GHND, (DWORD) s); +} + +void +_TIFFfree(tdata_t p) +{ + GlobalFreePtr(p); +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + return (tdata_t) GlobalReAllocPtr(p, (DWORD) s, GHND); +} + +void +_TIFFmemset(tdata_t p, int v, tsize_t c) +{ + char* pp = (char*) p; + + while (c > 0) { + tsize_t chunk = 0x10000 - ((uint32) pp & 0xffff);/* What's left in segment */ + if (chunk > 0xff00) /* No more than 0xff00 */ + chunk = 0xff00; + if (chunk > c) /* No more than needed */ + chunk = c; + memset(pp, v, chunk); + pp = (char*) (chunk + (char huge*) pp); + c -= chunk; + } +} + +void +_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c) +{ + if (c > 0xFFFF) + hmemcpy((void _huge*) d, (void _huge*) s, c); + else + (void) memcpy(d, s, (size_t) c); +} + +int +_TIFFmemcmp(const tdata_t d, const tdata_t s, tsize_t c) +{ + char* dd = (char*) d; + char* ss = (char*) s; + tsize_t chunks, chunkd, chunk; + int result; + + while (c > 0) { + chunks = 0x10000 - ((uint32) ss & 0xffff); /* What's left in segment */ + chunkd = 0x10000 - ((uint32) dd & 0xffff); /* What's left in segment */ + chunk = c; /* Get the largest of */ + if (chunk > chunks) /* c, chunks, chunkd, */ + chunk = chunks; /* 0xff00 */ + if (chunk > chunkd) + chunk = chunkd; + if (chunk > 0xff00) + chunk = 0xff00; + result = memcmp(dd, ss, chunk); + if (result != 0) + return (result); + dd = (char*) (chunk + (char huge*) dd); + ss = (char*) (chunk + (char huge*) ss); + c -= chunk; + } + return (0); +} + +static void +win3WarningHandler(const char* module, const char* fmt, va_list ap) +{ + char e[512] = { '\0' }; + if (module != NULL) + strcat(strcpy(e, module), ":"); + vsprintf(e+strlen(e), fmt, ap); + strcat(e, "."); + MessageBox(GetActiveWindow(), e, "LibTIFF Warning", + MB_OK|MB_ICONEXCLAMATION); +} +TIFFErrorHandler _TIFFwarningHandler = win3WarningHandler; + +static void +win3ErrorHandler(const char* module, const char* fmt, va_list ap) +{ + char e[512] = { '\0' }; + if (module != NULL) + strcat(strcpy(e, module), ":"); + vsprintf(e+strlen(e), fmt, ap); + strcat(e, "."); + MessageBox(GetActiveWindow(), e, "LibTIFF Error", MB_OK|MB_ICONSTOP); +} +TIFFErrorHandler _TIFFerrorHandler = win3ErrorHandler; diff --git a/freeimage241/Source/LibTIFF/tif_win32.c b/freeimage241/Source/LibTIFF/tif_win32.c new file mode 100644 index 0000000..266d652 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_win32.c @@ -0,0 +1,323 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_win32.c,v 1.0 2001-04-13 00:42:39+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library Win32-specific Routines. Adapted from tif_unix.c 4/5/95 by + * Scott Wagner (wagner@itek.com), Itek Graphix, Rochester, NY USA + */ +#include +#include "tiffiop.h" + +static tsize_t +_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + DWORD dwSizeRead; + if (!ReadFile(fd, buf, size, &dwSizeRead, NULL)) + return(0); + return ((tsize_t) dwSizeRead); +} + +static tsize_t +_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size) +{ + DWORD dwSizeWritten; + if (!WriteFile(fd, buf, size, &dwSizeWritten, NULL)) + return(0); + return ((tsize_t) dwSizeWritten); +} + +static toff_t +_tiffSeekProc(thandle_t fd, toff_t off, int whence) +{ + DWORD dwMoveMethod, dwMoveHigh; + + /* we use this as a special code, so avoid accepting it */ + if( off == 0xFFFFFFFF ) + return 0xFFFFFFFF; + + switch(whence) + { + case SEEK_SET: + dwMoveMethod = FILE_BEGIN; + break; + case SEEK_CUR: + dwMoveMethod = FILE_CURRENT; + break; + case SEEK_END: + dwMoveMethod = FILE_END; + break; + default: + dwMoveMethod = FILE_BEGIN; + break; + } + dwMoveHigh = 0; + return ((toff_t)SetFilePointer(fd, (LONG) off, (PLONG)&dwMoveHigh, + dwMoveMethod)); +} + +static int +_tiffCloseProc(thandle_t fd) +{ + return (CloseHandle(fd) ? 0 : -1); +} + +static toff_t +_tiffSizeProc(thandle_t fd) +{ + return ((toff_t)GetFileSize(fd, NULL)); +} + +#ifdef __BORLANDC__ +#pragma argsused +#endif +static int +_tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + return (0); +} + +/* + * From "Hermann Josef Hill" : + * + * Windows uses both a handle and a pointer for file mapping, + * but according to the SDK documentation and Richter's book + * "Advanced Windows Programming" it is safe to free the handle + * after obtaining the file mapping pointer + * + * This removes a nasty OS dependency and cures a problem + * with Visual C++ 5.0 + */ +static int +_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize) +{ + toff_t size; + HANDLE hMapFile; + + if ((size = _tiffSizeProc(fd)) == 0xFFFFFFFF) + return (0); + hMapFile = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL); + if (hMapFile == NULL) + return (0); + *pbase = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); + CloseHandle(hMapFile); + if (*pbase == NULL) + return (0); + *psize = size; + return(1); +} + +#ifdef __BORLANDC__ +#pragma argsused +#endif +static void +_tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ +} + +static void +_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size) +{ + UnmapViewOfFile(base); +} + +/* + * Open a TIFF file descriptor for read/writing. + * Note that TIFFFdOpen and TIFFOpen recognise the character 'u' in the mode + * string, which forces the file to be opened unmapped. + */ +TIFF* +TIFFFdOpen(int ifd, const char* name, const char* mode) +{ + TIFF* tif; + BOOL fSuppressMap = (mode[1] == 'u' || (mode[1]!=0 && mode[2] == 'u')); + + tif = TIFFClientOpen(name, mode, + (thandle_t)ifd, + _tiffReadProc, _tiffWriteProc, + _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, + fSuppressMap ? _tiffDummyMapProc : _tiffMapProc, + fSuppressMap ? _tiffDummyUnmapProc : _tiffUnmapProc); + if (tif) + tif->tif_fd = ifd; + return (tif); +} + +/* + * Open a TIFF file for read/writing. + */ +TIFF* +TIFFOpen(const char* name, const char* mode) +{ + static const char module[] = "TIFFOpen"; + thandle_t fd; + int m; + DWORD dwMode; + + m = _TIFFgetMode(mode, module); + + switch(m) + { + case O_RDONLY: + dwMode = OPEN_EXISTING; + break; + case O_RDWR: + dwMode = OPEN_ALWAYS; + break; + case O_RDWR|O_CREAT: + dwMode = OPEN_ALWAYS; + break; + case O_RDWR|O_TRUNC: + dwMode = CREATE_ALWAYS; + break; + case O_RDWR|O_CREAT|O_TRUNC: + dwMode = CREATE_ALWAYS; + break; + default: + return ((TIFF*)0); + } + fd = (thandle_t)CreateFile(name, (m == O_RDONLY) ? GENERIC_READ : + (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ, NULL, dwMode, + (m == O_RDONLY) ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL, NULL); + if (fd == INVALID_HANDLE_VALUE) { + TIFFError(module, "%s: Cannot open", name); + return ((TIFF *)0); + } + return (TIFFFdOpen((int)fd, name, mode)); +} + +tdata_t +_TIFFmalloc(tsize_t s) +{ + return ((tdata_t)GlobalAlloc(GMEM_FIXED, s)); +} + +void +_TIFFfree(tdata_t p) +{ + GlobalFree(p); + return; +} + +tdata_t +_TIFFrealloc(tdata_t p, tsize_t s) +{ + void* pvTmp; + tsize_t old=GlobalSize(p); + if (old>=s) + { + if ((pvTmp = GlobalAlloc(GMEM_FIXED, s)) != NULL) { + CopyMemory(pvTmp, p, s); + GlobalFree(p); + } + } + else + { + if ((pvTmp = GlobalAlloc(GMEM_FIXED, s)) != NULL) { + CopyMemory(pvTmp, p, old); + GlobalFree(p); + } + } + return ((tdata_t)pvTmp); +} + +void +_TIFFmemset(void* p, int v, tsize_t c) +{ + FillMemory(p, c, (BYTE)v); +} + +void +_TIFFmemcpy(void* d, const tdata_t s, tsize_t c) +{ + CopyMemory(d, s, c); +} + +int +_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) +{ + register const BYTE *pb1 = (const BYTE *) p1; + register const BYTE *pb2 = (const BYTE *) p2; + register DWORD dwTmp = c; + register int iTmp; + for (iTmp = 0; dwTmp-- && !iTmp; iTmp = (int)*pb1++ - (int)*pb2++) + ; + return (iTmp); +} + +static void +Win32WarningHandler(const char* module, const char* fmt, va_list ap) +{ +#ifndef TIF_PLATFORM_CONSOLE + LPTSTR szTitle; + LPTSTR szTmp; + LPCTSTR szTitleText = "%s Warning"; + LPCTSTR szDefaultModule = "TIFFLIB"; + szTmp = (module == NULL) ? (LPTSTR)szDefaultModule : (LPTSTR)module; + if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, (lstrlen(szTmp) + + lstrlen(szTitleText) + lstrlen(fmt) + 128)*sizeof(TCHAR))) == NULL) + return; + wsprintf(szTitle, szTitleText, szTmp); + szTmp = szTitle + (lstrlen(szTitle)+2)*sizeof(TCHAR); + wvsprintf(szTmp, fmt, ap); + MessageBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION); + LocalFree(szTitle); + return; +#else + if (module != NULL) + fprintf(stderr, "%s: ", module); + fprintf(stderr, "Warning, "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +#endif +} +TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler; + +static void +Win32ErrorHandler(const char* module, const char* fmt, va_list ap) +{ +#ifndef TIF_PLATFORM_CONSOLE + LPTSTR szTitle; + LPTSTR szTmp; + LPCTSTR szTitleText = "%s Error"; + LPCTSTR szDefaultModule = "TIFFLIB"; + szTmp = (module == NULL) ? (LPTSTR)szDefaultModule : (LPTSTR)module; + if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, (lstrlen(szTmp) + + lstrlen(szTitleText) + lstrlen(fmt) + 128)*sizeof(TCHAR))) == NULL) + return; + wsprintf(szTitle, szTitleText, szTmp); + szTmp = szTitle + (lstrlen(szTitle)+2)*sizeof(TCHAR); + wvsprintf(szTmp, fmt, ap); + MessageBox(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION); + LocalFree(szTitle); + return; +#else + if (module != NULL) + fprintf(stderr, "%s: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ".\n"); +#endif +} +TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler; diff --git a/freeimage241/Source/LibTIFF/tif_write.c b/freeimage241/Source/LibTIFF/tif_write.c new file mode 100644 index 0000000..d0bfc70 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_write.c @@ -0,0 +1,659 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_write.c,v 1.0 2001-04-13 00:42:39+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +/* + * TIFF Library. + * + * Scanline-oriented Write Support + */ +#include "tiffiop.h" +#include +#include + +#define REWRITE_HACK + +#define STRIPINCR 20 /* expansion factor on strip array */ + +#define WRITECHECKSTRIPS(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module)) +#define WRITECHECKTILES(tif, module) \ + (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module)) +#define BUFFERCHECK(tif) \ + ((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) || \ + TIFFWriteBufferSetup((tif), NULL, (tsize_t) -1)) + +static int TIFFGrowStrips(TIFF*, int, const char*); +static int TIFFAppendToStrip(TIFF*, tstrip_t, tidata_t, tsize_t); +static int TIFFSetupStrips(TIFF*); + +int +TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample) +{ + static const char module[] = "TIFFWriteScanline"; + register TIFFDirectory *td; + int status, imagegrew = 0; + tstrip_t strip; + + if (!WRITECHECKSTRIPS(tif, module)) + return (-1); + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return (-1); + td = &tif->tif_dir; + /* + * Extend image length if needed + * (but only for PlanarConfig=1). + */ + if (row >= td->td_imagelength) { /* extend image */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFError(tif->tif_name, + "Can not change \"ImageLength\" when using separate planes"); + return (-1); + } + td->td_imagelength = row+1; + imagegrew = 1; + } + /* + * Calculate strip and check for crossings. + */ + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + if (sample >= td->td_samplesperpixel) { + TIFFError(tif->tif_name, + "%d: Sample out of range, max %d", + sample, td->td_samplesperpixel); + return (-1); + } + strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; + } else + strip = row / td->td_rowsperstrip; + if (strip != tif->tif_curstrip) { + /* + * Changing strips -- flush any data present. + */ + if (!TIFFFlushData(tif)) + return (-1); + tif->tif_curstrip = strip; + /* + * Watch out for a growing image. The value of + * strips/image will initially be 1 (since it + * can't be deduced until the imagelength is known). + */ + if (strip >= td->td_stripsperimage && imagegrew) + td->td_stripsperimage = + TIFFhowmany(td->td_imagelength,td->td_rowsperstrip); + tif->tif_row = + (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return (-1); + tif->tif_flags |= TIFF_CODERSETUP; + } + if (!(*tif->tif_preencode)(tif, sample)) + return (-1); + tif->tif_flags |= TIFF_POSTENCODE; + } + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module)) + return (-1); + /* + * Ensure the write is either sequential or at the + * beginning of a strip (or that we can randomly + * access the data -- i.e. no encoding). + */ + if (row != tif->tif_row) { + if (row < tif->tif_row) { + /* + * Moving backwards within the same strip: + * backup to the start and then decode + * forward (below). + */ + tif->tif_row = (strip % td->td_stripsperimage) * + td->td_rowsperstrip; + tif->tif_rawcp = tif->tif_rawdata; + } + /* + * Seek forward to the desired row. + */ + if (!(*tif->tif_seek)(tif, row - tif->tif_row)) + return (-1); + tif->tif_row = row; + } + status = (*tif->tif_encoderow)(tif, (tidata_t) buf, + tif->tif_scanlinesize, sample); + tif->tif_row++; + return (status); +} + +/* + * Encode the supplied data and write it to the + * specified strip. There must be space for the + * data; we don't check if strips overlap! + * + * NB: Image length must be setup before writing. + */ +tsize_t +TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedStrip"; + TIFFDirectory *td = &tif->tif_dir; + tsample_t sample; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFError(tif->tif_name, + "Can not grow image by strips when using separate planes"); + return ((tsize_t) -1); + } + if (!TIFFGrowStrips(tif, 1, module)) + return ((tsize_t) -1); + td->td_stripsperimage = + TIFFhowmany(td->td_imagelength, td->td_rowsperstrip); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized according to the directory + * info. + */ + if (!BUFFERCHECK(tif)) + return ((tsize_t) -1); + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tsize_t) -1); + tif->tif_flags |= TIFF_CODERSETUP; + } + +#ifdef REWRITE_HACK + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if( td->td_stripbytecount[strip] > 0 ) + { + /* if we are writing over existing tiles, zero length. */ + td->td_stripbytecount[strip] = 0; + + /* this forces TIFFAppendToStrip() to do a seek */ + tif->tif_curoff = 0; + } +#endif + + tif->tif_flags &= ~TIFF_POSTENCODE; + sample = (tsample_t)(strip / td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tsize_t) -1); + if (!(*tif->tif_encodestrip)(tif, (tidata_t) data, cc, sample)) + return ((tsize_t) 0); + if (!(*tif->tif_postencode)(tif)) + return ((tsize_t) -1); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && + !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc)) + return ((tsize_t) -1); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * There must be space for the data; we don't check + * if strips overlap! + * + * NB: Image length must be setup before writing. + */ +tsize_t +TIFFWriteRawStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteRawStrip"; + TIFFDirectory *td = &tif->tif_dir; + + if (!WRITECHECKSTRIPS(tif, module)) + return ((tsize_t) -1); + /* + * Check strip array to make sure there's space. + * We don't support dynamically growing files that + * have data organized in separate bitplanes because + * it's too painful. In that case we require that + * the imagelength be set properly before the first + * write (so that the strips array will be fully + * allocated above). + */ + if (strip >= td->td_nstrips) { + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { + TIFFError(tif->tif_name, + "Can not grow image by strips when using separate planes"); + return ((tsize_t) -1); + } + /* + * Watch out for a growing image. The value of + * strips/image will initially be 1 (since it + * can't be deduced until the imagelength is known). + */ + if (strip >= td->td_stripsperimage) + td->td_stripsperimage = + TIFFhowmany(td->td_imagelength,td->td_rowsperstrip); + if (!TIFFGrowStrips(tif, 1, module)) + return ((tsize_t) -1); + } + tif->tif_curstrip = strip; + tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; + return (TIFFAppendToStrip(tif, strip, (tidata_t) data, cc) ? + cc : (tsize_t) -1); +} + +/* + * Write and compress a tile of data. The + * tile is selected by the (x,y,z,s) coordinates. + */ +tsize_t +TIFFWriteTile(TIFF* tif, + tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s) +{ + if (!TIFFCheckTile(tif, x, y, z, s)) + return (-1); + /* + * NB: A tile size of -1 is used instead of tif_tilesize knowing + * that TIFFWriteEncodedTile will clamp this to the tile size. + * This is done because the tile size may not be defined until + * after the output buffer is setup in TIFFWriteBufferSetup. + */ + return (TIFFWriteEncodedTile(tif, + TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1)); +} + +/* + * Encode the supplied data and write it to the + * specified tile. There must be space for the + * data. The function clamps individual writes + * to a tile to the tile size, but does not (and + * can not) check that multiple writes to the same + * tile do not write more than tile size data. + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tsize_t +TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteEncodedTile"; + TIFFDirectory *td; + tsample_t sample; + + if (!WRITECHECKTILES(tif, module)) + return ((tsize_t) -1); + td = &tif->tif_dir; + if (tile >= td->td_nstrips) { + TIFFError(module, "%s: Tile %lu out of range, max %lu", + tif->tif_name, (u_long) tile, (u_long) td->td_nstrips); + return ((tsize_t) -1); + } + /* + * Handle delayed allocation of data buffer. This + * permits it to be sized more intelligently (using + * directory information). + */ + if (!BUFFERCHECK(tif)) + return ((tsize_t) -1); + tif->tif_curtile = tile; + +#ifdef REWRITE_HACK + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + + if( td->td_stripbytecount[tile] > 0 ) + { + /* if we are writing over existing tiles, zero length. */ + td->td_stripbytecount[tile] = 0; + + /* this forces TIFFAppendToStrip() to do a seek */ + tif->tif_curoff = 0; + } +#endif + + /* + * Compute tiles per row & per column to compute + * current row and column + */ + tif->tif_row = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) + * td->td_tilelength; + tif->tif_col = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) + * td->td_tilewidth; + + if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { + if (!(*tif->tif_setupencode)(tif)) + return ((tsize_t) -1); + tif->tif_flags |= TIFF_CODERSETUP; + } + tif->tif_flags &= ~TIFF_POSTENCODE; + sample = (tsample_t)(tile/td->td_stripsperimage); + if (!(*tif->tif_preencode)(tif, sample)) + return ((tsize_t) -1); + /* + * Clamp write amount to the tile size. This is mostly + * done so that callers can pass in some large number + * (e.g. -1) and have the tile size used instead. + */ + if ( cc < 1 || cc > tif->tif_tilesize) + cc = tif->tif_tilesize; + if (!(*tif->tif_encodetile)(tif, (tidata_t) data, cc, sample)) + return ((tsize_t) 0); + if (!(*tif->tif_postencode)(tif)) + return ((tsize_t) -1); + if (!isFillOrder(tif, td->td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((u_char *)tif->tif_rawdata, tif->tif_rawcc); + if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile, + tif->tif_rawdata, tif->tif_rawcc)) + return ((tsize_t) -1); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + return (cc); +} + +/* + * Write the supplied data to the specified strip. + * There must be space for the data; we don't check + * if strips overlap! + * + * NB: Image length must be setup before writing; this + * interface does not support automatically growing + * the image on each write (as TIFFWriteScanline does). + */ +tsize_t +TIFFWriteRawTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) +{ + static const char module[] = "TIFFWriteRawTile"; + + if (!WRITECHECKTILES(tif, module)) + return ((tsize_t) -1); + if (tile >= tif->tif_dir.td_nstrips) { + TIFFError(module, "%s: Tile %lu out of range, max %lu", + tif->tif_name, (u_long) tile, + (u_long) tif->tif_dir.td_nstrips); + return ((tsize_t) -1); + } + return (TIFFAppendToStrip(tif, tile, (tidata_t) data, cc) ? + cc : (tsize_t) -1); +} + +#define isUnspecified(tif, f) \ + (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0) + +static int +TIFFSetupStrips(TIFF* tif) +{ + TIFFDirectory* td = &tif->tif_dir; + + if (isTiled(tif)) + td->td_stripsperimage = + isUnspecified(tif, FIELD_TILEDIMENSIONS) ? + td->td_samplesperpixel : TIFFNumberOfTiles(tif); + else + td->td_stripsperimage = + isUnspecified(tif, FIELD_ROWSPERSTRIP) ? + td->td_samplesperpixel : TIFFNumberOfStrips(tif); + td->td_nstrips = td->td_stripsperimage; + if (td->td_planarconfig == PLANARCONFIG_SEPARATE) + td->td_stripsperimage /= td->td_samplesperpixel; + td->td_stripoffset = (uint32 *) + _TIFFmalloc(td->td_nstrips * sizeof (uint32)); + td->td_stripbytecount = (uint32 *) + _TIFFmalloc(td->td_nstrips * sizeof (uint32)); + if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) + return (0); + /* + * Place data at the end-of-file + * (by setting offsets to zero). + */ + _TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint32)); + _TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint32)); + TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); + TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); + return (1); +} +#undef isUnspecified + +/* + * Verify file is writable and that the directory + * information is setup properly. In doing the latter + * we also "freeze" the state of the directory so + * that important information is not changed. + */ +int +TIFFWriteCheck(TIFF* tif, int tiles, const char* module) +{ + if (tif->tif_mode == O_RDONLY) { + TIFFError(module, "%s: File not open for writing", + tif->tif_name); + return (0); + } + if (tiles ^ isTiled(tif)) { + TIFFError(tif->tif_name, tiles ? + "Can not write tiles to a stripped image" : + "Can not write scanlines to a tiled image"); + return (0); + } + /* + * On the first write verify all the required information + * has been setup and initialize any data structures that + * had to wait until directory information was set. + * Note that a lot of our work is assumed to remain valid + * because we disallow any of the important parameters + * from changing after we start writing (i.e. once + * TIFF_BEENWRITING is set, TIFFSetField will only allow + * the image's length to be changed). + */ + if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { + TIFFError(module, + "%s: Must set \"ImageWidth\" before writing data", + tif->tif_name); + return (0); + } + if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { + TIFFError(module, + "%s: Must set \"PlanarConfiguration\" before writing data", + tif->tif_name); + return (0); + } + if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { + tif->tif_dir.td_nstrips = 0; + TIFFError(module, "%s: No space for %s arrays", + tif->tif_name, isTiled(tif) ? "tile" : "strip"); + return (0); + } + tif->tif_tilesize = TIFFTileSize(tif); + tif->tif_scanlinesize = TIFFScanlineSize(tif); + tif->tif_flags |= TIFF_BEENWRITING; + return (1); +} + +/* + * Setup the raw data buffer used for encoding. + */ +int +TIFFWriteBufferSetup(TIFF* tif, tdata_t bp, tsize_t size) +{ + static const char module[] = "TIFFWriteBufferSetup"; + + if (tif->tif_rawdata) { + if (tif->tif_flags & TIFF_MYBUFFER) { + _TIFFfree(tif->tif_rawdata); + tif->tif_flags &= ~TIFF_MYBUFFER; + } + tif->tif_rawdata = NULL; + } + if (size == (tsize_t) -1) { + size = (isTiled(tif) ? + tif->tif_tilesize : tif->tif_scanlinesize); + /* + * Make raw data buffer at least 8K + */ + if (size < 8*1024) + size = 8*1024; + bp = NULL; /* NB: force malloc */ + } + if (bp == NULL) { + bp = _TIFFmalloc(size); + if (bp == NULL) { + TIFFError(module, "%s: No space for output buffer", + tif->tif_name); + return (0); + } + tif->tif_flags |= TIFF_MYBUFFER; + } else + tif->tif_flags &= ~TIFF_MYBUFFER; + tif->tif_rawdata = (tidata_t) bp; + tif->tif_rawdatasize = size; + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + tif->tif_flags |= TIFF_BUFFERSETUP; + return (1); +} + +/* + * Grow the strip data structures by delta strips. + */ +static int +TIFFGrowStrips(TIFF* tif, int delta, const char* module) +{ + TIFFDirectory *td = &tif->tif_dir; + + assert(td->td_planarconfig == PLANARCONFIG_CONTIG); + td->td_stripoffset = (uint32*)_TIFFrealloc(td->td_stripoffset, + (td->td_nstrips + delta) * sizeof (uint32)); + td->td_stripbytecount = (uint32*)_TIFFrealloc(td->td_stripbytecount, + (td->td_nstrips + delta) * sizeof (uint32)); + if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) { + td->td_nstrips = 0; + TIFFError(module, "%s: No space to expand strip arrays", + tif->tif_name); + return (0); + } + _TIFFmemset(td->td_stripoffset+td->td_nstrips, 0, delta*sizeof (uint32)); + _TIFFmemset(td->td_stripbytecount+td->td_nstrips, 0, delta*sizeof (uint32)); + td->td_nstrips += delta; + return (1); +} + +/* + * Append the data to the specified strip. + * + * NB: We don't check that there's space in the + * file (i.e. that strips do not overlap). + */ +static int +TIFFAppendToStrip(TIFF* tif, tstrip_t strip, tidata_t data, tsize_t cc) +{ + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "TIFFAppendToStrip"; + + if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) { + /* + * No current offset, set the current strip. + */ + if (td->td_stripoffset[strip] != 0) { + if (!SeekOK(tif, td->td_stripoffset[strip])) { + TIFFError(module, + "%s: Seek error at scanline %lu", + tif->tif_name, (u_long) tif->tif_row); + return (0); + } + } else + td->td_stripoffset[strip] = + TIFFSeekFile(tif, (toff_t) 0, SEEK_END); + tif->tif_curoff = td->td_stripoffset[strip]; + } + if (!WriteOK(tif, data, cc)) { + TIFFError(module, "%s: Write error at scanline %lu", + tif->tif_name, (u_long) tif->tif_row); + return (0); + } + tif->tif_curoff += cc; + td->td_stripbytecount[strip] += cc; + return (1); +} + +/* + * Internal version of TIFFFlushData that can be + * called by ``encodestrip routines'' w/o concern + * for infinite recursion. + */ +int +TIFFFlushData1(TIFF* tif) +{ + if (tif->tif_rawcc > 0) { + if (!isFillOrder(tif, tif->tif_dir.td_fillorder) && + (tif->tif_flags & TIFF_NOBITREV) == 0) + TIFFReverseBits((u_char *)tif->tif_rawdata, + tif->tif_rawcc); + if (!TIFFAppendToStrip(tif, + isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, + tif->tif_rawdata, tif->tif_rawcc)) + return (0); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + } + return (1); +} + +/* + * Set the current write offset. This should only be + * used to set the offset to a known previous location + * (very carefully), or to 0 so that the next write gets + * appended to the end of the file. + */ +void +TIFFSetWriteOffset(TIFF* tif, toff_t off) +{ + tif->tif_curoff = off; +} diff --git a/freeimage241/Source/LibTIFF/tif_zip.c b/freeimage241/Source/LibTIFF/tif_zip.c new file mode 100644 index 0000000..d8b4d10 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tif_zip.c @@ -0,0 +1,367 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tif_zip.c,v 1.0 2001-04-13 00:42:40+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1995-1997 Sam Leffler + * Copyright (c) 1995-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "tiffiop.h" +#ifdef ZIP_SUPPORT +/* + * TIFF Library. + * + * ZIP (aka Deflate) Compression Support + * + * This file is simply an interface to the zlib library written by + * Jean-loup Gailly and Mark Adler. You must use version 1.0 or later + * of the library: this code assumes the 1.0 API and also depends on + * the ability to write the zlib header multiple times (one per strip) + * which was not possible with versions prior to 0.95. Note also that + * older versions of this codec avoided this bug by supressing the header + * entirely. This means that files written with the old library cannot + * be read; they should be converted to a different compression scheme + * and then reconverted. + * + * The data format used by the zlib library is described in the files + * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the + * directory ftp://ftp.uu.net/pub/archiving/zip/doc. The library was + * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz. + */ +#include "tif_predict.h" +#include "zlib.h" + +#include +#include + +/* + * Sigh, ZLIB_VERSION is defined as a string so there's no + * way to do a proper check here. Instead we guess based + * on the presence of #defines that were added between the + * 0.95 and 1.0 distributions. + */ +#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED) +#error "Antiquated ZLIB software; you must use version 1.0 or later" +#endif + +/* + * State block for each open TIFF + * file using ZIP compression/decompression. + */ +typedef struct { + TIFFPredictorState predict; + z_stream stream; + int zipquality; /* compression level */ + int state; /* state flags */ +#define ZSTATE_INIT 0x1 /* zlib setup successfully */ + + TIFFVGetMethod vgetparent; /* super-class method */ + TIFFVSetMethod vsetparent; /* super-class method */ +} ZIPState; + +#define ZState(tif) ((ZIPState*) (tif)->tif_data) +#define DecoderState(tif) ZState(tif) +#define EncoderState(tif) ZState(tif) + +static int ZIPEncode(TIFF*, tidata_t, tsize_t, tsample_t); +static int ZIPDecode(TIFF*, tidata_t, tsize_t, tsample_t); + +static int +ZIPSetupDecode(TIFF* tif) +{ + ZIPState* sp = DecoderState(tif); + static const char module[] = "ZIPSetupDecode"; + + assert(sp != NULL); + if (inflateInit(&sp->stream) != Z_OK) { + TIFFError(module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= ZSTATE_INIT; + return (1); + } +} + +/* + * Setup state for decoding a strip. + */ +static int +ZIPPreDecode(TIFF* tif, tsample_t s) +{ + ZIPState* sp = DecoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_in = tif->tif_rawdata; + sp->stream.avail_in = tif->tif_rawcc; + return (inflateReset(&sp->stream) == Z_OK); +} + +static int +ZIPDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) +{ + ZIPState* sp = DecoderState(tif); + static const char module[] = "ZIPDecode"; + + (void) s; + assert(sp != NULL); + sp->stream.next_out = op; + sp->stream.avail_out = occ; + do { + int state = inflate(&sp->stream, Z_PARTIAL_FLUSH); + if (state == Z_STREAM_END) + break; + if (state == Z_DATA_ERROR) { + TIFFError(module, + "%s: Decoding error at scanline %d, %s", + tif->tif_name, tif->tif_row, sp->stream.msg); + if (inflateSync(&sp->stream) != Z_OK) + return (0); + continue; + } + if (state != Z_OK) { + TIFFError(module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (sp->stream.avail_out > 0); + if (sp->stream.avail_out != 0) { + TIFFError(module, + "%s: Not enough data at scanline %d (short %d bytes)", + tif->tif_name, tif->tif_row, sp->stream.avail_out); + return (0); + } + return (1); +} + +static int +ZIPSetupEncode(TIFF* tif) +{ + ZIPState* sp = EncoderState(tif); + static const char module[] = "ZIPSetupEncode"; + + assert(sp != NULL); + if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) { + TIFFError(module, "%s: %s", tif->tif_name, sp->stream.msg); + return (0); + } else { + sp->state |= ZSTATE_INIT; + return (1); + } +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +ZIPPreEncode(TIFF* tif, tsample_t s) +{ + ZIPState *sp = EncoderState(tif); + + (void) s; + assert(sp != NULL); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + return (deflateReset(&sp->stream) == Z_OK); +} + +/* + * Encode a chunk of pixels. + */ +static int +ZIPEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) +{ + ZIPState *sp = EncoderState(tif); + static const char module[] = "ZIPEncode"; + + (void) s; + sp->stream.next_in = bp; + sp->stream.avail_in = cc; + do { + if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) { + TIFFError(module, "%s: Encoder error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + if (sp->stream.avail_out == 0) { + tif->tif_rawcc = tif->tif_rawdatasize; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + } while (sp->stream.avail_in > 0); + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +ZIPPostEncode(TIFF* tif) +{ + ZIPState *sp = EncoderState(tif); + static const char module[] = "ZIPPostEncode"; + int state; + + sp->stream.avail_in = 0; + do { + state = deflate(&sp->stream, Z_FINISH); + switch (state) { + case Z_STREAM_END: + case Z_OK: + if (sp->stream.avail_out != tif->tif_rawdatasize) { + tif->tif_rawcc = + tif->tif_rawdatasize - sp->stream.avail_out; + TIFFFlushData1(tif); + sp->stream.next_out = tif->tif_rawdata; + sp->stream.avail_out = tif->tif_rawdatasize; + } + break; + default: + TIFFError(module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } while (state != Z_STREAM_END); + return (1); +} + +static void +ZIPCleanup(TIFF* tif) +{ + ZIPState* sp = ZState(tif); + if (sp) { + if (sp->state&ZSTATE_INIT) { + /* NB: avoid problems in the library */ + if (tif->tif_mode == O_RDONLY) + inflateEnd(&sp->stream); + else + deflateEnd(&sp->stream); + } + _TIFFfree(sp); + tif->tif_data = NULL; + } +} + +static int +ZIPVSetField(TIFF* tif, ttag_t tag, va_list ap) +{ + ZIPState* sp = ZState(tif); + static const char module[] = "ZIPVSetField"; + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + sp->zipquality = va_arg(ap, int); + if (tif->tif_mode != O_RDONLY && (sp->state&ZSTATE_INIT)) { + if (deflateParams(&sp->stream, + sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) { + TIFFError(module, "%s: zlib error: %s", + tif->tif_name, sp->stream.msg); + return (0); + } + } + return (1); + default: + return (*sp->vsetparent)(tif, tag, ap); + } + /*NOTREACHED*/ +} + +static int +ZIPVGetField(TIFF* tif, ttag_t tag, va_list ap) +{ + ZIPState* sp = ZState(tif); + + switch (tag) { + case TIFFTAG_ZIPQUALITY: + *va_arg(ap, int*) = sp->zipquality; + break; + default: + return (*sp->vgetparent)(tif, tag, ap); + } + return (1); +} + +static const TIFFFieldInfo zipFieldInfo[] = { + { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO, + TRUE, FALSE, "" }, +}; +#define N(a) (sizeof (a) / sizeof (a[0])) + +int +TIFFInitZIP(TIFF* tif, int scheme) +{ + ZIPState* sp; + + assert( (scheme == COMPRESSION_DEFLATE) || (scheme == COMPRESSION_ADOBE_DEFLATE)); + + /* + * Allocate state block so tag methods have storage to record values. + */ + tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (ZIPState)); + if (tif->tif_data == NULL) + goto bad; + sp = ZState(tif); + sp->stream.zalloc = NULL; + sp->stream.zfree = NULL; + sp->stream.opaque = NULL; + sp->stream.data_type = Z_BINARY; + + /* + * Merge codec-specific tag information and + * override parent get/set field methods. + */ + _TIFFMergeFieldInfo(tif, zipFieldInfo, N(zipFieldInfo)); + sp->vgetparent = tif->tif_vgetfield; + tif->tif_vgetfield = ZIPVGetField; /* hook for codec tags */ + sp->vsetparent = tif->tif_vsetfield; + tif->tif_vsetfield = ZIPVSetField; /* hook for codec tags */ + + /* Default values for codec-specific fields */ + sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */ + sp->state = 0; + + /* + * Install codec methods. + */ + tif->tif_setupdecode = ZIPSetupDecode; + tif->tif_predecode = ZIPPreDecode; + tif->tif_decoderow = ZIPDecode; + tif->tif_decodestrip = ZIPDecode; + tif->tif_decodetile = ZIPDecode; + tif->tif_setupencode = ZIPSetupEncode; + tif->tif_preencode = ZIPPreEncode; + tif->tif_postencode = ZIPPostEncode; + tif->tif_encoderow = ZIPEncode; + tif->tif_encodestrip = ZIPEncode; + tif->tif_encodetile = ZIPEncode; + tif->tif_cleanup = ZIPCleanup; + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); + return (1); +bad: + TIFFError("TIFFInitZIP", "No space for ZIP state block"); + return (0); +} +#endif /* ZIP_SUPORT */ diff --git a/freeimage241/Source/LibTIFF/tiff.h b/freeimage241/Source/LibTIFF/tiff.h new file mode 100644 index 0000000..b822347 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tiff.h @@ -0,0 +1,441 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tiff.h,v 1.0 2001-04-13 00:42:26+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFF_ +#define _TIFF_ +/* + * Tag Image File Format (TIFF) + * + * Based on Rev 6.0 from: + * Developer's Desk + * Aldus Corporation + * 411 First Ave. South + * Suite 200 + * Seattle, WA 98104 + * 206-622-5500 + */ +#define TIFF_VERSION 42 + +#define TIFF_BIGENDIAN 0x4d4d +#define TIFF_LITTLEENDIAN 0x4949 + +#ifndef _TIFF_DATA_TYPEDEFS_ +#define _TIFF_DATA_TYPEDEFS_ +/* + * Intrinsic data types required by the file format: + * + * 8-bit quantities int8/uint8 + * 16-bit quantities int16/uint16 + * 32-bit quantities int32/uint32 + * strings unsigned char* + */ +#ifdef __STDC__ +typedef signed char int8; /* NB: non-ANSI compilers may not grok */ +#else +typedef char int8; +#endif +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; /* sizeof (uint16) must == 2 */ +#if defined(__alpha) || (defined(_MIPS_SZLONG) && _MIPS_SZLONG == 64) +typedef int int32; +typedef unsigned int uint32; /* sizeof (uint32) must == 4 */ +#else +typedef long int32; +typedef unsigned long uint32; /* sizeof (uint32) must == 4 */ +#endif +#endif /* _TIFF_DATA_TYPEDEFS_ */ + +/* For TIFFReassignTagToIgnore */ +enum TIFFIgnoreSense /* IGNORE tag table */ +{ + TIS_STORE, + TIS_EXTRACT, + TIS_EMPTY +}; + +typedef struct { + uint16 tiff_magic; /* magic number (defines byte order) */ + uint16 tiff_version; /* TIFF version number */ + uint32 tiff_diroff; /* byte offset to first directory */ +} TIFFHeader; + +/* + * TIFF Image File Directories are comprised of + * a table of field descriptors of the form shown + * below. The table is sorted in ascending order + * by tag. The values associated with each entry + * are disjoint and may appear anywhere in the file + * (so long as they are placed on a word boundary). + * + * If the value is 4 bytes or less, then it is placed + * in the offset field to save space. If the value + * is less than 4 bytes, it is left-justified in the + * offset field. + */ +typedef struct { + uint16 tdir_tag; /* see below */ + uint16 tdir_type; /* data type; see below */ + uint32 tdir_count; /* number of items; length in spec */ + uint32 tdir_offset; /* byte offset to field data */ +} TIFFDirEntry; + +/* + * NB: In the comments below, + * - items marked with a + are obsoleted by revision 5.0, + * - items marked with a ! are introduced in revision 6.0. + * - items marked with a % are introduced post revision 6.0. + * - items marked with a $ are obsoleted by revision 6.0. + */ + +/* + * Tag data type information. + * + * Note: RATIONALs are the ratio of two 32-bit integer values. + */ +typedef enum { + TIFF_NOTYPE = 0, /* placeholder */ + TIFF_BYTE = 1, /* 8-bit unsigned integer */ + TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */ + TIFF_SHORT = 3, /* 16-bit unsigned integer */ + TIFF_LONG = 4, /* 32-bit unsigned integer */ + TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */ + TIFF_SBYTE = 6, /* !8-bit signed integer */ + TIFF_UNDEFINED = 7, /* !8-bit untyped data */ + TIFF_SSHORT = 8, /* !16-bit signed integer */ + TIFF_SLONG = 9, /* !32-bit signed integer */ + TIFF_SRATIONAL = 10, /* !64-bit signed fraction */ + TIFF_FLOAT = 11, /* !32-bit IEEE floating point */ + TIFF_DOUBLE = 12 /* !64-bit IEEE floating point */ +} TIFFDataType; + +/* + * TIFF Tag Definitions. + */ +#define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */ +#define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */ +#define FILETYPE_PAGE 0x2 /* one page of many */ +#define FILETYPE_MASK 0x4 /* transparency mask */ +#define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */ +#define OFILETYPE_IMAGE 1 /* full resolution image data */ +#define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */ +#define OFILETYPE_PAGE 3 /* one page of many */ +#define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */ +#define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */ +#define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */ +#define TIFFTAG_COMPRESSION 259 /* data compression technique */ +#define COMPRESSION_NONE 1 /* dump mode */ +#define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */ +#define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */ +#define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */ +#define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */ +#define COMPRESSION_OJPEG 6 /* !6.0 JPEG */ +#define COMPRESSION_JPEG 7 /* %JPEG DCT compression */ +#define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */ +#define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */ +#define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */ +#define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */ +/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT */ +#define COMPRESSION_DCS 32947 /* Kodak DCS encoding */ +#define COMPRESSION_JBIG 34661 /* ISO JBIG */ +#define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */ +#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */ +#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */ +#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */ +#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */ +#define PHOTOMETRIC_RGB 2 /* RGB color model */ +#define PHOTOMETRIC_PALETTE 3 /* color map indexed */ +#define PHOTOMETRIC_MASK 4 /* $holdout mask */ +#define PHOTOMETRIC_SEPARATED 5 /* !color separations */ +#define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */ +#define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */ +#define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */ +#define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */ +#define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */ +#define THRESHHOLD_BILEVEL 1 /* b&w art scan */ +#define THRESHHOLD_HALFTONE 2 /* or dithered scan */ +#define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */ +#define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */ +#define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */ +#define TIFFTAG_FILLORDER 266 /* data order within a byte */ +#define FILLORDER_MSB2LSB 1 /* most significant -> least */ +#define FILLORDER_LSB2MSB 2 /* least significant -> most */ +#define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */ +#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +#define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +#define TIFFTAG_MODEL 272 /* scanner model name/number */ +#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +#define TIFFTAG_ORIENTATION 274 /* +image orientation */ +#define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */ +#define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */ +#define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */ +#define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */ +#define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */ +#define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */ +#define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */ +#define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */ +#define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */ +#define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */ +#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +#define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */ +#define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */ +#define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */ +#define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */ +#define TIFFTAG_PLANARCONFIG 284 /* storage organization */ +#define PLANARCONFIG_CONTIG 1 /* single image plane */ +#define PLANARCONFIG_SEPARATE 2 /* separate planes of data */ +#define TIFFTAG_PAGENAME 285 /* page name image is from */ +#define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */ +#define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */ +#define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */ +#define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */ +#define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */ +#define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */ +#define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */ +#define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */ +#define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */ +#define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */ +#define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */ +#define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */ +#define RESUNIT_NONE 1 /* no meaningful units */ +#define RESUNIT_INCH 2 /* english */ +#define RESUNIT_CENTIMETER 3 /* metric */ +#define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */ +#define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */ +#define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */ +#define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */ +#define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */ +#define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */ +#define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */ +#define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */ +#define TIFFTAG_SOFTWARE 305 /* name & release */ +#define TIFFTAG_DATETIME 306 /* creation date and time */ +#define TIFFTAG_ARTIST 315 /* creator of image */ +#define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */ +#define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */ +#define TIFFTAG_WHITEPOINT 318 /* image white point */ +#define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */ +#define TIFFTAG_COLORMAP 320 /* RGB map for pallette image */ +#define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */ +#define TIFFTAG_TILEWIDTH 322 /* !rows/data tile */ +#define TIFFTAG_TILELENGTH 323 /* !cols/data tile */ +#define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */ +#define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */ +#define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */ +#define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */ +#define CLEANFAXDATA_CLEAN 0 /* no errors detected */ +#define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */ +#define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */ +#define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */ +#define TIFFTAG_SUBIFD 330 /* subimage descriptors */ +#define TIFFTAG_INKSET 332 /* !inks in separated image */ +#define INKSET_CMYK 1 /* !cyan-magenta-yellow-black */ +#define TIFFTAG_INKNAMES 333 /* !ascii names of inks */ +#define TIFFTAG_NUMBEROFINKS 334 /* !number of inks */ +#define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */ +#define TIFFTAG_TARGETPRINTER 337 /* !separation target */ +#define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */ +#define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */ +#define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */ +#define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */ +#define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */ +#define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */ +#define SAMPLEFORMAT_INT 2 /* !signed integer data */ +#define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */ +#define SAMPLEFORMAT_VOID 4 /* !untyped data */ +#define SAMPLEFORMAT_COMPLEXINT 5 /* !complex signed int */ +#define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !complex ieee floating */ +#define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */ +#define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */ +#define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */ +/* + * Tags 512-521 are obsoleted by Technical Note #2 + * which specifies a revised JPEG-in-TIFF scheme. + */ +#define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */ +#define JPEGPROC_BASELINE 1 /* !baseline sequential */ +#define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */ +#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ +#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ +#define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */ +#define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */ +#define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */ +#define TIFFTAG_JPEGQTABLES 519 /* !Q matrice offsets */ +#define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */ +#define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */ +#define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */ +#define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */ +#define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */ +#define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */ +#define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */ +#define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */ +/* tags 32952-32956 are private tags registered to Island Graphics */ +#define TIFFTAG_REFPTS 32953 /* image reference points */ +#define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */ +#define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */ +#define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */ +/* tags 32995-32999 are private tags registered to SGI */ +#define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */ +#define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */ +#define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */ +#define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */ +/* tags 33300-33309 are private tags registered to Pixar */ +/* + * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH + * are set when an image has been cropped out of a larger image. + * They reflect the size of the original uncropped image. + * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used + * to determine the position of the smaller image in the larger one. + */ +#define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */ +#define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */ + /* Tags 33302-33306 are used to identify special image modes and data + * used by Pixar's texture formats. + */ +#define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */ +#define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */ +#define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */ +#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305 +#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306 +/* tag 33405 is a private tag registered to Eastman Kodak */ +#define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */ +/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */ +#define TIFFTAG_COPYRIGHT 33432 /* copyright string */ +/* IPTC TAG from RichTIFF specifications */ +#define TIFFTAG_RICHTIFFIPTC 33723 +/* 34016-34029 are reserved for ANSI IT8 TIFF/IT */ +#define TIFFTAG_STONITS 37439 /* Sample value to Nits */ +/* tag 34929 is a private tag registered to FedEx */ +#define TIFFTAG_FEDEX_EDR 34929 /* unknown use */ +/* tag 65535 is an undefined tag used by Eastman Kodak */ +#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */ + +/* + * The following are ``pseudo tags'' that can be + * used to control codec-specific functionality. + * These tags are not written to file. Note that + * these values start at 0xffff+1 so that they'll + * never collide with Aldus-assigned tags. + * + * If you want your private pseudo tags ``registered'' + * (i.e. added to this file), send mail to sam@sgi.com + * with the appropriate C definitions to add. + */ +#define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */ +#define FAXMODE_CLASSIC 0x0000 /* default, include RTC */ +#define FAXMODE_NORTC 0x0001 /* no RTC at end of data */ +#define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */ +#define FAXMODE_BYTEALIGN 0x0004 /* byte align row */ +#define FAXMODE_WORDALIGN 0x0008 /* word align row */ +#define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */ +#define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */ +/* Note: quality level is on the IJG 0-100 scale. Default value is 75 */ +#define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */ +#define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */ +#define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */ +#define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */ +#define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */ +#define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */ +/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */ +#define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */ +#define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */ +#define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */ +#define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */ +#define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */ +#define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */ +#define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */ +#define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */ +/* 65550-65556 are allocated to Oceana Matrix */ +#define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */ +#define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */ +#define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */ +#define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */ +#define DCSIMAGERFILTER_IR 0 /* infrared filter */ +#define DCSIMAGERFILTER_MONO 1 /* monochrome filter */ +#define DCSIMAGERFILTER_CFA 2 /* color filter array */ +#define DCSIMAGERFILTER_OTHER 3 /* other filter */ +#define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */ +#define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */ +#define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */ +#define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */ +#define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */ +#define TIFFTAG_DCSGAMMA 65554 /* gamma value */ +#define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */ +#define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */ +/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */ +#define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */ +#define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */ +/* 65559 is allocated to Oceana Matrix */ +#define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */ +#define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */ +#define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */ +#define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */ +#define SGILOGDATAFMT_RAW 2 /* uninterpreted data */ +#define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */ +#endif /* _TIFF_ */ diff --git a/freeimage241/Source/LibTIFF/tiffcomp.h b/freeimage241/Source/LibTIFF/tiffcomp.h new file mode 100644 index 0000000..5ad8264 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tiffcomp.h @@ -0,0 +1,214 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tiffcomp.h,v 1.0 2001-04-13 00:42:26+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1990-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _COMPAT_ +#define _COMPAT_ +/* + * This file contains a hodgepodge of definitions and + * declarations that are needed to provide compatibility + * between the native system and the base implementation + * that the library assumes. + * + * NB: This file is a mess. + */ + +/* + * Setup basic type definitions and function declaratations. + */ + +/* + * Simplify Acorn RISC OS identifier (to avoid confusion with Acorn RISC iX + * and with defunct Unix Risc OS) + * No need to specify __arm - hey, Acorn might port the OS, no problem here! + */ +#ifdef __acornriscos +#undef __acornriscos +#endif +#if defined(__acorn) && defined(__riscos) +#define __acornriscos +#endif + +#if defined(__MWERKS__) || defined(THINK_C) +#include +#include +#endif + +#include + +#if defined(__PPCC__) || defined(__SC__) || defined(__MRC__) +#include +#elif !defined(__MWERKS__) && !defined(THINK_C) && !defined(__acornriscos) && !defined(applec) +#include +#endif + +#if defined(VMS) +#include +#include +#elif !defined(__acornriscos) +#include +#endif + +/* + * This maze of checks controls defines or not the + * target system has BSD-style typdedefs declared in + * an include file and/or whether or not to include + * to get the SEEK_* definitions. Some + * additional includes are also done to pull in the + * appropriate definitions we're looking for. + */ +#if defined(__MWERKS__) || defined(THINK_C) || defined(__PPCC__) || defined(__SC__) || defined(__MRC__) +#include +#define BSDTYPES +#define HAVE_UNISTD_H 0 +#elif (defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) || defined(_WIN32)) && !defined(unix) +#define BSDTYPES +#elif defined(OS2_16) || defined(OS2_32) +#define BSDTYPES +#elif defined(__acornriscos) +#include +#define BSDTYPES +#define HAVE_UNISTD_H 0 +#elif defined(VMS) +#define HAVE_UNISTD_H 0 +#else +#define HAVE_UNISTD_H 1 +#endif + +/* + * The library uses the ANSI C/POSIX SEEK_* + * definitions that should be defined in unistd.h + * (except on system where they are in stdio.h and + * there is no unistd.h). + */ +#if !defined(SEEK_SET) && HAVE_UNISTD_H +#include +#endif + +/* + * The library uses memset, memcpy, and memcmp. + * ANSI C and System V define these in string.h. + */ +#include + +/* + * The BSD typedefs are used throughout the library. + * If your system doesn't have them in , + * then define BSDTYPES in your Makefile. + */ +#if defined(BSDTYPES) +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; +#endif + +/* + * dblparam_t is the type that a double precision + * floating point value will have on the parameter + * stack (when coerced by the compiler). + */ +/* Note: on MacPowerPC "extended" is undefined. So only use it for 68K-Macs */ +#if defined(__SC__) || defined(THINK_C) +typedef extended dblparam_t; +#else +typedef double dblparam_t; +#endif + +/* + * If your compiler supports inline functions, then + * set INLINE appropriately to get the known hotspots + * in the library expanded inline. + */ +#if defined(__GNUC__) +#if defined(__STRICT_ANSI__) +#define INLINE __inline__ +#else +#define INLINE inline +#endif +#else /* !__GNUC__ */ +#define INLINE +#endif + +/* + * GLOBALDATA is a macro that is used to define global variables + * private to the library. We use this indirection to hide + * brain-damage in VAXC (and GCC) under VAX/VMS. In these + * environments the macro places the variable in a non-shareable + * program section, which ought to be done by default (sigh!) + * + * Apparently DEC are aware of the problem as this behaviour is the + * default under VMS on AXP. + * + * The GNU C variant is untested. + */ +#if defined(VAX) && defined(VMS) +#if defined(VAXC) +#define GLOBALDATA(TYPE,NAME) extern noshare TYPE NAME +#endif +#if defined(__GNUC__) +#define GLOBALDATA(TYPE,NAME) extern TYPE NAME \ + asm("_$$PsectAttributes_NOSHR$$" #NAME) +#endif +#else /* !VAX/VMS */ +#define GLOBALDATA(TYPE,NAME) extern TYPE NAME +#endif + +#if defined(__acornriscos) +/* + * osfcn.h is part of C++Lib on Acorn C/C++, and as such can't be used + * on C alone. For that reason, the relevant functions are + * implemented in tif_acorn.c, and the elements from the header + * file are included here. + */ +#if defined(__cplusplus) +#include +#else +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_APPEND 8 +#define O_CREAT 0x200 +#define O_TRUNC 0x400 +typedef long off_t; +extern int open(const char *name, int flags, int mode); +extern int close(int fd); +extern int write(int fd, const char *buf, int nbytes); +extern int read(int fd, char *buf, int nbytes); +extern off_t lseek(int fd, off_t offset, int whence); +extern int creat(const char *path, int mode); +#endif /* __cplusplus */ +#endif /* __acornriscos */ + +/* Bit and byte order, the default is MSB to LSB */ +#ifdef VMS +#undef HOST_FILLORDER +#undef HOST_BIGENDIAN +#define HOST_FILLORDER FILLORDER_LSB2MSB +#define HOST_BIGENDIAN 0 +#endif + + +#endif /* _COMPAT_ */ diff --git a/freeimage241/Source/LibTIFF/tiffconf.h b/freeimage241/Source/LibTIFF/tiffconf.h new file mode 100644 index 0000000..65cbbcd --- /dev/null +++ b/freeimage241/Source/LibTIFF/tiffconf.h @@ -0,0 +1,143 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tiffconf.h,v 1.0 2001-04-13 00:42:26+02 floris_van_den_berg Exp floris_van_den_berg $ */ +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFCONF_ +#define _TIFFCONF_ +/* + * Library Configuration Definitions. + * + * This file defines the default configuration for the library. + * If the target system does not have make or a way to specify + * #defines on the command line, this file can be edited to + * configure the library. Otherwise, one can override portability + * and configuration-related definitions from a Makefile or command + * line by defining FEATURE_SUPPORT and COMPRESSION_SUPPORT (see below). + */ + +/* + * General portability-related defines: + * + * HAVE_IEEEFP define as 0 or 1 according to the floating point + * format suported by the machine + * BSDTYPES define this if your system does NOT define the + * usual 4BSD typedefs u_int et. al. + * HAVE_MMAP enable support for memory mapping read-only files; + * this is typically deduced by the configure script + * HOST_FILLORDER native cpu bit order: one of FILLORDER_MSB2LSB + * or FILLODER_LSB2MSB; this is typically set by the + * configure script + * HOST_BIGENDIAN native cpu byte order: 1 if big-endian (Motorola) + * or 0 if little-endian (Intel); this may be used + * in codecs to optimize code + * USE_64BIT_API set to 1 if tif_unix.c should use lseek64(), + * fstat64() and stat64 allowing 2-4GB files. + */ +#ifndef HAVE_IEEEFP +#define HAVE_IEEEFP 1 +#endif +#ifndef HOST_FILLORDER +#define HOST_FILLORDER FILLORDER_MSB2LSB +#endif +#ifndef HOST_BIGENDIAN +#define HOST_BIGENDIAN 1 +#endif + +#ifndef USE_64BIT_API +# define USE_64BIT_API 0 +#endif + +#ifndef FEATURE_SUPPORT +/* + * Feature support definitions: + * + * COLORIMETRY_SUPPORT enable support for 6.0 colorimetry tags + * YCBCR_SUPPORT enable support for 6.0 YCbCr tags + * CMYK_SUPPORT enable support for 6.0 CMYK tags + * ICC_SUPPORT enable support for ICC profile tag + * PHOTOSHOP_SUPPORT enable support for PHOTOSHOP resource tag + * IPTC_SUPPORT enable support for RichTIFF IPTC tag + */ +#define COLORIMETRY_SUPPORT +#define YCBCR_SUPPORT +#define CMYK_SUPPORT +#define ICC_SUPPORT +#define PHOTOSHOP_SUPPORT +#define IPTC_SUPPORT +#endif /* FEATURE_SUPPORT */ + +#ifndef COMPRESSION_SUPPORT +/* + * Compression support defines: + * + * CCITT_SUPPORT enable support for CCITT Group 3 & 4 algorithms + * PACKBITS_SUPPORT enable support for Macintosh PackBits algorithm + * LZW_SUPPORT enable support for LZW algorithm + * THUNDER_SUPPORT enable support for ThunderScan 4-bit RLE algorithm + * NEXT_SUPPORT enable support for NeXT 2-bit RLE algorithm + * OJPEG_SUPPORT enable support for 6.0-style JPEG DCT algorithms + * (no builtin support, only a codec hook) + * JPEG_SUPPORT enable support for post-6.0-style JPEG DCT algorithms + * (requires freely available IJG software, see tif_jpeg.c) + * ZIP_SUPPORT enable support for Deflate algorithm + * (requires freely available zlib software, see tif_zip.c) + * PIXARLOG_SUPPORT enable support for Pixar log-format algorithm + * LOGLUV_SUPPORT enable support for LogLuv high dynamic range encoding + */ +#define CCITT_SUPPORT +#define PACKBITS_SUPPORT +#define LZW_SUPPORT +#define THUNDER_SUPPORT +#define NEXT_SUPPORT +#define LOGLUV_SUPPORT +#endif /* COMPRESSION_SUPPORT */ + +/* + * If JPEG compression is enabled then we must also include + * support for the colorimetry and YCbCr-related tags. + */ +#ifdef JPEG_SUPPORT +#ifndef YCBCR_SUPPORT +#define YCBCR_SUPPORT +#endif +#ifndef COLORIMETRY_SUPPORT +#define COLORIMETRY_SUPPORT +#endif +#endif /* JPEG_SUPPORT */ + +/* + * ``Orthogonal Features'' + * + * STRIPCHOP_DEFAULT default handling of strip chopping support (whether + * or not to convert single-strip uncompressed images + * to mutiple strips of ~8Kb--to reduce memory use) + * SUBIFD_SUPPORT enable support for SubIFD tag (thumbnails and such) + */ +#ifndef STRIPCHOP_DEFAULT +#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP /* default is to enable */ +#endif +#ifndef SUBIFD_SUPPORT +#define SUBIFD_SUPPORT 1 /* enable SubIFD tag (330) support */ +#endif +#endif /* _TIFFCONF_ */ diff --git a/freeimage241/Source/LibTIFF/tiffio.h b/freeimage241/Source/LibTIFF/tiffio.h new file mode 100644 index 0000000..c4de583 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tiffio.h @@ -0,0 +1,334 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tiffio.h,v 1.0 2001-04-13 00:42:27+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIO_ +#define _TIFFIO_ + +/* + * TIFF I/O Library Definitions. + */ +#include "tiff.h" +//#include "tiffvers.h" + +/* + * TIFF is defined as an incomplete type to hide the + * library's internal data structures from clients. + */ +typedef struct tiff TIFF; + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is int32 and not uint32 because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets being the most important, and to ensure + * that it is unsigned, rather than signed. + */ +typedef uint32 ttag_t; /* directory tag */ +typedef uint16 tdir_t; /* directory index */ +typedef uint16 tsample_t; /* sample number */ +typedef uint32 tstrip_t; /* strip number */ +typedef uint32 ttile_t; /* tile number */ +typedef int32 tsize_t; /* i/o size in bytes */ +typedef void* tdata_t; /* image data ref */ +typedef uint32 toff_t; /* file offset */ + +#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32)) +#define __WIN32__ +#endif + +/* + * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c + * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). + * + * By default tif_win32.c is assumed on windows if not using the cygwin + * environment. + */ + +#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) +# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILIO) +# define USE_WIN32_FILEIO +# endif +#endif + +#if defined(USE_WIN32_FILEIO) +#include +#ifdef __WIN32__ +DECLARE_HANDLE(thandle_t); /* Win32 file handle */ +#else +typedef HFILE thandle_t; /* client data handle */ +#endif +#else +typedef void* thandle_t; /* client data handle */ +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* + * Flags to pass to TIFFPrintDirectory to control + * printing of data structures that are potentially + * very large. Bit-or these flags to enable printing + * multiple items. + */ +#define TIFFPRINT_NONE 0x0 /* no extra info */ +#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */ +#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */ +#define TIFFPRINT_COLORMAP 0x4 /* colormap */ +#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */ +#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */ +#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */ + +/* + * RGBA-style image support. + */ +typedef unsigned char TIFFRGBValue; /* 8-bit samples */ +typedef struct _TIFFRGBAImage TIFFRGBAImage; +/* + * The image reading and conversion routines invoke + * ``put routines'' to copy/image/whatever tiles of + * raw image data. A default set of routines are + * provided to convert/copy raw image data to 8-bit + * packed ABGR format rasters. Applications can supply + * alternate routines that unpack the data into a + * different format or, for example, unpack the data + * and draw the unpacked raster on the display. + */ +typedef void (*tileContigRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*); +typedef void (*tileSeparateRoutine) + (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, + unsigned char*, unsigned char*, unsigned char*, unsigned char*); +/* + * RGBA-reader state. + */ +typedef struct { /* YCbCr->RGB support */ + TIFFRGBValue* clamptab; /* range clamping table */ + int* Cr_r_tab; + int* Cb_b_tab; + int32* Cr_g_tab; + int32* Cb_g_tab; + float coeffs[3]; /* cached for repeated use */ +} TIFFYCbCrToRGB; + +struct _TIFFRGBAImage { + TIFF* tif; /* image handle */ + int stoponerr; /* stop on read error */ + int isContig; /* data is packed/separate */ + int alpha; /* type of alpha data present */ + uint32 width; /* image width */ + uint32 height; /* image height */ + uint16 bitspersample; /* image bits/sample */ + uint16 samplesperpixel; /* image samples/pixel */ + uint16 orientation; /* image orientation */ + uint16 photometric; /* image photometric interp */ + uint16* redcmap; /* colormap pallete */ + uint16* greencmap; + uint16* bluecmap; + /* get image data routine */ + int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32); + union { + void (*any)(TIFFRGBAImage*); + tileContigRoutine contig; + tileSeparateRoutine separate; + } put; /* put decoded strip/tile */ + TIFFRGBValue* Map; /* sample mapping array */ + uint32** BWmap; /* black&white map */ + uint32** PALmap; /* palette image map */ + TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */ + + int row_offset; + int col_offset; +}; + +/* + * Macros for extracting components from the + * packed ABGR form returned by TIFFReadRGBAImage. + */ +#define TIFFGetR(abgr) ((abgr) & 0xff) +#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff) +#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff) +#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff) + +/* + * A CODEC is a software package that implements decoding, + * encoding, or decoding+encoding of a compression algorithm. + * The library provides a collection of builtin codecs. + * More codecs may be registered through calls to the library + * and/or the builtin implementations may be overridden. + */ +typedef int (*TIFFInitMethod)(TIFF*, int); +typedef struct { + char* name; + uint16 scheme; + TIFFInitMethod init; +} TIFFCodec; + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif +typedef void (*TIFFErrorHandler)(const char*, const char*, va_list); +typedef tsize_t (*TIFFReadWriteProc)(thandle_t, tdata_t, tsize_t); +typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int); +typedef int (*TIFFCloseProc)(thandle_t); +typedef toff_t (*TIFFSizeProc)(thandle_t); +typedef int (*TIFFMapFileProc)(thandle_t, tdata_t*, toff_t*); +typedef void (*TIFFUnmapFileProc)(thandle_t, tdata_t, toff_t); +typedef void (*TIFFExtendProc)(TIFF*); + +extern const char* TIFFGetVersion(void); + +extern const TIFFCodec* TIFFFindCODEC(uint16); +extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod); +extern void TIFFUnRegisterCODEC(TIFFCodec*); + +extern tdata_t _TIFFmalloc(tsize_t); +extern tdata_t _TIFFrealloc(tdata_t, tsize_t); +extern void _TIFFmemset(tdata_t, int, tsize_t); +extern void _TIFFmemcpy(tdata_t, const tdata_t, tsize_t); +extern int _TIFFmemcmp(const tdata_t, const tdata_t, tsize_t); +extern void _TIFFfree(tdata_t); + +extern void TIFFClose(TIFF*); +extern int TIFFFlush(TIFF*); +extern int TIFFFlushData(TIFF*); +extern int TIFFGetField(TIFF*, ttag_t, ...); +extern int TIFFVGetField(TIFF*, ttag_t, va_list); +extern int TIFFGetFieldDefaulted(TIFF*, ttag_t, ...); +extern int TIFFVGetFieldDefaulted(TIFF*, ttag_t, va_list); +extern int TIFFReadDirectory(TIFF*); +extern tsize_t TIFFScanlineSize(TIFF*); +extern tsize_t TIFFRasterScanlineSize(TIFF*); +extern tsize_t TIFFStripSize(TIFF*); +extern tsize_t TIFFVStripSize(TIFF*, uint32); +extern tsize_t TIFFTileRowSize(TIFF*); +extern tsize_t TIFFTileSize(TIFF*); +extern tsize_t TIFFVTileSize(TIFF*, uint32); +extern uint32 TIFFDefaultStripSize(TIFF*, uint32); +extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*); +extern int TIFFFileno(TIFF*); +extern int TIFFGetMode(TIFF*); +extern int TIFFIsTiled(TIFF*); +extern int TIFFIsByteSwapped(TIFF*); +extern int TIFFIsUpSampled(TIFF*); +extern int TIFFIsMSB2LSB(TIFF*); +extern uint32 TIFFCurrentRow(TIFF*); +extern tdir_t TIFFCurrentDirectory(TIFF*); +extern tdir_t TIFFNumberOfDirectories(TIFF*); +extern uint32 TIFFCurrentDirOffset(TIFF*); +extern tstrip_t TIFFCurrentStrip(TIFF*); +extern ttile_t TIFFCurrentTile(TIFF*); +extern int TIFFReadBufferSetup(TIFF*, tdata_t, tsize_t); +extern int TIFFWriteBufferSetup(TIFF*, tdata_t, tsize_t); +extern int TIFFWriteCheck(TIFF*, int, const char *); +extern int TIFFCreateDirectory(TIFF*); +extern int TIFFLastDirectory(TIFF*); +extern int TIFFSetDirectory(TIFF*, tdir_t); +extern int TIFFSetSubDirectory(TIFF*, uint32); +extern int TIFFUnlinkDirectory(TIFF*, tdir_t); +extern int TIFFSetField(TIFF*, ttag_t, ...); +extern int TIFFVSetField(TIFF*, ttag_t, va_list); +extern int TIFFWriteDirectory(TIFF *); +extern int TIFFReassignTagToIgnore(enum TIFFIgnoreSense, int); + +#if defined(c_plusplus) || defined(__cplusplus) +extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0); +extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t = 0); +extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t = 0); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0); +#else +extern void TIFFPrintDirectory(TIFF*, FILE*, long); +extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t); +extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t); +extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int); +#endif + +extern int TIFFReadRGBAStrip(TIFF*, tstrip_t, uint32 * ); +extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * ); +extern int TIFFRGBAImageOK(TIFF*, char [1024]); +extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]); +extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32); +extern void TIFFRGBAImageEnd(TIFFRGBAImage*); +extern TIFF* TIFFOpen(const char*, const char*); +extern TIFF* TIFFFdOpen(int, const char*, const char*); +extern TIFF* TIFFClientOpen(const char*, const char*, + thandle_t, + TIFFReadWriteProc, TIFFReadWriteProc, + TIFFSeekProc, TIFFCloseProc, + TIFFSizeProc, + TIFFMapFileProc, TIFFUnmapFileProc); +extern const char* TIFFFileName(TIFF*); +extern void TIFFError(const char*, const char*, ...); +extern void TIFFWarning(const char*, const char*, ...); +extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler); +extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler); +extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc); +extern ttile_t TIFFComputeTile(TIFF*, uint32, uint32, uint32, tsample_t); +extern int TIFFCheckTile(TIFF*, uint32, uint32, uint32, tsample_t); +extern ttile_t TIFFNumberOfTiles(TIFF*); +extern tsize_t TIFFReadTile(TIFF*, + tdata_t, uint32, uint32, uint32, tsample_t); +extern tsize_t TIFFWriteTile(TIFF*, + tdata_t, uint32, uint32, uint32, tsample_t); +extern tstrip_t TIFFComputeStrip(TIFF*, uint32, tsample_t); +extern tstrip_t TIFFNumberOfStrips(TIFF*); +extern tsize_t TIFFReadEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFReadRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFReadEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFReadRawTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern tsize_t TIFFWriteRawTile(TIFF*, ttile_t, tdata_t, tsize_t); +extern void TIFFSetWriteOffset(TIFF*, toff_t); +extern void TIFFSwabShort(uint16*); +extern void TIFFSwabLong(uint32*); +extern void TIFFSwabDouble(double*); +extern void TIFFSwabArrayOfShort(uint16*, unsigned long); +extern void TIFFSwabArrayOfLong(uint32*, unsigned long); +extern void TIFFSwabArrayOfDouble(double*, unsigned long); +extern void TIFFReverseBits(unsigned char *, unsigned long); +extern const unsigned char* TIFFGetBitRevTable(int); +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFIO_ */ diff --git a/freeimage241/Source/LibTIFF/tiffiop.h b/freeimage241/Source/LibTIFF/tiffiop.h new file mode 100644 index 0000000..788b853 --- /dev/null +++ b/freeimage241/Source/LibTIFF/tiffiop.h @@ -0,0 +1,279 @@ +/* $Header: C:\\RCS\\D\\FreeImage\\Source\\LibTIFF\\tiffiop.h,v 1.0 2001-04-13 00:42:27+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* + * Copyright (c) 1988-1997 Sam Leffler + * Copyright (c) 1991-1997 Silicon Graphics, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that (i) the above copyright notices and this permission notice appear in + * all copies of the software and related documentation, and (ii) the names of + * Sam Leffler and Silicon Graphics may not be used in any advertising or + * publicity relating to the software without the specific, prior written + * permission of Sam Leffler and Silicon Graphics. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR + * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, + * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _TIFFIOP_ +#define _TIFFIOP_ +/* + * ``Library-private'' definitions. + */ +/* + * UNIX systems should run the configure script to generate + * a port.h file that reflects the system capabilities. + * Doing this obviates all the dreck done in tiffcomp.h. + */ +#if defined(unix) || defined(__unix) +#include "port.h" +#include "tiffconf.h" +#else +#include "tiffconf.h" +#include "tiffcomp.h" +#endif +#include "tiffio.h" +#include "tif_dir.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* + * Typedefs for ``method pointers'' used internally. + */ +typedef unsigned char tidataval_t; /* internal image data value type */ +typedef tidataval_t* tidata_t; /* reference to internal image data */ + +typedef void (*TIFFVoidMethod)(TIFF*); +typedef int (*TIFFBoolMethod)(TIFF*); +typedef int (*TIFFPreMethod)(TIFF*, tsample_t); +typedef int (*TIFFCodeMethod)(TIFF*, tidata_t, tsize_t, tsample_t); +typedef int (*TIFFSeekMethod)(TIFF*, uint32); +typedef void (*TIFFPostMethod)(TIFF*, tidata_t, tsize_t); +typedef int (*TIFFVSetMethod)(TIFF*, ttag_t, va_list); +typedef int (*TIFFVGetMethod)(TIFF*, ttag_t, va_list); +typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long); +typedef uint32 (*TIFFStripMethod)(TIFF*, uint32); +typedef void (*TIFFTileMethod)(TIFF*, uint32*, uint32*); + +struct tiff { + char* tif_name; /* name of open file */ + int tif_fd; /* open file descriptor */ + int tif_mode; /* open mode (O_*) */ + uint32 tif_flags; +#define TIFF_FILLORDER 0x0003 /* natural bit fill order for machine */ +#define TIFF_DIRTYHEADER 0x0004 /* header must be written on close */ +#define TIFF_DIRTYDIRECT 0x0008 /* current directory must be written */ +#define TIFF_BUFFERSETUP 0x0010 /* data buffers setup */ +#define TIFF_CODERSETUP 0x0020 /* encoder/decoder setup done */ +#define TIFF_BEENWRITING 0x0040 /* written 1+ scanlines to file */ +#define TIFF_SWAB 0x0080 /* byte swap file information */ +#define TIFF_NOBITREV 0x0100 /* inhibit bit reversal logic */ +#define TIFF_MYBUFFER 0x0200 /* my raw data buffer; free on close */ +#define TIFF_ISTILED 0x0400 /* file is tile, not strip- based */ +#define TIFF_MAPPED 0x0800 /* file is mapped into memory */ +#define TIFF_POSTENCODE 0x1000 /* need call to postencode routine */ +#define TIFF_INSUBIFD 0x2000 /* currently writing a subifd */ +#define TIFF_UPSAMPLED 0x4000 /* library is doing data up-sampling */ +#define TIFF_STRIPCHOP 0x8000 /* enable strip chopping support */ + toff_t tif_diroff; /* file offset of current directory */ + toff_t tif_nextdiroff; /* file offset of following directory */ + TIFFDirectory tif_dir; /* internal rep of current directory */ + TIFFHeader tif_header; /* file's header block */ + tidata_t tif_clientdir; /* client TIFF directory */ + const int* tif_typeshift; /* data type shift counts */ + const long* tif_typemask; /* data type masks */ + uint32 tif_row; /* current scanline */ + tdir_t tif_curdir; /* current directory (index) */ + tstrip_t tif_curstrip; /* current strip for read/write */ + toff_t tif_curoff; /* current offset for read/write */ + toff_t tif_dataoff; /* current offset for writing dir */ +#if SUBIFD_SUPPORT + uint16 tif_nsubifd; /* remaining subifds to write */ + toff_t tif_subifdoff; /* offset for patching SubIFD link */ +#endif +/* tiling support */ + uint32 tif_col; /* current column (offset by row too) */ + ttile_t tif_curtile; /* current tile for read/write */ + tsize_t tif_tilesize; /* # of bytes in a tile */ +/* compression scheme hooks */ + TIFFBoolMethod tif_setupdecode;/* called once before predecode */ + TIFFPreMethod tif_predecode; /* pre- row/strip/tile decoding */ + TIFFBoolMethod tif_setupencode;/* called once before preencode */ + TIFFPreMethod tif_preencode; /* pre- row/strip/tile encoding */ + TIFFBoolMethod tif_postencode; /* post- row/strip/tile encoding */ + TIFFCodeMethod tif_decoderow; /* scanline decoding routine */ + TIFFCodeMethod tif_encoderow; /* scanline encoding routine */ + TIFFCodeMethod tif_decodestrip;/* strip decoding routine */ + TIFFCodeMethod tif_encodestrip;/* strip encoding routine */ + TIFFCodeMethod tif_decodetile; /* tile decoding routine */ + TIFFCodeMethod tif_encodetile; /* tile encoding routine */ + TIFFVoidMethod tif_close; /* cleanup-on-close routine */ + TIFFSeekMethod tif_seek; /* position within a strip routine */ + TIFFVoidMethod tif_cleanup; /* cleanup state routine */ + TIFFStripMethod tif_defstripsize;/* calculate/constrain strip size */ + TIFFTileMethod tif_deftilesize;/* calculate/constrain tile size */ + tidata_t tif_data; /* compression scheme private data */ +/* input/output buffering */ + tsize_t tif_scanlinesize;/* # of bytes in a scanline */ + tsize_t tif_scanlineskew;/* scanline skew for reading strips */ + tidata_t tif_rawdata; /* raw data buffer */ + tsize_t tif_rawdatasize;/* # of bytes in raw data buffer */ + tidata_t tif_rawcp; /* current spot in raw buffer */ + tsize_t tif_rawcc; /* bytes unread from raw buffer */ +/* memory-mapped file support */ + tidata_t tif_base; /* base of mapped file */ + toff_t tif_size; /* size of mapped file region (bytes) */ + TIFFMapFileProc tif_mapproc; /* map file method */ + TIFFUnmapFileProc tif_unmapproc;/* unmap file method */ +/* input/output callback methods */ + thandle_t tif_clientdata; /* callback parameter */ + TIFFReadWriteProc tif_readproc; /* read method */ + TIFFReadWriteProc tif_writeproc;/* write method */ + TIFFSeekProc tif_seekproc; /* lseek method */ + TIFFCloseProc tif_closeproc; /* close method */ + TIFFSizeProc tif_sizeproc; /* filesize method */ +/* post-decoding support */ + TIFFPostMethod tif_postdecode; /* post decoding routine */ +/* tag support */ + TIFFFieldInfo** tif_fieldinfo; /* sorted table of registered tags */ + int tif_nfields; /* # entries in registered tag table */ + TIFFVSetMethod tif_vsetfield; /* tag set routine */ + TIFFVGetMethod tif_vgetfield; /* tag get routine */ + TIFFPrintMethod tif_printdir; /* directory print routine */ +}; + +#define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ + +#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0) +#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0) +#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0) +#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0) +#define TIFFReadFile(tif, buf, size) \ + ((*(tif)->tif_readproc)((tif)->tif_clientdata,buf,size)) +#define TIFFWriteFile(tif, buf, size) \ + ((*(tif)->tif_writeproc)((tif)->tif_clientdata,buf,size)) +#define TIFFSeekFile(tif, off, whence) \ + ((*(tif)->tif_seekproc)((tif)->tif_clientdata,(toff_t)(off),whence)) +#define TIFFCloseFile(tif) \ + ((*(tif)->tif_closeproc)((tif)->tif_clientdata)) +#define TIFFGetFileSize(tif) \ + ((*(tif)->tif_sizeproc)((tif)->tif_clientdata)) +#define TIFFMapFileContents(tif, paddr, psize) \ + ((*(tif)->tif_mapproc)((tif)->tif_clientdata,paddr,psize)) +#define TIFFUnmapFileContents(tif, addr, size) \ + ((*(tif)->tif_unmapproc)((tif)->tif_clientdata,addr,size)) + +/* + * Default Read/Seek/Write definitions. + */ +#ifndef ReadOK +#define ReadOK(tif, buf, size) \ + (TIFFReadFile(tif, (tdata_t) buf, (tsize_t)(size)) == (tsize_t)(size)) +#endif +#ifndef SeekOK +#define SeekOK(tif, off) \ + (TIFFSeekFile(tif, (toff_t) off, SEEK_SET) == (toff_t) off) +#endif +#ifndef WriteOK +#define WriteOK(tif, buf, size) \ + (TIFFWriteFile(tif, (tdata_t) buf, (tsize_t) size) == (tsize_t) size) +#endif + +/* NB: the uint32 casts are to silence certain ANSI-C compilers */ +#define TIFFhowmany(x, y) ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) +#define TIFFroundup(x, y) (TIFFhowmany(x,y)*((uint32)(y))) + +#if defined(__cplusplus) +extern "C" { +#endif +extern int _TIFFgetMode(const char*, const char*); +extern int _TIFFNoRowEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoStripEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoTileEncode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoRowDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoStripDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern int _TIFFNoTileDecode(TIFF*, tidata_t, tsize_t, tsample_t); +extern void _TIFFNoPostDecode(TIFF*, tidata_t, tsize_t); +extern int _TIFFNoPreCode (TIFF*, tsample_t); +extern int _TIFFNoSeek(TIFF*, uint32); +extern void _TIFFSwab16BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab32BitData(TIFF*, tidata_t, tsize_t); +extern void _TIFFSwab64BitData(TIFF*, tidata_t, tsize_t); +extern int TIFFFlushData1(TIFF*); +extern void TIFFFreeDirectory(TIFF*); +extern int TIFFDefaultDirectory(TIFF*); +extern int TIFFSetCompressionScheme(TIFF*, int); +extern int TIFFSetDefaultCompressionState(TIFF*); +extern uint32 _TIFFDefaultStripSize(TIFF*, uint32); +extern void _TIFFDefaultTileSize(TIFF*, uint32*, uint32*); + +extern void _TIFFsetByteArray(void**, void*, long); +extern void _TIFFsetString(char**, char*); +extern void _TIFFsetShortArray(uint16**, uint16*, long); +extern void _TIFFsetLongArray(uint32**, uint32*, long); +extern void _TIFFsetFloatArray(float**, float*, long); +extern void _TIFFsetDoubleArray(double**, double*, long); + +extern void _TIFFprintAscii(FILE*, const char*); +extern void _TIFFprintAsciiTag(FILE*, const char*, const char*); + +GLOBALDATA(TIFFErrorHandler,_TIFFwarningHandler); +GLOBALDATA(TIFFErrorHandler,_TIFFerrorHandler); + +extern int TIFFInitDumpMode(TIFF*, int); +#ifdef PACKBITS_SUPPORT +extern int TIFFInitPackBits(TIFF*, int); +#endif +#ifdef CCITT_SUPPORT +extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int); +extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int); +#endif +#ifdef THUNDER_SUPPORT +extern int TIFFInitThunderScan(TIFF*, int); +#endif +#ifdef NEXT_SUPPORT +extern int TIFFInitNeXT(TIFF*, int); +#endif +#ifdef LZW_SUPPORT +extern int TIFFInitLZW(TIFF*, int); +#endif +#ifdef OJPEG_SUPPORT +extern int TIFFInitOJPEG(TIFF*, int); +#endif +#ifdef JPEG_SUPPORT +extern int TIFFInitJPEG(TIFF*, int); +#endif +#ifdef JBIG_SUPPORT +extern int TIFFInitJBIG(TIFF*, int); +#endif +#ifdef ZIP_SUPPORT +extern int TIFFInitZIP(TIFF*, int); +#endif +#ifdef PIXARLOG_SUPPORT +extern int TIFFInitPixarLog(TIFF*, int); +#endif +#ifdef LOGLUV_SUPPORT +extern int TIFFInitSGILog(TIFF*, int); +#endif +#ifdef VMS +extern const TIFFCodec _TIFFBuiltinCODECS[]; +#else +extern TIFFCodec _TIFFBuiltinCODECS[]; +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* _TIFFIOP_ */ diff --git a/freeimage241/Source/LibTIFF/uvcode.h b/freeimage241/Source/LibTIFF/uvcode.h new file mode 100644 index 0000000..8d96e44 --- /dev/null +++ b/freeimage241/Source/LibTIFF/uvcode.h @@ -0,0 +1,173 @@ +/* Version 1.0 generated April 7, 1997 by Greg Ward Larson, SGI */ +#define UV_SQSIZ (float)0.003500 +#define UV_NDIVS 16289 +#define UV_VSTART (float)0.016940 +#define UV_NVS 163 +static struct { + float ustart; + short nus, ncum; +} uv_row[UV_NVS] = { + (float)0.247663, 4, 0, + (float)0.243779, 6, 4, + (float)0.241684, 7, 10, + (float)0.237874, 9, 17, + (float)0.235906, 10, 26, + (float)0.232153, 12, 36, + (float)0.228352, 14, 48, + (float)0.226259, 15, 62, + (float)0.222371, 17, 77, + (float)0.220410, 18, 94, + (float)0.214710, 21, 112, + (float)0.212714, 22, 133, + (float)0.210721, 23, 155, + (float)0.204976, 26, 178, + (float)0.202986, 27, 204, + (float)0.199245, 29, 231, + (float)0.195525, 31, 260, + (float)0.193560, 32, 291, + (float)0.189878, 34, 323, + (float)0.186216, 36, 357, + (float)0.186216, 36, 393, + (float)0.182592, 38, 429, + (float)0.179003, 40, 467, + (float)0.175466, 42, 507, + (float)0.172001, 44, 549, + (float)0.172001, 44, 593, + (float)0.168612, 46, 637, + (float)0.168612, 46, 683, + (float)0.163575, 49, 729, + (float)0.158642, 52, 778, + (float)0.158642, 52, 830, + (float)0.158642, 52, 882, + (float)0.153815, 55, 934, + (float)0.153815, 55, 989, + (float)0.149097, 58, 1044, + (float)0.149097, 58, 1102, + (float)0.142746, 62, 1160, + (float)0.142746, 62, 1222, + (float)0.142746, 62, 1284, + (float)0.138270, 65, 1346, + (float)0.138270, 65, 1411, + (float)0.138270, 65, 1476, + (float)0.132166, 69, 1541, + (float)0.132166, 69, 1610, + (float)0.126204, 73, 1679, + (float)0.126204, 73, 1752, + (float)0.126204, 73, 1825, + (float)0.120381, 77, 1898, + (float)0.120381, 77, 1975, + (float)0.120381, 77, 2052, + (float)0.120381, 77, 2129, + (float)0.112962, 82, 2206, + (float)0.112962, 82, 2288, + (float)0.112962, 82, 2370, + (float)0.107450, 86, 2452, + (float)0.107450, 86, 2538, + (float)0.107450, 86, 2624, + (float)0.107450, 86, 2710, + (float)0.100343, 91, 2796, + (float)0.100343, 91, 2887, + (float)0.100343, 91, 2978, + (float)0.095126, 95, 3069, + (float)0.095126, 95, 3164, + (float)0.095126, 95, 3259, + (float)0.095126, 95, 3354, + (float)0.088276, 100, 3449, + (float)0.088276, 100, 3549, + (float)0.088276, 100, 3649, + (float)0.088276, 100, 3749, + (float)0.081523, 105, 3849, + (float)0.081523, 105, 3954, + (float)0.081523, 105, 4059, + (float)0.081523, 105, 4164, + (float)0.074861, 110, 4269, + (float)0.074861, 110, 4379, + (float)0.074861, 110, 4489, + (float)0.074861, 110, 4599, + (float)0.068290, 115, 4709, + (float)0.068290, 115, 4824, + (float)0.068290, 115, 4939, + (float)0.068290, 115, 5054, + (float)0.063573, 119, 5169, + (float)0.063573, 119, 5288, + (float)0.063573, 119, 5407, + (float)0.063573, 119, 5526, + (float)0.057219, 124, 5645, + (float)0.057219, 124, 5769, + (float)0.057219, 124, 5893, + (float)0.057219, 124, 6017, + (float)0.050985, 129, 6141, + (float)0.050985, 129, 6270, + (float)0.050985, 129, 6399, + (float)0.050985, 129, 6528, + (float)0.050985, 129, 6657, + (float)0.044859, 134, 6786, + (float)0.044859, 134, 6920, + (float)0.044859, 134, 7054, + (float)0.044859, 134, 7188, + (float)0.040571, 138, 7322, + (float)0.040571, 138, 7460, + (float)0.040571, 138, 7598, + (float)0.040571, 138, 7736, + (float)0.036339, 142, 7874, + (float)0.036339, 142, 8016, + (float)0.036339, 142, 8158, + (float)0.036339, 142, 8300, + (float)0.032139, 146, 8442, + (float)0.032139, 146, 8588, + (float)0.032139, 146, 8734, + (float)0.032139, 146, 8880, + (float)0.027947, 150, 9026, + (float)0.027947, 150, 9176, + (float)0.027947, 150, 9326, + (float)0.023739, 154, 9476, + (float)0.023739, 154, 9630, + (float)0.023739, 154, 9784, + (float)0.023739, 154, 9938, + (float)0.019504, 158, 10092, + (float)0.019504, 158, 10250, + (float)0.019504, 158, 10408, + (float)0.016976, 161, 10566, + (float)0.016976, 161, 10727, + (float)0.016976, 161, 10888, + (float)0.016976, 161, 11049, + (float)0.012639, 165, 11210, + (float)0.012639, 165, 11375, + (float)0.012639, 165, 11540, + (float)0.009991, 168, 11705, + (float)0.009991, 168, 11873, + (float)0.009991, 168, 12041, + (float)0.009016, 170, 12209, + (float)0.009016, 170, 12379, + (float)0.009016, 170, 12549, + (float)0.006217, 173, 12719, + (float)0.006217, 173, 12892, + (float)0.005097, 175, 13065, + (float)0.005097, 175, 13240, + (float)0.005097, 175, 13415, + (float)0.003909, 177, 13590, + (float)0.003909, 177, 13767, + (float)0.002340, 177, 13944, + (float)0.002389, 170, 14121, + (float)0.001068, 164, 14291, + (float)0.001653, 157, 14455, + (float)0.000717, 150, 14612, + (float)0.001614, 143, 14762, + (float)0.000270, 136, 14905, + (float)0.000484, 129, 15041, + (float)0.001103, 123, 15170, + (float)0.001242, 115, 15293, + (float)0.001188, 109, 15408, + (float)0.001011, 103, 15517, + (float)0.000709, 97, 15620, + (float)0.000301, 89, 15717, + (float)0.002416, 82, 15806, + (float)0.003251, 76, 15888, + (float)0.003246, 69, 15964, + (float)0.004141, 62, 16033, + (float)0.005963, 55, 16095, + (float)0.008839, 47, 16150, + (float)0.010490, 40, 16197, + (float)0.016994, 31, 16237, + (float)0.023659, 21, 16268, +}; diff --git a/freeimage241/Source/Plugin.h b/freeimage241/Source/Plugin.h new file mode 100644 index 0000000..43e639c --- /dev/null +++ b/freeimage241/Source/Plugin.h @@ -0,0 +1,66 @@ +// ========================================================== +// Internal plugins +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef PLUGIN_H +#define PLUGIN_H + +#ifndef FREEIMAGE_H +#include "FreeImage.h" +#endif + +// ========================================================== + +struct Plugin; + +// ========================================================== +// Plugin Initialisation Callback +// ========================================================== + +void DLL_CALLCONV FreeImage_OutputMessage(int fif, const char *message); + +// ========================================================== +// Plugin validation +// ========================================================== + +extern "C" { BOOL DLL_CALLCONV FreeImage_Validate(FREE_IMAGE_FORMAT fif, FreeImageIO &io, fi_handle handle); } + +// ========================================================== +// Internal plugins +// ========================================================== + +void DLL_CALLCONV InitBMP(Plugin &plugin, int format_id); +void DLL_CALLCONV InitICO(Plugin &plugin, int format_id); +void DLL_CALLCONV InitIFF(Plugin &plugin, int format_id); +void DLL_CALLCONV InitJPEG(Plugin &plugin, int format_id); +void DLL_CALLCONV InitKOALA(Plugin &plugin, int format_id); +void DLL_CALLCONV InitLBM(Plugin &plugin, int format_id); +void DLL_CALLCONV InitMNG(Plugin &plugin, int format_id); +void DLL_CALLCONV InitPCD(Plugin &plugin, int format_id); +void DLL_CALLCONV InitPCX(Plugin &plugin, int format_id); +void DLL_CALLCONV InitPNG(Plugin &plugin, int format_id); +void DLL_CALLCONV InitPNM(Plugin &plugin, int format_id); +void DLL_CALLCONV InitPSD(Plugin &plugin, int format_id); +void DLL_CALLCONV InitRAS(Plugin &plugin, int format_id); +void DLL_CALLCONV InitTARGA(Plugin &plugin, int format_id); +void DLL_CALLCONV InitTIFF(Plugin &plugin, int format_id); +void DLL_CALLCONV InitWBMP(Plugin &plugin, int format_id); + +#endif //!PLUGIN_H diff --git a/freeimage241/Source/Quantizers.h b/freeimage241/Source/Quantizers.h new file mode 100644 index 0000000..154f6a2 --- /dev/null +++ b/freeimage241/Source/Quantizers.h @@ -0,0 +1,90 @@ +// ============================================================= +// Quantizer objects and functions +// +// Design and implementation by: +// - Hervé Drolon +// +// This file is part of FreeImage +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ============================================================= + +// Xiaolin Wu color quantization algorithm +//////////////////////////////////////////////////////////////// + +#include "FreeImage.h" + +//////////////////////////////////////////////////////////////// + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned long uint32; +typedef long int32; + +typedef struct { + int r0; // min value, exclusive + int r1; // max value, inclusive + int g0; + int g1; + int b0; + int b1; + int vol; +} Box; + + +class WuQuantizer +{ + protected: + float *gm2; + int32 *wt, *mr, *mg, *mb; + uint16 *Qadd; + + // DIB data + uint16 width, height; + uint16 pitch; + FIBITMAP *m_dib; + + protected: + void Hist3D(int32 *vwt, int32 *vmr, int32 *vmg, int32 *vmb, float *m2) ; + void M3D(int32 *vwt, int32 *vmr, int32 *vmg, int32 *vmb, float *m2); + int32 Vol(Box *cube, int32 *mmt); + int32 Bottom(Box *cube, uint8 dir, int32 *mmt); + int32 Top(Box *cube, uint8 dir, int pos, int32 *mmt); + float Var(Box *cube); + float Maximize(Box *cube, uint8 dir, int first, int last , int *cut, + int32 whole_r, int32 whole_g, int32 whole_b, int32 whole_w); + bool Cut(Box *set1, Box *set2); + void Mark(Box *cube, int label, uint8 *tag); + + public: + // Constructor - Input parameter: DIB 24-bit to be quantized + WuQuantizer(FIBITMAP *dib); + // Destructor + ~WuQuantizer(); + // Quantizer - Return value: quantized 8-bit (color palette) DIB + FIBITMAP* Quantize(); +}; + +// NEUQUANT Neural-Net quantization algorithm by Anthony Dekker +//////////////////////////////////////////////////////////////// + +// Input parameters: +// - void* dib: DIB 24-bit to be quantized +// - int sampling: a sampling factor in range 1..30 +// 1 => slower, 30 => faster. Default value is 15 +// Return value: +// - NULL if the DIB is not valid or if it's not a 24-bit DIB +// - the quantized 8-bit (color palette) DIB otherwise + +FIBITMAP *NNQuantizer(FIBITMAP *dib, int sampling = 15); + diff --git a/freeimage241/Source/Test/Test.cpp b/freeimage241/Source/Test/Test.cpp new file mode 100644 index 0000000..99422ad --- /dev/null +++ b/freeimage241/Source/Test/Test.cpp @@ -0,0 +1,293 @@ +// ========================================================== +// FreeImage 2 Test Script +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +//#define QT +#define API + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#ifdef QT +#include +#include +#include +#include +#include +#include "FreeImageQt.h" +#endif + +#ifdef API +#include "FreeImage.h" +#endif + +// ---------------------------------------------------------- + +/* +FIBITMAP * +FreeImage_ExtractTransparency(FIBITMAP *dib) { + if (FreeImage_GetBPP(dib) == 32) { + FIBITMAP *new_dib = FreeImage_Allocate(FreeImage_GetWidth(dib), FreeImage_GetHeight(dib), 8); + + // make a grayscale palette + + RGBQUAD *quad = FreeImage_GetPalette(new_dib); + + for (int i = 0; i < 256; ++i) { + quad[i].rgbRed = + quad[i].rgbGreen = + quad[i].rgbBlue = i; + } + + // copy the alpha channel + + for (unsigned y = 0; y < FreeImage_GetHeight(dib); ++y) { + BYTE *t = FreeImage_GetScanLine(new_dib, y); + RGBQUAD *s = (RGBQUAD *)FreeImage_GetScanLine(dib, y); + + for (unsigned x = 0; x < FreeImage_GetWidth(dib); ++x) { + t[x] = s[x].rgbReserved; + } + } + + return new_dib; + } + + return NULL; +} +*/ + +// ---------------------------------------------------------- + +struct Extensions { + char *ext; + void *function; +}; + +static Extensions s_extensions[] = { + "bmp", FreeImage_SaveBMP, + "jpg", FreeImage_SaveJPEG, + "png", FreeImage_SavePNG, + "pnm", FreeImage_SavePNM, + "tif", FreeImage_SaveTIFF, + "wbmp", FreeImage_SaveWBMP, +}; + +// ---------------------------------------------------------- + +#ifdef API +int __cdecl +TestAPI(int argc, char *argv[]) { + FreeImage_Initialise(); + + FIBITMAP *dib = NULL; + int id = 1; + + printf(FreeImage_GetVersion()); + printf(FreeImage_GetCopyrightMessage()); + + // open the log file + + FILE *log_file = fopen("log_file.txt", "w"); + + // batch convert all supported bitmaps + + _finddata_t finddata; + + long handle; + + if ((handle = _findfirst("c:\\projects\\test images\\*.bmp", &finddata)) != -1) { + do { + dib = NULL; + + // grab the extension + + char ext[4]; + ext[3] = 0; + strncpy(ext, finddata.name + strlen(finddata.name) - 3, 3); + + // make a path to a directory + + char directory[128]; + strcpy(directory, "c:\\projects\\test images\\"); + strcat(directory, finddata.name); + + // open the file + + switch(FreeImage_GetFIFFromFilename(directory)) { + case FIF_BMP : + dib = FreeImage_LoadBMP(directory, BMP_DEFAULT); + break; + + case FIF_ICO : + dib = FreeImage_LoadICO(directory, ICO_DEFAULT); + break; + + case FIF_LBM : + dib = FreeImage_LoadLBM(directory, LBM_DEFAULT); + break; + + case FIF_JPEG : + dib = FreeImage_LoadJPEG(directory, JPEG_DEFAULT); + break; + + case FIF_KOALA : + dib = FreeImage_LoadKOALA(directory, KOALA_DEFAULT); + break; + + case FIF_PCD : + dib = FreeImage_LoadPCD(directory, PCD_DEFAULT); + break; + + case FIF_PCX : + dib = FreeImage_LoadPCX(directory, PCX_DEFAULT); + break; + + case FIF_PNG : + dib = FreeImage_LoadPNG(directory, PNG_DEFAULT); + break; + + case FIF_PBM : + dib = FreeImage_LoadPNM(directory, PNM_DEFAULT); + break; + + case FIF_PGM : + dib = FreeImage_LoadPNM(directory, PNM_DEFAULT); + break; + + case FIF_PPM : + dib = FreeImage_LoadPNM(directory, PNM_DEFAULT); + break; + + case FIF_PSD : + dib = FreeImage_LoadPSD(directory, PSD_DEFAULT); + break; + + case FIF_RAS : + dib = FreeImage_LoadRAS(directory, RAS_DEFAULT); + break; + + case FIF_TARGA : + dib = FreeImage_LoadTARGA(directory, TARGA_DEFAULT); + break; + + case FIF_TIFF : + dib = FreeImage_LoadTIFF(directory, TIFF_DEFAULT); + break; + }; + + if (dib != NULL) { + char unique[128]; + + FreeImage_SetTransparent(dib, FALSE); + + for (int i = 0; i < 1; ++i) { +// for (int i = 0; i < sizeof(s_extensions) / sizeof(s_extensions[0]); ++i) { + itoa(id, unique, 10); + strcat(unique, "."); + strcat(unique, s_extensions[i].ext); + static_cast(s_extensions[i].function)(dib, unique, BMP_DEFAULT); + } + + FreeImage_Free(dib); + + fwrite(unique, strlen(unique), 1, log_file); + fwrite(" >> ", 4, 1, log_file); + fwrite(directory, strlen(directory), 1, log_file); + fwrite("\n", 1, 1, log_file); + + id++; + } + } while (_findnext(handle, &finddata) == 0); + + _findclose(handle); + } + + fclose(log_file); + + FreeImage_DeInitialise(); + + return 0; +} +#endif + +// ---------------------------------------------------------- + +#ifdef QT +int __cdecl +TestQt(int argc, char *argv[]) { + FIQT_Register(false); + + QApplication application(argc, argv); + + QMainWindow window(NULL); + + _finddata_t finddata; + + int count = 0; + + long handle; + + int i = FIQT_GetFIFCount(); + + printf("supported bitmaps: %d\n", i); + + for (int j = 0; j < i; ++j) + printf("bitmap type %d (%s): %s (%s)\n", j, FIQT_GetFormatFromFIF((FREE_IMAGE_FORMAT)j), FIQT_GetFIFDescription((FREE_IMAGE_FORMAT)j), FIQT_GetFIFExtensionList((FREE_IMAGE_FORMAT)j)); + + if ((handle = _findfirst("d:\\test images\\*.jpg", &finddata)) != -1) { + do { + QPixmap pixmap(QObject::tr("d:\\test images\\%1").arg(finddata.name)); + + if (FIQT_FIFSupportsWriting(FIQT_GetFIFFromFormat("PNG"))) + pixmap.save(QObject::tr("%1.png").arg(count++), "PNG"); + } while (_findnext(handle, &finddata) == 0); + + _findclose(handle); + } + + return 0; +} +#endif +// ---------------------------------------------------------- + +int __cdecl +main(int argc, char *argv[]) { +#ifdef API + for (int j = FreeImage_GetFIFCount() - 1; j >= 0; --j) + printf("bitmap type %d (%s): %s (%s)\n", j, FreeImage_GetFormatFromFIF((FREE_IMAGE_FORMAT)j), FreeImage_GetFIFDescription((FREE_IMAGE_FORMAT)j), FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)j)); + + return TestAPI(argc, argv); +#endif +#ifdef QT + return TestQt(argc, argv); +#endif + + return 0; +} diff --git a/freeimage241/Source/Test/Test.dsp b/freeimage241/Source/Test/Test.dsp new file mode 100644 index 0000000..c5b6b29 --- /dev/null +++ b/freeimage241/Source/Test/Test.dsp @@ -0,0 +1,105 @@ +# Microsoft Developer Studio Project File - Name="Test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Test.mak" CFG="Test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "..\\" /I "..\zlib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib Imm32.lib Ws2_32.lib freeimage.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "Test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib Imm32.lib Ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# SUBTRACT LINK32 /pdb:none /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "Test - Win32 Release" +# Name "Test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/Test/Test.dsw b/freeimage241/Source/Test/Test.dsw new file mode 100644 index 0000000..d4e2b94 --- /dev/null +++ b/freeimage241/Source/Test/Test.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Test"=.\Test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/freeimage241/Source/Utilities.h b/freeimage241/Source/Utilities.h new file mode 100644 index 0000000..927469d --- /dev/null +++ b/freeimage241/Source/Utilities.h @@ -0,0 +1,98 @@ +// ========================================================== +// Utility functions +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef UTILITIES_H +#define UTILITIES_H + +#ifndef _INC_MATH +#include +#endif + +#ifndef _INC_STDLIB +#include +#endif + +#ifndef _INC_MEMORY +#include +#endif + +#ifndef _INC_STDIO +#include +#endif + +// ========================================================== +// Utility functions +// ========================================================== + +inline int +round(double x) { + return (int)floor(x + 0.5); +} + +inline unsigned char +HINIBBLE (unsigned char byte) { + return byte & 240; +} + +inline unsigned char +LOWNIBBLE (unsigned char byte) { + return byte & 15; +} + +inline int +CalculateUsedBits(int bits) { + int bit_count = 0; + unsigned bit = 1; + + for (unsigned i = 0; i < 32; i++) { + if ((bits & bit) == bit) { + bit_count++; + } + + bit <<= 1; + } + + return bit_count; +} + +inline int +CalculateLine(int width, int bitdepth) { + return ((width * bitdepth) + 7) / 8; +} + +inline int +CalculatePitch(int line) { + return line + 3 & ~3; +} + +inline int +CalculateUsedColors(int bitcount) { + int c = 1 << bitcount; + + return ((c <= 256) && (c > 1)) ? c : 0; +} + +inline unsigned char * +CalculateScanLine(unsigned char *bits, unsigned pitch, int scanline) { + return (bits + (pitch * scanline)); +} + +#endif diff --git a/freeimage241/Source/ZLib/ZLib.dsp b/freeimage241/Source/ZLib/ZLib.dsp new file mode 100644 index 0000000..f541f8e --- /dev/null +++ b/freeimage241/Source/ZLib/ZLib.dsp @@ -0,0 +1,192 @@ +# Microsoft Developer Studio Project File - Name="ZLib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=ZLib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ZLib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ZLib.mak" CFG="ZLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ZLib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "ZLib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/FreeImage/ZLib", KNAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ZLib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /Gd /MT /W3 /GX /O1 /I "..\zlib" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "ZLib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "ZLib - Win32 Release" +# Name "ZLib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\adler32.c +# End Source File +# Begin Source File + +SOURCE=.\compress.c +# End Source File +# Begin Source File + +SOURCE=.\crc32.c +# End Source File +# Begin Source File + +SOURCE=.\deflate.c +# End Source File +# Begin Source File + +SOURCE=.\gzio.c +# End Source File +# Begin Source File + +SOURCE=.\infblock.c +# End Source File +# Begin Source File + +SOURCE=.\infcodes.c +# End Source File +# Begin Source File + +SOURCE=.\inffast.c +# End Source File +# Begin Source File + +SOURCE=.\inflate.c +# End Source File +# Begin Source File + +SOURCE=.\inftrees.c +# End Source File +# Begin Source File + +SOURCE=.\infutil.c +# End Source File +# Begin Source File + +SOURCE=.\trees.c +# End Source File +# Begin Source File + +SOURCE=.\uncompr.c +# End Source File +# Begin Source File + +SOURCE=.\zutil.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\deflate.h +# End Source File +# Begin Source File + +SOURCE=.\infblock.h +# End Source File +# Begin Source File + +SOURCE=.\infcodes.h +# End Source File +# Begin Source File + +SOURCE=.\inffast.h +# End Source File +# Begin Source File + +SOURCE=.\inffixed.h +# End Source File +# Begin Source File + +SOURCE=.\inftrees.h +# End Source File +# Begin Source File + +SOURCE=.\infutil.h +# End Source File +# Begin Source File + +SOURCE=.\trees.h +# End Source File +# Begin Source File + +SOURCE=.\zconf.h +# End Source File +# Begin Source File + +SOURCE=.\zlib.h +# End Source File +# Begin Source File + +SOURCE=.\zutil.h +# End Source File +# End Group +# End Target +# End Project diff --git a/freeimage241/Source/ZLib/adler32.c b/freeimage241/Source/ZLib/adler32.c new file mode 100644 index 0000000..4bbea6a --- /dev/null +++ b/freeimage241/Source/ZLib/adler32.c @@ -0,0 +1,48 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: adler32.c,v 1.0 2001-04-13 00:42:43+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#include "zlib.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/freeimage241/Source/ZLib/compress.c b/freeimage241/Source/ZLib/compress.c new file mode 100644 index 0000000..774f3a2 --- /dev/null +++ b/freeimage241/Source/ZLib/compress.c @@ -0,0 +1,68 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: compress.c,v 1.0 2001-04-13 00:42:43+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} diff --git a/freeimage241/Source/ZLib/crc32.c b/freeimage241/Source/ZLib/crc32.c new file mode 100644 index 0000000..fafce59 --- /dev/null +++ b/freeimage241/Source/ZLib/crc32.c @@ -0,0 +1,162 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: crc32.c,v 1.0 2001-04-13 00:42:43+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#include "zlib.h" + +#define local static + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local uLongf crc_table[256]; +local void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +local void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +local const uLongf crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLongf * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLongf *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong ZEXPORT crc32(crc, buf, len) + uLong crc; + const Bytef *buf; + uInt len; +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} diff --git a/freeimage241/Source/ZLib/deflate.c b/freeimage241/Source/ZLib/deflate.c new file mode 100644 index 0000000..fef91d9 --- /dev/null +++ b/freeimage241/Source/ZLib/deflate.c @@ -0,0 +1,1350 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in ftp://ds.internic.net/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id: deflate.c,v 1.0 2001-04-13 00:42:44+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.1.3 Copyright 1995-1998 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_slow OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int noheader = 0; + static const char* my_version = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == Z_NULL) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == Z_NULL) strm->zfree = zcfree; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#ifdef FASTEST + level = 1; +#endif + + if (windowBits < 0) { /* undocumented feature: suppress zlib header */ + noheader = 1; + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->noheader = noheader; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->status != INIT_STATE) return Z_STREAM_ERROR; + + s = strm->state; + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); +#ifndef USE_DICT_HEAD + dictionary += dictLength - length; /* use the tail of the dictionary */ +#endif + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->noheader < 0) { + s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + } + s->status = s->noheader ? BUSY_STATE : INIT_STATE; + strm->adler = 1; + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + + if (level == Z_DEFAULT_COMPRESSION) { + level = 6; + } + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the zlib header */ + if (s->status == INIT_STATE) { + + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags = (s->level-1) >> 1; + + if (level_flags > 3) level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = 1L; + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUFF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->noheader) return Z_STREAM_END; + + /* Write the zlib trailer (adler32) */ + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + s->noheader = -1; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + *dest = *source; + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + *ds = *ss; + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (!strm->state->noheader) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +#ifndef FASTEST +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} + +#else /* FASTEST */ +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return len <= s->lookahead ? len : s->lookahead; +} +#endif /* FASTEST */ +#endif /* ASMV */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + } else if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in hash table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} diff --git a/freeimage241/Source/ZLib/deflate.h b/freeimage241/Source/ZLib/deflate.h new file mode 100644 index 0000000..2978fe3 --- /dev/null +++ b/freeimage241/Source/ZLib/deflate.h @@ -0,0 +1,318 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-1998 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: deflate.h,v 1.0 2001-04-13 00:42:44+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +#include "zutil.h" + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif diff --git a/freeimage241/Source/ZLib/gzio.c b/freeimage241/Source/ZLib/gzio.c new file mode 100644 index 0000000..e9d26e7 --- /dev/null +++ b/freeimage241/Source/ZLib/gzio.c @@ -0,0 +1,875 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_DEFLATE to avoid the compression code. + */ + +/* @(#) $Id: gzio.c,v 1.0 2001-04-13 00:42:44+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#include + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + long startpos; /* start of compressed data in file (header skipped) */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open return NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->startpos = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * startpos anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->startpos = (ftell(s->file) - s->stream.avail_in); + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + c = get_byte(s); + if (c != gz_magic[len]) { + if (len != 0) s->stream.avail_in++, s->stream.next_in--; + if (c != EOF) { + s->stream.avail_in++, s->stream.next_in--; + s->transparent = 1; + } + s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; + return; + } + } + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_DEFLATE + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + len -= s->stream.avail_out; + s->stream.total_in += (uLong)len; + s->stream.total_out += (uLong)len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may + * be different from s->stream.total_out) in case of + * concatenated .gz files. Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + uLong total_in = s->stream.total_in; + uLong total_out = s->stream.total_out; + + inflateReset(&(s->stream)); + s->stream.total_in = total_in; + s->stream.total_out = total_out; + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_DEFLATE +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + const voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + va_start(va, format); +#ifdef HAS_vsnprintf + (void)vsnprintf(buf, sizeof(buf), format, va); +#else + (void)vsprintf(buf, format, va); +#endif + va_end(va); + len = strlen(buf); /* some *sprintf don't return the nb of bytes written */ + if (len <= 0) return 0; + + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + +#ifdef HAS_snprintf + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +#else + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +#endif + len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */ + if (len <= 0) return 0; + + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->z_err = deflate(&(s->stream), flush); + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_DEFLATE */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->stream.total_in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return (z_off_t)s->stream.total_in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->stream.total_out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->stream.total_in = s->stream.total_out = (uLong)offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if ((uLong)offset >= s->stream.total_out) { + offset -= s->stream.total_out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return (z_off_t)s->stream.total_out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + + if (s->startpos == 0) { /* not a compressed file */ + rewind(s->file); + return 0; + } + + (void) inflateReset(&s->stream); + return fseek(s->file, s->startpos, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + return (s == NULL || s->mode != 'r') ? 0 : s->z_eof; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_DEFLATE + return Z_STREAM_ERROR; +#else + err = do_flush (file, Z_FINISH); + if (err != Z_OK) return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, s->stream.total_in); +#endif + } + return destroy((gz_stream*)file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char* ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} diff --git a/freeimage241/Source/ZLib/infblock.c b/freeimage241/Source/ZLib/infblock.c new file mode 100644 index 0000000..f4920fa --- /dev/null +++ b/freeimage241/Source/ZLib/infblock.c @@ -0,0 +1,398 @@ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); + Tracev((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_streamp z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(s, z) +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(s, d, n) +inflate_blocks_statef *s; +const Bytef *d; +uInt n; +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(s) +inflate_blocks_statef *s; +{ + return s->mode == LENS; +} diff --git a/freeimage241/Source/ZLib/infblock.h b/freeimage241/Source/ZLib/infblock.h new file mode 100644 index 0000000..bd25c80 --- /dev/null +++ b/freeimage241/Source/ZLib/infblock.h @@ -0,0 +1,39 @@ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); diff --git a/freeimage241/Source/ZLib/infcodes.c b/freeimage241/Source/ZLib/infcodes.c new file mode 100644 index 0000000..d4e5ee9 --- /dev/null +++ b/freeimage241/Source/ZLib/infcodes.c @@ -0,0 +1,257 @@ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +z_streamp z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_streamp z; +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} diff --git a/freeimage241/Source/ZLib/infcodes.h b/freeimage241/Source/ZLib/infcodes.h new file mode 100644 index 0000000..6c750d8 --- /dev/null +++ b/freeimage241/Source/ZLib/infcodes.h @@ -0,0 +1,27 @@ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + diff --git a/freeimage241/Source/ZLib/inffast.c b/freeimage241/Source/ZLib/inffast.c new file mode 100644 index 0000000..61a78ee --- /dev/null +++ b/freeimage241/Source/ZLib/inffast.c @@ -0,0 +1,170 @@ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} diff --git a/freeimage241/Source/ZLib/inffast.h b/freeimage241/Source/ZLib/inffast.h new file mode 100644 index 0000000..8facec5 --- /dev/null +++ b/freeimage241/Source/ZLib/inffast.h @@ -0,0 +1,17 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); diff --git a/freeimage241/Source/ZLib/inffixed.h b/freeimage241/Source/ZLib/inffixed.h new file mode 100644 index 0000000..77f7e76 --- /dev/null +++ b/freeimage241/Source/ZLib/inffixed.h @@ -0,0 +1,151 @@ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local uInt fixed_bl = 9; +local uInt fixed_bd = 5; +local inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; diff --git a/freeimage241/Source/ZLib/inflate.c b/freeimage241/Source/ZLib/inflate.c new file mode 100644 index 0000000..32e9b8d --- /dev/null +++ b/freeimage241/Source/ZLib/inflate.c @@ -0,0 +1,366 @@ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" + +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ + +typedef enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int ZEXPORT inflateReset(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int ZEXPORT inflateEnd(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + + +int ZEXPORT inflateInit2_(z, w, version, stream_size) +z_streamp z; +int w; +const char *version; +int stream_size; +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int ZEXPORT inflateInit_(z, version, stream_size) +z_streamp z; +const char *version; +int stream_size; +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int ZEXPORT inflate(z, f) +z_streamp z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) +z_streamp z; +const Bytef *dictionary; +uInt dictLength; +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + + +int ZEXPORT inflateSync(z) +z_streamp z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} diff --git a/freeimage241/Source/ZLib/inftrees.c b/freeimage241/Source/ZLib/inftrees.c new file mode 100644 index 0000000..ef1e0b6 --- /dev/null +++ b/freeimage241/Source/ZLib/inftrees.c @@ -0,0 +1,455 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#if !defined(BUILDFIXED) && !defined(STDC) +# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ +#endif + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ +struct internal_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uIntf * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +local int huft_build(b, n, s, d, e, t, m, hp, hn, v) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= 288) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +const uIntf *d; /* list of base values for non-simple codes */ +const uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +inflate_huft *hp; /* space for trees */ +uInt *hn; /* hufts used in space */ +uIntf *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(c, bb, tb, hp, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +#ifdef BUILDFIXED +local int fixed_built = 0; +#define FIXEDH 544 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; +#else +#include "inffixed.h" +#endif + + +int inflate_trees_fixed(bl, bd, tl, td, z) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for memory allocation */ +{ +#ifdef BUILDFIXED + /* build fixed tables if not already */ + if (!fixed_built) + { + int k; /* temporary variable */ + uInt f = 0; /* number of hufts used in fixed_mem */ + uIntf *c; /* length list for huft_build */ + uIntf *v; /* work area for huft_build */ + + /* allocate memory */ + if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + { + ZFREE(z, c); + return Z_MEM_ERROR; + } + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 9; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, + fixed_mem, &f, v); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, + fixed_mem, &f, v); + + /* done */ + ZFREE(z, v); + ZFREE(z, c); + fixed_built = 1; + } +#endif + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} diff --git a/freeimage241/Source/ZLib/inftrees.h b/freeimage241/Source/ZLib/inftrees.h new file mode 100644 index 0000000..85853e0 --- /dev/null +++ b/freeimage241/Source/ZLib/inftrees.h @@ -0,0 +1,58 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp)); /* for memory allocation */ diff --git a/freeimage241/Source/ZLib/infutil.c b/freeimage241/Source/ZLib/infutil.c new file mode 100644 index 0000000..824dab5 --- /dev/null +++ b/freeimage241/Source/ZLib/infutil.c @@ -0,0 +1,87 @@ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} diff --git a/freeimage241/Source/ZLib/infutil.h b/freeimage241/Source/ZLib/infutil.h new file mode 100644 index 0000000..99d1135 --- /dev/null +++ b/freeimage241/Source/ZLib/infutil.h @@ -0,0 +1,98 @@ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#endif diff --git a/freeimage241/Source/ZLib/maketree.c b/freeimage241/Source/ZLib/maketree.c new file mode 100644 index 0000000..949d786 --- /dev/null +++ b/freeimage241/Source/ZLib/maketree.c @@ -0,0 +1,85 @@ +/* maketree.c -- make inffixed.h table for decoding fixed codes + * Copyright (C) 1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* This program is included in the distribution for completeness. + You do not need to compile or run this program since inffixed.h + is already included in the distribution. To use this program + you need to compile zlib with BUILDFIXED defined and then compile + and link this program with the zlib library. Then the output of + this program can be piped to inffixed.h. */ + +#include +#include +#include "zutil.h" +#include "inftrees.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* generate initialization table for an inflate_huft structure array */ +void maketree(uInt b, inflate_huft *t) +{ + int i, e; + + i = 0; + while (1) + { + e = t[i].exop; + if (e && (e & (16+64)) == 0) /* table pointer */ + { + fprintf(stderr, "maketree: cannot initialize sub-tables!\n"); + exit(1); + } + if (i % 4 == 0) + printf("\n "); + printf(" {{{%u,%u}},%u}", t[i].exop, t[i].bits, t[i].base); + if (++i == (1< +#include "zlib.h" + +#ifdef STDC +# include +# include +#else + extern void exit OF((int)); +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + int len = strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [-f] [-h] [-1 to -9] [files...] + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + char outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + argc--, argv++; + + while (argc > 0) { + if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv, outmode); + } + } while (argv++, --argc); + } + exit(0); + return 0; /* to avoid warning */ +} diff --git a/freeimage241/Source/ZLib/mssccprj.scc b/freeimage241/Source/ZLib/mssccprj.scc new file mode 100644 index 0000000..c2433a7 --- /dev/null +++ b/freeimage241/Source/ZLib/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[ZLib.dsp] +SCC_Aux_Path = "\\ASIMOV\Magenta\SourceSafe" +SCC_Project_Name = "$/FreeImage/ZLib", KNAAAAAA diff --git a/freeimage241/Source/ZLib/trees.c b/freeimage241/Source/ZLib/trees.c new file mode 100644 index 0000000..688462f --- /dev/null +++ b/freeimage241/Source/ZLib/trees.c @@ -0,0 +1,1214 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-1998 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id: trees.c,v 1.0 2001-04-13 00:42:49+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +#define MAX(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/freeimage241/Source/ZLib/trees.h b/freeimage241/Source/ZLib/trees.h new file mode 100644 index 0000000..72facf9 --- /dev/null +++ b/freeimage241/Source/ZLib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/freeimage241/Source/ZLib/uncompr.c b/freeimage241/Source/ZLib/uncompr.c new file mode 100644 index 0000000..42a17ee --- /dev/null +++ b/freeimage241/Source/ZLib/uncompr.c @@ -0,0 +1,58 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: uncompr.c,v 1.0 2001-04-13 00:42:49+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/freeimage241/Source/ZLib/vssver.scc b/freeimage241/Source/ZLib/vssver.scc new file mode 100644 index 0000000..05119d1 Binary files /dev/null and b/freeimage241/Source/ZLib/vssver.scc differ diff --git a/freeimage241/Source/ZLib/zconf.h b/freeimage241/Source/ZLib/zconf.h new file mode 100644 index 0000000..bc02462 --- /dev/null +++ b/freeimage241/Source/ZLib/zconf.h @@ -0,0 +1,279 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zconf.h,v 1.0 2001-04-13 00:42:50+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Old Borland C incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR _far +# endif +#endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include +# define ZEXPORT __declspec(dllexport) WINAPI +# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT _export +# define ZEXPORTVA _export +# endif +# endif +# endif +#endif + +#if defined (__BEOS__) +# if defined (ZLIB_DLL) +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +#endif + +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(MACOS) && !defined(TARGET_OS_MAC) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") +#endif + +#endif /* _ZCONF_H */ diff --git a/freeimage241/Source/ZLib/zlib.h b/freeimage241/Source/ZLib/zlib.h new file mode 100644 index 0000000..49f56b4 --- /dev/null +++ b/freeimage241/Source/ZLib/zlib.h @@ -0,0 +1,893 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */ diff --git a/freeimage241/Source/ZLib/zutil.c b/freeimage241/Source/ZLib/zutil.c new file mode 100644 index 0000000..89e5d02 --- /dev/null +++ b/freeimage241/Source/ZLib/zutil.c @@ -0,0 +1,225 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id: zutil.c,v 1.0 2001-04-13 00:42:51+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/freeimage241/Source/ZLib/zutil.h b/freeimage241/Source/ZLib/zutil.h new file mode 100644 index 0000000..8d5313e --- /dev/null +++ b/freeimage241/Source/ZLib/zutil.h @@ -0,0 +1,220 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id: zutil.h,v 1.0 2001-04-13 00:42:51+02 floris_van_den_berg Exp floris_van_den_berg $ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# define fdopen(fd,type) _fdopen(fd,type) +#endif + + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, + uInt len)); +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ diff --git a/freeimage241/Source/freeimage.h b/freeimage241/Source/freeimage.h new file mode 100644 index 0000000..d95d1de --- /dev/null +++ b/freeimage241/Source/freeimage.h @@ -0,0 +1,579 @@ +// ========================================================== +// FreeImage 2 +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// +// Contributors: +// - Adam Gates (adam.gates@str.com.au) +// - Alex Kwak +// - Alexander Dymerets (sashad@te.net.ua) +// - Hervé Drolon (drolon@iut.univ-lehavre.fr) +// - Jan L. Nauta (jln@magentammt.com) +// - Jani Kajala (janik@remedy.fi) +// - Luca Piergentili (l.pierge@terra.es) +// - Machiel ten Brinke (brinkem@uni-one.nl) +// - Markus Loibl (markus.loibl@epost.de) +// - Martin Weber (martweb@gmx.net) +// +// This file is part of FreeImage 2 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef FREEIMAGE_H +#define FREEIMAGE_H + +#if defined(_LIB) || defined(FREEIMAGE_LIB) || !defined(WIN32) +#define DLL_API +#define DLL_CALLCONV _cdecl +#else +#define WIN32_LEAN_AND_MEAN +#define DLL_CALLCONV _stdcall +#ifdef FREEIMAGE_EXPORTS +#define DLL_API __declspec(dllexport) +#else +#define DLL_API __declspec(dllimport) +#endif +#endif + +// For C compatility -------------------------------------------------------- + +#ifdef __cplusplus +#define FI_DEFAULT(x) = x +#define FI_ENUM(x) enum x +#define FI_STRUCT(x) struct x +#else +#define FI_DEFAULT(x) +#define FI_ENUM(x) typedef int x; enum x +#define FI_STRUCT(x) typedef struct x x; struct x +#endif + +// Bitmap types ------------------------------------------------------------- + +FI_STRUCT (FIBITMAP) { void *data; }; + +// Types used in the library (directly copied from Windows) ----------------- + +#ifndef _WINDOWS_ +#define _WINDOWS_ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef NULL +#define NULL 0 +#endif + +typedef long BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef long LONG; + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#define BI_RGB 0L +#define BI_RLE8 1L +#define BI_RLE4 2L +#define BI_BITFIELDS 3L + +typedef struct tagRGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; +} RGBQUAD; + +typedef struct tagBITMAPINFOHEADER{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER, *PBITMAPINFOHEADER; + +typedef struct tagBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} BITMAPINFO, *PBITMAPINFO; + +#endif + +// Important enums ---------------------------------------------------------- + +FI_ENUM(FREE_IMAGE_FORMAT) { + FIF_UNKNOWN = -1, + FIF_BMP = 0, +// FIF_ICO, + FIF_JPEG, +// FIF_JNG, +// FIF_KOALA, + FIF_LBM, +// FIF_MNG, +// FIF_PBM, +// FIF_PBMRAW, +// FIF_PCD, + FIF_PCX, +// FIF_PGM, +// FIF_PGMRAW, + FIF_PNG, +// FIF_PPM, +// FIF_PPMRAW, +// FIF_RAS, + FIF_TARGA, +// FIF_TIFF, +// FIF_WBMP, +// FIF_PSD, + FIF_IFF = FIF_LBM, +}; + +FI_ENUM(FREE_IMAGE_COLOR_TYPE) { + FIC_MINISWHITE = 0, // min value is white + FIC_MINISBLACK = 1, // min value is black + FIC_RGB = 2, // RGB color model + FIC_PALETTE = 3, // color map indexed + FIC_RGBALPHA = 4, // RGB color model with alpha channel +}; + +FI_ENUM(FREE_IMAGE_QUANTIZE) { + FIQ_WUQUANT = 0, // Xiaolin Wu color quantization algorithm + FIQ_NNQUANT = 1 // NeuQuant neural-net quantization algorithm by Anthony Dekker +}; + +// File IO routines --------------------------------------------------------- + +#ifndef FREEIMAGE_IO +#define FREEIMAGE_IO + +#define fi_handle void* + +typedef unsigned (*FI_ReadProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef unsigned (*FI_WriteProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef int (*FI_SeekProc) (fi_handle handle, long offset, int origin); +typedef long (*FI_TellProc) (fi_handle handle); + +#ifdef WIN32 +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +FI_STRUCT(FreeImageIO) { + FI_ReadProc read_proc; // pointer to the function used to read data + FI_WriteProc write_proc; // pointer to the function used to write data + FI_SeekProc seek_proc; // pointer to the function used to seek + FI_TellProc tell_proc; // pointer to the function used to aquire the current position +}; + +#ifdef WIN32 +#pragma pack(pop) +#else +#pragma pack(4) +#endif + +// Plugin routines ---------------------------------------------------------- + +#ifndef PLUGINS +#define PLUGINS + +FI_STRUCT (Plugin); +FI_STRUCT (FreeImage); + +typedef FIBITMAP *(DLL_CALLCONV * FI_AllocateProc)(int width, int height, int bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask); +typedef void (DLL_CALLCONV *FI_FreeProc)(FIBITMAP *dib); +typedef void (DLL_CALLCONV *FI_UnloadProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetColorsUsedProc)(FIBITMAP *dib); +typedef BYTE *(DLL_CALLCONV *FI_GetBitsProc)(FIBITMAP *dib); +typedef BYTE *(DLL_CALLCONV *FI_GetBitsRowColProc)(FIBITMAP *dib, int col, int row); +typedef BYTE *(DLL_CALLCONV *FI_GetScanLineProc)(FIBITMAP *dib, int scanline); +typedef unsigned (DLL_CALLCONV *FI_GetBPPProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetWidthProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetHeightProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetLineProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetPitchProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetDIBSizeProc)(FIBITMAP *dib); +typedef RGBQUAD *(DLL_CALLCONV *FI_GetPaletteProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetDotsPerMeterXProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetDotsPerMeterYProc)(FIBITMAP *dib); +typedef BITMAPINFOHEADER *(DLL_CALLCONV *FI_GetInfoHeaderProc)(FIBITMAP *dib); +typedef BITMAPINFO *(DLL_CALLCONV *FI_GetInfoProc)(FIBITMAP *dib); +typedef FREE_IMAGE_COLOR_TYPE (DLL_CALLCONV *FI_GetColorTypeProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetRedMaskProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetGreenMaskProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetBlueMaskProc)(FIBITMAP *dib); +typedef unsigned (DLL_CALLCONV *FI_GetTransparencyCountProc)(FIBITMAP *dib); +typedef BYTE * (DLL_CALLCONV *FI_GetTransparencyTableProc)(FIBITMAP *dib); +typedef void (DLL_CALLCONV *FI_SetTransparencyTableProc)(FIBITMAP *dib, BYTE *table, BYTE count); +typedef BOOL (DLL_CALLCONV *FI_IsTransparentProc)(FIBITMAP *dib); +typedef void (DLL_CALLCONV *FI_SetTransparentProc)(FIBITMAP *dib, BOOL enabled); +typedef void (DLL_CALLCONV *FI_OutputMessageProc)(int fif, const char *msg); +typedef void (DLL_CALLCONV *FI_ConvertLine1To8Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine4To8Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine16To8_555Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine16To8_565Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine24To8Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine32To8Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine1To16_555Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine4To16_555Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine8To16_555Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine16_565_To16_555Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine24To16_555Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine32To16_555Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine1To16_565Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine4To16_565Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine8To16_565Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine16_555_To16_565Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine24To16_565Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine32To16_565Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine1To24Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine4To24Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine8To24Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine16To24_555Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine16To24_565Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine32To24Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine1To32Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine4To32Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine8To32Proc)(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +typedef void (DLL_CALLCONV *FI_ConvertLine16To32_555Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine16To32_565Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_ConvertLine24To32Proc)(BYTE *target, BYTE *source, int width_in_pixels); +typedef void (DLL_CALLCONV *FI_InitProc)(Plugin &plugin, int format_id); + +typedef unsigned (*FI_ReadProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef unsigned (*FI_WriteProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef int (*FI_SeekProc) (fi_handle handle, long offset, int origin); +typedef long (*FI_TellProc) (fi_handle handle); + +typedef const char *(DLL_CALLCONV *FI_FormatProc) (); +typedef const char *(DLL_CALLCONV *FI_DescriptionProc) (); +typedef const char *(DLL_CALLCONV *FI_ExtensionListProc) (); +typedef const char *(DLL_CALLCONV *FI_RegExprProc) (); +typedef void *(DLL_CALLCONV *FI_OpenProc)(FreeImageIO &io, fi_handle handle, BOOL read); +typedef void (DLL_CALLCONV *FI_CloseProc)(FreeImageIO &io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCountProc)(FreeImageIO &io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCapabilityProc)(FreeImageIO &io, fi_handle handle, void *data); +typedef FIBITMAP *(DLL_CALLCONV *FI_LoadProc)(FreeImage &freeimage, FreeImageIO &io, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_SaveProc)(FreeImage &freeimage, FreeImageIO &io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_ValidateProc)(FreeImageIO &io, fi_handle handle); +typedef const char *(DLL_CALLCONV *FI_MimeProc) (); + +FI_STRUCT(FreeImage) { + FI_AllocateProc allocate_proc; + FI_UnloadProc unload_proc; + FI_FreeProc free_proc; + FI_GetColorsUsedProc get_colors_used_proc; + FI_GetBitsProc get_bits_proc; + FI_GetBitsRowColProc get_bits_row_col_proc; + FI_GetScanLineProc get_scanline_proc; + FI_GetBPPProc get_bpp_proc; + FI_GetWidthProc get_width_proc; + FI_GetHeightProc get_height_proc; + FI_GetLineProc get_line_proc; + FI_GetPitchProc get_pitch_proc; + FI_GetDIBSizeProc get_dib_size_proc; + FI_GetPaletteProc get_palette_proc; + FI_GetDotsPerMeterXProc get_dots_per_meter_x_proc; + FI_GetDotsPerMeterYProc get_dots_per_meter_y_proc; + FI_GetInfoHeaderProc get_info_header_proc; + FI_GetInfoProc get_info_proc; + FI_GetColorTypeProc get_color_type_proc; + FI_GetRedMaskProc get_red_mask_proc; + FI_GetGreenMaskProc get_green_mask_proc; + FI_GetBlueMaskProc get_blue_mask_proc; + FI_GetTransparencyCountProc get_transparency_count_proc; + FI_GetTransparencyTableProc get_transparency_table_proc; + FI_SetTransparencyTableProc set_transparency_table_proc; + FI_IsTransparentProc is_transparent_proc; + FI_SetTransparentProc set_transparent_proc; + FI_OutputMessageProc output_message_proc; + FI_ConvertLine1To8Proc convert_line1to8_proc; + FI_ConvertLine4To8Proc convert_line_4to8_proc; + FI_ConvertLine16To8_555Proc convert_line_16to8_555_proc; + FI_ConvertLine16To8_565Proc convert_line_16to8_565_proc; + FI_ConvertLine24To8Proc convert_line_24to8_proc; + FI_ConvertLine32To8Proc convert_line_32to8_proc; + FI_ConvertLine1To16_555Proc convert_line_1to16_555_proc; + FI_ConvertLine4To16_555Proc convert_line_4to16_555_proc; + FI_ConvertLine8To16_555Proc convert_line_8to16_555_proc; + FI_ConvertLine16_565_To16_555Proc convert_line_16_565_to_16_555_proc; + FI_ConvertLine24To16_555Proc convert_line_24to16_555_proc; + FI_ConvertLine32To16_555Proc convert_line_32to16_555_proc; + FI_ConvertLine1To16_565Proc convert_line_1to16_565_proc; + FI_ConvertLine4To16_565Proc convert_line_4to16_565_proc; + FI_ConvertLine8To16_565Proc convert_line_8to16_565_proc; + FI_ConvertLine16_555_To16_565Proc convert_line_16_555_to_16_565_proc; + FI_ConvertLine24To16_565Proc convert_line_24to16_565_proc; + FI_ConvertLine32To16_565Proc convert_line_32to16_565_proc; + FI_ConvertLine1To24Proc convert_line_1to24_proc; + FI_ConvertLine4To24Proc convert_line_4to24_proc; + FI_ConvertLine8To24Proc convert_line_8to24_proc; + FI_ConvertLine16To24_555Proc convert_line_16to24_555_proc; + FI_ConvertLine16To24_565Proc convert_line_16to24_565_proc; + FI_ConvertLine32To24Proc convert_line_32to24_proc; + FI_ConvertLine1To32Proc convert_line_1to32_proc; + FI_ConvertLine4To32Proc convert_line_4to32_proc; + FI_ConvertLine8To32Proc convert_line_8to32_proc; + FI_ConvertLine16To32_555Proc convert_line_16to32_555_proc; + FI_ConvertLine16To32_565Proc convert_line_16to32_565_proc; + FI_ConvertLine24To32Proc convert_line_24to32_proc; +}; + +FI_STRUCT (Plugin) { + FI_FormatProc format_proc; + FI_DescriptionProc description_proc; + FI_ExtensionListProc extension_proc; + FI_RegExprProc regexpr_proc; + FI_OpenProc open_proc; + FI_CloseProc close_proc; + FI_PageCountProc pagecount_proc; + FI_PageCapabilityProc pagecapability_proc; + FI_LoadProc load_proc; + FI_SaveProc save_proc; + FI_ValidateProc validate_proc; + FI_MimeProc mime_proc; +}; + +#endif +#endif + +// Load/Save flag constants ----------------------------------------------------- + +#define BMP_DEFAULT 0 +#define ICO_DEFAULT 0 +#define ICO_FIRST 0 +#define ICO_SECOND 0 +#define ICO_THIRD 0 +#define IFF_DEFAULT 0 +#define JPEG_DEFAULT 0 +#define JPEG_FAST 1 +#define JPEG_ACCURATE 2 +#define JPEG_QUALITYSUPERB 0x80 +#define JPEG_QUALITYGOOD 0x100 +#define JPEG_QUALITYNORMAL 0x200 +#define JPEG_QUALITYAVERAGE 0x400 +#define JPEG_QUALITYBAD 0x800 +#define KOALA_DEFAULT 0 +#define LBM_DEFAULT 0 +#define MNG_DEFAULT 0 +#define PCD_DEFAULT 0 +#define PCD_BASE 1 +#define PCD_BASEDIV4 2 +#define PCD_BASEDIV16 3 +#define PCX_DEFAULT 0 +#define PNG_DEFAULT 0 +#define PNM_DEFAULT 0 +#define PNM_SAVE_RAW 0 // If set the writer saves in RAW format (i.e. P4, P5 or P6) +#define PNM_SAVE_ASCII 1 // If set the writer saves in ASCII format (i.e. P1, P2 or P3) +#define RAS_DEFAULT 0 +#define TARGA_DEFAULT 0 +#define TARGA_LOAD_RGB888 1 // If set the loader converts RGB555 and ARGB8888 -> RGB888. +#define TARGA_LOAD_RGB555 2 // This flag is obsolete +#define TIFF_DEFAULT 0 +#define WBMP_DEFAULT 0 +#define PSD_DEFAULT 0 + +#ifdef __cplusplus +extern "C" { +#endif + +// Init/Error routines ------------------------------------------------------ + +DLL_API void DLL_CALLCONV FreeImage_Initialise(BOOL load_local_plugins_only = FALSE); +DLL_API void DLL_CALLCONV FreeImage_DeInitialise(); + +// Version routines --------------------------------------------------------- + +DLL_API const char *DLL_CALLCONV FreeImage_GetVersion(); +DLL_API const char *DLL_CALLCONV FreeImage_GetCopyrightMessage(); + +// Message output functions ------------------------------------------------- + +typedef void (*FreeImage_OutputMessageFunction)(FREE_IMAGE_FORMAT fif, const char *msg); +DLL_API void DLL_CALLCONV FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf); + +// Allocate/Unload routines ------------------------------------------------ + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API void DLL_CALLCONV FreeImage_Free(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_Unload(FIBITMAP *dib); + +// Plugin Interface -------------------------------------------------------- + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterLocalPlugin(FI_InitProc proc_address, const char *format = 0, const char *description = 0, const char *extension = 0, const char *regexpr = 0); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterExternalPlugin(const char *path, const char *format = 0, const char *description = 0, const char *extension = 0, const char *regexpr = 0); +DLL_API int DLL_CALLCONV FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif, BOOL enable); +DLL_API int DLL_CALLCONV FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif); +DLL_API int DLL_CALLCONV FreeImage_GetFIFCount(); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFormat(const char *format); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromMime(const char *mime); +DLL_API const char *DLL_CALLCONV FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif); +DLL_API const char * DLL_CALLCONV FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilename(const char *filename); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); + +// Old style bitmap load routines ------------------------------------------ + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadBMP(const char *filename, int flags FI_DEFAULT(BMP_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadBMPFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(BMP_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadICO(const char *filename, int flags FI_DEFAULT(ICO_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadICOFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(ICO_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadIFF(const char *filename, int flags FI_DEFAULT(IFF_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadIFFFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(IFF_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadJPEG(const char *filename, int flags FI_DEFAULT(JPEG_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadJPEGFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(JPEG_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadKOALA(const char *filename, int flags FI_DEFAULT(KOALA_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadKOALAFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(KOALA_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadLBM(const char *filename, int flags FI_DEFAULT(LBM_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadLBMFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(LBM_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadMNG(const char *filename, int flags FI_DEFAULT(MNG_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadMNGFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(MNG_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPCD(const char *filename, int flags FI_DEFAULT(PCD_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPCDFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(PCD_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPCX(const char *filename, int flags FI_DEFAULT(PCX_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPCXFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(PCX_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPNG(const char *filename, int flags FI_DEFAULT(PNG_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPNGFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(PNG_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPNM(const char *filename, int flags FI_DEFAULT(PNM_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPNMFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(PNM_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPSD(const char *filename, int flags FI_DEFAULT(PSD_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadPSDFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(PSD_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadRAS(const char *filename, int flags FI_DEFAULT(RAS_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadRASFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(RAS_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadTARGA(const char *filename, int flags FI_DEFAULT(TARGA_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadTARGAFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(TARGA_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadTIFF(const char *filename, int flags FI_DEFAULT(TIFF_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadTIFFFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(TIFF_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadWBMP(const char *filename, int flags FI_DEFAULT(WBMP_DEFAULT)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadWBMPFromHandle(FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(WBMP_DEFAULT)); + +// Bitmap save routines ----------------------------------------------------- + +DLL_API BOOL DLL_CALLCONV FreeImage_SaveBMP(FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(BMP_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveBMPToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(BMP_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveJPEG(FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(JPEG_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveJPEGToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(JPEG_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SavePNG(FIBITMAP *dib, const char *filename, int flags FI_DEFAULT( PNG_DEFAULT ) ); +DLL_API BOOL DLL_CALLCONV FreeImage_SavePNGToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(PNG_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SavePNM(FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(PNM_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SavePNMToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(PNM_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveTIFF(FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(TIFF_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveTIFFToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(TIFF_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveWBMP(FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(WBMP_DEFAULT)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveWBMPToHandle(FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(WBMP_DEFAULT)); + +// Filetype request routines ----------------------------------------------- + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileType(const char *filename, int size); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size); +DLL_API const char * DLL_CALLCONV FreeImage_GetFileTypeFromFormat(FREE_IMAGE_FORMAT fif); // this function is deprecated +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromExt(const char *filename); // this function is deprecated + +// FreeImage info routines ------------------------------------------------- + +DLL_API unsigned DLL_CALLCONV FreeImage_GetRedMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetGreenMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBlueMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetTransparencyCount(FIBITMAP *dib); +DLL_API BYTE * DLL_CALLCONV FreeImage_GetTransparencyTable(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled); +DLL_API void DLL_CALLCONV FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, BYTE count); +DLL_API BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib); + +// DIB info routines ------------------------------------------------------- + +DLL_API unsigned DLL_CALLCONV FreeImage_GetColorsUsed(FIBITMAP *dib); +DLL_API BYTE *DLL_CALLCONV FreeImage_GetBits(FIBITMAP *dib); +DLL_API BYTE *DLL_CALLCONV FreeImage_GetBitsRowCol(FIBITMAP *dib, int col, int row); +DLL_API BYTE *DLL_CALLCONV FreeImage_GetScanLine(FIBITMAP *dib, int scanline); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBPP(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetWidth(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetHeight(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetLine(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDIBSize(FIBITMAP *dib); +DLL_API RGBQUAD *DLL_CALLCONV FreeImage_GetPalette(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterX(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterY(FIBITMAP *dib); +DLL_API BITMAPINFOHEADER *DLL_CALLCONV FreeImage_GetInfoHeader(FIBITMAP *dib); +DLL_API BITMAPINFO *DLL_CALLCONV FreeImage_GetInfo(FIBITMAP *dib); +DLL_API FREE_IMAGE_COLOR_TYPE DLL_CALLCONV FreeImage_GetColorType(FIBITMAP *dib); + +// Conversion routines ----------------------------------------------------- + +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_565_To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_555_To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo8Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits555(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits565(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo24Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo32Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantize(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); +DLL_API void DLL_CALLCONV FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); + +#ifdef __cplusplus +} +#endif + +#endif // !FREEIMAGE_H diff --git a/freeimage241/Todo.txt b/freeimage241/Todo.txt new file mode 100644 index 0000000..8b55f40 --- /dev/null +++ b/freeimage241/Todo.txt @@ -0,0 +1,4 @@ +What's there to do for FreeImage + +* add a movie plugin (DirectShow based) +* start using c++ (stl) instead of c, since most things are now c++ anyway diff --git a/freeimage241/Whatsnew.txt b/freeimage241/Whatsnew.txt new file mode 100644 index 0000000..6c79510 --- /dev/null +++ b/freeimage241/Whatsnew.txt @@ -0,0 +1,373 @@ +Whats New for FreeImage + +* : fixed +- : removed +! : changed ++ : added + +July 30th 2001 - 2.4.1 +* [Jan Nauta] fixed some plugin ids not being passed to plugins +* [Jan Nauta] fixed some functions being natively called instead of indirect +* [Jan Nauta] fixed BMPs with signature BA not being regognised +* [Remo Eichenberger] fixed memory leak in the plugin system +* fixed seek bug in PluginIFF's Validate +* fixed transparency issue in PluginPNG +* fixed uncaught exceptions in WUQuantizer and NNQuantizer +* fixed some problems with PluginTARGA +* fixed some problems with PluginICO +* fixed some problems with PluginBMP +! improved FreeImageQt's load function a little +! tell/seek control for validation is now handled inside the plugin framework + +July 22th 2001 - 2.4.0 +* (Yours Detlev) fixed memory leak in FreeImage_GetFIFFromFilename +* (Yours Detlev) fixed memory leak in the ICO plugin +* (Yours Detlev) fixed memory leak in the PNG plugin +* fixed potential NULL-pointer access bug in Plugin::AddNode +* fixed problems with linking the static lib +- removed LBM plugin. Its functionality is placed in the IFF plugin now +- removed FreeImage_GetFIFByIndex +! FreeImage now uses LibMNG 1.0.2 +! FreeImage_SetTransparent now only enables alpha when the bitmap is 8 or 32 bit +! FreeImage_SetTransparencyTable now only enables alpha when the bitmap is 8 bit +! FreeImage_LoadLBM now uses Mark Sibly's IFF plugin +! FreeImage_SaveBMP now converts to 24-bit when bpp is 32 and transparency is off +! FreeImage_SaveJPEG now converts to 24-bit when bpp is 32 and transparency is off +! FreeImage_SavePNM now converts to 24-bit when bpp is 32 and transparency is off +! FreeImage_SaveTIFF now converts to 24-bit when bpp is 32 and transparency is off ++ [Mark Sibly] added IFF (ILBM) support ++ added basic support for Photoshop files ++ added mime type support (FreeImage_GetFIFFromMime) ++ added functions FreeImage_SetPluginEnabled and FreeImage_IsPluginEnabled + Disabling plugins modifies the behaviour of the following functions: + * FreeImage_LoadFromHandle + * FreeImage_SaveToHandle + * FreeImage_FIFSupportsReading + * FreeImage_FIFSupportsWriting + * FreeImage_GetFIFFromFormat + * FreeImage_GetFIFFromFilename + * FreeImage_GetFIFFromMime + * FreeImage_Validate + +June 30th 2001 - 2.3.2 +* fixed missing "targa" extension in targa extension list +* fixed small memory leak in PluginList::AddNode +* fixed 32 bit PNG saving suddenly disappeared from the distro? +* fixed 'black line' bug in LoadTARGA +- removed project FreeImageM2 +- removed FreeImage_Combine +! FreeImage_RegisterLocalPlugin now receives a FI_InitProc as first parameter +! FreeImage_GetFIFFromFilename now also takes the format id into account +! cleanup up the code a little for PluginPCD and PluginPCX ++ added static lib project + +June 11th 2001 - 2.3.1 +* [Machiel ten Brinke] fixed the loading of some 'ancient' TARGAs +* [Rui Lopes] fixed some bugs in the external plugin registration +* fixed the plugin system crashing when the init function isn't called +- removed project FreeImagePy +- removed 32 to 24 bit conversion while saving PNG in FreeImageQt +! the scanline convert functions are now accessable in plugins +! FreeImage now uses an STL map to store the plugin list +! PluginSDK.h is now integrated into FreeImage.h +! FreeImage_Register now receives the boolean parameter 'load_local_plugins_only' +! FreeImage now uses LibPNG 1.0.12 ++ [Rui Lopes] added plugin for GIF reading/writing support ++ added function FreeImage_SetTransparencyCount ++ added support for 32 bit PNG saving ++ added FreeImage_RegisterLocalPlugin to allow plugins inside apps ++ added FreeImage_RegisterExternalPlugin to manually load DLLs ++ added plugin for JBIG reading/writing support + +May 4th 2001 - 2.3.0 +* [Martin Weber] fixed some small bugs in the TARGA and BMP plugins +* [Martin Weber] fixed tiny bug in new 16 bit conversions +* [Martin Weber] fixed load flag inconsistency in the TARGA plugin +* [Martin Weber] fixed plugin id / load reference inconsistency for PNM +* [Jan Nauta] fixed bug in conversion 16 -> 16 +* [Herve Drolon] fixed small bug in 4-bit PCX loader +- removed code that loads BMPs renamed to ICO in PluginICO +! the flag TARGA_LOAD_RGB555 is now obsolete +! the plugin list is now sorted internally +! ConvertTo32Bits now stores the transparency table as alpha mask +! FreeImage now uses LibMNG 1.0,1 +! FreeImage now uses LibPNG 1.0.11 ++ added external plugin support via DLLs ++ added function FreeImage_GetFIFByIndex ++ added internal function CalculateScanLine ++ added transparency support for high-color PNGs ++ added transparency support for high-color TIFFs ++ added functions FreeImage_SetTransparent and FreeImage_IsTransparent ++ added constant FIC_RGBALPHA to FREE_IMAGE_COLOR_TYPE + +April 5th 2001 - 2.2.0 +* [Remo Eichenberger] fixed small bug concerning DLLMain and static LIB generation +* fixed 1-bit bitmaps not properly loading in FreeImageQt +* fixed bug in conversion 16->16 +* FreeImage now uses LibPNG 1.0.10 +! [Martin Weber] improved loading of BMP files +! [Martin Weber] improved loading of TARGA files +! [Dave Larson] improved visual appearance after 16 conversions +! FreeImageQt now converts 32-bit bitmaps to 24-bit when saving PNGs and JPEGs ++ added functions FreeImage_Initialise and FreeImage_DeInitialise ++ added internal plugins ++ re-added combine/alphablend functions + +March 8th 2001 - 2.1.0 +* [Martin Hemming] fixed bug in 16-bit TARGA loading code +* fixed PNG's with alpha masks not loading correctly +! FreeImage is now dual-licensed: the FI-License and the GPL license +! FreeImage now uses LibPNG 1.0.9 +! FreeImage now uses LibTIFF 3.5.6 Beta +! FreeImage now uses LiBMNG 1.0.0 +! changed the ordering of the FREE_IMAGE_FORMAT table +! improved linux support +! improved test script ++ added transparency table support to SavePNG ++ added BI_BITFIELDS support to LoadBMP and SaveBMP ++ added reading support for OS/2 2.x BMPs ++ added support for MNG and JNG reading using LibMNG ++ added support for Deluxe Paint reading ++ added 'hot swap' support to the Core DLL ++ added 'hot swap' support to FreeImage Qt ++ added functions GetFIFFromFormat and GetFIFFromFilename ++ added functions FIFSupportsReading and FIFSupportsWriting ++ added function GetFIFRegExpr + +January 14th 2001 - 2.0.0 +* [Herve Drolon] fixed a bug in the conversion 4->8 +* [Herve Drolon] fixed a bug in metrics handling in SaveJPEG +* [Herve Drolon] fixed a bug in the return value of the function SaveTIFF +* fixed the presence of two WuQuantizer.cpp files in the distribution +* fixed bug where a BMP renamed to ICO isn't loaded +- removed FreeImage_ConvertToGreyScale. Use FreeImage_ConvertTo8Bits instead. +- removed the boolean parameters from all conversion routines +- removed page handling in LoadTIFF. A new range of functions will be added. +! The void pointers used in FreeImage are now typed +! LoadBMP now takes palettes in 24/32 bit images in respect +! All effects and MMX functions are now stored in a new library (FreeEffects) +! [Herve Drolon] fixed bug in FreeImage_GetColorType +! [Herve Drolon] improved PCX loader. It can now read 1, 4, 8 and 24-bit images +! [Manfred Tausch] improved FreeImage_Rotate +! [Luca Piergentili] fixed crash bug when saving some 1-bit TIFFs +! rewrote all bitdepth conversion routines making use of the new scanline converters +! rewrote bitdepth conversion in FreeImageQt (uses less memory) +! FreeImage is now compiled __stdcall ++ [Herve Drolon] added WBMP (Wireless Bitmap Format) support: loading and saving ++ [Herve Drolon] added 4, 16 and 32 bitdepth handling in GetColorType ++ [Herve Drolon] added handling of 8-bit greyscale bitmaps in SaveJPEG ++ [Herve Drolon] added NeuQuant color reduction algorithm to ColorQuantize ++ added DLL_CALLCONV (calling convention) flag ++ added bitmask support to all bitmaps ++ added a series of functions converting scanlines from one bitdepth to another ++ added functions ConvertFromRawBits and ConvertToRawBits ++ added project FreeImageM2: Magenta II MMT bindings for FreeImage ++ added basic foundation for linux support + +December 2th 2000 - 1.4.4 +* fixed small bug related to TIFFSetDirectory in FreeImage_LoadTIFF +* fixed FreeImage_Rotate sometimes clipping too much pixels +* fixed other small bug in FreeImage_Rotate +* fixed FreeImage_Clone not taking the FREEIMAGEHEADER in account +* fixed bug in FreeImageQt where 1-bit images are not correctly allocated +* fixed FreeImage_Crop not copying the palette +* fixed message function pointer crash bug +* fixed bug where the palette wasn't copied when saving in FreeImageQt +* fixed FreeImage_Clone not copying the transparency table +- removed FreeImage_WritePaletteEntry +! [Adam Gates] rewrote parts of FreeImage so that c compilers can handle it better +! FreeImageQt doesn't statically link with the FreeImage lib anymore +! FreeImageQt now uses atexit() to automatically unregister +! rewrote parts of FreeImage_LoadBMP to increase speed ++ [Markus Loibl] added metrics handling code to LoadBMP, LoadJPEG, LoadTIFF and LoadPCX ++ added metrics handling code to FreeImageQt ++ added functions FIQT_IsLoaded, FIQT_GetVersion and FIQT_GetCopyrightMessage ++ added conversion 1 -> 16 ++ added FreeImage_SaveJPEG and JPEG quality settings ++ added FreeImage_GetBitsRowCol ++ added function FIQT_SetOutputMessage to FreeImageQt ++ added FreeImage_GetFileTypeFromExtension and FIQT_GetFileTypeFromFormat ++ added project FreeImagePy: python bindings for FreeImage + +November 7th 2000 - 1.4.3 +* fixed FreeImage_SavePNG crash bug +* fixed slighly corrupt size filter in FreeImage_Combine +* fixed FreeImage_SaveTIFF not saving 4-bit images +* [Herve Drolon] fixed bug in FreeImage_LoadTIFF +* [Herve Drolon] fixed bug in FreeImage_GetColorType +- removed fclose from FreeImage_SavePNM (who put it there?) +! rewrote FreeImage_Rotate +! FreeImageQt now automatically detects which formats are supported by Qt and which not +! FreeImage_Allocate now returns a void pointer +! FreeImage_Unload is now called FreeImage_Free ++ added 16-bit 5-5-5 support to FreeImage_LoadBMP ++ added RLE_DELTA support to FreeImage_LoadBMP ++ added directory support to FreeImage_LoadTIFF ++ added functions dealing with transparency ++ added transparency support to 8-bit PNG's in Qt ++ added FREE_IMAGE_QUANTIZE parameter to FreeImage_ColorQuantize ++ added custom FREEIMAGEHEADER header prepended to internal bitmaps ++ added new documentation + +October 18th 2000 - 1.4.2 +* fixed FreeImage_SaveBMP storing an incorrect bfSize value in the BITMAPFILEHEADER +* fixed bug where JPEG and PNG wouldn't load in FreeImageQt +* fixed FreeImage_Mirror mirroring one pixel less than needed +! FreeImage_MaskedCombine24 is now called FreeImage_MaskedCombine24Ex +! FreeImage_MaskedCombine32 is now called FreeImage_MaskedCombine32Ex ++ added 16-bit bitmap support to FreeImage_Mirror ++ added 16-bit bitmap support to FreeImage_ConvertTo8Bits ++ added simple version of FreeImage_MaskedCombine24 ++ added simple version of FreeImage_MaskedCombine32 + +October 17th 2000 - 1.4.1 +* [Herve Drolon] fixed bug in FreeImage_ConvertTo8Bits +* fixed bug in conversion with 16 -> 24 and 16 -> 32 +- removed static library support +- removed all unnecessary files from LibTIFF, LibPNG, LibJPEG and ZLib +- removed all absolute seeks from the library +! FreeImageQt now makes use of the DLL distro +! rebuilt the entire directory structure +! improved handling of BMP +! renamed FreeImage_MaskedCombine to FreeImage_MaskedCombine32 ++ [Alexander Dymerets] added 24-bit masked alpha blending with a seperate alpha mask ++ added FreeImage_Rotate (known bug in degrees 76 to 106) ++ added 4-bit bitmap support to FreeImage_ConvertTo16Bits ++ added 8-bit bitmap support to FreeImage_ConvertTo16Bits ++ added 32-bit bitmap support to FreeImage_ConvertTo16Bits ++ added 32-bit bitmap support to FreeImage_Mirror ++ added 16-bit 5-5-5 support to FreeImage_ConvertTo24Bits ++ added 16-bit 5-5-5 support to FreeImage_ConvertTo32Bits + +October 2th 2000 - 1.4.0 +* [Jani Kajala] fixed bug in conversion with 4 -> 24 and 8 -> 32 +* [Jani Kajala] fixed bug in FreeImage_Flip +* [Jani Kajala] fixed minor bug in FreeImage_LoadBMP +- [Herve Drolon] removed PBMFlags, PGMFlags and PPMFlags +- [Herve Drolon] removed FI_LoadGeneric +- removed FreeImage_Win32.h +! [Herve Drolon] changed FI_GetFileType +! [Herve Drolon] replaced FI_LoadPBM, FI_LoadPGM and FI_LoadPPM with FI_LoadPNM +! [Herve Drolon] improved FreeImage_LoadPNG +! FreeImage_WritePaletteEntry is now exported ++ [Herve Drolon] added FreeImage_SavePNG ++ [Herve Drolon] added FreeImage_SavePNM and PNMFlags ++ [Herve Drolon] added XXXFlags parameter to save functions ++ [Herve Drolon] added FreeImage_LoadRAS and FIF_RAS ++ added FreeImage_GetFileTypeFromExt + +September 7th 2000 - 1.3.5 ++ added conversion 4 -> 8 to FI_ConvertTo8Bits ++ added simple version of FI_GetFileType ++ added project FreeImageQt; a port of the library to the TrollTech library + +August 31th 2000 - 1.3.4 +* fixed 'ice effect' bug in new 24 bit PCX code +* fixed some bugs with the conversion 16 -> 24 and 16 -> 32 +! FI_Blur now returns void +! A debug build of the library now produces FreeImaged.dll and FreeImaged.lib +! TARGA_LOAD_ARGB8888 is now called TARGA_LOAD_RGB888 +! Alpha channels are now automatically loaded unless TARGA_LOAD_RGB888 is specified +! cleaned up the code a lot ++ added 32-bit bitmap support to FreeImage_ConvertToGreyscale ++ added support for 32-bit bottom-left TARGA images ++ added internal functions FreeImage_WritePaletteEntry() and FreeImage_GetScanLine() ++ added FreeImage_Win32.h, containing Windows functions needed to create DIBs ++ added documentation through Doxygen + +July 30th 2000 - 1.3.3 +* [Jani Kajala] fixed some bugs with the conversion 4 -> 24 and 8 -> 24 +* [Jani Kajala] fixed some bugs with the conversion 4 -> 32 and 8 -> 32 +* fixed bug in FI_LoadPNM's ASCII number loader +! [Herve Drolon] improved FI_LoadPNG +! [Herve Drolon] changed FI_ConvertToGreyScale (added changeable macro for conversion) +! improved FI_ConvertTo24Bits +! improved FI_ConvertTo32Bits +! freeImage now uses LibPNG 1.0.8 ++ [Herve Drolon] added FI_ColorQuantize, based on Wu's color quantizer ++ added the conversion 1 -> 24 ++ added the conversion 1 -> 32 ++ added FI_ConvertTo8Bits ++ added FI_Invert (very useful for image processing) ++ added FI_GetColorType and 'enum FREE_IMAGE_COLOR_TYPE' + +June 30th 2000 - 1.3.2 +- removed color reduction functions from the project +! [Herve Drolon] Improved FI_LoadTIFF code +! renamed FI_ToGrayscale to FI_ConvertToGreyScale +! renamed FI_IncreaseColors to FI_ConvertTo24Bits +! LoadBMP now supports 32-bit bitmaps +! [Jani Kajala] Improved FI_LoadTARGA and FI_LoadPCX code ++ added FI_ConvertTo32Bits to convert a bitmap to 32-bit ++ added FI_MaskCombine to combine two 32-bit bitmaps using a alpha mask ++ added FI_AddAlphaMask to enrich a 32-bit bitmap with an alpha mask ++ added FI_SaveTIFF ++ added 16-bit bitmap (565) support to the ConvertToXXX functions. ++ added FI_ConvertTo16Bits (555 and 565) + +June 1th 2000 - 1.3.1 +- removed Standard Template Library (STL) code +* [Jani Kajala] fixed minor bug in FI_LoadTARGA +* [Jani Kajala] fixed some minor bugs in FI_LoadPCX +! streamlined FI_LoadJPEG a little +! FreeImage now uses LibPNG 1.0.6 +! FreeImage now uses LibTIFF 3.5.5 +! FreeImage now uses malloc and free instead of new and delete ++ introduced compiler flags to disable certain features in the DLL ++ added experimental nearest color reduction (FI_ReduceColorsNearestColor) + +April 13th 2000 - 1.3.0 +* fixed some 8 bit PCX files loading incorrectly +* fixed tiny bug in internally used CalculateUsedColors function +- removed FI_SaveXPM. Only BMP is supported now. +- removed Windows dependencies for easier porting +! optimized FI_LoadKOALA a little +! optimized FI_Combine using MMX technology +! FI_Combine now receives an 'unsigned integer' as alpha blend parameter +! FI_InCreaseColors and FI_ReduceColors don't dispose the old bitmap anymore ++ added PNM support (PGM, PPM and PBM; both binary and ascii) ++ [Alexander Dymerets] added FI_EnableMMX and FI_DisableMMX ++ added various effect functions (FI_Blur, FI_Brighten and FI_Crop) + +March 1st 2000 - 1.2.1 +* fixed some 24 bit PCX files loading incorrectly + +February 8th 2000 - 1.2.0 +* fixed last bitmap data block in JPEG files being truncated +* fixed 4/8 bit BMP's incorrectly loading when the palette is smaller than the bitcount predicts +- removed FI_Load. There is no reliable way to identify all image formats +- removed FI_SetJpegDecodeMode. + Mode selection is now done using the 'DataEnum data' parameter of FI_LoadJPEG +! read_proc/write_proc/tell_proc in FreeImageIO now are same as fread/fwrite/ftell ++ added a 'DataEnum data' parameter to all FI_LoadXXX functions. ++ added 16 bit TARGA support ++ added RLE support for TARGA images ++ added FI_GetDIBSize to get the size of a DIB in bytes ++ added Kodak PhotoCD support (Base, Base/4 and Base/16 encoding) ++ added KOALA support ++ added FI_GetFileType. Note: there is no reliable way to identify TARGA, ICO and PCD. Therefore they have been excluded +In KOALA files only the files converted by a C64 emulator can be identified. ++ added FI_Combine to combine two 24-bit bitmaps with (optional) alpha blending + +January 15th 2000 - 1.1.1 +! FI_Copy is now called FI_Clone ++ added FI_ToGrayscale to convert a color bitmap to grayscale ++ added 32 bit TARGA support ++ added FI_IncreaseColors to increase the bitmap bitdepth from 4/8 bit to 24 bit + +January 14th 2000 - 1.1.0 +* FI_MIRROR: fixed nibbles not being mirrored in 4 bit images +* FI_MIRROR: fixed bits not being mirrored in 1 bit images +* fixed improper loading of 1, 4 and 8 bit OS/2 BMP's +* fixed some inconsistensies in the calculation of lines and pitches +* fixed incorrectly loading of Huffman and FAX encoded TIFFs +* fixed LoadTGA accepting 16 bit TGA's and returning corrupt DIB's +- removed LZW support for TIFFs +! FreeImage now uses LibTIFF 3.5.4 ++ added ICO support ++ added overridable file I/O support in the form of FreeImageIO and fi_handle ++ added FI_Load for generic image loading ++ added FI_ReduceColors for color reduction ++ added FI_Copy to copy a bitmap in memory + +January 5th 2000 - 1.0.0 diff --git a/freeimage241/archive.bat b/freeimage241/archive.bat new file mode 100644 index 0000000..7ec461f --- /dev/null +++ b/freeimage241/archive.bat @@ -0,0 +1 @@ +C:\TOOLS\JAR32 a -m4 -r FreeImage diff --git a/freeimage241/clean.bat b/freeimage241/clean.bat new file mode 100644 index 0000000..19089e4 --- /dev/null +++ b/freeimage241/clean.bat @@ -0,0 +1,43 @@ +rd Release /s +rd Debug /s +rd Source\FreeImageQt\Release /s +rd Source\FreeImageQt\Debug /s +rd Source\Source\Release /s +rd Source\Source\Debug /s +rd Source\LibJPEG\Debug /s +rd Source\LibJPEG\Release /s +rd Source\LibPNG\Debug /s +rd Source\LibPNG\Release /s +rd Source\LibMNG\Debug /s +rd Source\LibMNG\Release /s +rd Source\LibTIFF\Debug /s +rd Source\LibTIFF\Release /s +rd Source\Zlib\Debug /s +rd Source\Zlib\Release /s +rd Source\Test\Debug /s +rd Source\Test\Release /s +del Source\Test\FreeImage*.* +del Source\Test\*.txt +del Dist\*.* +del *.pch /s +del *.ncb /s +del *.obj /s +del *.dll /s +del *.exe /s +del *.bsc /s +del *.bak /s +del *.pdb /s +del *.sql /s +del *.mdb /s +del *.lib /s +del *.exp /s +del *.ilk /s +del *.bmp /s +del *.tga /s +del *.tif /s +del *.tiff /s +del *.ras /s +del *.jpg /s +del *.koa /s +del *.fip /s +del *.pyd /s diff --git a/freeimage241/license-fi.txt b/freeimage241/license-fi.txt new file mode 100644 index 0000000..479fb4d --- /dev/null +++ b/freeimage241/license-fi.txt @@ -0,0 +1,142 @@ +FreeImage Public License - Version 1.0 +--------------------------------------------- + +1. Definitions. + +1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. + +1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. + +1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. + +1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. + +1.5. "Executable" means Covered Code in any form other than Source Code. + +1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. + +1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. + +1.8. "License" means this document. + +1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a +Modification is: + +A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. + +B. Any new file that contains any part of the Original Code or previous Modifications. + +1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. + +1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control +compilation and installation of an Executable, or a list of source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. + +1.12. "You" means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. + +2. Source Code License. + +2.1. The Initial Developer Grant. +The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: + +(a) to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, or as part of a Larger Work; and + +(b) under patents now or hereafter owned or controlled by Initial Developer, to make, have made, use and sell ("Utilize") the Original Code (or portions thereof), but solely to the extent that +any such patent is reasonably necessary to enable You to Utilize the Original Code (or portions thereof) and not to any greater extent that may be necessary to Utilize further Modifications or +combinations. + +2.2. Contributor Grant. +Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: + +(a) to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code or as part of a Larger Work; and + +(b) under patents now or hereafter owned or controlled by Contributor, to Utilize the Contributor Version (or portions thereof), but solely to the extent that any such patent is reasonably necessary to enable You to Utilize the Contributor Version (or portions thereof), and not to any greater extent that +may be necessary to Utilize further Modifications or combinations. + +3. Distribution Obligations. + +3.1. Application of License. +The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or +restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. + +3.2. Availability of Source Code. +Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. + +3.3. Description of Modifications. +You must cause all Covered Code to which you contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. + +3.4. Intellectual Property Matters + +(a) Third Party Claims. +If You have knowledge that a party claims an intellectual property right in particular functionality or code (or its utilization under this License), you must include a text file with the source code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If you obtain such knowledge after You make Your Modification available as described in Section 3.2, You shall promptly modify the LEGAL file in all copies You make +available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. + +(b) Contributor APIs. +If Your Modification is an application programming interface and You own or control patents which are reasonably necessary to implement that API, you must also include this information in the LEGAL file. + +3.5. Required Notices. +You must duplicate the notice in Exhibit A in each file of the Source Code, and this License in any documentation for the Source Code, where You describe recipients' rights relating to Covered Code. If You created one or more Modification(s), You may add your name as a Contributor to the notice described in Exhibit A. If it is not possible to put such notice in a particular Source Code file due to its +structure, then you must include such notice in a location (such as a relevant directory file) where a user would be likely to look for such a notice. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or +liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of +warranty, support, indemnity or liability terms You offer. + +3.6. Distribution of Executable Versions. +You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You +describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code under a license of Your choice, which may contain terms different from this License, +provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + +3.7. Larger Works. +You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. + +5. Application of this License. + +This License applies to code to which the Initial Developer has attached the notice in Exhibit A, and to related Covered Code. + +6. Versions of the License. + +6.1. New Versions. +Floris van den Berg may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. + +6.2. Effect of New Versions. +Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Floris van den Berg +No one other than Floris van den Berg has the right to modify the terms applicable to Covered Code created under this License. + +6.3. Derivative Works. +If you create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), you must (a) rename Your license so that the phrases "FreeImage", `FreeImage Public License", "FIPL", or any confusingly similar phrase do not appear anywhere in your license and (b) otherwise make it clear that your version of the license contains terms which differ from the FreeImage Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) + +7. DISCLAIMER OF WARRANTY. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + +This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + +9. LIMITATION OF LIABILITY. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + +The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. + +11. MISCELLANEOUS. + +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by Dutch law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in, the The Netherlands: (a) unless otherwise agreed in writing, all disputes relating to this License (excepting any dispute relating to intellectual property rights) shall be subject to final and binding arbitration, with the losing party paying all costs of arbitration; (b) any arbitration relating to this Agreement shall be held in Almelo, The Netherlands; and (c) any litigation relating to this Agreement shall be subject to the jurisdiction of the court of Almelo, The Netherlands with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. + +12. RESPONSIBILITY FOR CLAIMS. + +Except in cases where another Contributor has failed to comply with Section 3.4, You are responsible for damages arising, directly or indirectly, out of Your utilization of rights under this License, based +on the number of copies of Covered Code you made available, the revenues you received from utilizing such rights, and other relevant factors. You agree to work with affected parties to distribute +responsibility on an equitable basis. + +EXHIBIT A. + +"The contents of this file are subject to the FreeImage Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://home.wxs.nl/~flvdberg/freeimage-license.txt + +Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. \ No newline at end of file diff --git a/freeimage241/license-gpl.txt b/freeimage241/license-gpl.txt new file mode 100644 index 0000000..1bcc46f --- /dev/null +++ b/freeimage241/license-gpl.txt @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + + diff --git a/gxruntime/ddutil.cpp b/gxruntime/ddutil.cpp index 2932c70..133cfcf 100644 --- a/gxruntime/ddutil.cpp +++ b/gxruntime/ddutil.cpp @@ -7,7 +7,7 @@ extern gxRuntime *gx_runtime; -#include "..\..\freeimage241\source\freeimage.h" +#include "..\freeimage241\source\freeimage.h" static AsmCoder asm_coder; diff --git a/gxruntime/gxlight.cpp b/gxruntime/gxlight.cpp index 5c1e654..acedd44 100644 --- a/gxruntime/gxlight.cpp +++ b/gxruntime/gxlight.cpp @@ -7,7 +7,7 @@ const float PI=3.14159265359f; //180 degrees const float TWOPI=PI*2.0f; //360 degrees const float HALFPI=PI*.5f; //90 degrees -const float EPSILON=.000001f; +const float FLT_EPSILON=.000001f; gxLight::gxLight( gxScene *s,int type ): scene(s){ diff --git a/gxruntime/gxruntime.vcxproj b/gxruntime/gxruntime.vcxproj new file mode 100644 index 0000000..7ba3e7f --- /dev/null +++ b/gxruntime/gxruntime.vcxproj @@ -0,0 +1,283 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {FF2D8BF7-1930-4CAB-BC48-05CD33B7DC18} + 10.0.10586.0 + + + + Application + v140 + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\gxruntime___Win32_Blitz2DRelease\ + .\gxruntime___Win32_Blitz2DRelease\ + false + + + .\gxruntime___Win32_Blitz3DRelease\ + .\gxruntime___Win32_Blitz3DRelease\ + false + + + .\Release\ + .\Release\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\gxruntime___Win32_Blitz2DRelease\ + .\gxruntime___Win32_Blitz2DRelease\gxruntime.pch + Use + std.h + .\gxruntime___Win32_Blitz2DRelease\ + .\gxruntime___Win32_Blitz2DRelease\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\gxruntime___Win32_Blitz2DRelease\gxruntime.bsc + + + true + .\gxruntime___Win32_Blitz2DRelease\gxruntime.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + _LIB;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\gxruntime___Win32_Blitz3DRelease\ + .\gxruntime___Win32_Blitz3DRelease\gxruntime.pch + + .\gxruntime___Win32_Blitz3DRelease\ + .\gxruntime___Win32_Blitz3DRelease\ + StdCall + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\gxruntime___Win32_Blitz3DRelease\gxruntime.bsc + + + true + .\gxruntime___Win32_Blitz3DRelease\gxruntime.lib + + + + + MultiThreaded + AnySuitable + true + MaxSpeed + true + Level3 + true + Size + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\gxruntime.pch + Use + std.h + .\Release\ + .\Release\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\gxruntime.bsc + + + true + .\Release\gxruntime.lib + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\gxruntime.pch + Use + std.h + .\Debug\ + .\Debug\ + EnableFastChecks + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\gxruntime.bsc + + + true + .\Debug\gxruntime.lib + + + + + + + + + + + + + + + + + + AssemblyAndSourceCode + AssemblyAndSourceCode + AssemblyAndSourceCode + + + + + + Create + std.h + Create + std.h + Create + std.h + Create + std.h + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gxruntime/gxruntime.vcxproj.filters b/gxruntime/gxruntime.vcxproj.filters new file mode 100644 index 0000000..fd7366c --- /dev/null +++ b/gxruntime/gxruntime.vcxproj.filters @@ -0,0 +1,128 @@ + + + + + {0a89eb89-90ea-49da-a7a1-d91131308af2} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {5df1f954-acd9-4c0c-b094-6f70a5211be9} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/gxruntime/std.h b/gxruntime/std.h index 157d843..78be9f3 100644 --- a/gxruntime/std.h +++ b/gxruntime/std.h @@ -2,7 +2,7 @@ #ifndef STD_H #define STD_H -#include "../../fmodapi375win/api/inc/fmod.h" +#include "../fmodapi375win/api/inc/fmod.h" #include "../config/config.h" #include "../stdutil/stdutil.h" diff --git a/linker/linker.vcxproj b/linker/linker.vcxproj new file mode 100644 index 0000000..5f2bb87 --- /dev/null +++ b/linker/linker.vcxproj @@ -0,0 +1,252 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {0B629BA3-D138-407A-801D-DBE7C8DC4324} + 10.0.10586.0 + + + + Application + v140 + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + .\Release\ + .\Release\ + false + + + .\linker___Win32_Blitz2DRelease\ + .\linker___Win32_Blitz2DRelease\ + false + + + .\linker___Win32_Blitz3DRelease\ + .\linker___Win32_Blitz3DRelease\ + false + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\linker.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\linker.bsc + + + true + .\Debug\linker.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\linker.pch + Use + std.h + .\Release\ + .\Release\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\linker.bsc + + + true + .\Release\linker.lib + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\linker___Win32_Blitz2DRelease\ + .\linker___Win32_Blitz2DRelease\linker.pch + Use + std.h + .\linker___Win32_Blitz2DRelease\ + .\linker___Win32_Blitz2DRelease\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\linker___Win32_Blitz2DRelease\linker.bsc + + + true + .\linker___Win32_Blitz2DRelease\linker.lib + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _LIB;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\linker___Win32_Blitz3DRelease\ + .\linker___Win32_Blitz3DRelease\linker.pch + + .\linker___Win32_Blitz3DRelease\ + .\linker___Win32_Blitz3DRelease\ + StdCall + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\linker___Win32_Blitz3DRelease\linker.bsc + + + true + .\linker___Win32_Blitz3DRelease\linker.lib + + + + + + + Create + std.h + Create + std.h + Create + std.h + + + + + + + + + + {3e355353-96d8-4aaf-bf95-8e6ca0d4b1ba} + false + + + {6bcfc5ca-ea71-4ae9-8b96-28b8701f939e} + false + + + + + + \ No newline at end of file diff --git a/linker_dll/linker_dll.vcxproj b/linker_dll/linker_dll.vcxproj new file mode 100644 index 0000000..ee307c3 --- /dev/null +++ b/linker_dll/linker_dll.vcxproj @@ -0,0 +1,283 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {778BCC7F-40F9-4309-9A88-C0F60D9B364D} + 10.0.10586.0 + + + + Application + v140 + + + DynamicLibrary + v140 + false + MultiByte + + + DynamicLibrary + v140 + false + MultiByte + + + DynamicLibrary + v140 + false + MultiByte + + + DynamicLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\linker_dll___Win32_Blitz3DRelease\ + .\linker_dll___Win32_Blitz3DRelease\ + false + + + .\linker_dll___Win32_Blitz2DRelease\ + .\linker_dll___Win32_Blitz2DRelease\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + false + + + .\Release\ + .\Release\ + false + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + _WINDOWS;_USRDLL;LINKER_DLL_EXPORTS;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\linker_dll___Win32_Blitz3DRelease\ + .\linker_dll___Win32_Blitz3DRelease\linker_dll.pch + .\linker_dll___Win32_Blitz3DRelease\ + .\linker_dll___Win32_Blitz3DRelease\ + StdCall + + + true + NDEBUG;%(PreprocessorDefinitions) + .\linker_dll___Win32_Blitz3DRelease\linker_dll.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\linker_dll___Win32_Blitz3DRelease\linker_dll.bsc + + + true + true + Console + ../_release/bin/linker.dll + .\linker_dll___Win32_Blitz3DRelease\linker.lib + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + Default + true + true + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;LINKER_DLL_EXPORTS;%(PreprocessorDefinitions) + .\linker_dll___Win32_Blitz2DRelease\ + .\linker_dll___Win32_Blitz2DRelease\linker_dll.pch + .\linker_dll___Win32_Blitz2DRelease\ + .\linker_dll___Win32_Blitz2DRelease\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\linker_dll___Win32_Blitz2DRelease\linker_dll.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\linker_dll___Win32_Blitz2DRelease\linker_dll.bsc + + + true + true + Console + ..\..\release\blitz2drelease\bin\linker.dll + .\linker_dll___Win32_Blitz2DRelease\linker.lib + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_WINDOWS;_USRDLL;LINKER_DLL_EXPORTS;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\linker_dll.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\linker_dll.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\linker_dll.bsc + + + true + true + true + Console + ..\blitzbasic\bin\linker.dll + .\Debug\linker.lib + /FIXED:NO + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;LINKER_DLL_EXPORTS;%(PreprocessorDefinitions) + .\Release\ + .\Release\linker_dll.pch + .\Release\ + .\Release\ + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\linker_dll.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\linker_dll.bsc + + + true + true + Console + ..\blitzbasic\bin\linker.dll + .\Release\linker.lib + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + {3e355353-96d8-4aaf-bf95-8e6ca0d4b1ba} + false + + + {0b629ba3-d138-407a-801d-dbe7c8dc4324} + false + + + {6bcfc5ca-ea71-4ae9-8b96-28b8701f939e} + false + + + + + + \ No newline at end of file diff --git a/stdutil/stdutil.vcxproj b/stdutil/stdutil.vcxproj new file mode 100644 index 0000000..38c2290 --- /dev/null +++ b/stdutil/stdutil.vcxproj @@ -0,0 +1,235 @@ + + + + + Blitz2DRelease + Win32 + + + Blitz3DRelease + Win32 + + + Debug + Win32 + + + Release + Win32 + + + Template + Win32 + + + + + + {6BCFC5CA-EA71-4AE9-8B96-28B8701F939E} + 10.0.10586.0 + + + + Application + v140 + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + StaticLibrary + v140 + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + .\Release\ + .\Release\ + false + + + ..\#Build\$(ProjectName)\$(ConfigurationName)\ + ..\#Intermediate\$(ProjectName)\$(ConfigurationName)\ + true + + + .\stdutil___Win32_Blitz2DRelease\ + .\stdutil___Win32_Blitz2DRelease\ + false + + + .\stdutil___Win32_Blitz3DRelease\ + .\stdutil___Win32_Blitz3DRelease\ + false + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\Release\ + .\Release\stdutil.pch + + .\Release\ + .\Release\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\stdutil.bsc + + + true + .\Release\stdutil.lib + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + .\Debug\ + .\Debug\stdutil.pch + .\Debug\ + .\Debug\ + EnableFastChecks + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\stdutil.bsc + + + true + .\Debug\stdutil.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\stdutil___Win32_Blitz2DRelease\ + .\stdutil___Win32_Blitz2DRelease\stdutil.pch + + .\stdutil___Win32_Blitz2DRelease\ + .\stdutil___Win32_Blitz2DRelease\ + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\stdutil___Win32_Blitz2DRelease\stdutil.bsc + + + true + .\stdutil___Win32_Blitz2DRelease\stdutil.lib + + + + + MultiThreaded + AnySuitable + true + true + MaxSpeed + true + Level3 + _LIB;WIN32;NDEBUG;PRO;%(PreprocessorDefinitions) + .\stdutil___Win32_Blitz3DRelease\ + .\stdutil___Win32_Blitz3DRelease\stdutil.pch + + .\stdutil___Win32_Blitz3DRelease\ + .\stdutil___Win32_Blitz3DRelease\ + StdCall + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\stdutil___Win32_Blitz3DRelease\stdutil.bsc + + + true + .\stdutil___Win32_Blitz3DRelease\stdutil.lib + + + + + + + + + + + {3e355353-96d8-4aaf-bf95-8e6ca0d4b1ba} + false + + + + + + \ No newline at end of file